From 8312adafc93146128133de3c5fdff86a6abdc0b2 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Mon, 11 Sep 2023 15:18:30 +0200 Subject: [PATCH] Initial commit --- .editorconfig | 29 - .github/CONTRIBUTING.md | 45 - .github/ISSUE_TEMPLATE.md | 20 - .github/ISSUE_TEMPLATE/bug_report.md | 17 - .github/ISSUE_TEMPLATE/feature_request.md | 20 - .github/dependabot.yml | 6 - .github/workflows/codeql.yaml | 49 - .github/workflows/deploy-docs.yml | 53 + .github/workflows/maven.yml | 32 - .gitignore | 64 +- .mvn/maven.config | 1 - .mvn/wrapper/maven-wrapper.jar | Bin 58727 -> 50710 bytes .mvn/wrapper/maven-wrapper.properties | 20 +- .sdkmanrc | 3 - .settings.xml | 77 - LICENSE | 202 - README.adoc | 389 +- ...antora-playbook.yml => antora-playbook.yml | 33 +- asciidoctor.css | 2011 ------- config/releaser.yml | 5 - docker/pom.xml | 72 - .../spring-cloud-contract-docker/Dockerfile | 45 - .../build_adocs.sh | 12 - .../get_dependencies.sh | 27 - docker/spring-cloud-contract-docker/pom.xml | 231 - .../.gradle/7.5.1/checksums/checksums.lock | Bin 0 -> 17 bytes .../.gradle/7.5.1/checksums/md5-checksums.bin | Bin 0 -> 24797 bytes .../7.5.1/checksums/sha1-checksums.bin | Bin 0 -> 25571 bytes .../dependencies-accessors.lock | Bin 0 -> 17 bytes .../dependencies-accessors/gc.properties | 0 .../.gradle/7.5.1/fileChanges/last-build.bin | Bin 0 -> 1 bytes .../.gradle/7.5.1/fileHashes/fileHashes.bin | Bin 0 -> 18947 bytes .../.gradle/7.5.1/fileHashes/fileHashes.lock | Bin 0 -> 17 bytes .../project/.gradle/7.5.1/gc.properties | 0 .../.gradle/8.3/checksums/checksums.lock | Bin 0 -> 17 bytes .../.gradle/8.3/checksums/md5-checksums.bin | Bin 0 -> 25497 bytes .../.gradle/8.3/checksums/sha1-checksums.bin | Bin 0 -> 26057 bytes .../dependencies-accessors.lock | Bin 0 -> 17 bytes .../8.3/dependencies-accessors/gc.properties | 0 .../8.3/executionHistory/executionHistory.bin | Bin 0 -> 19735 bytes .../executionHistory/executionHistory.lock | Bin 0 -> 17 bytes .../.gradle/8.3/fileChanges/last-build.bin | Bin 0 -> 1 bytes .../.gradle/8.3/fileHashes/fileHashes.bin | Bin 0 -> 19147 bytes .../.gradle/8.3/fileHashes/fileHashes.lock | Bin 0 -> 17 bytes .../8.3/fileHashes/resourceHashesCache.bin | Bin 0 -> 18599 bytes .../project/.gradle/8.3/gc.properties | 0 .../buildOutputCleanup.lock | Bin 0 -> 17 bytes .../buildOutputCleanup/cache.properties | 2 + .../buildOutputCleanup/outputFiles.bin | Bin 0 -> 18749 bytes .../project/.gradle/file-system.probe | Bin 0 -> 8 bytes .../project/.gradle/vcs-1/gc.properties | 0 .../project/.idea/.gitignore | 8 + .../project/.idea/codeStyles/Project.xml | 89 + .../.idea/codeStyles/codeStyleConfig.xml | 5 + .../project/.idea/compiler.xml | 6 + .../project/.idea/gradle.xml | 20 + .../project/.idea/jarRepositories.xml | 40 + .../project/.idea/misc.xml | 8 + .../59f81c123b3abbcb97274545796dd18706c3e106 | 0 .../f07866736216be0ee2aba49e392191aeae700a35 | 0 .../.idea/sonarlint/issuestore/index.pb | 5 + .../project/.idea/vcs.xml | 6 + .../project/README.adoc | 24 - .../project/build.gradle | 269 - .../project/build.sh | 17 - .../7.2/executionHistory/executionHistory.bin | Bin 0 -> 31363 bytes .../executionHistory/executionHistory.lock | Bin 0 -> 17 bytes .../executionHistory/executionHistory.bin | Bin 0 -> 31752 bytes .../executionHistory/executionHistory.lock | Bin 0 -> 17 bytes .../7.3/executionHistory/executionHistory.bin | Bin 0 -> 41634 bytes .../executionHistory/executionHistory.lock | Bin 0 -> 17 bytes .../.gradle/7.4.1/checksums/checksums.lock | Bin 0 -> 17 bytes .../.gradle/7.4.1/checksums/md5-checksums.bin | Bin 0 -> 18697 bytes .../7.4.1/checksums/sha1-checksums.bin | Bin 0 -> 18713 bytes .../dependencies-accessors.lock | Bin 0 -> 17 bytes .../dependencies-accessors/gc.properties | 0 .../executionHistory/executionHistory.bin | Bin 0 -> 41970 bytes .../executionHistory/executionHistory.lock | Bin 0 -> 17 bytes .../.gradle/7.4.1/fileChanges/last-build.bin | Bin 0 -> 1 bytes .../.gradle/7.4.1/fileHashes/fileHashes.lock | Bin 0 -> 17 bytes .../buildSrc/.gradle/7.4.1/gc.properties | 0 .../.gradle/7.5.1/checksums/checksums.lock | Bin 0 -> 17 bytes .../.gradle/7.5.1/checksums/md5-checksums.bin | Bin 0 -> 18697 bytes .../7.5.1/checksums/sha1-checksums.bin | Bin 0 -> 18713 bytes .../dependencies-accessors.lock | Bin 0 -> 17 bytes .../dependencies-accessors/gc.properties | 0 .../executionHistory/executionHistory.bin | Bin 0 -> 31507 bytes .../executionHistory/executionHistory.lock | Bin 0 -> 17 bytes .../.gradle/7.5.1/fileChanges/last-build.bin | Bin 0 -> 1 bytes .../.gradle/7.5.1/fileHashes/fileHashes.lock | Bin 0 -> 17 bytes .../buildSrc/.gradle/7.5.1/gc.properties | 0 .../8.3/executionHistory/executionHistory.bin | Bin 0 -> 29963 bytes .../executionHistory/executionHistory.lock | Bin 0 -> 17 bytes .../buildOutputCleanup.lock | Bin 0 -> 17 bytes .../buildOutputCleanup/cache.properties | 2 + .../buildOutputCleanup/outputFiles.bin | Bin 0 -> 18965 bytes .../buildSrc/.gradle/file-system.probe | Bin 0 -> 8 bytes .../buildSrc/.gradle/noVersion/buildSrc.lock | Bin 0 -> 2 bytes .../buildSrc/.gradle/vcs-1/gc.properties | 0 .../project/buildSrc/build.gradle | 21 - .../main/java/contracts/DocsFromSources.java | 160 - .../project/gradle.properties | 4 - .../project/gradle/wrapper/gradle-wrapper.jar | Bin 63721 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - .../project/gradlew | 249 - .../project/gradlew.bat | 92 - .../java/contracts/ContractTestsBase.java | 183 - .../java/contracts/MessagingAutoConfig.java | 192 - ...ot.autoconfigure.AutoConfiguration.imports | 1 - .../resources/application-messagingtype.yml | 1 - .../sdkman.config | 8 - .../sdkman/sdkman-wrapper.sh | 7 - .../Dockerfile | 40 - .../log.log | 176 + .../pom.xml | 301 - .../run.sh | 18 - .../sdkman.config | 8 - .../sdkman/sdkman-wrapper.sh | 7 - docs/.github/workflows/deploy-docs.yml | 32 - docs/antora.yml | 12 - docs/modules/ROOT/assets/images/Deps.png | Bin 37192 -> 0 bytes docs/modules/ROOT/assets/images/Stubs1.png | Bin 35170 -> 0 bytes docs/modules/ROOT/assets/images/Stubs2.png | Bin 18143 -> 0 bytes .../images/start_spring_io_dependencies.png | Bin 347308 -> 0 bytes docs/modules/ROOT/nav.adoc | 84 - docs/modules/ROOT/pages/README.adoc | 22 - .../_additional-stubrunner-configprops.adoc | 17 - docs/modules/ROOT/pages/_attributes.adoc | 36 - docs/modules/ROOT/pages/_building.adoc | 145 - docs/modules/ROOT/pages/_configprops.adoc | 47 - docs/modules/ROOT/pages/_index.adoc | 18 - docs/modules/ROOT/pages/_index_pdf.adoc | 6 - docs/modules/ROOT/pages/_index_single.adoc | 7 - .../pages/_project-features-contract.adoc | 50 - .../common-top-elements.adoc | 305 - .../_project-features-contract/dsl-async.adoc | 134 - .../dsl-dynamic-properties.adoc | 797 --- .../dsl-http-top-level-elements.adoc | 45 - .../dsl-multiple.adoc | 134 - .../dsl-request.adoc | 271 - .../dsl-response.adoc | 41 - .../_project-features-contract/dsl-xml.adoc | 121 - .../_project-features-contract/groovy.adoc | 18 - .../_project-features-contract/java.adoc | 33 - .../_project-features-contract/kotlin.adoc | 73 - .../limitations.adoc | 13 - .../stateful-contracts.adoc | 38 - .../pages/_project-features-contract/yml.adoc | 6 - .../ROOT/pages/_project-features-flows.adoc | 5 - .../context-paths.adoc | 62 - .../_project-features-flows/custom-mode.adoc | 104 - .../feature-webflux-explicit.adoc | 46 - .../feature-webflux.adoc | 53 - .../_project-features-flows/graphql.adoc | 185 - .../pages/_project-features-flows/grpc.adoc | 277 - .../pages/_project-features-flows/jax-rs.adoc | 26 - .../_project-features-flows/rest-docs.adoc | 307 - .../pages/_project-features-messaging.adoc | 621 -- .../pages/_project-features-stubrunner.adoc | 12 - .../stub-runner-boot.adoc | 131 - .../stub-runner-cloud.adoc | 63 - .../stub-runner-common.adoc | 60 - .../stub-runner-core.adoc | 304 - .../stub-runner-fail-on-no-stubs.adoc | 39 - ...stub-runner-generate-stubs-at-runtime.adoc | 43 - .../stub-runner-junit.adoc | 167 - .../stub-runner-publishing-stubs-as-jars.adoc | 32 - .../stub-runner-snapshot-versions.adoc | 21 - .../stub-runner-stubs-per-consumer.adoc | 98 - .../stub-runner-stubs-protocol.adoc | 121 - .../pages/_project-features-wiremock.adoc | 201 - docs/modules/ROOT/pages/advanced.adoc | 462 -- docs/modules/ROOT/pages/appendix.adoc | 20 - docs/modules/ROOT/pages/docker-project.adoc | 627 -- .../ROOT/pages/documentation-overview.adoc | 129 - docs/modules/ROOT/pages/getting-started.adoc | 10 - .../ROOT/pages/getting-started/cdc.adoc | 588 -- .../getting-started/first-application.adoc | 491 -- .../introducing-spring-cloud-contract.adoc | 126 - .../getting-started/three-second-tour.adoc | 176 - .../pages/getting-started/whats-next.adoc | 30 - docs/modules/ROOT/pages/gradle-project.adoc | 563 -- docs/modules/ROOT/pages/howto.adoc | 16 - .../pages/howto/contract-dsl-rest-docs.adoc | 40 - .../how-to-common-repo-with-contracts.adoc | 310 - .../pages/howto/how-to-debug-wiremock.adoc | 18 - .../ROOT/pages/howto/how-to-debug.adoc | 19 - .../howto/how-to-do-stubs-versioning.adoc | 98 - .../howto/how-to-generate-pact-from-scc.adoc | 67 - .../how-to-generate-stubs-at-runtime.adoc | 6 - .../how-to-mark-contract-in-progress.adoc | 7 - .../how-to-not-write-contracts-in-groovy.adoc | 8 - .../howto/how-to-provide-dynamic-values.adoc | 106 - .../how-to-reference-text-from-file.adoc | 8 - .../howto/how-to-see-registered-stubs.adoc | 8 - .../howto/how-to-use-git-as-storage.adoc | 279 - .../how-to-use-stubs-from-a-location.adoc | 6 - .../how-to-use-the-failonnostubs-feature.adoc | 8 - .../howto/how-to-work-with-transitivie.adoc | 49 - .../howto/why-spring-cloud-contract.adoc | 17 - docs/modules/ROOT/pages/legal.adoc | 13 - docs/modules/ROOT/pages/maven-project.adoc | 661 --- docs/modules/ROOT/pages/project-features.adoc | 34 - docs/modules/ROOT/pages/sagan-boot.adoc | 105 - docs/modules/ROOT/pages/sagan-index.adoc | 69 - .../ROOT/pages/spring-cloud-contract.adoc | 18 - docs/modules/ROOT/pages/using.adoc | 869 --- docs/modules/ROOT/pages/yml-schema.adoc | 14 - docs/pom.xml | 221 - docs/src/main/asciidoc/ghpages.sh | 330 -- docs/src/main/asciidoc/images/Deps.png | Bin 37192 -> 0 bytes docs/src/main/asciidoc/images/Stubs1.png | Bin 35170 -> 0 bytes docs/src/main/asciidoc/images/Stubs2.png | Bin 18143 -> 0 bytes .../images/start_spring_io_dependencies.png | Bin 347308 -> 0 bytes docs/src/main/asciidoc/index.htmladoc | 1 - docs/src/main/asciidoc/index.htmlsingleadoc | 1 - docs/src/main/asciidoc/index.pdfadoc | 1 - .../spring-cloud-contract.htmlsingleadoc | 17 - .../asciidoc/spring-cloud-contract.pdfadoc | 17 - .../cloud/contract/docs/Main.java | 157 - .../AdditionalResourcesGenerationTests.java | 104 - docs/src/test/resources/contract.yml | 72 - ideas.md | 17 - log.log | 116 + mvnw | 18 +- mvnw.cmd | 370 +- pom.xml | 737 +-- samples/pom.xml | 137 - samples/src/it/settings.xml | 41 - samples/standalone/.idea/.gitignore | 8 + .../standalone/.idea/codeStyles/Project.xml | 89 + .../.idea/codeStyles/codeStyleConfig.xml | 5 + samples/standalone/.idea/compiler.xml | 29 + samples/standalone/.idea/encodings.xml | 21 + samples/standalone/.idea/jarRepositories.xml | 50 + samples/standalone/.idea/misc.xml | 12 + .../.idea/sonarlint/issuestore/index.pb | 0 samples/standalone/.idea/vcs.xml | 6 + samples/standalone/.mvn/jvm.config | 1 - samples/standalone/.mvn/maven.config | 1 - .../.mvn/wrapper/MavenWrapperDownloader.java | 117 - .../standalone/.mvn/wrapper/maven-wrapper.jar | Bin 58727 -> 0 bytes .../.mvn/wrapper/maven-wrapper.properties | 18 - samples/standalone/README.adoc | 20 - .../contracts/.mvn/wrapper/maven-wrapper.jar | Bin 49519 -> 0 bytes .../.mvn/wrapper/maven-wrapper.properties | 1 - samples/standalone/contracts/README.adoc | 68 - samples/standalone/contracts/build.log | 45 + .../example/server/client1/expectation.groovy | 82 - .../example/server/client2/expectation.groovy | 83 - .../example/server/client3/expectation.groovy | 83 - .../contracts/com/example/server/pom.xml | 109 - samples/standalone/contracts/mvnw | 234 - samples/standalone/contracts/mvnw.cmd | 145 - samples/standalone/contracts/pom.xml | 44 - .../contracts/src/assembly/contracts.xml | 23 - samples/standalone/dsl/build.log | 5071 +++++++++++++++++ samples/standalone/dsl/http-client/.gitignore | 6 - .../.gradle/8.1.1/checksums/checksums.lock | Bin 0 -> 17 bytes .../.gradle/8.1.1/checksums/md5-checksums.bin | Bin 0 -> 25597 bytes .../8.1.1/checksums/sha1-checksums.bin | Bin 0 -> 30755 bytes .../dependencies-accessors.lock | Bin 0 -> 17 bytes .../dependencies-accessors/gc.properties | 0 .../executionHistory/executionHistory.bin | Bin 0 -> 441670 bytes .../executionHistory/executionHistory.lock | Bin 0 -> 17 bytes .../.gradle/8.1.1/fileChanges/last-build.bin | Bin 0 -> 1 bytes .../.gradle/8.1.1/fileHashes/fileHashes.bin | Bin 0 -> 23547 bytes .../.gradle/8.1.1/fileHashes/fileHashes.lock | Bin 0 -> 17 bytes .../8.1.1/fileHashes/resourceHashesCache.bin | Bin 0 -> 22645 bytes .../http-client/.gradle/8.1.1/gc.properties | 0 .../.gradle/8.3/checksums/checksums.lock | Bin 0 -> 17 bytes .../.gradle/8.3/checksums/md5-checksums.bin | Bin 0 -> 23697 bytes .../.gradle/8.3/checksums/sha1-checksums.bin | Bin 0 -> 26489 bytes .../dependencies-accessors.lock | Bin 0 -> 17 bytes .../8.3/dependencies-accessors/gc.properties | 0 .../8.3/executionHistory/executionHistory.bin | Bin 0 -> 182232 bytes .../executionHistory/executionHistory.lock | Bin 0 -> 17 bytes .../.gradle/8.3/fileChanges/last-build.bin | Bin 0 -> 1 bytes .../.gradle/8.3/fileHashes/fileHashes.bin | Bin 0 -> 21997 bytes .../.gradle/8.3/fileHashes/fileHashes.lock | Bin 0 -> 17 bytes .../8.3/fileHashes/resourceHashesCache.bin | Bin 0 -> 21489 bytes .../dsl/http-client/.gradle/8.3/gc.properties | 0 .../buildOutputCleanup.lock | Bin 0 -> 17 bytes .../buildOutputCleanup/cache.properties | 2 + .../buildOutputCleanup/outputFiles.bin | Bin 0 -> 19037 bytes .../.gradle/checksums/checksums.lock | Bin 0 -> 17 bytes .../.gradle/checksums/md5-checksums.bin | Bin 0 -> 23497 bytes .../.gradle/checksums/sha1-checksums.bin | Bin 0 -> 26111 bytes .../dsl/http-client/.gradle/file-system.probe | Bin 0 -> 8 bytes .../http-client/.gradle/vcs-1/gc.properties | 0 .../dsl/http-client/.mvn/jvm.config | 1 - .../dsl/http-client/.mvn/maven.config | 1 - .../.mvn/wrapper/MavenWrapperDownloader.java | 117 - .../.mvn/wrapper/maven-wrapper.jar | Bin 58727 -> 0 bytes .../.mvn/wrapper/maven-wrapper.properties | 18 - .../standalone/dsl/http-client/README.adoc | 26 - .../standalone/dsl/http-client/build.gradle | 65 - .../dsl/http-client/gradle.properties | 3 - .../gradle/wrapper/gradle-wrapper.jar | Bin 62076 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 - samples/standalone/dsl/http-client/gradlew | 245 - .../standalone/dsl/http-client/gradlew.bat | 92 - samples/standalone/dsl/http-client/mvnw | 316 - samples/standalone/dsl/http-client/mvnw.cmd | 188 - samples/standalone/dsl/http-client/pom.xml | 253 - .../dsl/http-client/settings.gradle | 15 - .../java/com/example/loan/Application.java | 29 - .../main/java/com/example/loan/Listener.java | 41 - .../example/loan/LoanApplicationService.java | 126 - .../java/com/example/loan/SensorData.java | 44 - .../java/com/example/loan/model/Client.java | 38 - .../example/loan/model/FraudCheckStatus.java | 23 - .../loan/model/FraudServiceRequest.java | 54 - .../loan/model/FraudServiceResponse.java | 47 - .../example/loan/model/LoanApplication.java | 61 - .../loan/model/LoanApplicationResult.java | 50 - .../loan/model/LoanApplicationStatus.java | 23 - .../java/com/example/loan/model/Response.java | 38 - .../src/main/resources/application.yml | 7 - .../com/example/loan/GoodbyeWorldTests.java | 55 - ...oanApplicationServiceContextPathTests.java | 70 - .../loan/LoanApplicationServiceTests.java | 228 - .../example/loan/MessageConsumedTests.java | 58 - .../com/example/loan/TestControllerTests.java | 55 - .../test/resources/application-gradle.yaml | 3 - .../test/resources/application-test-repo.yaml | 3 - .../src/test/resources/application.yaml | 5 - .../src/test/resources/binary/request.pdf | Bin 14631 -> 0 bytes .../src/test/resources/binary/response.pdf | Bin 15767 -> 0 bytes .../contractsAtRuntime/goodbyeWorld.groovy | 28 - samples/standalone/dsl/http-server/.gitignore | 6 - .../.gradle/8.1.1/checksums/checksums.lock | Bin 0 -> 17 bytes .../.gradle/8.1.1/checksums/md5-checksums.bin | Bin 0 -> 25997 bytes .../8.1.1/checksums/sha1-checksums.bin | Bin 0 -> 27137 bytes .../dependencies-accessors.lock | Bin 0 -> 17 bytes .../dependencies-accessors/gc.properties | 0 .../.gradle/8.1.1/fileChanges/last-build.bin | Bin 0 -> 1 bytes .../.gradle/8.1.1/fileHashes/fileHashes.lock | Bin 0 -> 17 bytes .../http-server/.gradle/8.1.1/gc.properties | 0 .../.gradle/8.3/checksums/checksums.lock | Bin 0 -> 17 bytes .../.gradle/8.3/checksums/md5-checksums.bin | Bin 0 -> 41897 bytes .../.gradle/8.3/checksums/sha1-checksums.bin | Bin 0 -> 97493 bytes .../dependencies-accessors.lock | Bin 0 -> 17 bytes .../8.3/dependencies-accessors/gc.properties | 0 .../8.3/executionHistory/executionHistory.bin | Bin 0 -> 694829 bytes .../executionHistory/executionHistory.lock | Bin 0 -> 17 bytes .../.gradle/8.3/fileChanges/last-build.bin | Bin 0 -> 1 bytes .../.gradle/8.3/fileHashes/fileHashes.bin | Bin 0 -> 31847 bytes .../.gradle/8.3/fileHashes/fileHashes.lock | Bin 0 -> 17 bytes .../8.3/fileHashes/resourceHashesCache.bin | Bin 0 -> 24719 bytes .../dsl/http-server/.gradle/8.3/gc.properties | 0 .../buildOutputCleanup.lock | Bin 0 -> 17 bytes .../buildOutputCleanup/cache.properties | 2 + .../buildOutputCleanup/outputFiles.bin | Bin 0 -> 19775 bytes .../dsl/http-server/.gradle/file-system.probe | Bin 0 -> 8 bytes .../http-server/.gradle/vcs-1/gc.properties | 0 .../dsl/http-server/.idea/.gitignore | 8 + .../http-server/.idea/codeStyles/Project.xml | 89 + .../.idea/codeStyles/codeStyleConfig.xml | 5 + .../dsl/http-server/.idea/compiler.xml | 21 + .../dsl/http-server/.idea/encodings.xml | 7 + .../dsl/http-server/.idea/jarRepositories.xml | 35 + .../libraries/Maven__cglib_cglib_3_3_0.xml | 13 + ...__ch_qos_logback_logback_classic_1_4_5.xml | 13 + ...ven__ch_qos_logback_logback_core_1_4_5.xml | 13 + .../Maven__com_fasterxml_classmate_1_5_1.xml | 13 + ...ackson_core_jackson_annotations_2_14_1.xml | 13 + ...erxml_jackson_core_jackson_core_2_14_1.xml | 13 + ...l_jackson_core_jackson_databind_2_14_1.xml | 13 + ...aformat_jackson_dataformat_yaml_2_14_1.xml | 13 + ..._datatype_jackson_datatype_jdk8_2_14_1.xml | 13 + ...atatype_jackson_datatype_jsr310_2_14_1.xml | 13 + ..._jackson_module_parameter_names_2_14_1.xml | 13 + ...en__com_github_jknack_handlebars_4_3_0.xml | 13 + ...ehurst_wiremock_jre8_standalone_2_35_0.xml | 13 + .../Maven__com_ibm_icu_icu4j_4_6.xml | 13 + ...n__com_jayway_jsonpath_json_path_2_7_0.xml | 13 + ...Maven__com_rabbitmq_amqp_client_5_16_0.xml | 13 + ...lipse_wst_xml_xpath2_processor_2_1_100.xml | 13 + ...muchcoding_jsonassert_jsonassert_0_6_2.xml | 13 + ...ogle_android_json_0_0_20131108_vaadin1.xml | 13 + ...mons_beanutils_commons_beanutils_1_9_4.xml | 13 + ...aven__commons_codec_commons_codec_1_15.xml | 13 + ..._collections_commons_collections_3_2_2.xml | 13 + ...n__commons_logging_commons_logging_1_2.xml | 13 + .../Maven__dk_brics_automaton_1_12_4.xml | 13 + .../Maven__edu_princeton_cup_java_cup_10k.xml | 13 + ...o_micrometer_micrometer_commons_1_10_2.xml | 13 + ...__io_micrometer_micrometer_core_1_10_2.xml | 13 + ...crometer_micrometer_observation_1_10_2.xml | 13 + ...ubator_codec_classes_quic_0_0_34_Final.xml | 13 + ..._native_quic_linux_x86_64_0_0_34_Final.xml | 13 + ...en__io_netty_netty_buffer_4_1_86_Final.xml | 13 + ...ven__io_netty_netty_codec_4_1_86_Final.xml | 13 + ..._io_netty_netty_codec_dns_4_1_86_Final.xml | 13 + ...o_netty_netty_codec_http2_4_1_86_Final.xml | 13 + ...io_netty_netty_codec_http_4_1_86_Final.xml | 13 + ...o_netty_netty_codec_socks_4_1_86_Final.xml | 13 + ...en__io_netty_netty_common_4_1_86_Final.xml | 13 + ...n__io_netty_netty_handler_4_1_86_Final.xml | 13 + ...netty_netty_handler_proxy_4_1_86_Final.xml | 13 + ...__io_netty_netty_resolver_4_1_86_Final.xml | 13 + ..._netty_netty_resolver_dns_4_1_86_Final.xml | 13 + ...esolver_dns_classes_macos_4_1_86_Final.xml | 13 + ...s_native_macos_osx_x86_64_4_1_86_Final.xml | 13 + ..._io_netty_netty_transport_4_1_86_Final.xml | 13 + ...y_transport_classes_epoll_4_1_86_Final.xml | 13 + ...native_epoll_linux_x86_64_4_1_86_Final.xml | 13 + ...nsport_native_unix_common_4_1_86_Final.xml | 13 + ...tor_reactor_netty_incubator_quic_0_1_1.xml | 13 + ...ojectreactor_netty_reactor_netty_1_1_1.xml | 13 + ...reactor_netty_reactor_netty_core_1_1_1.xml | 13 + ...reactor_netty_reactor_netty_http_1_1_1.xml | 13 + ...__io_projectreactor_reactor_core_3_5_1.xml | 13 + ...Maven__io_rest_assured_json_path_5_2_1.xml | 13 + ...en__io_rest_assured_rest_assured_5_2_1.xml | 13 + ...rest_assured_rest_assured_common_5_2_1.xml | 13 + ...__io_rest_assured_spring_commons_5_2_1.xml | 13 + ..._io_rest_assured_spring_mock_mvc_5_2_1.xml | 13 + .../Maven__io_rest_assured_xml_path_5_2_1.xml | 13 + ...ctivation_jakarta_activation_api_2_1_0.xml | 13 + ...nnotation_jakarta_annotation_api_2_1_1.xml | 13 + ...alidation_jakarta_validation_api_3_0_2.xml | 13 + ...ta_xml_bind_jakarta_xml_bind_api_4_0_0.xml | 13 + ..._activation_javax_activation_api_1_2_0.xml | 13 + ..._annotation_javax_annotation_api_1_3_2.xml | 13 + .../Maven__javax_inject_javax_inject_1.xml | 13 + ...aven__net_bytebuddy_byte_buddy_1_12_20.xml | 13 + ...net_bytebuddy_byte_buddy_agent_1_12_20.xml | 13 + ...mbs_json_unit_json_unit_assertj_2_32_0.xml | 13 + ...crumbs_json_unit_json_unit_core_2_32_0.xml | 13 + ...s_json_unit_json_unit_json_path_2_32_0.xml | 13 + .../Maven__net_jodah_typetools_0_6_2.xml | 13 + ...ven__net_minidev_accessors_smart_2_4_8.xml | 13 + .../Maven__net_minidev_json_smart_2_4_8.xml | 13 + ...rg_apache_commons_commons_lang3_3_12_0.xml | 13 + ...org_apache_commons_commons_text_1_10_0.xml | 13 + .../Maven__org_apache_groovy_groovy_4_0_6.xml | 13 + ...n__org_apache_groovy_groovy_json_4_0_6.xml | 13 + ...en__org_apache_groovy_groovy_nio_4_0_6.xml | 13 + ...en__org_apache_groovy_groovy_xml_4_0_6.xml | 13 + ...pache_httpcomponents_httpclient_4_5_14.xml | 13 + ..._apache_httpcomponents_httpcore_4_4_16.xml | 13 + ..._apache_httpcomponents_httpmime_4_5_14.xml | 13 + ..._apache_logging_log4j_log4j_api_2_19_0.xml | 13 + ...he_logging_log4j_log4j_to_slf4j_2_19_0.xml | 13 + ...aven_resolver_maven_resolver_api_1_4_1.xml | 13 + ..._tomcat_embed_tomcat_embed_core_10_1_4.xml | 13 + ...he_tomcat_embed_tomcat_embed_el_10_1_4.xml | 13 + ...at_embed_tomcat_embed_websocket_10_1_4.xml | 13 + ..._org_apiguardian_apiguardian_api_1_1_2.xml | 13 + ...Maven__org_assertj_assertj_core_3_23_1.xml | 13 + ...__org_ccil_cowan_tagsoup_tagsoup_1_2_1.xml | 13 + .../Maven__org_hamcrest_hamcrest_2_2.xml | 13 + .../Maven__org_hamcrest_hamcrest_core_2_2.xml | 13 + ...__org_hdrhistogram_HdrHistogram_2_1_12.xml | 13 + ...idator_hibernate_validator_8_0_0_Final.xml | 13 + ...boss_logging_jboss_logging_3_5_0_Final.xml | 13 + .../Maven__org_jetbrains_annotations_13_0.xml | 13 + ..._jetbrains_kotlin_kotlin_stdlib_1_7_22.xml | 13 + ...ins_kotlin_kotlin_stdlib_common_1_7_22.xml | 13 + ...rains_kotlin_kotlin_stdlib_jdk7_1_7_22.xml | 13 + ...rains_kotlin_kotlin_stdlib_jdk8_1_7_22.xml | 13 + ..._org_junit_jupiter_junit_jupiter_5_9_1.xml | 13 + ..._junit_jupiter_junit_jupiter_api_5_9_1.xml | 13 + ...nit_jupiter_junit_jupiter_engine_5_9_1.xml | 13 + ...nit_jupiter_junit_jupiter_params_5_9_1.xml | 13 + ..._platform_junit_platform_commons_1_9_1.xml | 13 + ...t_platform_junit_platform_engine_1_9_1.xml | 13 + ...n__org_latencyutils_LatencyUtils_2_0_3.xml | 13 + .../Maven__org_mockito_mockito_core_4_8_1.xml | 13 + ...rg_mockito_mockito_junit_jupiter_4_8_1.xml | 13 + .../Maven__org_objenesis_objenesis_3_2.xml | 13 + ...Maven__org_opentest4j_opentest4j_1_2_0.xml | 13 + .../libraries/Maven__org_ow2_asm_asm_7_1.xml | 13 + ...reactivestreams_reactive_streams_1_0_4.xml | 13 + ...aven__org_skyscreamer_jsonassert_1_5_1.xml | 13 + .../Maven__org_slf4j_jul_to_slf4j_2_0_6.xml | 13 + .../Maven__org_slf4j_slf4j_api_2_0_6.xml | 13 + ...springframework_amqp_spring_amqp_3_0_0.xml | 13 + ...ringframework_amqp_spring_rabbit_3_0_0.xml | 13 + ...springframework_boot_spring_boot_3_0_1.xml | 13 + ...mework_boot_spring_boot_actuator_3_0_1.xml | 13 + ...ring_boot_actuator_autoconfigure_3_0_1.xml | 13 + ...k_boot_spring_boot_autoconfigure_3_0_1.xml | 13 + ...amework_boot_spring_boot_starter_3_0_1.xml | 13 + ...oot_spring_boot_starter_actuator_3_0_1.xml | 13 + ...rk_boot_spring_boot_starter_amqp_3_0_1.xml | 13 + ...rk_boot_spring_boot_starter_json_3_0_1.xml | 13 + ...boot_spring_boot_starter_logging_3_0_1.xml | 13 + ...pring_boot_starter_reactor_netty_3_0_1.xml | 13 + ...rk_boot_spring_boot_starter_test_3_0_1.xml | 13 + ..._boot_spring_boot_starter_tomcat_3_0_1.xml | 13 + ...t_spring_boot_starter_validation_3_0_1.xml | 13 + ...ork_boot_spring_boot_starter_web_3_0_1.xml | 13 + ...boot_spring_boot_starter_webflux_3_0_1.xml | 13 + ...gframework_boot_spring_boot_test_3_0_1.xml | 13 + ...t_spring_boot_test_autoconfigure_3_0_1.xml | 13 + ...ng_cloud_contract_shade_4_0_1_SNAPSHOT.xml | 13 + ...ing_cloud_contract_spec_4_0_1_SNAPSHOT.xml | 13 + ...ud_contract_spec_groovy_4_0_1_SNAPSHOT.xml | 13 + ...loud_contract_spec_java_4_0_1_SNAPSHOT.xml | 13 + ...cloud_contract_verifier_4_0_0_SNAPSHOT.xml | 110 + ...cloud_contract_verifier_4_0_1_SNAPSHOT.xml | 13 + ...ud_spring_cloud_function_context_4_0_0.xml | 13 + ...cloud_spring_cloud_function_core_4_0_0.xml | 13 + ...arter_contract_verifier_4_0_1_SNAPSHOT.xml | 13 + ...ring_cloud_starter_stream_rabbit_4_0_0.xml | 13 + ...mework_cloud_spring_cloud_stream_4_0_0.xml | 13 + ...pring_cloud_stream_binder_rabbit_4_0_0.xml | 13 + ..._cloud_stream_binder_rabbit_core_4_0_0.xml | 13 + ..._spring_cloud_stream_test_binder_4_0_0.xml | 13 + ...egration_spring_integration_amqp_6_0_1.xml | 13 + ...egration_spring_integration_core_6_0_1.xml | 13 + ...tegration_spring_integration_jmx_6_0_1.xml | 13 + ...ringframework_retry_spring_retry_2_0_0.xml | 13 + ...__org_springframework_spring_aop_6_0_3.xml | 13 + ...org_springframework_spring_beans_6_0_3.xml | 13 + ...g_springframework_spring_context_6_0_3.xml | 13 + ..._org_springframework_spring_core_6_0_3.xml | 13 + ...pringframework_spring_expression_6_0_3.xml | 13 + ...__org_springframework_spring_jcl_6_0_3.xml | 13 + ...springframework_spring_messaging_6_0_3.xml | 13 + ..._org_springframework_spring_test_6_0_3.xml | 13 + ...n__org_springframework_spring_tx_6_0_3.xml | 13 + ...__org_springframework_spring_web_6_0_3.xml | 13 + ...g_springframework_spring_webflux_6_0_3.xml | 13 + ...rg_springframework_spring_webmvc_6_0_3.xml | 13 + .../Maven__org_xmlunit_xmlunit_core_2_9_0.xml | 13 + .../Maven__org_yaml_snakeyaml_1_33.xml | 13 + .../standalone/dsl/http-server/.idea/misc.xml | 11 + .../dsl/http-server/.idea/modules.xml | 8 + .../.idea/sonarlint/issuestore/index.pb | 0 .../sonarlint/securityhotspotstore/index.pb | 0 .../standalone/dsl/http-server/.idea/vcs.xml | 6 + .../dsl/http-server/.mvn/jvm.config | 1 - .../dsl/http-server/.mvn/maven.config | 1 - .../.mvn/wrapper/MavenWrapperDownloader.java | 117 - .../.mvn/wrapper/maven-wrapper.jar | Bin 58727 -> 0 bytes .../.mvn/wrapper/maven-wrapper.properties | 18 - .../standalone/dsl/http-server/README.adoc | 20 - .../standalone/dsl/http-server/build.gradle | 95 - .../dsl/http-server/gradle.properties | 4 - .../gradle/wrapper/gradle-wrapper.jar | Bin 63721 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - samples/standalone/dsl/http-server/gradlew | 249 - .../standalone/dsl/http-server/gradlew.bat | 92 - samples/standalone/dsl/http-server/log.log | 154 + samples/standalone/dsl/http-server/mvnw | 316 - samples/standalone/dsl/http-server/mvnw.cmd | 188 - samples/standalone/dsl/http-server/pom.xml | 352 -- .../dsl/http-server/settings.gradle | 24 - .../java/com/example/fraud/Application.java | 29 - .../java/com/example/fraud/FooController.java | 33 - .../fraud/FraudDetectionController.java | 63 - .../example/fraud/FraudNameController.java | 122 - .../example/fraud/FraudStatsController.java | 94 - .../java/com/example/fraud/MessageSender.java | 64 - .../example/fraud/MessagingConfiguration.java | 39 - .../com/example/fraud/TestController.java | 97 - .../com/example/fraud/model/FraudCheck.java | 49 - .../example/fraud/model/FraudCheckResult.java | 52 - .../example/fraud/model/FraudCheckStatus.java | 23 - .../src/main/resources/application.properties | 5 - .../java/com/example/fraud/BinaryBase.java | 29 - .../java/com/example/fraud/FraudBase.java | 46 - .../java/com/example/fraud/FraudnameBase.java | 33 - .../java/com/example/fraud/MessagingBase.java | 69 - .../java/com/example/fraud/MultipartBase.java | 29 - .../test/java/com/example/fraud/TestBase.java | 29 - .../java/com/example/fraud/YmlFraudBase.java | 46 - .../com/example/fraud/YmlFraudnameBase.java | 33 - .../resources/contracts/binary/request.pdf | Bin 14631 -> 0 bytes .../resources/contracts/binary/response.pdf | Bin 15767 -> 0 bytes .../binary/shouldWorkWithBinaryPayload.groovy | 37 - .../fraud/shouldMarkClientAsFraud.groovy | 73 - .../fraud/shouldMarkClientAsNotFraud.groovy | 49 - .../fraud/shouldReturnFraudStats.groovy | 66 - .../fraudname/shouldReturnACookie.groovy | 32 - .../shouldReturnAFraudForTheName.groovy | 41 - .../shouldReturnNonFraudForTheName.groovy | 39 - .../resources/contracts/messaging/output.pdf | Bin 15767 -> 0 bytes .../shouldProduceValidSensorData.groovy | 42 - .../shouldReturnOkWhenServiceIsHealthy.yml | 6 - .../shouldWorkWithInputOutputBinary.groovy | 33 - ...kForMultipartAsBytesWithContentType.groovy | 52 - ...ouldWorkForMultipartWithContentType.groovy | 35 - .../resources/contracts/multipart/test.json | 3 - .../contracts/test/MyHttpContract.java | 36 - .../resources/contracts/test/request.json | 1 - .../yml/fraud/shouldMarkClientAsFraud.yml | 52 - .../yml/fraud/shouldMarkClientAsNotFraud.yaml | 25 - .../yml/fraud/shouldReturnFraudStats.yml | 31 - .../shouldReturnAFraudForTheName.yml | 15 - .../shouldReturnNonFraudForTheName.yml | 18 - samples/standalone/dsl/pom.xml | 42 - samples/standalone/mvnw | 316 - samples/standalone/mvnw.cmd | 188 - samples/standalone/pom.xml | 71 - samples/standalone/restdocs/build.log | 885 +++ .../restdocs/http-client/.gitignore | 7 - .../.gradle/8.3/checksums/checksums.lock | Bin 0 -> 17 bytes .../.gradle/8.3/checksums/md5-checksums.bin | Bin 0 -> 22797 bytes .../.gradle/8.3/checksums/sha1-checksums.bin | Bin 0 -> 30161 bytes .../dependencies-accessors.lock | Bin 0 -> 17 bytes .../8.3/dependencies-accessors/gc.properties | 0 .../8.3/executionHistory/executionHistory.bin | Bin 0 -> 99402 bytes .../executionHistory/executionHistory.lock | Bin 0 -> 17 bytes .../.gradle/8.3/fileChanges/last-build.bin | Bin 0 -> 1 bytes .../.gradle/8.3/fileHashes/fileHashes.bin | Bin 0 -> 21097 bytes .../.gradle/8.3/fileHashes/fileHashes.lock | Bin 0 -> 17 bytes .../8.3/fileHashes/resourceHashesCache.bin | Bin 0 -> 20231 bytes .../http-client/.gradle/8.3/gc.properties | 0 .../buildOutputCleanup.lock | Bin 0 -> 17 bytes .../buildOutputCleanup/cache.properties | 2 + .../buildOutputCleanup/outputFiles.bin | Bin 0 -> 19145 bytes .../.gradle/checksums/checksums.lock | Bin 0 -> 17 bytes .../.gradle/checksums/md5-checksums.bin | Bin 0 -> 21197 bytes .../.gradle/checksums/sha1-checksums.bin | Bin 0 -> 23573 bytes .../http-client/.gradle/file-system.probe | Bin 0 -> 8 bytes .../http-client/.gradle/vcs-1/gc.properties | 0 .../restdocs/http-client/.idea/.gitignore | 8 + .../restdocs/http-client/.idea/compiler.xml | 18 + .../restdocs/http-client/.idea/encodings.xml | 6 + .../http-client/.idea/jarRepositories.xml | 35 + .../restdocs/http-client/.idea/misc.xml | 12 + .../0f0eab2c174d28b70b02de758125b58bdbb2cb13 | 7 + .../418b368109de47f2deab6ae6f859bba79503b690 | 7 + .../442292b8a7efeabbe4cc176709b833b1792140ec | 0 .../8485b3d5dbc2b6f87bd101a3a996a5faab5574ea | 7 + .../d4407a9ef49dcf7dd4b936e7fb4249f7579e0fbb | 7 + .../f07866736216be0ee2aba49e392191aeae700a35 | 0 .../.idea/sonarlint/issuestore/index.pb | 13 + .../restdocs/http-client/.idea/vcs.xml | 6 + .../restdocs/http-client/.mvn/jvm.config | 1 - .../restdocs/http-client/.mvn/maven.config | 1 - .../.mvn/wrapper/MavenWrapperDownloader.java | 117 - .../.mvn/wrapper/maven-wrapper.jar | Bin 58727 -> 0 bytes .../.mvn/wrapper/maven-wrapper.properties | 18 - .../restdocs/http-client/README.adoc | 26 - .../restdocs/http-client/build.gradle | 77 - .../restdocs/http-client/gradle.properties | 4 - .../gradle/wrapper/gradle-wrapper.jar | Bin 63721 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - .../standalone/restdocs/http-client/gradlew | 249 - .../restdocs/http-client/gradlew.bat | 92 - samples/standalone/restdocs/http-client/mvnw | 316 - .../standalone/restdocs/http-client/mvnw.cmd | 188 - .../standalone/restdocs/http-client/pom.xml | 275 - .../restdocs/http-client/settings.gradle | 1 - .../java/com/example/loan/Application.java | 31 - .../example/loan/LoanApplicationService.java | 110 - .../java/com/example/loan/model/Client.java | 38 - .../example/loan/model/FraudCheckStatus.java | 23 - .../loan/model/FraudServiceRequest.java | 51 - .../loan/model/FraudServiceResponse.java | 44 - .../example/loan/model/LoanApplication.java | 61 - .../loan/model/LoanApplicationResult.java | 50 - .../loan/model/LoanApplicationStatus.java | 23 - .../src/main/resources/application.yml | 6 - .../loan/LoanApplicationServiceTests.java | 87 - ...pplicationServiceusingStubRunnerTests.java | 77 - .../com/example/loan/XmlServiceTests.java | 109 - .../loan/XmlServiceUsingStubRunnerTests.java | 66 - .../test/resources/application-gradle.yaml | 2 - .../restdocs/http-server/.gitignore | 6 - .../.gradle/8.3/checksums/checksums.lock | Bin 0 -> 17 bytes .../.gradle/8.3/checksums/md5-checksums.bin | Bin 0 -> 24947 bytes .../.gradle/8.3/checksums/sha1-checksums.bin | Bin 0 -> 25463 bytes .../dependencies-accessors.lock | Bin 0 -> 17 bytes .../8.3/dependencies-accessors/gc.properties | 0 .../8.3/executionHistory/executionHistory.bin | Bin 0 -> 19719 bytes .../executionHistory/executionHistory.lock | Bin 0 -> 17 bytes .../.gradle/8.3/fileChanges/last-build.bin | Bin 0 -> 1 bytes .../.gradle/8.3/fileHashes/fileHashes.bin | Bin 0 -> 18697 bytes .../.gradle/8.3/fileHashes/fileHashes.lock | Bin 0 -> 17 bytes .../http-server/.gradle/8.3/gc.properties | 0 .../buildOutputCleanup.lock | Bin 0 -> 17 bytes .../buildOutputCleanup/cache.properties | 2 + .../buildOutputCleanup/outputFiles.bin | Bin 0 -> 18767 bytes .../.gradle/checksums/checksums.lock | Bin 0 -> 17 bytes .../.gradle/checksums/md5-checksums.bin | Bin 0 -> 25247 bytes .../.gradle/checksums/sha1-checksums.bin | Bin 0 -> 28271 bytes .../http-server/.gradle/file-system.probe | Bin 0 -> 8 bytes .../http-server/.gradle/vcs-1/gc.properties | 0 .../restdocs/http-server/.idea/.gitignore | 8 + .../restdocs/http-server/.idea/compiler.xml | 18 + .../restdocs/http-server/.idea/encodings.xml | 6 + .../http-server/.idea/jarRepositories.xml | 35 + .../restdocs/http-server/.idea/misc.xml | 12 + .../442292b8a7efeabbe4cc176709b833b1792140ec | 0 .../47243719dc78f8a57d390d73624d6c31feb69d10 | 7 + .../cecf7cde4af07dd004c5c09953f0e7e7dbc86439 | 0 .../ea4a50232d6976a3ad6f2619cfb817ba6e474859 | 7 + .../.idea/sonarlint/issuestore/index.pb | 9 + .../restdocs/http-server/.idea/vcs.xml | 6 + .../restdocs/http-server/.mvn/jvm.config | 1 - .../restdocs/http-server/.mvn/maven.config | 1 - .../.mvn/wrapper/MavenWrapperDownloader.java | 117 - .../.mvn/wrapper/maven-wrapper.jar | Bin 58727 -> 0 bytes .../.mvn/wrapper/maven-wrapper.properties | 18 - .../restdocs/http-server/README.adoc | 20 - .../restdocs/http-server/build.gradle | 130 - .../restdocs/http-server/gradle.properties | 4 - .../gradle/wrapper/gradle-wrapper.jar | Bin 63721 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - .../standalone/restdocs/http-server/gradlew | 249 - .../restdocs/http-server/gradlew.bat | 92 - samples/standalone/restdocs/http-server/mvnw | 316 - .../standalone/restdocs/http-server/mvnw.cmd | 188 - .../standalone/restdocs/http-server/pom.xml | 290 - .../restdocs/http-server/settings.gradle | 22 - .../http-server/src/assembly/stub.xml | 51 - .../java/com/example/fraud/Application.java | 33 - .../fraud/FraudDetectionController.java | 60 - .../fraud/FraudDetectionXmlController.java | 59 - .../com/example/fraud/model/FraudCheck.java | 46 - .../example/fraud/model/FraudCheckResult.java | 49 - .../example/fraud/model/FraudCheckStatus.java | 23 - .../fraud/FraudBaseWithStandaloneSetup.java | 45 - .../fraud/FraudBaseWithWebAppSetup.java | 56 - .../com/example/fraud/StubGeneratorTests.java | 92 - .../example/fraud/XmlStubGeneratorTests.java | 62 - .../standalone/shouldMarkClientAsFraud.groovy | 82 - .../webapp/shouldMarkClientAsNotFraud.groovy | 46 - samples/standalone/restdocs/pom.xml | 42 - samples/standalone/webclient/build.log | 477 ++ .../webclient/http-client/.gitignore | 7 - .../.gradle/8.3/checksums/checksums.lock | Bin 0 -> 17 bytes .../.gradle/8.3/checksums/md5-checksums.bin | Bin 0 -> 22497 bytes .../.gradle/8.3/checksums/sha1-checksums.bin | Bin 0 -> 25139 bytes .../dependencies-accessors.lock | Bin 0 -> 17 bytes .../8.3/dependencies-accessors/gc.properties | 0 .../8.3/executionHistory/executionHistory.bin | Bin 0 -> 94765 bytes .../executionHistory/executionHistory.lock | Bin 0 -> 17 bytes .../.gradle/8.3/fileChanges/last-build.bin | Bin 0 -> 1 bytes .../.gradle/8.3/fileHashes/fileHashes.bin | Bin 0 -> 21097 bytes .../.gradle/8.3/fileHashes/fileHashes.lock | Bin 0 -> 17 bytes .../8.3/fileHashes/resourceHashesCache.bin | Bin 0 -> 20231 bytes .../http-client/.gradle/8.3/gc.properties | 0 .../buildOutputCleanup.lock | Bin 0 -> 17 bytes .../buildOutputCleanup/cache.properties | 2 + .../buildOutputCleanup/outputFiles.bin | Bin 0 -> 19145 bytes .../.gradle/checksums/checksums.lock | Bin 0 -> 17 bytes .../.gradle/checksums/md5-checksums.bin | Bin 0 -> 22847 bytes .../.gradle/checksums/sha1-checksums.bin | Bin 0 -> 25355 bytes .../http-client/.gradle/file-system.probe | Bin 0 -> 8 bytes .../http-client/.gradle/vcs-1/gc.properties | 0 .../webclient/http-client/.mvn/jvm.config | 1 - .../webclient/http-client/.mvn/maven.config | 1 - .../.mvn/wrapper/MavenWrapperDownloader.java | 117 - .../.mvn/wrapper/maven-wrapper.jar | Bin 58727 -> 0 bytes .../.mvn/wrapper/maven-wrapper.properties | 18 - .../webclient/http-client/README.adoc | 26 - .../webclient/http-client/build.gradle | 66 - .../webclient/http-client/gradle.properties | 4 - .../gradle/wrapper/gradle-wrapper.jar | Bin 63721 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - .../standalone/webclient/http-client/gradlew | 249 - .../webclient/http-client/gradlew.bat | 92 - samples/standalone/webclient/http-client/mvnw | 316 - .../standalone/webclient/http-client/mvnw.cmd | 188 - .../standalone/webclient/http-client/pom.xml | 245 - .../webclient/http-client/settings.gradle | 14 - .../java/com/example/loan/Application.java | 31 - .../example/loan/LoanApplicationService.java | 106 - .../java/com/example/loan/model/Client.java | 38 - .../example/loan/model/FraudCheckStatus.java | 23 - .../loan/model/FraudServiceRequest.java | 51 - .../loan/model/FraudServiceResponse.java | 44 - .../example/loan/model/LoanApplication.java | 61 - .../loan/model/LoanApplicationResult.java | 50 - .../loan/model/LoanApplicationStatus.java | 23 - .../src/main/resources/application.yml | 5 - .../loan/LoanApplicationServiceTests.java | 87 - ...tionServiceusingStubRunnerGradleTests.java | 77 - ...pplicationServiceusingStubRunnerTests.java | 77 - .../test/resources/application-gradle.yaml | 2 - .../webclient/http-server/.gitignore | 6 - .../.gradle/8.3/checksums/checksums.lock | Bin 0 -> 17 bytes .../.gradle/8.3/checksums/md5-checksums.bin | Bin 0 -> 24947 bytes .../.gradle/8.3/checksums/sha1-checksums.bin | Bin 0 -> 25463 bytes .../dependencies-accessors.lock | Bin 0 -> 17 bytes .../8.3/dependencies-accessors/gc.properties | 0 .../8.3/executionHistory/executionHistory.bin | Bin 0 -> 19723 bytes .../executionHistory/executionHistory.lock | Bin 0 -> 17 bytes .../.gradle/8.3/fileChanges/last-build.bin | Bin 0 -> 1 bytes .../.gradle/8.3/fileHashes/fileHashes.bin | Bin 0 -> 18697 bytes .../.gradle/8.3/fileHashes/fileHashes.lock | Bin 0 -> 17 bytes .../http-server/.gradle/8.3/gc.properties | 0 .../buildOutputCleanup.lock | Bin 0 -> 17 bytes .../buildOutputCleanup/cache.properties | 2 + .../buildOutputCleanup/outputFiles.bin | Bin 0 -> 18767 bytes .../.gradle/checksums/checksums.lock | Bin 0 -> 17 bytes .../.gradle/checksums/md5-checksums.bin | Bin 0 -> 25147 bytes .../.gradle/checksums/sha1-checksums.bin | Bin 0 -> 28379 bytes .../http-server/.gradle/file-system.probe | Bin 0 -> 8 bytes .../http-server/.gradle/vcs-1/gc.properties | 0 .../webclient/http-server/.idea/.gitignore | 8 + .../webclient/http-server/.idea/compiler.xml | 18 + .../webclient/http-server/.idea/encodings.xml | 6 + .../http-server/.idea/jarRepositories.xml | 35 + .../webclient/http-server/.idea/misc.xml | 12 + .../442292b8a7efeabbe4cc176709b833b1792140ec | 0 .../4933a334253a42a1b13f0397013f3267a154e096 | 7 + .../.idea/sonarlint/issuestore/index.pb | 5 + .../webclient/http-server/.idea/vcs.xml | 6 + .../webclient/http-server/.mvn/jvm.config | 1 - .../webclient/http-server/.mvn/maven.config | 1 - .../.mvn/wrapper/MavenWrapperDownloader.java | 117 - .../.mvn/wrapper/maven-wrapper.jar | Bin 58727 -> 0 bytes .../.mvn/wrapper/maven-wrapper.properties | 18 - .../webclient/http-server/README.adoc | 20 - .../webclient/http-server/build.gradle | 130 - .../webclient/http-server/gradle.properties | 4 - .../gradle/wrapper/gradle-wrapper.jar | Bin 63721 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - .../standalone/webclient/http-server/gradlew | 249 - .../webclient/http-server/gradlew.bat | 92 - samples/standalone/webclient/http-server/mvnw | 316 - .../standalone/webclient/http-server/mvnw.cmd | 188 - .../standalone/webclient/http-server/pom.xml | 257 - .../webclient/http-server/settings.gradle | 22 - .../http-server/src/assembly/stub.xml | 35 - .../java/com/example/fraud/Application.java | 33 - .../fraud/FraudDetectionController.java | 60 - .../com/example/fraud/model/FraudCheck.java | 46 - .../example/fraud/model/FraudCheckResult.java | 49 - .../example/fraud/model/FraudCheckStatus.java | 23 - .../src/main/resources/application.yml | 1 - .../com/example/fraud/StubGeneratorTests.java | 92 - samples/standalone/webclient/pom.xml | 42 - scripts/buildWithDocs.sh | 10 - scripts/ciBuild.sh | 11 - scripts/common.sh | 24 - scripts/compileOnly.sh | 9 - scripts/downloadDependencies.sh | 20 - scripts/fastBuild.sh | 10 - scripts/generateDocs.sh | 16 - scripts/gradleOnly.sh | 11 - scripts/integrationOnly.sh | 10 - scripts/noIntegration.sh | 10 - scripts/parallelBuild.sh | 10 - scripts/runTests.sh | 18 - scripts/updateWrappers.sh | 13 - specs/README.adoc | 4 - specs/pom.xml | 43 - .../README.adoc | 3 - .../spring-cloud-contract-spec-groovy/pom.xml | 82 - .../internal/GroovyDslPropertyConverter.java | 54 - .../main/resources/META-INF/spring.factories | 2 - .../spec/internal/ContractSpec.groovy | 58 - .../README.adoc | 3 - specs/spring-cloud-contract-spec-java/pom.xml | 95 - .../cloud/contract/spec/Contract.java | 414 -- .../contract/spec/ContractConverter.java | 54 - .../cloud/contract/spec/ContractReader.java | 38 - .../cloud/contract/spec/ContractStorer.java | 43 - .../cloud/contract/spec/ContractTemplate.java | 234 - .../spec/ContractVerifierException.java | 32 - .../cloud/contract/spec/internal/Body.java | 76 - .../contract/spec/internal/BodyMatcher.java | 58 - .../contract/spec/internal/BodyMatchers.java | 144 - .../contract/spec/internal/CanBeDynamic.java | 33 - .../spec/internal/ClientDslProperty.java | 34 - .../spec/internal/ClientOutputMessage.java | 25 - .../cloud/contract/spec/internal/Common.java | 393 -- .../internal/CompositeContractTemplate.java | 164 - .../contract/spec/internal/ContractUtils.java | 45 - .../cloud/contract/spec/internal/Cookie.java | 86 - .../cloud/contract/spec/internal/Cookies.java | 112 - .../contract/spec/internal/DslProperty.java | 88 - .../spec/internal/DslPropertyConverter.java | 94 - .../spec/internal/ExecutionProperty.java | 73 - .../spec/internal/FromFileProperty.java | 104 - .../contract/spec/internal/FromRequest.java | 219 - .../internal/HandlebarsContractTemplate.java | 158 - .../cloud/contract/spec/internal/Header.java | 85 - .../cloud/contract/spec/internal/Headers.java | 462 -- .../contract/spec/internal/HttpHeaders.java | 436 -- .../contract/spec/internal/HttpMethods.java | 94 - .../contract/spec/internal/HttpStatus.java | 448 -- .../cloud/contract/spec/internal/Input.java | 237 - .../spec/internal/JSONCompareMode.java | 43 - .../spec/internal/MatchingStrategy.java | 147 - .../contract/spec/internal/MatchingType.java | 68 - .../spec/internal/MatchingTypeValue.java | 125 - .../internal/MatchingTypeValueHolder.java | 39 - .../contract/spec/internal/MediaTypes.java | 122 - .../spec/internal/MessagingHeaders.java | 37 - .../contract/spec/internal/Multipart.java | 61 - .../contract/spec/internal/NamedProperty.java | 125 - .../spec/internal/NotToEscapePattern.java | 37 - .../spec/internal/OptionalProperty.java | 86 - .../contract/spec/internal/OutputMessage.java | 343 -- .../spec/internal/PathBodyMatcher.java | 82 - .../internal/PatternValueDslProperty.java | 174 - .../spec/internal/QueryParameter.java | 93 - .../spec/internal/QueryParameters.java | 73 - .../spec/internal/RandomStringGenerator.java | 39 - .../spec/internal/RegexCreatingProperty.java | 68 - .../spec/internal/RegexMatchingTypeValue.java | 70 - .../contract/spec/internal/RegexPatterns.java | 204 - .../contract/spec/internal/RegexProperty.java | 232 - .../cloud/contract/spec/internal/Request.java | 798 --- .../contract/spec/internal/Response.java | 790 --- .../spec/internal/ResponseBodyMatchers.java | 47 - .../spec/internal/ServerDslProperty.java | 34 - .../spec/internal/ServerOutputMessage.java | 25 - .../cloud/contract/spec/internal/Url.java | 103 - .../contract/spec/internal/UrlHelper.java | 61 - .../cloud/contract/spec/internal/UrlPath.java | 39 - .../cloud/contract/spec/util/RegexpUtils.java | 42 - .../contract/spec/util/ValidateUtils.java | 93 - .../repackaged/nl/flotsam/xeger/Xeger.java | 143 - .../spec/internal/HttpHeadersTests.java | 327 -- .../spec/internal/HttpMethodsTests.java | 67 - .../spec/internal/MediaTypesTests.java | 112 - .../spec/internal/MessagingHeadersTests.java | 32 - .../spec/internal/RegexPropertyTests.java | 47 - .../nl/flotsam/xeger/XegerTest.java | 106 - .../nl/flotsam/xeger/XegerUtilsTest.java | 38 - .../README.adoc | 3 - .../spring-cloud-contract-spec-kotlin/pom.xml | 109 - .../cloud/contract/spec/ContractDsl.kt | 159 - .../contract/spec/ContractDslExtensions.kt | 51 - .../contract/spec/internal/BodyMatchersDsl.kt | 84 - .../cloud/contract/spec/internal/CommonDsl.kt | 241 - .../spec/internal/ContractDslMarker.kt | 25 - .../contract/spec/internal/CookiesDsl.kt | 47 - .../contract/spec/internal/FromRequestDsl.kt | 176 - .../contract/spec/internal/HeadersDsl.kt | 459 -- .../cloud/contract/spec/internal/InputDsl.kt | 140 - .../spec/internal/KotlinContractConverter.kt | 111 - .../contract/spec/internal/MultipartDsl.kt | 39 - .../spec/internal/OutputMessageDsl.kt | 174 - .../contract/spec/internal/RequestDsl.kt | 331 -- .../spec/internal/ResponseBodyMatchersDsl.kt | 40 - .../contract/spec/internal/ResponseDsl.kt | 425 -- .../services/javax.script.ScriptEngineFactory | 1 - .../main/resources/META-INF/spring.factories | 2 - .../cloud/contract/spec/ContractTests.kt | 807 --- .../internal/KotlinContractConverterTests.kt | 57 - .../test/resources/contracts/multipart.kts | 47 - .../contracts/multipleDefinitions.kts | 48 - .../src/test/resources/contracts/request.pdf | Bin 14631 -> 0 bytes .../src/test/resources/contracts/response.pdf | Bin 15767 -> 0 bytes .../contracts/shouldWorkWithBinaryPayload.kts | 39 - .../resources/contracts/singleDefinition.kts | 43 - .../src/test/resources/contracts/test.json | 3 - .../resources/contracts/unnamed_multiple.kts | 34 - .../resources/contracts/unnamed_single.kts | 26 - specs/spring-cloud-contract-spec/README.adoc | 3 - specs/spring-cloud-contract-spec/pom.xml | 62 - .../spec/internal/ContractSpec.groovy | 391 -- .../contract/spec/internal/CookiesSpec.groovy | 44 - .../internal/ExecutionPropertySpec.groovy | 47 - .../spec/internal/HttpStatusTests.java | 328 -- .../contract/spec/internal/InputSpec.groovy | 116 - .../spec/internal/MatchingTypeSpec.groovy | 39 - .../spec/internal/OutputMessageSpec.groovy | 116 - .../spec/internal/RegexPatternsSpec.groovy | 391 -- .../contract/spec/internal/RequestSpec.groovy | 147 - .../spec/internal/ResponseSpec.groovy | 134 - .../.factorypath | 167 - spring-cloud-contract-dependencies/pom.xml | 171 - .../dependency-reduced-pom.xml | 205 + spring-cloud-contract-shade/pom.xml | 311 - spring-cloud-contract-starters/pom.xml | 38 - .../README.adoc | 3 - .../pom.xml | 80 - .../pom.xml | 103 - .../pom.xml | 66 - .../.gitignore | 1 - .../log.log | 169 + .../pom.xml | 61 - .../stubrunner/server/StubRunnerBoot.java | 33 - .../resources/META-INF/thin-kafka.properties | 2 - .../resources/META-INF/thin-rabbit.properties | 2 - .../src/main/resources/application.yml | 11 - spring-cloud-contract-stub-runner/.gitignore | 1 - spring-cloud-contract-stub-runner/pom.xml | 290 - .../contract/stubrunner/AetherFactories.java | 160 - .../stubrunner/AetherStubDownloader.java | 279 - .../AetherStubDownloaderBuilder.java | 41 - .../cloud/contract/stubrunner/Arguments.java | 60 - .../stubrunner/AvailablePortScanner.java | 119 - .../contract/stubrunner/BatchStubRunner.java | 178 - .../stubrunner/BatchStubRunnerFactory.java | 67 - .../stubrunner/ClasspathStubProvider.java | 88 - .../CompositeStubDownloaderBuilder.java | 107 - .../stubrunner/ContractDownloader.java | 210 - .../stubrunner/ContractProjectUpdater.java | 283 - .../stubrunner/FileStubDownloader.java | 240 - .../cloud/contract/stubrunner/GitRepo.java | 415 -- .../contract/stubrunner/HttpServerStub.java | 88 - .../HttpServerStubConfiguration.java | 78 - .../stubrunner/HttpServerStubConfigurer.java | 62 - .../contract/stubrunner/MappingGenerator.java | 78 - .../contract/stubrunner/MavenSettings.java | 80 - .../MessageNotMatchingException.java | 27 - .../stubrunner/NoOpHttpServerStub.java | 62 - .../contract/stubrunner/ProjectVersion.java | 358 -- .../contract/stubrunner/ResourceResolver.java | 76 - .../ResourceResolvingStubDownloader.java | 229 - .../contract/stubrunner/RunningStubs.java | 142 - .../stubrunner/ScmStubDownloaderBuilder.java | 411 -- .../stubrunner/StubConfiguration.java | 221 - .../contract/stubrunner/StubDownloader.java | 45 - .../stubrunner/StubDownloaderBuilder.java | 50 - .../StubDownloaderBuilderProvider.java | 66 - .../cloud/contract/stubrunner/StubFinder.java | 63 - .../stubrunner/StubNotFoundException.java | 35 - .../contract/stubrunner/StubRepository.java | 172 - .../cloud/contract/stubrunner/StubRunner.java | 187 - .../stubrunner/StubRunnerExecutor.java | 340 -- .../stubrunner/StubRunnerFactory.java | 185 - .../stubrunner/StubRunnerOptions.java | 378 -- .../stubrunner/StubRunnerOptionsBuilder.java | 312 - .../stubrunner/StubRunnerPropertyUtils.java | 118 - .../contract/stubrunner/StubRunning.java | 34 - .../cloud/contract/stubrunner/StubServer.java | 147 - .../contract/stubrunner/StubTrigger.java | 63 - .../stubrunner/TemporaryFileStorage.java | 121 - .../ExceptionThrowingMessageVerifier.java | 54 - .../junit/PortStubRunnerExtensionOptions.java | 27 - .../junit/PortStubRunnerRuleOptions.java | 28 - .../stubrunner/junit/StubRunnerExtension.java | 374 -- .../junit/StubRunnerExtensionOptions.java | 187 - .../stubrunner/junit/StubRunnerRule.java | 322 -- .../junit/StubRunnerRuleOptions.java | 182 - ...ubRunnerWireMockTestExecutionListener.java | 60 - .../wiremock/WireMockHttpServerStub.java | 330 -- .../WireMockHttpServerStubConfigurer.java | 37 - .../server/EnableStubRunnerServer.java | 41 - .../server/HttpStubsController.java | 57 - .../stubrunner/server/StubRunnerBoot.java | 36 - .../server/StubRunnerServerConfiguration.java | 38 - .../stubrunner/server/TriggerController.java | 77 - .../spring/AutoConfigureStubRunner.java | 159 - .../spring/StubRunnerConfiguration.java | 208 - .../stubrunner/spring/StubRunnerPort.java | 42 - .../StubRunnerPortBeanPostProcessor.java | 79 - .../spring/StubRunnerProperties.java | 327 -- ...ConditionalOnStubbedDiscoveryDisabled.java | 40 - .../ConditionalOnStubbedDiscoveryEnabled.java | 42 - .../spring/cloud/StubMapperProperties.java | 82 - .../cloud/StubRunnerDiscoveryClient.java | 168 - .../StubRunnerReactiveDiscoveryClient.java | 119 - .../cloud/StubRunnerServiceInstance.java | 78 - ...tubRunnerSpringCloudAutoConfiguration.java | 139 - .../spring/cloud/StubsRegistrar.java | 29 - .../cloud/consul/ConsulStubsRegistrar.java | 116 - ...nerSpringCloudConsulAutoConfiguration.java | 56 - .../eureka/ConditionalOnEurekaEnabled.java | 40 - .../cloud/eureka/EurekaStubsRegistrar.java | 182 - ...nerSpringCloudEurekaAutoConfiguration.java | 112 - ...ingCloudLoadBalancerAutoConfiguration.java | 248 - ...SpringCloudZookeeperAutoConfiguration.java | 56 - .../zookeeper/ZookeeperStubsRegistrar.java | 119 - .../contract/stubrunner/util/StubsParser.java | 138 - .../contract/stubrunner/util/ZipCategory.java | 107 - ...itional-spring-configuration-metadata.json | 88 - .../main/resources/META-INF/spring.factories | 3 - ...ner.spring.AutoConfigureStubRunner.imports | 6 - .../AetherStubDownloaderSpec.groovy | 135 - .../AvailablePortScannerSpec.groovy | 70 - .../stubrunner/BatchStubRunnerSpec.groovy | 62 - .../stubrunner/ContractDownloaderSpec.groovy | 63 - .../GitStubDownloaderPropertiesSpec.groovy | 66 - .../stubrunner/RunningStubsSpec.groovy | 87 - .../stubrunner/StubConfigurationSpec.groovy | 63 - .../stubrunner/StubRepositorySpec.groovy | 66 - .../stubrunner/StubRunnerExecutorSpec.groovy | 278 - .../stubrunner/StubRunnerFactorySpec.groovy | 56 - .../StubRunnerOptionsBuilderSpec.groovy | 330 -- .../StubRunnerPropertyUtilsSpec.groovy | 116 - .../contract/stubrunner/StubRunnerSpec.groovy | 124 - .../contract/stubrunner/StubServerSpec.groovy | 56 - ...StubRunnerRuleCustomMsgVerifierSpec.groovy | 93 - .../StubRunnerRuleCustomPortJUnitTest.java | 94 - ...StubRunnerRuleExceptionThrowingSpec.groovy | 61 - .../junit4/StubRunnerRuleJUnitTest.java | 91 - .../junit4/StubRunnerRuleSpec.groovy | 73 - .../wiremock/TestWireMockExtensions.groovy | 84 - .../WireMockHttpServerStubAccessor.groovy | 29 - .../WireMockHttpServerStubSpec.groovy | 125 - .../server/StubRunnerBootSpec.groovy | 133 - .../StubRunnerBootConsulExample.java | 52 - .../StubRunnerBootEurekaExample.java | 62 - .../StubRunnerBootZookeeperExample.java | 51 - .../spring/StubRunnerConfigurationSpec.groovy | 182 - .../StubRunnerOptionsBuilderSpec.groovy | 56 - .../cloud/StubMapperPropertiesSpec.groovy | 37 - ...nerSpringCloudAutoConfigurationSpec.groovy | 103 - ...gCloudReactiveAutoConfigurationSpec.groovy | 100 - .../StubRunnerStubsPerConsumerSpec.groovy | 105 - ...tubsPerConsumerWithConsumerNameSpec.groovy | 108 - ...ingCloudConsulAutoConfigurationSpec.groovy | 122 - .../stubrunner/util/ZipCategorySpec.groovy | 52 - .../contract/stubrunner/AbstractGitTest.java | 93 - .../stubrunner/ClasspathStubProviderTest.java | 38 - .../CompositeStubDownloaderBuilderTests.java | 140 - .../ContractProjectUpdaterTest.java | 157 - .../stubrunner/FileStubDownloaderTests.java | 43 - .../contract/stubrunner/GitRepoTests.java | 209 - .../stubrunner/GitStubDownloaderTests.java | 241 - .../StubDownloaderBuilderProviderTests.java | 61 - .../stubrunner/StubRepositoryTest.java | 49 - .../stubrunner/StubRunnerSliceTests.java | 89 - .../stubrunner/StubsStubDownloaderTests.java | 83 - .../TestCustomYamlContractConverter.java | 59 - .../cloud/contract/stubrunner/TestUtils.java | 42 - .../stubrunner/issue1225/Issue1225Tests.java | 77 - ...t5ExtensionCustomMessageVerifierTests.java | 102 - ...bRunnerJUnit5ExtensionCustomPortTests.java | 89 - ...JUnit5ExtensionExceptionThrowingTests.java | 66 - .../junit/StubRunnerJUnit5ExtensionTests.java | 84 - .../StubRunnerJUnit5MethodExtensionTests.java | 84 - .../StubRunnerServerConfigurationTests.java | 60 - .../test/resources/.m2/settings-security.xml | 3 - .../src/test/resources/.m2/settings.xml | 9 - .../test/resources/META-INF/spring.factories | 4 - .../mappings/spring/cloud/bar/bar.json | 13 - .../mappings/spring/cloud/foo/bar/foobar.json | 13 - .../mappings/spring/cloud/foo/foo.json | 13 - .../projects/brokers/brokers.json | 5 - .../brokers/nested/anotherDescriptor.json | 5 - .../projects/descriptor.json | 5 - .../test/resources/application-cloudtest.yml | 17 - .../src/test/resources/application-eureka.yml | 9 - .../resources/application-streamconsumer.yml | 5 - .../application-test-with-placeholders.yml | 23 - .../src/test/resources/application-test.yml | 15 - .../src/test/resources/application.yml | 11 - .../src/test/resources/arbitrary.json | 12 - .../src/test/resources/broken.json | 7 - .../customYamlRepository/contracts/custom.yml | 16 - .../src/test/resources/file.zip | Bin 171 -> 0 bytes .../generateStubs/contracts/goodbye.groovy | 28 - .../contracts/goodbye_from_file.groovy | 28 - .../contracts/goodbye_response.txt | 1 - .../generateStubs/contracts/hello.groovy | 28 - .../generateStubs/contracts/hello.json | 13 - .../git_samples/contract-git/LICENSE.txt | 202 - .../shouldSendAcceptedVerification.groovy | 49 - .../shouldSendRejectedVerification.groovy | 49 - .../rest/shouldGrantABeerIfOldEnough.groovy | 54 - .../rest/shouldRejectABeerIfTooYoung.groovy | 54 - .../rest/shouldGrantABeerIfOldEnough.json | 28 - .../rest/shouldRejectABeerIfTooYoung.json | 28 - .../shouldSendAcceptedVerification.groovy | 49 - .../shouldSendRejectedVerification.groovy | 49 - .../rest/shouldGrantABeerIfOldEnough.groovy | 54 - .../rest/shouldRejectABeerIfTooYoung.groovy | 54 - .../rest/shouldGrantABeerIfOldEnough.json | 28 - .../rest/shouldRejectABeerIfTooYoung.json | 28 - .../shouldSendAcceptedVerification.groovy | 49 - .../shouldSendRejectedVerification.groovy | 49 - .../rest/shouldGrantABeerIfOldEnough.groovy | 54 - .../rest/shouldRejectABeerIfTooYoung.groovy | 54 - .../rest/shouldGrantABeerIfOldEnough.json | 28 - .../rest/shouldRejectABeerIfTooYoung.json | 28 - .../shouldSendAcceptedVerification.groovy | 49 - .../shouldSendRejectedVerification.groovy | 49 - .../rest/shouldGrantABeerIfOldEnough.groovy | 54 - .../rest/shouldRejectABeerIfTooYoung.groovy | 54 - .../rest/shouldGrantABeerIfOldEnough.json | 28 - .../rest/shouldRejectABeerIfTooYoung.json | 28 - .../shouldSendAcceptedVerification.groovy | 49 - .../shouldSendRejectedVerification.groovy | 49 - .../rest/shouldGrantABeerIfOldEnough.groovy | 54 - .../rest/shouldRejectABeerIfTooYoung.groovy | 54 - .../rest/shouldGrantABeerIfOldEnough.json | 28 - .../rest/shouldRejectABeerIfTooYoung.json | 28 - .../shouldSendAcceptedVerification.groovy | 49 - .../shouldSendRejectedVerification.groovy | 49 - .../rest/shouldGrantABeerIfOldEnough.groovy | 54 - .../rest/shouldRejectABeerIfTooYoung.groovy | 54 - .../rest/shouldGrantABeerIfOldEnough.json | 28 - .../rest/shouldRejectABeerIfTooYoung.json | 28 - .../shouldSendAcceptedVerification.groovy | 49 - .../shouldSendRejectedVerification.groovy | 49 - .../rest/shouldGrantABeerIfOldEnough.groovy | 54 - .../rest/shouldRejectABeerIfTooYoung.groovy | 54 - .../rest/shouldGrantABeerIfOldEnough.json | 28 - .../rest/shouldRejectABeerIfTooYoung.json | 28 - .../shouldSendAcceptedVerification.groovy | 49 - .../shouldSendRejectedVerification.groovy | 49 - .../rest/shouldGrantABeerIfOldEnough.groovy | 54 - .../rest/shouldRejectABeerIfTooYoung.groovy | 54 - .../rest/shouldGrantABeerIfOldEnough.json | 28 - .../rest/shouldRejectABeerIfTooYoung.json | 28 - .../shouldSendAcceptedVerification.groovy | 49 - .../shouldSendRejectedVerification.groovy | 49 - .../rest/shouldGrantABeerIfOldEnough.groovy | 54 - .../rest/shouldRejectABeerIfTooYoung.groovy | 54 - .../rest/shouldGrantABeerIfOldEnough.json | 28 - .../rest/shouldRejectABeerIfTooYoung.json | 28 - .../shouldSendAcceptedVerification.groovy | 49 - .../shouldSendRejectedVerification.groovy | 49 - .../rest/shouldGrantABeerIfOldEnough.groovy | 54 - .../rest/shouldRejectABeerIfTooYoung.groovy | 54 - .../rest/shouldGrantABeerIfOldEnough.json | 28 - .../rest/shouldRejectABeerIfTooYoung.json | 28 - .../shouldSendAcceptedVerification.groovy | 49 - .../shouldSendRejectedVerification.groovy | 49 - .../rest/shouldGrantABeerIfOldEnough.groovy | 54 - .../rest/shouldRejectABeerIfTooYoung.groovy | 54 - .../rest/shouldGrantABeerIfOldEnough.json | 28 - .../rest/shouldRejectABeerIfTooYoung.json | 28 - .../bazConsumer1/rest/shouldSayHello.groovy | 27 - .../bazConsumer1/rest/shouldSayHello.json | 14 - .../git_samples/contract-git/README.adoc | 70 - .../contract-git/git/COMMIT_EDITMSG | 1 - .../git_samples/contract-git/git/HEAD | 1 - .../git_samples/contract-git/git/config | 10 - .../git_samples/contract-git/git/description | 1 - .../git/hooks/applypatch-msg.sample | 15 - .../contract-git/git/hooks/commit-msg.sample | 24 - .../contract-git/git/hooks/post-update.sample | 8 - .../git/hooks/pre-applypatch.sample | 14 - .../contract-git/git/hooks/pre-commit.sample | 49 - .../contract-git/git/hooks/pre-push.sample | 53 - .../contract-git/git/hooks/pre-rebase.sample | 169 - .../contract-git/git/hooks/pre-receive.sample | 24 - .../git/hooks/prepare-commit-msg.sample | 36 - .../contract-git/git/hooks/update.sample | 128 - .../git_samples/contract-git/git/index | Bin 17291 -> 0 bytes .../git_samples/contract-git/git/info/exclude | 6 - .../git_samples/contract-git/git/logs/HEAD | 3 - .../contract-git/git/logs/refs/heads/master | 3 - .../git/logs/refs/remotes/origin/HEAD | 1 - .../04/f59ff38f1c76629d41d71f38dcb87afecdf9ab | Bin 67 -> 0 bytes .../0a/124cc494496bf3574617f02e505975e8d64e5c | Bin 756 -> 0 bytes .../0b/b008b1d235cb760e13408f10662dda01027d1d | Bin 64 -> 0 bytes .../0f/c31c163430ef5913e1a85b3a6c4e36bcbf32e1 | Bin 759 -> 0 bytes .../1e/bb28e0982e1e497fe57311c4f8f34bae6f382f | Bin 79 -> 0 bytes .../1e/c084220c52398ce8cd2f8235018019504030f2 | Bin 67 -> 0 bytes .../2b/42d52aec21936e5578be5ea0e2fdb9c539ce88 | Bin 84 -> 0 bytes .../35/c8489a4e3d4761ae82a8606ea82e0e52b05376 | Bin 66 -> 0 bytes .../3b/d42890d5105a30abd82d0205b63cbf20a59e83 | 1 - .../46/ea77fbb81bcd831368a980a2c296014be94bf8 | Bin 517 -> 0 bytes .../49/c8705a4409b1a4bd0f767665632c6ae11b5b90 | 2 - .../4d/48d4d56d4bf80700498dcb29d326c0ab35cb19 | Bin 113 -> 0 bytes .../4e/5ffb7085c01081f98321985b6663f64939cdb2 | Bin 118 -> 0 bytes .../57/4590052afef4af132f7b8c5b92682401635807 | Bin 54 -> 0 bytes .../5b/0ae7cddbd14fc6ced6f87f4b9587afd6b0bd18 | Bin 127 -> 0 bytes .../5f/25f6f934c0e7e5dcc18e1bd831dd288fa6ad8a | 4 - .../5f/8216428856a5d6240f82dda04f348ba8bb742c | Bin 59 -> 0 bytes .../61/9c03cba4276c76c43b9a307ed00f39dc44616e | Bin 68 -> 0 bytes .../61/fcad6942801c44ad275671c7d125efb564f799 | Bin 83 -> 0 bytes .../62/589edd12a37dd28b6b6fed1e2d728ac9f05c8d | Bin 4447 -> 0 bytes .../63/201c9f9cfbe294f3f314df8b9c94cfee88e622 | Bin 56 -> 0 bytes .../6e/06f676c9ba4459c1feb922de8ee603ea6bebce | Bin 119 -> 0 bytes .../78/3688df3e22c6b8e1d8f58167baf4f511d369c5 | Bin 54 -> 0 bytes .../83/1a7e732650ab7428f60d51ba7d9ea33c51cf26 | Bin 88 -> 0 bytes .../90/126ac925d26698516838a646e286e037acd55e | Bin 46 -> 0 bytes .../95/f833faccac8775b5528e38f3c30b9036d5c538 | Bin 53 -> 0 bytes .../9a/4d31b7e5ca02bf207e3b04b2312ee9585ee560 | Bin 306 -> 0 bytes .../9e/5ec949f441e1828b21b7760ded76c1d42ea9bc | Bin 121 -> 0 bytes .../a1/84578130917b3bf6a6568f900f66c1ed0e72e1 | Bin 88 -> 0 bytes .../b0/cdfa5512c23af490d213948c7bdcd76d59a93e | Bin 741 -> 0 bytes .../b4/fc3812c95e3f5eed2ac1964a131464293786aa | Bin 127 -> 0 bytes .../c4/25167fb2a107afddca629fad83f8603fe2c215 | Bin 59 -> 0 bytes .../d2/5d733109a6de5ea294154f1612aaf5cb9ae06b | Bin 168 -> 0 bytes .../d2/ccedaea7b8739a11c17c91561cc2ace0a0a999 | Bin 77 -> 0 bytes .../d7/2fbbffa2d0b1ea0707df4b533f3adf69383eaa | Bin 46 -> 0 bytes .../d9/ab57c99263dac1e164883dcb7e06c542b89906 | 6 - .../fc/a3d789524348301d622344c8375d89b40f8b5d | Bin 83 -> 0 bytes .../fe/2d022c3d254c5c7a5a65783e6976fac499d9c6 | Bin 46 -> 0 bytes ...eb4e6b44a393bca412489cd42ac7cc572b42d3.idx | Bin 1968 -> 0 bytes ...b4e6b44a393bca412489cd42ac7cc572b42d3.pack | Bin 8048 -> 0 bytes .../git_samples/contract-git/git/packed-refs | 2 - .../contract-git/git/refs/heads/master | 1 - .../contract-git/git/refs/remotes/origin/HEAD | 1 - .../contract-predefined-names-git/LICENSE.txt | 202 - .../shouldSendAcceptedVerification.groovy | 49 - .../shouldSendRejectedVerification.groovy | 49 - .../rest/shouldGrantABeerIfOldEnough.groovy | 54 - .../rest/shouldRejectABeerIfTooYoung.groovy | 54 - .../rest/shouldGrantABeerIfOldEnough.json | 28 - .../rest/shouldRejectABeerIfTooYoung.json | 28 - .../shouldSendAcceptedVerification.groovy | 49 - .../shouldSendRejectedVerification.groovy | 49 - .../rest/shouldGrantABeerIfOldEnough.groovy | 54 - .../rest/shouldRejectABeerIfTooYoung.groovy | 54 - .../rest/shouldGrantABeerIfOldEnough.json | 28 - .../rest/shouldRejectABeerIfTooYoung.json | 28 - .../shouldSendAcceptedVerification.groovy | 49 - .../shouldSendRejectedVerification.groovy | 49 - .../rest/shouldGrantABeerIfOldEnough.groovy | 54 - .../rest/shouldRejectABeerIfTooYoung.groovy | 54 - .../rest/shouldGrantABeerIfOldEnough.json | 28 - .../rest/shouldRejectABeerIfTooYoung.json | 28 - .../shouldSendAcceptedVerification.groovy | 49 - .../shouldSendRejectedVerification.groovy | 49 - .../rest/shouldGrantABeerIfOldEnough.groovy | 54 - .../rest/shouldRejectABeerIfTooYoung.groovy | 54 - .../rest/shouldGrantABeerIfOldEnough.json | 28 - .../rest/shouldRejectABeerIfTooYoung.json | 28 - .../shouldSendAcceptedVerification.groovy | 49 - .../shouldSendRejectedVerification.groovy | 49 - .../rest/shouldGrantABeerIfOldEnough.groovy | 54 - .../rest/shouldRejectABeerIfTooYoung.groovy | 54 - .../rest/shouldGrantABeerIfOldEnough.json | 28 - .../rest/shouldRejectABeerIfTooYoung.json | 28 - .../shouldSendAcceptedVerification.groovy | 49 - .../shouldSendRejectedVerification.groovy | 49 - .../rest/shouldGrantABeerIfOldEnough.groovy | 54 - .../rest/shouldRejectABeerIfTooYoung.groovy | 54 - .../rest/shouldGrantABeerIfOldEnough.json | 28 - .../rest/shouldRejectABeerIfTooYoung.json | 28 - .../shouldSendAcceptedVerification.groovy | 49 - .../shouldSendRejectedVerification.groovy | 49 - .../rest/shouldGrantABeerIfOldEnough.groovy | 54 - .../rest/shouldRejectABeerIfTooYoung.groovy | 54 - .../rest/shouldGrantABeerIfOldEnough.json | 28 - .../rest/shouldRejectABeerIfTooYoung.json | 28 - .../bazConsumer1/rest/shouldSayHello.groovy | 27 - .../bazConsumer1/rest/shouldSayHello.json | 14 - .../contract-predefined-names-git/README.adoc | 70 - .../git/COMMIT_EDITMSG | 1 - .../contract-predefined-names-git/git/HEAD | 1 - .../contract-predefined-names-git/git/config | 10 - .../git/description | 1 - .../git/hooks/applypatch-msg.sample | 15 - .../git/hooks/commit-msg.sample | 24 - .../git/hooks/post-update.sample | 8 - .../git/hooks/pre-applypatch.sample | 14 - .../git/hooks/pre-commit.sample | 49 - .../git/hooks/pre-push.sample | 53 - .../git/hooks/pre-rebase.sample | 169 - .../git/hooks/pre-receive.sample | 24 - .../git/hooks/prepare-commit-msg.sample | 36 - .../git/hooks/update.sample | 128 - .../contract-predefined-names-git/git/index | Bin 11127 -> 0 bytes .../git/info/exclude | 6 - .../git/logs/HEAD | 3 - .../git/logs/refs/heads/master | 3 - .../git/logs/refs/remotes/origin/HEAD | 1 - .../1e/c084220c52398ce8cd2f8235018019504030f2 | Bin 67 -> 0 bytes .../2b/42d52aec21936e5578be5ea0e2fdb9c539ce88 | Bin 84 -> 0 bytes .../3b/d42890d5105a30abd82d0205b63cbf20a59e83 | 1 - .../3d/4a9b398121c61313558bd84a37637267539b25 | Bin 67 -> 0 bytes .../51/326f92638a0342965bc511cbcc2eab61b41050 | Bin 166 -> 0 bytes .../83/1a7e732650ab7428f60d51ba7d9ea33c51cf26 | Bin 88 -> 0 bytes .../8d/d4290a6ccef367cde77cf95ec7449dca23d6bb | Bin 84 -> 0 bytes .../b4/fc3812c95e3f5eed2ac1964a131464293786aa | Bin 127 -> 0 bytes .../c7/e616f78096e2d77a0d908464bce9d415505961 | Bin 127 -> 0 bytes .../f5/f3b2ddf93a179e1a0a93ccbf582d1e80648ce6 | Bin 106 -> 0 bytes ...eb4e6b44a393bca412489cd42ac7cc572b42d3.idx | Bin 1968 -> 0 bytes ...b4e6b44a393bca412489cd42ac7cc572b42d3.pack | Bin 8048 -> 0 bytes .../git/packed-refs | 2 - .../git/refs/heads/master | 1 - .../git/refs/remotes/origin/HEAD | 1 - .../0.0.2/mappings/someMapping.json | 15 - .../src/test/resources/logback.xml | 27 - .../bootService-0.0.1-SNAPSHOT-stubs.jar | Bin 1583 -> 0 bytes .../bootService-0.0.1-SNAPSHOT.pom | 27 - .../stubs/bootService/maven-metadata.xml | 28 - ...udDetectionServer-0.0.1-SNAPSHOT-stubs.jar | Bin 1897 -> 0 bytes .../fraudDetectionServer-0.0.1-SNAPSHOT.pom | 27 - .../fraudDetectionServer/maven-metadata.xml | 28 - .../loanIssuance-0.0.1-SNAPSHOT-stubs.jar | Bin 639 -> 0 bytes .../loanIssuance-0.0.1-SNAPSHOT.pom | 27 - .../stubs/loanIssuance/maven-metadata.xml | 28 - ...MultipleConsumers-0.0.1-SNAPSHOT-stubs.jar | Bin 3681 -> 0 bytes ...erWithMultipleConsumers-0.0.1-SNAPSHOT.pom | 27 - .../maven-metadata.xml | 28 - .../test/resources/messages/message.groovy | 46 - .../repository/contracts/contract1.groovy | 45 - .../repository/contracts/contract2.groovy | 43 - .../repository/httpcontract/contract1.groovy | 45 - .../mappings/lv/spring/cloud/bye/lv_bye.json | 13 - .../mappings/pl/spring/cloud/bye/pl_bye.json | 13 - .../spring/cloud/bye/pl_overridden_bye.json | 13 - .../spring/cloud/bye/admin/admin.json | 9 - .../mappings/spring/cloud/bye/bye.json | 13 - .../mappings/spring/cloud/hello/README.md | 1 - .../spring/cloud/hello/admin/admin.json | 9 - .../mappings/spring/cloud/hello/hello.json | 13 - .../mappings/spring/cloud/ping/ping.json | 13 - .../messagecontract/contract1.groovy | 32 - .../messagecontract/contract2.groovy | 32 - .../messagecontract/contract3.groovy | 32 - .../messagecontract/contract4.groovy | 32 - .../messagecontract/orderplaced-event.bin | 1 - .../messagecontract/orderplaced-event.csv | 2 - .../messagecontract/orderplaced-event.json | 5 - .../messagecontract/orderplaced-event.xml | 6 - .../src/test/resources/request.pdf | Bin 14631 -> 0 bytes .../src/test/resources/response.pdf | Bin 15767 -> 0 bytes .../src/test/resources/simple.json | 15 - .../src/test/resources/simulation.json | 13 - .../src/test/resources/transformers.json | 17 - .../resources/zip/zip-malicious-traversal.zip | Bin 545 -> 0 bytes spring-cloud-contract-tools/pom.xml | 38 - .../spring-cloud-contract-converters/pom.xml | 102 - .../ConversionContractVerifierException.java | 32 - .../converter/RecursiveFilesConverter.java | 210 - .../RecursiveFilesConverterApplication.java | 46 - .../verifier/converter/StubGenerator.java | 102 - .../converter/StubGeneratorProvider.java | 48 - .../verifier/converter/StubPostProcessor.java | 53 - .../DefaultWireMockStubPostProcessor.java | 164 - .../DslToWireMockClientConverter.java | 104 - .../wiremock/DslToWireMockConverter.java | 72 - .../verifier/wiremock/WireMockMetaData.java | 79 - .../wiremock/WireMockStubPostProcessor.java | 31 - .../wiremock/WireMockToDslConverter.java | 293 - .../main/resources/META-INF/spring.factories | 3 - .../RecursiveFilesConverterSpec.groovy | 237 - .../DslToWireMockClientConverterSpec.groovy | 1197 ---- .../WireMockToDslConverterSpec.groovy | 576 -- .../WiremockScenarioConverterSpec.groovy | 67 - ...DefaultWireMockStubPostProcessorTests.java | 163 - .../converter/dir3/Account creating.yml | 51 - .../resources/converter/dir3/Test route.yml | 55 - .../scenario/main_scenario/01_login.groovy | 27 - .../scenario/main_scenario/02_showCart.groovy | 27 - .../scenario/main_scenario/03_logout.groovy | 27 - .../converter/source/dir1/1_scenario.groovy | 30 - .../converter/source/dir1/2_scenario.groovy | 30 - .../converter/source/dir1/dsl1.groovy | 30 - .../converter/source/dir1/dsl1_list.groovy | 32 - .../converter/source/dir1/dsl1_list2.groovy | 33 - .../converter/source/dir1/dsl1b.groovy | 30 - .../converter/source/dir1/scenario.groovy | 47 - .../converter/source/dir2/dsl2.groovy | 30 - .../resources/converter/source/dslRoot.groovy | 30 - .../.gitignore | 1 - .../.gradle/7.3/checksums/checksums.lock | Bin 0 -> 17 bytes .../.gradle/7.3/checksums/md5-checksums.bin | Bin 0 -> 26447 bytes .../.gradle/7.3/checksums/sha1-checksums.bin | Bin 0 -> 28595 bytes .../dependencies-accessors.lock | Bin 0 -> 17 bytes .../7.3/dependencies-accessors/gc.properties | 0 .../7.3/executionHistory/executionHistory.bin | Bin 0 -> 417238 bytes .../executionHistory/executionHistory.lock | Bin 0 -> 17 bytes .../.gradle/7.3/fileChanges/last-build.bin | Bin 0 -> 1 bytes .../.gradle/7.3/fileHashes/fileHashes.bin | Bin 0 -> 33897 bytes .../.gradle/7.3/fileHashes/fileHashes.lock | Bin 0 -> 17 bytes .../7.3/fileHashes/resourceHashesCache.bin | Bin 0 -> 24379 bytes .../.gradle/7.3/gc.properties | 0 .../.gradle/7.6.1/checksums/checksums.lock | Bin 0 -> 17 bytes .../.gradle/7.6.1/checksums/md5-checksums.bin | Bin 0 -> 40547 bytes .../7.6.1/checksums/sha1-checksums.bin | Bin 0 -> 43715 bytes .../dependencies-accessors.lock | Bin 0 -> 17 bytes .../dependencies-accessors/gc.properties | 0 .../executionHistory/executionHistory.bin | Bin 0 -> 730587 bytes .../executionHistory/executionHistory.lock | Bin 0 -> 17 bytes .../.gradle/7.6.1/fileChanges/last-build.bin | Bin 0 -> 1 bytes .../.gradle/7.6.1/fileHashes/fileHashes.bin | Bin 0 -> 39747 bytes .../.gradle/7.6.1/fileHashes/fileHashes.lock | Bin 0 -> 17 bytes .../7.6.1/fileHashes/resourceHashesCache.bin | Bin 0 -> 31757 bytes .../.gradle/7.6.1/gc.properties | 0 .../.gradle/8.3/checksums/checksums.lock | Bin 0 -> 17 bytes .../.gradle/8.3/checksums/md5-checksums.bin | Bin 0 -> 27897 bytes .../.gradle/8.3/checksums/sha1-checksums.bin | Bin 0 -> 29243 bytes .../8.3/checksums/sha256-checksums.bin | Bin 0 -> 18563 bytes .../8.3/checksums/sha512-checksums.bin | Bin 0 -> 18595 bytes .../dependencies-accessors.lock | Bin 0 -> 17 bytes .../8.3/dependencies-accessors/gc.properties | 0 .../8.3/executionHistory/executionHistory.bin | Bin 0 -> 348390 bytes .../executionHistory/executionHistory.lock | Bin 0 -> 17 bytes .../.gradle/8.3/fileChanges/last-build.bin | Bin 0 -> 1 bytes .../.gradle/8.3/fileHashes/fileHashes.bin | Bin 0 -> 34447 bytes .../.gradle/8.3/fileHashes/fileHashes.lock | Bin 0 -> 17 bytes .../8.3/fileHashes/resourceHashesCache.bin | Bin 0 -> 24311 bytes .../.gradle/8.3/gc.properties | 0 .../buildOutputCleanup.lock | Bin 0 -> 17 bytes .../buildOutputCleanup/cache.properties | 2 + .../buildOutputCleanup/outputFiles.bin | Bin 0 -> 19379 bytes .../.gradle/checksums/checksums.lock | Bin 0 -> 17 bytes .../.gradle/checksums/md5-checksums.bin | Bin 0 -> 22797 bytes .../.gradle/checksums/sha1-checksums.bin | Bin 0 -> 23141 bytes .../.gradle/file-system.probe | Bin 0 -> 8 bytes .../.gradle/vcs-1/gc.properties | 0 .../.idea/.gitignore | 8 + .../.idea/codeStyles/Project.xml | 524 ++ .../.idea/codeStyles/codeStyleConfig.xml | 5 + .../.idea/compiler.xml | 6 + .../.idea/gradle.xml | 18 + .../.idea/jarRepositories.xml | 45 + .../.idea/misc.xml | 8 + .../.idea/sonarlint/issuestore/index.pb | 0 .../sonarlint/securityhotspotstore/index.pb | 0 .../.idea/uiDesigner.xml | 124 + .../.idea/vcs.xml | 6 + .../build.gradle | 139 - .../gradle.properties | 26 - .../gradle/release.gradle | 86 - .../gradle/wrapper/gradle-wrapper.jar | Bin 61574 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 - .../gradlew | 244 - .../gradlew.bat | 92 - .../pom.xml | 399 -- .../plugin/ContractVerifierExtension.java | 740 --- .../verifier/plugin/ContractsCopyTask.java | 569 -- .../GenerateClientStubsFromDslTask.java | 153 - .../plugin/GenerateServerTestsTask.java | 301 - .../plugin/PublishStubsToScmTask.java | 219 - ...ringCloudContractVerifierGradlePlugin.java | 439 -- .../verifier/plugin/VersionExtractor.java | 54 - ....springframework.cloud.contract.properties | 16 - .../spring-cloud-contract.properties | 16 - .../ContractVerifierIntegrationTest.groovy | 200 - ...ntractVerifierKotlinIntegrationTest.groovy | 40 - .../plugin/ContractVerifierTest.groovy | 235 - .../functionalTest/bootSimple/build.gradle | 66 - .../bootSimple/gradle.properties | 19 - .../gradle/wrapper/gradle-wrapper.jar | Bin 58694 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - .../functionalTest/bootSimple/gradlew | 183 - .../functionalTest/bootSimple/gradlew.bat | 103 - .../pairId/collerate_PlacesFrom_Tweet.groovy | 37 - .../pairId/moreComplexVersion.groovy | 44 - .../functionalTest/bootSimple/settings.gradle | 18 - .../twitter/place/PairIdController.groovy | 53 - .../cloud/twitter/place/Tweet.java | 31 - .../twitter/places/AcceptanceSpec.groovy | 40 - .../twitter/places/BaseMockMvcSpec.groovy | 40 - .../src/test/resources/logback-test.groovy | 31 - .../scenarioProject/build.gradle | 151 - .../1_shouldMarkClientAsNotFraud.groovy | 49 - .../2_shouldMarkClientAsFraud.groovy | 49 - .../cloud/frauddetection/Application.java | 34 - .../FraudDetectionController.java | 54 - .../frauddetection/model/FraudCheck.java | 46 - .../model/FraudCheckResult.java | 49 - .../model/FraudCheckStatus.java | 23 - .../src/main/resources/application.yml | 1 - .../org/springframework/cloud/MvcSpec.groovy | 32 - .../org/springframework/cloud/MvcTest.java | 34 - .../scenarioProject/gradle.properties | 20 - .../gradle/wrapper/gradle-wrapper.jar | Bin 58694 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - .../functionalTest/scenarioProject/gradlew | 183 - .../scenarioProject/gradlew.bat | 103 - .../cloud/frauddetection/Application.java | 34 - .../LoanApplicationService.java | 83 - .../cloud/frauddetection/model/Client.java | 31 - .../model/FraudCheckStatus.java | 23 - .../model/FraudServiceRequest.java | 51 - .../model/FraudServiceResponse.java | 44 - .../frauddetection/model/LoanApplication.java | 53 - .../model/LoanApplicationResult.java | 50 - .../model/LoanApplicationStatus.java | 23 - .../src/main/resources/application.yml | 1 - .../cloud/LoanApplicationServiceSpec.groovy | 74 - .../scenarioProject/settings.gradle | 37 - .../scenarioProjectKotlin/build.gradle.kts | 147 - .../1_shouldMarkClientAsNotFraud.groovy | 49 - .../2_shouldMarkClientAsFraud.groovy | 49 - .../cloud/frauddetection/Application.java | 34 - .../FraudDetectionController.java | 54 - .../frauddetection/model/FraudCheck.java | 46 - .../model/FraudCheckResult.java | 49 - .../model/FraudCheckStatus.java | 23 - .../src/main/resources/application.yml | 1 - .../org/springframework/cloud/MvcSpec.groovy | 32 - .../org/springframework/cloud/MvcTest.java | 34 - .../scenarioProjectKotlin/gradle.properties | 20 - .../gradle/wrapper/gradle-wrapper.jar | Bin 58694 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - .../scenarioProjectKotlin/gradlew | 183 - .../scenarioProjectKotlin/gradlew.bat | 103 - .../cloud/frauddetection/Application.java | 34 - .../LoanApplicationService.java | 83 - .../cloud/frauddetection/model/Client.java | 31 - .../model/FraudCheckStatus.java | 23 - .../model/FraudServiceRequest.java | 51 - .../model/FraudServiceResponse.java | 44 - .../frauddetection/model/LoanApplication.java | 53 - .../model/LoanApplicationResult.java | 50 - .../model/LoanApplicationStatus.java | 23 - .../src/main/resources/application.yml | 1 - .../cloud/LoanApplicationServiceSpec.groovy | 74 - .../scenarioProjectKotlin/settings.gradle.kts | 39 - .../pom.xml | 27 - .../.gitignore | 13 - .../pom.xml | 487 -- .../maven/verifier/BaseClassMapping.java | 78 - .../maven/verifier/ChangeDetector.java | 51 - .../contract/maven/verifier/ConvertMojo.java | 303 - .../maven/verifier/CopyContracts.java | 122 - .../maven/verifier/GenerateStubsMojo.java | 173 - .../maven/verifier/GenerateTestsMojo.java | 379 -- .../maven/verifier/LeftOverPrevention.java | 59 - .../maven/verifier/ManifestCreator.java | 69 - .../verifier/MavenContractsDownloader.java | 172 - .../maven/verifier/PushStubsToScmMojo.java | 132 - .../contract/maven/verifier/RunMojo.java | 182 - .../AetherStubDownloaderFactory.java | 79 - .../verifier/stubrunner/LocalStubRunner.java | 45 - .../verifier/stubrunner/RemoteStubRunner.java | 67 - .../m2e/lifecycle-mapping-metadata.xml | 21 - .../resources/META-INF/plexus/components.xml | 45 - .../src/site/asciidoc/complex.adoc | 45 - .../src/site/asciidoc/configs.adoc | 45 - .../src/site/asciidoc/index.adoc | 24 - .../src/site/asciidoc/junit.adoc | 31 - .../src/site/asciidoc/spock.adoc | 31 - .../src/site/asciidoc/usage.adoc | 38 - .../src/site/site.xml | 60 - .../maven/verifier/AbstractMojoTest.java | 88 - .../maven/verifier/ChangeDetectorTests.java | 40 - .../MavenContractsDownloaderTests.java | 110 - .../maven/verifier/PluginUnitTest.java | 350 -- .../InclusionPropertiesAccessor.java | 25 - .../basic-baseclass-from-mappings/pom.xml | 49 - .../contracts/com/hello/v1/Messaging.groovy | 29 - .../contracts/com/hello/v1/Sample.groovy | 32 - .../contracts/com/hello/v1/WithList.groovy | 32 - .../basic-generated-baseclass/pom.xml | 43 - .../contracts/hello/v1/Messaging.groovy | 29 - .../contracts/hello/v1/Sample.groovy | 32 - .../contracts/hello/v1/WithList.groovy | 32 - .../basic-remote-contracts/pom-with-repo.xml | 50 - .../projects/basic-remote-contracts/pom.xml | 45 - .../src/test/projects/basic/pom.xml | 39 - .../test/resources/contracts/Messaging.groovy | 29 - .../test/resources/contracts/Sample.groovy | 32 - .../test/resources/contracts/WithList.groovy | 33 - .../common-repo/consumer1/Messaging.groovy | 29 - .../common-repo/consumer1/Sample.groovy | 32 - .../common-repo/consumer1/WithList.groovy | 32 - .../src/test/projects/common-repo/pom.xml | 51 - .../pom.xml | 62 - .../java/com/example/services/TestBase.java | 27 - .../projects/complex-configuration/.gitignore | 1 - .../projects/complex-configuration/pom.xml | 142 - .../frauddetection/Application.java | 27 - .../FraudDetectionController.java | 53 - .../frauddetection/model/FraudCheck.java | 44 - .../model/FraudCheckResult.java | 47 - .../model/FraudCheckStatus.java | 21 - .../src/test/contracts/brokenContract.groovy | 45 - .../contracts/shouldMarkClientAsFraud.groovy | 43 - .../shouldMarkClientAsNotFraud.groovy | 45 - .../frauddetection/BaseAccurest.java | 27 - .../matchers/CustomMatchers.java | 25 - .../projects/complex-remote-contracts/pom.xml | 47 - .../different-module-configuration/.gitignore | 1 - .../module/pom.xml | 140 - .../frauddetection/Application.java | 27 - .../FraudDetectionController.java | 53 - .../frauddetection/model/FraudCheck.java | 44 - .../model/FraudCheckResult.java | 47 - .../model/FraudCheckStatus.java | 21 - .../src/test/contracts/brokenContract.groovy | 45 - .../contracts/shouldMarkClientAsFraud.groovy | 43 - .../shouldMarkClientAsNotFraud.groovy | 45 - .../frauddetection/BaseAccurest.java | 27 - .../matchers/CustomMatchers.java | 25 - .../different-module-configuration/pom.xml | 37 - .../test/projects/generatedStubs/.gitignore | 1 - .../src/test/projects/generatedStubs/pom.xml | 39 - .../target/stubs/contracts/Sample.groovy | 18 - .../target/stubs/mappings/Sample.json | 25 - .../projects/generatedStubsOnly/.gitignore | 1 - .../target/stubs/Sample.json | 25 - .../git-basic-remote-contracts/pom.xml | 39 - .../test/projects/multiple-contracts/pom.xml | 49 - .../contracts/com/hello/v1/WithList.groovy | 40 - .../test/projects/plugin-extension/pom.xml | 146 - .../src/main/java/hello/Application.java | 27 - .../src/main/java/hello/Greeting.java | 36 - .../main/java/hello/GreetingController.java | 36 - .../src/test/java/hello/BaseAccurest.java | 27 - .../resources/contracts/greetings_ok.groovy | 35 - .../greetings_with_default_value.groovy | 31 - .../src/test/projects/pomless/Sample.groovy | 32 - .../test/projects/spring-boot-groovy/pom.xml | 191 - .../src/main/java/hello/Application.java | 27 - .../src/main/java/hello/Greeting.java | 36 - .../main/java/hello/GreetingController.java | 52 - .../src/main/java/hello/GreetingResponse.java | 47 - .../src/test/groovy/hello/BaseAccurest.groovy | 27 - .../resources/contracts/greetings_ok.groovy | 35 - .../contracts/greetings_post_ok.groovy | 45 - .../greetings_with_default_value.groovy | 31 - .../test/projects/spring-boot-java/pom.xml | 146 - .../src/main/java/hello/Application.java | 27 - .../src/main/java/hello/Greeting.java | 36 - .../main/java/hello/GreetingController.java | 36 - .../src/test/java/hello/BaseAccurest.java | 27 - .../resources/contracts/greetings_ok.groovy | 35 - .../greetings_with_default_value.groovy | 31 - .../src/test/projects/withStubs/pom.xml | 38 - .../src/test/resources/stubs/Sample.groovy | 32 - .../src/test/resources/logback.xml | 25 - .../contracts-0.0.1-SNAPSHOT.jar | Bin 3880 -> 0 bytes .../contracts-0.0.1-SNAPSHOT.pom | 27 - .../0.0.1-SNAPSHOT/maven-metadata-local.xml | 24 - .../contracts-0.0.1-SNAPSHOT.pom | 27 - .../com/example/contracts/maven-metadata.xml | 28 - .../1.0.4-SNAPSHOT/maven-metadata-local.xml | 24 - .../services-contracts-1.0.4-SNAPSHOT.jar | Bin 15718 -> 0 bytes .../services-contracts-1.0.4-SNAPSHOT.pom | 27 - .../services-contracts/maven-metadata.xml | 28 - spring-cloud-contract-verifier/pom.xml | 344 -- .../verifier/util/BodyExtractor.groovy | 106 - .../verifier/util/ContentUtils.groovy | 697 --- .../util/JsonToJsonPathsConverter.groovy | 634 --- .../util/xml/XmlToXPathsConverter.groovy | 331 -- .../cloud/contract/verifier/FileSaver.java | 73 - .../contract/verifier/TestGenerator.java | 195 - .../verifier/TestGeneratorApplication.java | 43 - .../verifier/assertion/CollectionAssert.java | 198 - .../assertion/ContractCollectionAssert.java | 122 - .../SpringCloudContractAssertions.java | 45 - .../contract/verifier/builder/Acceptor.java | 23 - .../verifier/builder/BaseClassProvider.java | 69 - .../verifier/builder/BlockBuilder.java | 246 - .../builder/BodyAssertionLineCreator.java | 117 - .../builder/BodyMethodGeneration.java | 81 - .../verifier/builder/BodyMethodVisitor.java | 135 - .../contract/verifier/builder/BodyParser.java | 165 - .../contract/verifier/builder/BodyReader.java | 127 - .../contract/verifier/builder/BodyThen.java | 37 - .../verifier/builder/ClassAnnotation.java | 21 - .../builder/ClassAnnotationsBuilder.java | 57 - .../verifier/builder/ClassBodyBuilder.java | 91 - .../verifier/builder/ClassMetaData.java | 35 - .../verifier/builder/ClassVerifier.java | 30 - .../verifier/builder/CommunicationType.java | 29 - .../verifier/builder/ComparisonBuilder.java | 105 - .../verifier/builder/ContentHelper.java | 53 - .../builder/CookieElementProcessor.java | 88 - .../verifier/builder/CustomModeAcceptor.java | 39 - .../verifier/builder/CustomModeBodyGiven.java | 90 - .../builder/CustomModeBodyParser.java | 34 - .../builder/CustomModeCookiesGiven.java | 72 - .../builder/CustomModeCookiesThen.java | 60 - .../verifier/builder/CustomModeFields.java | 45 - .../verifier/builder/CustomModeGiven.java | 70 - .../builder/CustomModeHeadersGiven.java | 76 - .../builder/CustomModeHeadersThen.java | 82 - .../verifier/builder/CustomModeImports.java | 48 - .../builder/CustomModeMethodWithUrlGiven.java | 68 - .../builder/CustomModeQueryParamsGiven.java | 96 - .../builder/CustomModeRequestBuildGiven.java | 42 - .../builder/CustomModeRequestGiven.java | 43 - .../builder/CustomModeResponseWhen.java | 43 - .../CustomModeSchemeProtocolGiven.java | 47 - .../builder/CustomModeStaticImports.java | 45 - .../builder/CustomModeStatusCodeThen.java | 47 - .../verifier/builder/CustomModeThen.java | 55 - .../verifier/builder/CustomModeWhen.java | 58 - .../builder/CustomMultipartGiven.java | 41 - .../builder/DefaultBaseClassProvider.java | 35 - .../builder/DefaultClassMetadata.java | 42 - .../verifier/builder/DefaultImports.java | 59 - .../builder/DefaultJsonStaticImports.java | 48 - .../builder/DefaultStaticImports.java | 44 - .../verifier/builder/ExplicitAcceptor.java | 27 - .../builder/ExplicitRequestGiven.java | 43 - .../builder/ExplicitResponseWhen.java | 43 - .../builder/ExplicitRestAssuredImports.java | 49 - .../ExplicitRestAssuredStaticImports.java | 48 - .../contract/verifier/builder/Field.java | 21 - .../verifier/builder/FieldBuilder.java | 47 - .../builder/GeneratedClassDataForMethod.java | 61 - .../builder/GeneratedClassMetaData.java | 76 - .../verifier/builder/GeneratedTestClass.java | 38 - .../builder/GeneratedTestClassBuilder.java | 179 - .../builder/GenericBinaryBodyThen.java | 62 - .../verifier/builder/GenericHttpBodyThen.java | 66 - .../verifier/builder/GenericJsonBodyThen.java | 211 - .../verifier/builder/GenericTextBodyThen.java | 73 - .../verifier/builder/GenericXmlBodyThen.java | 55 - .../contract/verifier/builder/Given.java | 21 - .../verifier/builder/GroovyBodyParser.java | 95 - .../verifier/builder/GroovyClassMetaData.java | 103 - .../builder/GroovyComparisonBuilder.java | 68 - .../contract/verifier/builder/Imports.java | 21 - .../verifier/builder/ImportsBuilder.java | 111 - .../verifier/builder/JUnit4IgnoreImports.java | 46 - .../builder/JUnit4IgnoreMethodAnnotation.java | 51 - .../verifier/builder/JUnit4Imports.java | 47 - .../builder/JUnit4MethodAnnotation.java | 48 - .../builder/JUnit4OrderClassAnnotation.java | 48 - .../verifier/builder/JUnit4OrderImports.java | 48 - .../verifier/builder/JUnit5IgnoreImports.java | 46 - .../builder/JUnit5IgnoreMethodAnnotation.java | 51 - .../verifier/builder/JUnit5Imports.java | 48 - .../builder/JUnit5MethodAnnotation.java | 48 - .../builder/JUnit5OrderClassAnnotation.java | 48 - .../verifier/builder/JUnit5OrderImports.java | 49 - .../verifier/builder/JUnitMethodMetadata.java | 58 - .../verifier/builder/JavaClassMetaData.java | 98 - .../verifier/builder/JavaJaxRsThen.java | 37 - .../verifier/builder/JavaJaxRsWhen.java | 37 - .../builder/JavaMessagingBodyParser.java | 24 - .../builder/JavaMessagingWithBodyThen.java | 37 - .../verifier/builder/JavaMultipartGiven.java | 85 - .../builder/JavaRestAssuredGiven.java | 37 - .../verifier/builder/JavaRestAssuredThen.java | 38 - .../verifier/builder/JavaRestAssuredWhen.java | 37 - .../verifier/builder/JavaTestGenerator.java | 112 - .../verifier/builder/JaxRsAcceptor.java | 30 - .../verifier/builder/JaxRsBodyParser.java | 36 - .../contract/verifier/builder/JaxRsGiven.java | 39 - .../verifier/builder/JaxRsImports.java | 47 - .../builder/JaxRsRequestCookiesWhen.java | 80 - .../builder/JaxRsRequestHeadersWhen.java | 95 - .../builder/JaxRsRequestInvokerWhen.java | 40 - .../builder/JaxRsRequestMethodWhen.java | 77 - .../verifier/builder/JaxRsRequestWhen.java | 69 - .../builder/JaxRsResponseCookiesThen.java | 72 - .../builder/JaxRsResponseHeadersThen.java | 89 - .../verifier/builder/JaxRsStaticImports.java | 47 - .../verifier/builder/JaxRsStatusCodeThen.java | 47 - .../contract/verifier/builder/JaxRsThen.java | 55 - .../verifier/builder/JaxRsUrlPathWhen.java | 132 - .../contract/verifier/builder/JaxRsWhen.java | 71 - .../builder/JsonBodyVerificationBuilder.java | 363 -- .../verifier/builder/JsonPathImports.java | 48 - .../builder/MessagingAssertThatThen.java | 41 - .../builder/MessagingAssertThatWhen.java | 40 - .../verifier/builder/MessagingBodyParser.java | 43 - .../verifier/builder/MessagingBodyThen.java | 63 - .../verifier/builder/MessagingFields.java | 49 - .../builder/MessagingHeadersThen.java | 103 - .../verifier/builder/MessagingImports.java | 51 - .../builder/MessagingReceiveMessageThen.java | 68 - .../builder/MessagingSpockNoMessageThen.java | 45 - .../builder/MessagingStaticImports.java | 50 - .../builder/MessagingTriggeredByWhen.java | 41 - .../verifier/builder/MessagingWhen.java | 50 - .../builder/MessagingWithBodyThen.java | 59 - .../verifier/builder/MetaDataBuilder.java | 47 - .../verifier/builder/MethodAcceptor.java | 25 - .../builder/MethodAnnotationBuilder.java | 59 - .../verifier/builder/MethodAnnotations.java | 5 - .../verifier/builder/MethodMetadata.java | 35 - .../builder/MethodMetadataBuilder.java | 47 - .../verifier/builder/MethodPostProcessor.java | 21 - .../verifier/builder/MethodPreProcessor.java | 35 - .../verifier/builder/MethodVisitor.java | 25 - .../verifier/builder/MockMvcAcceptor.java | 30 - .../verifier/builder/MockMvcAsyncWhen.java | 58 - .../verifier/builder/MockMvcBodyGiven.java | 89 - .../verifier/builder/MockMvcCookiesGiven.java | 72 - .../verifier/builder/MockMvcHeadersGiven.java | 76 - .../builder/MockMvcQueryParamsWhen.java | 109 - .../verifier/builder/MockMvcRequestGiven.java | 43 - .../verifier/builder/MockMvcResponseWhen.java | 43 - .../builder/MockMvcRestAssuredImports.java | 50 - .../MockMvcRestAssuredStaticImports.java | 48 - .../verifier/builder/MockMvcUrlWhen.java | 69 - .../verifier/builder/NameProvider.java | 82 - .../verifier/builder/OurCallable.java | 23 - .../verifier/builder/QueryParamsResolver.java | 45 - .../verifier/builder/RestAssuredAcceptor.java | 31 - .../builder/RestAssuredBodyParser.java | 34 - .../builder/RestAssuredCookiesThen.java | 60 - .../verifier/builder/RestAssuredGiven.java | 71 - .../builder/RestAssuredHeadersThen.java | 82 - .../builder/RestAssuredStatusCodeThen.java | 47 - .../verifier/builder/RestAssuredThen.java | 55 - .../verifier/builder/RestAssuredWhen.java | 67 - .../verifier/builder/SingleMethodBuilder.java | 239 - .../verifier/builder/SingleTestGenerator.java | 60 - .../builder/SpockExplicitMultipartGiven.java | 68 - .../verifier/builder/SpockIgnoreImports.java | 46 - .../builder/SpockIgnoreMethodAnnotation.java | 51 - .../verifier/builder/SpockImports.java | 47 - .../builder/SpockJaxRsBodyParser.java | 40 - .../verifier/builder/SpockJaxRsThen.java | 38 - .../verifier/builder/SpockJaxRsWhen.java | 37 - .../builder/SpockMessagingBodyParser.java | 25 - .../builder/SpockMessagingEmptyThen.java | 48 - .../builder/SpockMessagingWithBodyThen.java | 37 - .../verifier/builder/SpockMethodMetadata.java | 57 - .../builder/SpockMockMvcMultipartGiven.java | 84 - .../builder/SpockMockMvcRequestGiven.java | 45 - .../builder/SpockMockMvcResponseWhen.java | 45 - .../builder/SpockOrderClassAnnotation.java | 48 - .../verifier/builder/SpockOrderImports.java | 48 - .../builder/SpockRestAssuredBodyParser.java | 35 - .../builder/SpockRestAssuredGiven.java | 37 - .../builder/SpockRestAssuredThen.java | 38 - .../builder/SpockRestAssuredWhen.java | 37 - .../SpockWebTestClientMultipartGiven.java | 68 - .../SuppressWarningsClassAnnotation.java | 42 - .../TemplateUpdatingMethodPostProcessor.java | 48 - .../verifier/builder/TestNGImports.java | 47 - .../builder/TestNGMethodAnnotation.java | 46 - .../builder/TestSideRequestTemplateModel.java | 215 - .../cloud/contract/verifier/builder/Then.java | 21 - .../verifier/builder/UserImports.java | 45 - .../verifier/builder/UserStaticImports.java | 45 - .../contract/verifier/builder/Visitor.java | 21 - .../builder/WebTestClientAcceptor.java | 27 - .../builder/WebTestClientRequestGiven.java | 43 - .../builder/WebTestClientResponseWhen.java | 43 - ...ebTestClientRestAssured3StaticImports.java | 48 - .../WebTestClientRestAssuredImports.java | 50 - .../cloud/contract/verifier/builder/When.java | 21 - .../builder/XmlBodyVerificationBuilder.java | 84 - .../contract/verifier/builder/XmlImports.java | 50 - .../handlebars/HandlebarsEscapeHelper.java | 62 - .../handlebars/HandlebarsJsonPathHelper.java | 104 - .../ContractVerifierConfigProperties.java | 366 -- .../verifier/config/TestFramework.java | 79 - .../contract/verifier/config/TestMode.java | 51 - .../config/framework/CustomDefinition.java | 48 - .../config/framework/JUnit5Definition.java | 48 - .../config/framework/JUnitDefinition.java | 48 - .../config/framework/SpockDefinition.java | 48 - .../framework/TestFrameworkDefinition.java | 54 - .../config/framework/TestNGDefinition.java | 50 - .../verifier/converter/ContractsToYaml.java | 557 -- .../verifier/converter/ToYamlConverter.java | 114 - .../converter/ToYamlConverterApplication.java | 36 - .../verifier/converter/YamlContract.java | 809 --- .../converter/YamlContractConverter.java | 116 - .../verifier/converter/YamlToContracts.java | 872 --- .../dsl/ContractVerifierMetadata.java | 70 - .../wiremock/BaseWireMockStubStrategy.java | 231 - .../wiremock/DefaultResponseTransformer.java | 60 - .../SpringCloudContractRequestMatcher.java | 182 - .../dsl/wiremock/WireMockExtensions.java | 34 - .../wiremock/WireMockRequestStubStrategy.java | 554 -- .../WireMockResponseStubStrategy.java | 137 - .../dsl/wiremock/WireMockStubMapping.java | 34 - .../dsl/wiremock/WireMockStubStrategy.java | 89 - ...atcherToWireMockValuePatternConverter.java | 41 - .../verifier/file/ContractFileScanner.java | 304 - .../verifier/file/ContractMetadata.java | 126 - .../verifier/file/SingleContractMetadata.java | 283 - .../cloud/contract/verifier/http/Body.java | 68 - .../http/ContractVerifierHttpMetaData.java | 189 - .../contract/verifier/http/HttpVerifier.java | 36 - .../verifier/http/OkHttpHttpVerifier.java | 138 - .../cloud/contract/verifier/http/Request.java | 397 -- .../contract/verifier/http/Response.java | 187 - .../messaging/MessageVerifierReceiver.java | 77 - .../messaging/MessageVerifierSender.java | 75 - .../verifier/messaging/amqp/AmqpMetadata.java | 153 - .../boot/AutoConfigureMessageVerifier.java | 37 - .../messaging/camel/CamelStubMessages.java | 129 - .../ContractVerifierCamelConfiguration.java | 115 - .../ContractVerifierCamelMessageBuilder.java | 45 - .../messaging/camel/StandaloneMetadata.java | 131 - ...tractVerifierIntegrationConfiguration.java | 109 - ...ractVerifierIntegrationMessageBuilder.java | 34 - .../SpringIntegrationStubMessages.java | 85 - .../internal/ContractVerifierMessage.java | 72 - .../ContractVerifierMessageMetadata.java | 90 - .../internal/ContractVerifierMessaging.java | 92 - .../ContractVerifierObjectMapper.java | 60 - .../jms/ContractVerifierJmsConfiguration.java | 157 - .../messaging/jms/JmsStubMessages.java | 113 - .../messaging/kafka/KafkaMetadata.java | 118 - ...NoOpContractVerifierAutoConfiguration.java | 100 - .../messaging/noop/NoOpStubMessages.java | 49 - ...ntractVerifierStreamAutoConfiguration.java | 118 - .../ContractVerifierStreamMessageBuilder.java | 38 - .../messaging/stream/DefaultChannels.java | 23 - .../messaging/stream/DestinationResolver.java | 83 - .../StreamInputDestinationMessageSender.java | 63 - ...treamOutputDestinationMessageReceiver.java | 58 - .../stream/StreamStubMessageSender.java | 73 - .../messaging/stream/StreamStubMessages.java | 61 - .../util/ContractVerifierMessagingUtil.java | 126 - .../template/HandlebarsTemplateProcessor.java | 259 - .../verifier/template/TemplateProcessor.java | 61 - .../contract/verifier/util/AssertionUtil.java | 39 - .../contract/verifier/util/CloneUtils.java | 43 - .../contract/verifier/util/ContentType.java | 61 - .../verifier/util/ContractScanner.java | 103 - .../util/ContractVerifierDslConverter.java | 321 -- .../verifier/util/ContractVerifierUtil.java | 246 - .../util/DelegatingJsonVerifiable.java | 410 -- .../verifier/util/DslParseException.java | 35 - .../FinishedDelegatingJsonVerifiable.java | 56 - .../contract/verifier/util/JsonPaths.java | 28 - .../contract/verifier/util/MapConverter.java | 236 - .../contract/verifier/util/MetadataUtil.java | 280 - .../verifier/util/MethodBuffering.java | 29 - .../util/MethodBufferingJsonVerifiable.java | 84 - .../contract/verifier/util/NamesUtil.java | 222 - .../verifier/util/RegexpBuilders.java | 169 - .../verifier/util/ShouldTraverse.java | 34 - .../util/SpringCloudContractMetadata.java | 53 - .../util/ToFileContractsTransformer.java | 109 - .../util/xml/ArrayValueAssertion.java | 144 - .../util/xml/DOMNamespaceContext.java | 76 - .../verifier/util/xml/FieldAssertion.java | 33 - .../verifier/util/xml/IteratingOverArray.java | 38 - .../util/xml/ReadyToCheckAsserter.java | 33 - .../verifier/util/xml/XPathBuilder.java | 50 - .../verifier/util/xml/XmlArrayVerifiable.java | 41 - .../verifier/util/xml/XmlAsserter.java | 445 -- .../util/xml/XmlAsserterConfiguration.java | 29 - .../verifier/util/xml/XmlAssertion.java | 117 - .../verifier/util/xml/XmlCachedObjects.java | 71 - .../contract/verifier/util/xml/XmlReader.java | 32 - .../verifier/util/xml/XmlVerifiable.java | 222 - ....boot.AutoConfigureMessageVerifier.imports | 5 - .../verifier/GeneratorScannerSpec.groovy | 66 - .../cloud/contract/verifier/MainTest.groovy | 33 - .../contract/verifier/TestGeneratorTests.java | 114 - .../verifier/builder/BlockBuilderTests.java | 91 - .../verifier/builder/BookReturned.groovy | 30 - .../verifier/builder/ClassBuilderSpec.groovy | 108 - .../builder/ContractHttpDocsSpec.groovy | 446 -- .../builder/GeneratedTestClassTests.java | 152 - .../JaxRsClientMethodBuilderSpec.groovy | 1590 ------ .../verifier/builder/JsonAssertTests.java | 37 - .../MessagingMethodBodyBuilderSpec.groovy | 1128 ---- .../builder/MethodBodyBuilderSpec.groovy | 2284 -------- .../verifier/builder/MethodBuilderSpec.groovy | 56 - ...vcMethodBodyBuilderWithMatchersSpec.groovy | 790 --- .../builder/QueryParamsResolverSpec.groovy | 100 - .../builder/SingleTestGeneratorSpec.groovy | 1143 ---- .../SpringTestMethodBodyBuildersSpec.groovy | 3403 ----------- .../builder/XmlMethodBodyBuilderSpec.groovy | 479 -- .../YamlMockMvcMethodBodyBuilderSpec.groovy | 2022 ------- .../verifier/builder/messageResponse.json | 3 - .../DslToYamlContractConverterSpec.groovy | 692 --- .../JavaContractConverterSpec.groovy | 196 - .../YamlContractConverterSpec.groovy | 1205 ---- .../converter/YamlContractSpec.groovy | 36 - .../wiremock/TestWireMockExtensions.groovy | 40 - .../dsl/wiremock/WireMockGroovyDslSpec.groovy | 3249 ----------- .../WireMockRequestStubStrategySpec.groovy | 76 - .../WireMockResponseStubStrategySpec.groovy | 315 - .../wiremock/WireMockStubMappingSpec.groovy | 75 - .../dsl/wiremock/WireMockStubVerifier.groovy | 46 - .../WireMockXmlStubStrategySpec.groovy | 400 -- .../file/ContractFileScannerNewApiSpec.groovy | 207 - .../file/ContractFileScannerSpec.groovy | 205 - ...ractVerifierCamelMessageBuilderSpec.groovy | 37 - .../ContractVerifierObjectMapperSpec.groovy | 70 - ...ContractVerifierHelperForStreamTest.groovy | 35 - ...eamStubMessagesWithDestinationsSpec.groovy | 100 - .../verifier/util/BodyExtractorSpec.groovy | 35 - .../verifier/util/ContentUtilsSpec.groovy | 51 - .../ContractVerifierDslConverterSpec.groovy | 222 - .../util/JsonToJsonPathsConverterSpec.groovy | 924 --- .../verifier/util/NamesUtilSpec.groovy | 170 - .../verifier/util/SyntaxChecker.groovy | 213 - .../ToFileContractsTransformerSpec.groovy | 49 - .../verifier/util/xml/XPathSpec.groovy | 40 - .../verifier/util/xml/XmlAssertionSpec.groovy | 594 -- .../util/xml/XmlToXPathsConverterSpec.groovy | 110 - .../assertion/CollectionAssertTests.java | 344 -- .../XmlBodyVerificationBuilderTest.java | 32 - .../dsl/ContractVerifierMetadataTests.java | 43 - .../wiremock/GraphQLRequestMatcherTests.java | 211 - ...pringCloudContractRequestMatcherTests.java | 157 - .../contract/verifier/http/RequestTests.java | 48 - .../contract/verifier/http/ResponseTests.java | 40 - .../messaging/amqp/AmqpMetadataTests.java | 59 - .../AutoConfigureMessageVerifierTests.java | 56 - ...ntractVerifierCamelConfigurationTests.java | 58 - ...VerifierIntegrationConfigurationTests.java | 42 - ...ContractVerifierJmsConfigurationTests.java | 58 - .../messaging/jms/JmsStubMessagesTests.java | 59 - .../messaging/kafka/KafkaMetadataTests.java | 47 - ...ontractVerifierAutoConfigurationTests.java | 41 - ...tVerifierStreamAutoConfigurationTests.java | 58 - .../util/ContractVerifierUtilTest.java | 217 - .../test/resources/META-INF/spring.factories | 4 - .../src/test/resources/application.properties | 1 - .../test/resources/body_builder/request.pdf | Bin 14631 -> 0 bytes .../test/resources/body_builder/response.pdf | Bin 15767 -> 0 bytes .../body_builder/worksWithPdf.groovy | 19 - .../charset/readFromFileWithCharset.groovy | 38 - .../src/test/resources/charset/request.json | 3 - .../src/test/resources/charset/response.json | 3 - .../resources/classpath/readFromFile.groovy | 35 - .../src/test/resources/classpath/request.json | 3 - .../src/test/resources/classpath/request.xml | 5 - .../test/resources/classpath/response.json | 3 - .../src/test/resources/contract.groovy | 35 - .../src/test/resources/contract.yml | 45 - .../contractsToCompile/contract.java | 48 - .../contract_docs_examples.java | 342 -- .../contract_multipart.java | 68 - .../contractsToCompile/contract_rest.java | 70 - .../contract_rest_from_file.java | 42 - .../contract_rest_from_pdf.java | 48 - .../contract_rest_with_tags.java | 116 - .../contractsToCompile/contract_xml.java | 65 - .../contractsToCompile/package_contract.java | 32 - .../resources/contractsToCompile/request.json | 3 - .../resources/contractsToCompile/request.pdf | Bin 14631 -> 0 bytes .../contractsToCompile/response.json | 3 - .../resources/contractsToCompile/response.pdf | Bin 15767 -> 0 bytes .../messaging/couponCollectedEventV1.groovy | 46 - .../messaging/couponCollectedEventV2.groovy | 46 - .../messaging/couponSentEventSm.groovy | 45 - .../admin/v1/shouldReturnBetRanges.groovy | 54 - ...uldReturnEmptyFriendsWhenGetFriends.groovy | 46 - .../rest/shouldUpdateUserInfo.groovy | 60 - .../directory/with/custom/yml/custom.yml | 16 - .../directory/with/mixed/contract.yml | 13 - .../resources/directory/with/mixed/dsl.groovy | 50 - .../directory/with/mixed/invalid.json | 23 - .../name-with-hyphen/car-rental/diff.groovy | 27 - .../directory/with/scenario/01_login.groovy | 27 - .../with/scenario/02_showCart.groovy | 27 - .../directory/with/scenario/03_logout.groovy | 27 - .../with/stubs/different/diff.groovy | 27 - .../with/stubs/other/different/diff.groovy | 27 - .../directory/with/stubs/other/other.groovy | 27 - .../directory/with/stubs/other/sample.groovy | 27 - .../with/stubs/package/exceptions/test.groovy | 27 - .../stubs/package/v1/exceptions/testv1.groovy | 27 - .../stubs/package/v2/exceptions/testv2.groovy | 27 - .../test/resources/dsl/basic/sampleDsl.groovy | 50 - .../src/test/resources/getBody.json | 17 - .../kotlin/contract_docs_examples.kts | 329 -- .../test/resources/kotlin/contract_rest.kts | 61 - .../test/resources/kotlin/contract_xml.kts | 60 - .../src/test/resources/kotlin/multipart.kts | 48 - .../test/resources/kotlin/readFromFile.kts | 37 - .../src/test/resources/kotlin/request.json | 3 - .../src/test/resources/kotlin/request.pdf | Bin 14631 -> 0 bytes .../src/test/resources/kotlin/response.json | 3 - .../src/test/resources/kotlin/response.pdf | Bin 15767 -> 0 bytes .../src/test/resources/logback.xml | 17 - .../src/test/resources/main.json | 17 - .../src/test/resources/messageResponse.json | 3 - .../test/resources/multiple_contracts.groovy | 37 - .../META-INF/1.0.0.SNAPSHOT/01_login.groovy | 17 - .../3.0.0.SNAPSHOT/01_login.groovy | 17 - .../3.0.0.SNAPSHOT/normal/01_login.groovy | 17 - .../1.0.0.SNAPSHOT/normal/01_login.groovy | 18 - .../META-INF/2.0.0.SNAPSHOT/01_login.groovy | 17 - .../strange_[3.3.3]_directory/02_login.groovy | 27 - .../bar/03_login.groovy | 27 - .../foo/01_login.groovy | 27 - .../stubs/wiremocks/other/sample.json | 23 - .../resources/stubs/wiremocks/sample.json | 23 - .../src/test/resources/yml/contract.yml | 87 - .../yml/contract_broken_request_headers.yml | 46 - .../yml/contract_broken_response_headers.yml | 12 - .../test/resources/yml/contract_cookies.yml | 34 - .../test/resources/yml/contract_from_file.yml | 7 - .../test/resources/yml/contract_matchers.yml | 206 - .../resources/yml/contract_matchers_url.yml | 8 - .../test/resources/yml/contract_message.yml | 30 - .../yml/contract_message_matchers.yml | 81 - .../resources/yml/contract_message_method.yml | 17 - .../yml/contract_message_scenario1.yml | 10 - .../resources/yml/contract_messaging_pdf.yml | 8 - .../test/resources/yml/contract_multipart.yml | 29 - .../src/test/resources/yml/contract_pdf.yml | 11 - .../yml/contract_reference_request.yml | 30 - .../src/test/resources/yml/contract_rest.yml | 49 - .../resources/yml/contract_rest_named_xml.yml | 17 - .../resources/yml/contract_rest_with_path.yml | 51 - .../test/resources/yml/contract_rest_xml.yml | 68 - .../src/test/resources/yml/issue1038.yml | 15 - .../src/test/resources/yml/issue1052.yml | 22 - .../test/resources/yml/multiple_contracts.yml | 21 - .../resources/yml/oa3/openapi_petstore.yml | 157 - .../src/test/resources/yml/request.json | 3 - .../src/test/resources/yml/request.pdf | Bin 14631 -> 0 bytes .../src/test/resources/yml/response.json | 3 - .../src/test/resources/yml/response.pdf | Bin 15767 -> 0 bytes spring-cloud-contract-wiremock/.gitignore | 1 - spring-cloud-contract-wiremock/pom.xml | 144 - .../wiremock/AutoConfigureHttpClient.java | 42 - .../wiremock/AutoConfigureWireMock.java | 95 - .../wiremock/WireMockApplicationListener.java | 126 - .../wiremock/WireMockConfiguration.java | 482 -- .../WireMockConfigurationCustomizer.java | 30 - .../wiremock/WireMockRestServiceServer.java | 456 -- .../WireMockRestTemplateConfiguration.java | 93 - .../contract/wiremock/WireMockSpring.java | 65 - .../wiremock/WireMockStubMapping.java | 34 - .../WireMockTestExecutionListener.java | 148 - .../wiremock/file/ResourcesFileSource.java | 280 - .../restdocs/BasicMappingBuilder.java | 258 - .../wiremock/restdocs/ContractDslSnippet.java | 201 - .../restdocs/ContractExchangeHandler.java | 327 -- .../restdocs/ContractResultHandler.java | 294 - ...icPortPlaceholderInserterPreprocessor.java | 43 - .../wiremock/restdocs/JsonPathValue.java | 82 - .../restdocs/SpringCloudContractRestDocs.java | 88 - .../WireMockRestAssuredConfiguration.java | 45 - .../wiremock/restdocs/WireMockRestDocs.java | 56 - .../WireMockRestDocsConfiguration.java | 54 - .../wiremock/restdocs/WireMockSnippet.java | 249 - .../restdocs/WireMockVerifyHelper.java | 108 - .../restdocs/WireMockWebTestClient.java | 57 - .../WireMockWebTestClientConfiguration.java | 54 - .../main/resources/META-INF/spring.factories | 6 - ...ure.restdocs.AutoConfigureRestDocs.imports | 3 - .../asciidoctor/default-dsl-contract.snippet | 4 - .../default-dsl-contract-only.snippet | 47 - .../markdown/default-dsl-contract.snippet | 3 - ...onfigureWireMockAdditionalImportTests.java | 144 - ...AutoConfigureWireMockApplicationTests.java | 66 - ...gureWireMockAutoStubsApplicationTests.java | 54 - ...eWireMockConfigurationCustomizerTests.java | 77 - ...igureWireMockConfigurationInYamlTests.java | 49 - ...kConfigurationMultipleCustomizerTests.java | 81 - ...utoConfigureWireMockDefaultSetupTests.java | 43 - ...onfigureWireMockFilesApplicationTests.java | 43 - ...kFilesApplicationWithUrlResourceTests.java | 63 - ...MockFilesApplicationWithoutSlashTests.java | 43 - ...gureWireMockHttpsPortApplicationTests.java | 79 - ...WireMockOnlyHttpsPortApplicationTests.java | 59 - ...ckOnlyRandomPortHttpsApplicationTests.java | 59 - ...ConfigureWireMockPortApplicationTests.java | 49 - ...ureWireMockRandomPortApplicationTests.java | 63 - ...reMockRandomPortHttpsApplicationTests.java | 61 - ...ckRandomPortInheretedApplicationTests.java | 22 - ...igureWireMockSamePortApplicationTests.java | 50 - ...WireMockStubsAndFilesApplicationTests.java | 43 - ...StubsAndMultipleFilesApplicationTests.java | 44 - ...onfigureWireMockStubsApplicationTests.java | 52 - ...ireMockStubsApplicationWithSlashTests.java | 43 - ...ithResetAfterEachTestApplicationTests.java | 88 - ...etAfterEachTestNestedApplicationTests.java | 88 - ...ithResetAfterEachTestApplicationTests.java | 105 - .../wiremock/WireMockStubMappingTest.java | 46 - .../WiremockHttpsServerApplicationTests.java | 52 - .../WiremockMockServerApplicationTests.java | 464 -- .../WiremockServerApplicationTests.java | 53 - ...mockServerRestAssuredApplicationTests.java | 93 - ...iremockServerRestDocsApplicationTests.java | 141 - ...verRestDocsHypermediaApplicationTests.java | 83 - ...ServerRestDocsMatcherApplicationTests.java | 97 - ...ckServerWebTestClientApplicationTests.java | 106 - .../wiremock/WiremockTestsApplication.java | 142 - .../file/ResourcesFileSourceTest.java | 89 - .../issue399/NotOrderedCustomizerTest.java | 57 - .../issue399/OrderedCustomizerTest.java | 59 - ...gContractWiremockIssueDemoApplication.java | 107 - .../sameConfigsDifferentTests/Client.java | 38 - .../sameConfigsDifferentTests/FirstTests.java | 79 - .../FraudCheckStatus.java | 23 - .../FraudServiceRequest.java | 51 - .../FraudServiceResponse.java | 44 - .../LoanApplication.java | 61 - .../SecondTests.java | 78 - .../issues/staticInit/ClientProperties.java | 34 - .../staticInit/RestTemplateConfiguration.java | 33 - .../issues/staticInit/TimeoutApplication.java | 29 - .../wiremock/issues/staticInit/WebClient.java | 41 - .../issues/staticInit/WebClientTest.java | 80 - .../restdocs/ContractDslSnippetTests.java | 217 - .../restdocs/WireMockSnippetTests.java | 489 -- .../src/test/resources/__files/hello.json | 3 - .../test/resources/application-customfoo.yml | 7 - .../src/test/resources/application.yml | 4 - .../custom-from-yml/__files/hello-custom.json | 3 - .../mappings/custom-test-endpoint.json | 11 - .../src/test/resources/custom/hello.json | 3 - .../shouldMarkClientAsFraud.json | 26 - .../shouldMarkClientAsNotFraud.json | 26 - .../test/resources/files/__files/hello.json | 3 - .../__files/response-bannerList-error.json | 5 - .../__files/response-bannerList-success.json | 17 - .../__files/response-noticeList-error.json | 5 - .../__files/response-noticeList-success.json | 17 - .../resources/io.stubs/mappings/link.json | 12 - .../resources/io.stubs/mappings/resource.json | 10 - .../jarfiles/module-banner-test-fixtures.jar | Bin 1146 -> 0 bytes .../src/test/resources/mappings/accept.json | 15 - .../mappings/body-matches-equaltojson.json | 15 - .../mappings/body-matches-equaltoxml.json | 15 - .../mappings/body-matches-jsonpath.json | 15 - .../mappings/body-matches-regex.json | 15 - .../mappings/body-matches-xpath.json | 15 - .../resources/mappings/header-contains.json | 15 - .../mappings/header-matches-precise.json | 18 - .../resources/mappings/header-matches.json | 15 - .../src/test/resources/mappings/poster.json | 10 - .../mappings/resource-with-base64-body.json | 11 - .../mappings/resource-with-body-file.json | 11 - .../mappings/resource-with-content-type.json | 15 - .../mappings/resource-with-empty-path.json | 14 - .../mappings/resource-with-high-priority.json | 11 - .../mappings/resource-with-json-body.json | 13 - .../mappings/resource-with-low-priority.json | 11 - .../resource-without-content-type.json | 14 - .../src/test/resources/mappings/resource.json | 11 - .../test/resources/mappings/url-matches.json | 10 - .../resources/mappings/url-path-pattern.json | 10 - ...imple-path-pattern-with-leading-slash.json | 10 - ...le-path-pattern-without-leading-slash.json | 10 - .../test/resources/root/__files/hello.json | 3 - .../test/resources/root/mappings/accept.json | 15 - .../mappings/resource-with-body-file.json | 10 - .../resources/root/mappings/url-matches.json | 10 - src/checkstyle/checkstyle-suppressions.xml | 51 - supplemental-ui/partials/nav-search.hbs | 11 + supplemental-ui/partials/search.hbs | 27 + tests/pom.xml | 88 - tests/samples-messaging-amqp/pom.xml | 57 - .../com/example/AmqpMessagingApplication.java | 68 - .../src/main/java/com/example/Book.java | 39 - .../Issue178ListenerConfiguration.java | 106 - .../java/com/example/MessagePublisher.java | 37 - .../main/java/com/example/RabbitManager.java | 129 - .../AmqpMessagingApplicationSpec.groovy | 98 - .../src/test/resources/application.yml | 1 - tests/samples-messaging-camel/.springBeans | 16 - tests/samples-messaging-camel/log.log | 164 + tests/samples-messaging-camel/pom.xml | 76 - .../main/java/com/example/BookReturned.java | 39 - .../com/example/BookRouteConfiguration.java | 53 - .../main/java/com/example/BookService.java | 42 - .../example/CamelMessagingApplication.java | 29 - .../CamelMessagingApplicationSpec.groovy | 98 - .../src/test/resources/logback-test.xml | 15 - .../.springBeans | 16 - tests/samples-messaging-integration/pom.xml | 49 - .../main/java/com/example/BookDeleted.java | 41 - .../main/java/com/example/BookListener.java | 42 - .../main/java/com/example/BookReturned.java | 41 - .../main/java/com/example/BookService.java | 50 - .../IntegrationMessagingApplication.java | 31 - .../main/resources/integration-context.xml | 39 - ...IntegrationMessagingApplicationSpec.groovy | 94 - tests/samples-messaging-jms/.springBeans | 16 - tests/samples-messaging-jms/pom.xml | 58 - .../main/java/com/example/BookDeleted.java | 34 - .../main/java/com/example/BookReturned.java | 34 - .../main/java/com/example/BookService.java | 52 - .../com/example/JmsMessagingApplication.java | 31 - .../JmsMessagingApplicationSpec.groovy | 97 - .../src/test/resources/application.yml | 2 - .../pom.xml | 74 - .../amqp/AmqpMessagingApplication.java | 128 - .../messaging/amqp/MessageSubscriber.java | 30 - .../amqp/MessageSubscriberRabbitListener.java | 45 - .../stubrunner/messaging/amqp/Person.java | 46 - .../AmqpStubRunnerRabbitListenerSpec.groovy | 48 - .../messaging/amqp/AmqpStubRunnerSpec.groovy | 84 - .../src/test/resources/application.yml | 8 - .../0.4.0-SNAPSHOT/maven-metadata-local.xml | 12 - ...ontract-amqp-test-0.4.0-SNAPSHOT-stubs.jar | Bin 3013 -> 0 bytes ...loud-contract-amqp-test-0.4.0-SNAPSHOT.pom | 27 - .../maven-metadata-local.xml | 28 - .../maven-metadata.xml | 28 - .../pom.xml | 74 - ...ingCloudEurekaAutoConfigurationSpec.groovy | 179 - .../src/test/resources/application.yml | 5 - .../src/test/resources/logback.xml | 25 - .../bootService-0.0.1-SNAPSHOT-stubs.jar | Bin 1583 -> 0 bytes .../bootService-0.0.1-SNAPSHOT.pom | 27 - .../stubs/bootService/maven-metadata.xml | 28 - ...udDetectionServer-0.0.1-SNAPSHOT-stubs.jar | Bin 1897 -> 0 bytes .../fraudDetectionServer-0.0.1-SNAPSHOT.pom | 27 - .../fraudDetectionServer/maven-metadata.xml | 28 - .../loanIssuance-0.0.1-SNAPSHOT-stubs.jar | Bin 639 -> 0 bytes .../loanIssuance-0.0.1-SNAPSHOT.pom | 27 - .../stubs/loanIssuance/maven-metadata.xml | 28 - .../pom.xml | 88 - ...CloudZookeeperAutoConfigurationSpec.groovy | 107 - .../src/test/resources/application.yml | 5 - .../src/test/resources/logback.xml | 25 - .../bootService-0.0.1-SNAPSHOT-stubs.jar | Bin 1583 -> 0 bytes .../bootService-0.0.1-SNAPSHOT.pom | 27 - .../stubs/bootService/maven-metadata.xml | 28 - ...udDetectionServer-0.0.1-SNAPSHOT-stubs.jar | Bin 1897 -> 0 bytes .../fraudDetectionServer-0.0.1-SNAPSHOT.pom | 27 - .../fraudDetectionServer/maven-metadata.xml | 28 - .../loanIssuance-0.0.1-SNAPSHOT-stubs.jar | Bin 639 -> 0 bytes .../loanIssuance-0.0.1-SNAPSHOT.pom | 27 - .../stubs/loanIssuance/maven-metadata.xml | 28 - .../pom.xml | 46 - .../java/com/example/loan/Application.java | 41 - .../example/loan/LoanApplicationService.java | 82 - .../java/com/example/loan/model/Client.java | 38 - .../example/loan/model/FraudCheckStatus.java | 23 - .../loan/model/FraudServiceRequest.java | 51 - .../loan/model/FraudServiceResponse.java | 44 - .../example/loan/model/LoanApplication.java | 61 - .../loan/model/LoanApplicationResult.java | 49 - .../loan/model/LoanApplicationStatus.java | 23 - .../src/main/resources/application.yml | 4 - .../FailFastLoanApplicationServiceTests.java | 68 - .../loan/LoanApplicationServiceTests.java | 97 - ...udDetectionServer-0.0.1-SNAPSHOT-stubs.jar | Bin 1916 -> 0 bytes ...athFraudDetectionServer-0.0.1-SNAPSHOT.pom | 27 - .../maven-metadata.xml | 28 - .../pom.xml | 75 - .../messaging/integration/BookReturned.groovy | 32 - .../IntegrationStubRunnerSpec.groovy | 164 - .../src/test/resources/application.yml | 5 - .../test/resources/integration-context.xml | 35 - ...ntegrationService-0.0.1-SNAPSHOT-stubs.jar | Bin 988 -> 0 bytes .../integrationService-0.0.1-SNAPSHOT.pom | 27 - .../0.0.1-SNAPSHOT/maven-metadata-local.xml | 28 - .../maven-metadata-local.xml | 28 - .../integrationService/maven-metadata.xml | 28 - .../pom.xml | 58 - .../messaging/jms/BookReturned.groovy | 32 - .../messaging/jms/JmsStubRunnerSpec.groovy | 197 - .../src/test/resources/application.yml | 14 - .../test/resources/stubs/bookReturned1.groovy | 13 - .../pom.xml | 73 - .../messaging/kafka/BookReturned.groovy | 34 - .../kafka/KafkaStubRunnerSpec.groovy | 305 - .../src/test/resources/application.yml | 22 - .../test/resources/stubs/bookReturned1.groovy | 13 - .../pom.xml | 47 - .../1.0.0/contracts/nested/contract2.groovy | 43 - .../1.0.0/mappings/nested/shouldSayBye.json | 12 - .../1.0.0/mappings/shouldSayHello.json | 12 - .../nested/contract3.groovy | 43 - .../nested/shouldSayBye2.json | 12 - .../resources/mappings/shouldSayHello2.json | 12 - .../pom.xml | 78 - .../provider/moco/MocoHttpServerStub.groovy | 94 - .../moco/MocoHttpServerStubSpec.groovy | 62 - .../test/resources/META-INF/spring.factories | 4 - .../src/test/resources/application-test.yaml | 2 - .../src/test/resources/application.yml | 5 - .../src/test/resources/logback.xml | 25 - .../pom.xml | 63 - .../messaging/stream/BookReturned.groovy | 32 - .../stream/StreamStubRunnerSpec.groovy | 183 - .../src/test/resources/application.yml | 18 - .../0.0.1-SNAPSHOT/maven-metadata-local.xml | 28 - .../streamService-0.0.1-SNAPSHOT-stubs.jar | Bin 990 -> 0 bytes .../streamService-0.0.1-SNAPSHOT.pom | 27 - .../streamService/maven-metadata-local.xml | 28 - .../stubs/streamService/maven-metadata.xml | 28 - .../src/test/resources/request.pdf | Bin 14631 -> 0 bytes .../src/test/resources/response.pdf | Bin 15767 -> 0 bytes 2433 files changed, 11795 insertions(+), 164370 deletions(-) delete mode 100644 .editorconfig delete mode 100644 .github/CONTRIBUTING.md delete mode 100644 .github/ISSUE_TEMPLATE.md delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md delete mode 100644 .github/dependabot.yml delete mode 100644 .github/workflows/codeql.yaml create mode 100644 .github/workflows/deploy-docs.yml delete mode 100644 .github/workflows/maven.yml delete mode 100644 .mvn/maven.config delete mode 100644 .sdkmanrc delete mode 100644 .settings.xml delete mode 100644 LICENSE rename docs/antora-playbook.yml => antora-playbook.yml (61%) delete mode 100644 asciidoctor.css delete mode 100644 config/releaser.yml delete mode 100644 docker/pom.xml delete mode 100644 docker/spring-cloud-contract-docker/Dockerfile delete mode 100755 docker/spring-cloud-contract-docker/build_adocs.sh delete mode 100755 docker/spring-cloud-contract-docker/get_dependencies.sh delete mode 100644 docker/spring-cloud-contract-docker/pom.xml create mode 100644 docker/spring-cloud-contract-docker/project/.gradle/7.5.1/checksums/checksums.lock create mode 100644 docker/spring-cloud-contract-docker/project/.gradle/7.5.1/checksums/md5-checksums.bin create mode 100644 docker/spring-cloud-contract-docker/project/.gradle/7.5.1/checksums/sha1-checksums.bin create mode 100644 docker/spring-cloud-contract-docker/project/.gradle/7.5.1/dependencies-accessors/dependencies-accessors.lock rename .springformat => docker/spring-cloud-contract-docker/project/.gradle/7.5.1/dependencies-accessors/gc.properties (100%) create mode 100644 docker/spring-cloud-contract-docker/project/.gradle/7.5.1/fileChanges/last-build.bin create mode 100644 docker/spring-cloud-contract-docker/project/.gradle/7.5.1/fileHashes/fileHashes.bin create mode 100644 docker/spring-cloud-contract-docker/project/.gradle/7.5.1/fileHashes/fileHashes.lock rename docs/modules/ROOT/pages/index.adoc => docker/spring-cloud-contract-docker/project/.gradle/7.5.1/gc.properties (100%) create mode 100644 docker/spring-cloud-contract-docker/project/.gradle/8.3/checksums/checksums.lock create mode 100644 docker/spring-cloud-contract-docker/project/.gradle/8.3/checksums/md5-checksums.bin create mode 100644 docker/spring-cloud-contract-docker/project/.gradle/8.3/checksums/sha1-checksums.bin create mode 100644 docker/spring-cloud-contract-docker/project/.gradle/8.3/dependencies-accessors/dependencies-accessors.lock rename samples/standalone/restdocs/http-server/src/main/resources/application.yml => docker/spring-cloud-contract-docker/project/.gradle/8.3/dependencies-accessors/gc.properties (100%) create mode 100644 docker/spring-cloud-contract-docker/project/.gradle/8.3/executionHistory/executionHistory.bin create mode 100644 docker/spring-cloud-contract-docker/project/.gradle/8.3/executionHistory/executionHistory.lock create mode 100644 docker/spring-cloud-contract-docker/project/.gradle/8.3/fileChanges/last-build.bin create mode 100644 docker/spring-cloud-contract-docker/project/.gradle/8.3/fileHashes/fileHashes.bin create mode 100644 docker/spring-cloud-contract-docker/project/.gradle/8.3/fileHashes/fileHashes.lock create mode 100644 docker/spring-cloud-contract-docker/project/.gradle/8.3/fileHashes/resourceHashesCache.bin rename spring-cloud-contract-stub-runner/src/test/resources/emptyrepo/.gitkeep => docker/spring-cloud-contract-docker/project/.gradle/8.3/gc.properties (100%) create mode 100644 docker/spring-cloud-contract-docker/project/.gradle/buildOutputCleanup/buildOutputCleanup.lock create mode 100644 docker/spring-cloud-contract-docker/project/.gradle/buildOutputCleanup/cache.properties create mode 100644 docker/spring-cloud-contract-docker/project/.gradle/buildOutputCleanup/outputFiles.bin create mode 100644 docker/spring-cloud-contract-docker/project/.gradle/file-system.probe rename spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/fake/.gitkeep => docker/spring-cloud-contract-docker/project/.gradle/vcs-1/gc.properties (100%) create mode 100644 docker/spring-cloud-contract-docker/project/.idea/.gitignore create mode 100644 docker/spring-cloud-contract-docker/project/.idea/codeStyles/Project.xml create mode 100644 docker/spring-cloud-contract-docker/project/.idea/codeStyles/codeStyleConfig.xml create mode 100644 docker/spring-cloud-contract-docker/project/.idea/compiler.xml create mode 100644 docker/spring-cloud-contract-docker/project/.idea/gradle.xml create mode 100644 docker/spring-cloud-contract-docker/project/.idea/jarRepositories.xml create mode 100644 docker/spring-cloud-contract-docker/project/.idea/misc.xml rename spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/mappings/.gitkeep => docker/spring-cloud-contract-docker/project/.idea/sonarlint/issuestore/5/9/59f81c123b3abbcb97274545796dd18706c3e106 (100%) rename spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/mappings/.gitkeep => docker/spring-cloud-contract-docker/project/.idea/sonarlint/issuestore/f/0/f07866736216be0ee2aba49e392191aeae700a35 (100%) create mode 100644 docker/spring-cloud-contract-docker/project/.idea/sonarlint/issuestore/index.pb create mode 100644 docker/spring-cloud-contract-docker/project/.idea/vcs.xml delete mode 100644 docker/spring-cloud-contract-docker/project/README.adoc delete mode 100644 docker/spring-cloud-contract-docker/project/build.gradle delete mode 100755 docker/spring-cloud-contract-docker/project/build.sh create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.2/executionHistory/executionHistory.bin create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.2/executionHistory/executionHistory.lock create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.3.3/executionHistory/executionHistory.bin create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.3.3/executionHistory/executionHistory.lock create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.3/executionHistory/executionHistory.bin create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.3/executionHistory/executionHistory.lock create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.4.1/checksums/checksums.lock create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.4.1/checksums/md5-checksums.bin create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.4.1/checksums/sha1-checksums.bin create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.4.1/dependencies-accessors/dependencies-accessors.lock rename spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/common-repo/target/IgnoreMe.groovy => docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.4.1/dependencies-accessors/gc.properties (100%) create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.4.1/executionHistory/executionHistory.bin create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.4.1/executionHistory/executionHistory.lock create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.4.1/fileChanges/last-build.bin create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.4.1/fileHashes/fileHashes.lock rename spring-cloud-contract-verifier/src/test/resources/directory/with/stubs/stubsRepositoryIndicator => docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.4.1/gc.properties (100%) create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.5.1/checksums/checksums.lock create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.5.1/checksums/md5-checksums.bin create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.5.1/checksums/sha1-checksums.bin create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.5.1/dependencies-accessors/dependencies-accessors.lock rename tests/spring-cloud-contract-stub-runner-integration/.jdk8 => docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.5.1/dependencies-accessors/gc.properties (100%) create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.5.1/executionHistory/executionHistory.bin create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.5.1/executionHistory/executionHistory.lock create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.5.1/fileChanges/last-build.bin create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.5.1/fileHashes/fileHashes.lock create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.5.1/gc.properties create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/8.3/executionHistory/executionHistory.bin create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/8.3/executionHistory/executionHistory.lock create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/buildOutputCleanup/buildOutputCleanup.lock create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/buildOutputCleanup/cache.properties create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/buildOutputCleanup/outputFiles.bin create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/file-system.probe create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/noVersion/buildSrc.lock create mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/.gradle/vcs-1/gc.properties delete mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/build.gradle delete mode 100644 docker/spring-cloud-contract-docker/project/buildSrc/src/main/java/contracts/DocsFromSources.java delete mode 100644 docker/spring-cloud-contract-docker/project/gradle.properties delete mode 100644 docker/spring-cloud-contract-docker/project/gradle/wrapper/gradle-wrapper.jar delete mode 100644 docker/spring-cloud-contract-docker/project/gradle/wrapper/gradle-wrapper.properties delete mode 100755 docker/spring-cloud-contract-docker/project/gradlew delete mode 100644 docker/spring-cloud-contract-docker/project/gradlew.bat delete mode 100644 docker/spring-cloud-contract-docker/project/src/test/java/contracts/ContractTestsBase.java delete mode 100644 docker/spring-cloud-contract-docker/project/src/test/java/contracts/MessagingAutoConfig.java delete mode 100644 docker/spring-cloud-contract-docker/project/src/test/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports delete mode 100644 docker/spring-cloud-contract-docker/project/src/test/resources/application-messagingtype.yml delete mode 100644 docker/spring-cloud-contract-docker/sdkman.config delete mode 100755 docker/spring-cloud-contract-docker/sdkman/sdkman-wrapper.sh delete mode 100644 docker/spring-cloud-contract-stub-runner-docker/Dockerfile create mode 100644 docker/spring-cloud-contract-stub-runner-docker/log.log delete mode 100644 docker/spring-cloud-contract-stub-runner-docker/pom.xml delete mode 100755 docker/spring-cloud-contract-stub-runner-docker/run.sh delete mode 100644 docker/spring-cloud-contract-stub-runner-docker/sdkman.config delete mode 100755 docker/spring-cloud-contract-stub-runner-docker/sdkman/sdkman-wrapper.sh delete mode 100644 docs/.github/workflows/deploy-docs.yml delete mode 100644 docs/antora.yml delete mode 100644 docs/modules/ROOT/assets/images/Deps.png delete mode 100644 docs/modules/ROOT/assets/images/Stubs1.png delete mode 100644 docs/modules/ROOT/assets/images/Stubs2.png delete mode 100644 docs/modules/ROOT/assets/images/start_spring_io_dependencies.png delete mode 100644 docs/modules/ROOT/nav.adoc delete mode 100644 docs/modules/ROOT/pages/README.adoc delete mode 100644 docs/modules/ROOT/pages/_additional-stubrunner-configprops.adoc delete mode 100644 docs/modules/ROOT/pages/_attributes.adoc delete mode 100644 docs/modules/ROOT/pages/_building.adoc delete mode 100644 docs/modules/ROOT/pages/_configprops.adoc delete mode 100644 docs/modules/ROOT/pages/_index.adoc delete mode 100644 docs/modules/ROOT/pages/_index_pdf.adoc delete mode 100644 docs/modules/ROOT/pages/_index_single.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-contract.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-contract/common-top-elements.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-contract/dsl-async.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-contract/dsl-dynamic-properties.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-contract/dsl-http-top-level-elements.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-contract/dsl-multiple.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-contract/dsl-request.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-contract/dsl-response.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-contract/dsl-xml.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-contract/groovy.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-contract/java.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-contract/kotlin.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-contract/limitations.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-contract/stateful-contracts.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-contract/yml.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-flows.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-flows/context-paths.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-flows/custom-mode.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-flows/feature-webflux-explicit.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-flows/feature-webflux.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-flows/graphql.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-flows/grpc.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-flows/jax-rs.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-flows/rest-docs.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-messaging.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-stubrunner.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-boot.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-cloud.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-common.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-core.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-fail-on-no-stubs.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-generate-stubs-at-runtime.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-junit.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-publishing-stubs-as-jars.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-snapshot-versions.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-stubs-per-consumer.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-stubs-protocol.adoc delete mode 100644 docs/modules/ROOT/pages/_project-features-wiremock.adoc delete mode 100644 docs/modules/ROOT/pages/advanced.adoc delete mode 100644 docs/modules/ROOT/pages/appendix.adoc delete mode 100644 docs/modules/ROOT/pages/docker-project.adoc delete mode 100644 docs/modules/ROOT/pages/documentation-overview.adoc delete mode 100644 docs/modules/ROOT/pages/getting-started.adoc delete mode 100644 docs/modules/ROOT/pages/getting-started/cdc.adoc delete mode 100644 docs/modules/ROOT/pages/getting-started/first-application.adoc delete mode 100644 docs/modules/ROOT/pages/getting-started/introducing-spring-cloud-contract.adoc delete mode 100644 docs/modules/ROOT/pages/getting-started/three-second-tour.adoc delete mode 100644 docs/modules/ROOT/pages/getting-started/whats-next.adoc delete mode 100644 docs/modules/ROOT/pages/gradle-project.adoc delete mode 100644 docs/modules/ROOT/pages/howto.adoc delete mode 100644 docs/modules/ROOT/pages/howto/contract-dsl-rest-docs.adoc delete mode 100644 docs/modules/ROOT/pages/howto/how-to-common-repo-with-contracts.adoc delete mode 100644 docs/modules/ROOT/pages/howto/how-to-debug-wiremock.adoc delete mode 100644 docs/modules/ROOT/pages/howto/how-to-debug.adoc delete mode 100644 docs/modules/ROOT/pages/howto/how-to-do-stubs-versioning.adoc delete mode 100644 docs/modules/ROOT/pages/howto/how-to-generate-pact-from-scc.adoc delete mode 100644 docs/modules/ROOT/pages/howto/how-to-generate-stubs-at-runtime.adoc delete mode 100644 docs/modules/ROOT/pages/howto/how-to-mark-contract-in-progress.adoc delete mode 100644 docs/modules/ROOT/pages/howto/how-to-not-write-contracts-in-groovy.adoc delete mode 100644 docs/modules/ROOT/pages/howto/how-to-provide-dynamic-values.adoc delete mode 100644 docs/modules/ROOT/pages/howto/how-to-reference-text-from-file.adoc delete mode 100644 docs/modules/ROOT/pages/howto/how-to-see-registered-stubs.adoc delete mode 100644 docs/modules/ROOT/pages/howto/how-to-use-git-as-storage.adoc delete mode 100644 docs/modules/ROOT/pages/howto/how-to-use-stubs-from-a-location.adoc delete mode 100644 docs/modules/ROOT/pages/howto/how-to-use-the-failonnostubs-feature.adoc delete mode 100644 docs/modules/ROOT/pages/howto/how-to-work-with-transitivie.adoc delete mode 100644 docs/modules/ROOT/pages/howto/why-spring-cloud-contract.adoc delete mode 100644 docs/modules/ROOT/pages/legal.adoc delete mode 100644 docs/modules/ROOT/pages/maven-project.adoc delete mode 100644 docs/modules/ROOT/pages/project-features.adoc delete mode 100644 docs/modules/ROOT/pages/sagan-boot.adoc delete mode 100644 docs/modules/ROOT/pages/sagan-index.adoc delete mode 100644 docs/modules/ROOT/pages/spring-cloud-contract.adoc delete mode 100644 docs/modules/ROOT/pages/using.adoc delete mode 100644 docs/modules/ROOT/pages/yml-schema.adoc delete mode 100644 docs/pom.xml delete mode 100755 docs/src/main/asciidoc/ghpages.sh delete mode 100644 docs/src/main/asciidoc/images/Deps.png delete mode 100644 docs/src/main/asciidoc/images/Stubs1.png delete mode 100644 docs/src/main/asciidoc/images/Stubs2.png delete mode 100644 docs/src/main/asciidoc/images/start_spring_io_dependencies.png delete mode 100644 docs/src/main/asciidoc/index.htmladoc delete mode 100644 docs/src/main/asciidoc/index.htmlsingleadoc delete mode 100644 docs/src/main/asciidoc/index.pdfadoc delete mode 100644 docs/src/main/asciidoc/spring-cloud-contract.htmlsingleadoc delete mode 100644 docs/src/main/asciidoc/spring-cloud-contract.pdfadoc delete mode 100644 docs/src/main/java/org/springframework/cloud/contract/docs/Main.java delete mode 100644 docs/src/test/java/org/springframework/cloud/contract/docs/AdditionalResourcesGenerationTests.java delete mode 100644 docs/src/test/resources/contract.yml delete mode 100644 ideas.md create mode 100644 log.log delete mode 100644 samples/pom.xml delete mode 100644 samples/src/it/settings.xml create mode 100644 samples/standalone/.idea/.gitignore create mode 100644 samples/standalone/.idea/codeStyles/Project.xml create mode 100644 samples/standalone/.idea/codeStyles/codeStyleConfig.xml create mode 100644 samples/standalone/.idea/compiler.xml create mode 100644 samples/standalone/.idea/encodings.xml create mode 100644 samples/standalone/.idea/jarRepositories.xml create mode 100644 samples/standalone/.idea/misc.xml create mode 100644 samples/standalone/.idea/sonarlint/issuestore/index.pb create mode 100644 samples/standalone/.idea/vcs.xml delete mode 100644 samples/standalone/.mvn/jvm.config delete mode 100644 samples/standalone/.mvn/maven.config delete mode 100644 samples/standalone/.mvn/wrapper/MavenWrapperDownloader.java delete mode 100644 samples/standalone/.mvn/wrapper/maven-wrapper.jar delete mode 100644 samples/standalone/.mvn/wrapper/maven-wrapper.properties delete mode 100644 samples/standalone/README.adoc delete mode 100644 samples/standalone/contracts/.mvn/wrapper/maven-wrapper.jar delete mode 100644 samples/standalone/contracts/.mvn/wrapper/maven-wrapper.properties delete mode 100644 samples/standalone/contracts/README.adoc create mode 100644 samples/standalone/contracts/build.log delete mode 100644 samples/standalone/contracts/com/example/server/client1/expectation.groovy delete mode 100644 samples/standalone/contracts/com/example/server/client2/expectation.groovy delete mode 100644 samples/standalone/contracts/com/example/server/client3/expectation.groovy delete mode 100644 samples/standalone/contracts/com/example/server/pom.xml delete mode 100755 samples/standalone/contracts/mvnw delete mode 100644 samples/standalone/contracts/mvnw.cmd delete mode 100644 samples/standalone/contracts/pom.xml delete mode 100644 samples/standalone/contracts/src/assembly/contracts.xml create mode 100644 samples/standalone/dsl/build.log delete mode 100644 samples/standalone/dsl/http-client/.gitignore create mode 100644 samples/standalone/dsl/http-client/.gradle/8.1.1/checksums/checksums.lock create mode 100644 samples/standalone/dsl/http-client/.gradle/8.1.1/checksums/md5-checksums.bin create mode 100644 samples/standalone/dsl/http-client/.gradle/8.1.1/checksums/sha1-checksums.bin create mode 100644 samples/standalone/dsl/http-client/.gradle/8.1.1/dependencies-accessors/dependencies-accessors.lock create mode 100644 samples/standalone/dsl/http-client/.gradle/8.1.1/dependencies-accessors/gc.properties create mode 100644 samples/standalone/dsl/http-client/.gradle/8.1.1/executionHistory/executionHistory.bin create mode 100644 samples/standalone/dsl/http-client/.gradle/8.1.1/executionHistory/executionHistory.lock create mode 100644 samples/standalone/dsl/http-client/.gradle/8.1.1/fileChanges/last-build.bin create mode 100644 samples/standalone/dsl/http-client/.gradle/8.1.1/fileHashes/fileHashes.bin create mode 100644 samples/standalone/dsl/http-client/.gradle/8.1.1/fileHashes/fileHashes.lock create mode 100644 samples/standalone/dsl/http-client/.gradle/8.1.1/fileHashes/resourceHashesCache.bin create mode 100644 samples/standalone/dsl/http-client/.gradle/8.1.1/gc.properties create mode 100644 samples/standalone/dsl/http-client/.gradle/8.3/checksums/checksums.lock create mode 100644 samples/standalone/dsl/http-client/.gradle/8.3/checksums/md5-checksums.bin create mode 100644 samples/standalone/dsl/http-client/.gradle/8.3/checksums/sha1-checksums.bin create mode 100644 samples/standalone/dsl/http-client/.gradle/8.3/dependencies-accessors/dependencies-accessors.lock create mode 100644 samples/standalone/dsl/http-client/.gradle/8.3/dependencies-accessors/gc.properties create mode 100644 samples/standalone/dsl/http-client/.gradle/8.3/executionHistory/executionHistory.bin create mode 100644 samples/standalone/dsl/http-client/.gradle/8.3/executionHistory/executionHistory.lock create mode 100644 samples/standalone/dsl/http-client/.gradle/8.3/fileChanges/last-build.bin create mode 100644 samples/standalone/dsl/http-client/.gradle/8.3/fileHashes/fileHashes.bin create mode 100644 samples/standalone/dsl/http-client/.gradle/8.3/fileHashes/fileHashes.lock create mode 100644 samples/standalone/dsl/http-client/.gradle/8.3/fileHashes/resourceHashesCache.bin create mode 100644 samples/standalone/dsl/http-client/.gradle/8.3/gc.properties create mode 100644 samples/standalone/dsl/http-client/.gradle/buildOutputCleanup/buildOutputCleanup.lock create mode 100644 samples/standalone/dsl/http-client/.gradle/buildOutputCleanup/cache.properties create mode 100644 samples/standalone/dsl/http-client/.gradle/buildOutputCleanup/outputFiles.bin create mode 100644 samples/standalone/dsl/http-client/.gradle/checksums/checksums.lock create mode 100644 samples/standalone/dsl/http-client/.gradle/checksums/md5-checksums.bin create mode 100644 samples/standalone/dsl/http-client/.gradle/checksums/sha1-checksums.bin create mode 100644 samples/standalone/dsl/http-client/.gradle/file-system.probe create mode 100644 samples/standalone/dsl/http-client/.gradle/vcs-1/gc.properties delete mode 100644 samples/standalone/dsl/http-client/.mvn/jvm.config delete mode 100644 samples/standalone/dsl/http-client/.mvn/maven.config delete mode 100644 samples/standalone/dsl/http-client/.mvn/wrapper/MavenWrapperDownloader.java delete mode 100644 samples/standalone/dsl/http-client/.mvn/wrapper/maven-wrapper.jar delete mode 100644 samples/standalone/dsl/http-client/.mvn/wrapper/maven-wrapper.properties delete mode 100644 samples/standalone/dsl/http-client/README.adoc delete mode 100644 samples/standalone/dsl/http-client/build.gradle delete mode 100644 samples/standalone/dsl/http-client/gradle.properties delete mode 100644 samples/standalone/dsl/http-client/gradle/wrapper/gradle-wrapper.jar delete mode 100644 samples/standalone/dsl/http-client/gradle/wrapper/gradle-wrapper.properties delete mode 100755 samples/standalone/dsl/http-client/gradlew delete mode 100644 samples/standalone/dsl/http-client/gradlew.bat delete mode 100755 samples/standalone/dsl/http-client/mvnw delete mode 100644 samples/standalone/dsl/http-client/mvnw.cmd delete mode 100644 samples/standalone/dsl/http-client/pom.xml delete mode 100644 samples/standalone/dsl/http-client/settings.gradle delete mode 100644 samples/standalone/dsl/http-client/src/main/java/com/example/loan/Application.java delete mode 100644 samples/standalone/dsl/http-client/src/main/java/com/example/loan/Listener.java delete mode 100644 samples/standalone/dsl/http-client/src/main/java/com/example/loan/LoanApplicationService.java delete mode 100644 samples/standalone/dsl/http-client/src/main/java/com/example/loan/SensorData.java delete mode 100644 samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/Client.java delete mode 100644 samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/FraudCheckStatus.java delete mode 100644 samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/FraudServiceRequest.java delete mode 100644 samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/FraudServiceResponse.java delete mode 100644 samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/LoanApplication.java delete mode 100644 samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/LoanApplicationResult.java delete mode 100644 samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/LoanApplicationStatus.java delete mode 100644 samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/Response.java delete mode 100644 samples/standalone/dsl/http-client/src/main/resources/application.yml delete mode 100644 samples/standalone/dsl/http-client/src/test/java/com/example/loan/GoodbyeWorldTests.java delete mode 100644 samples/standalone/dsl/http-client/src/test/java/com/example/loan/LoanApplicationServiceContextPathTests.java delete mode 100644 samples/standalone/dsl/http-client/src/test/java/com/example/loan/LoanApplicationServiceTests.java delete mode 100644 samples/standalone/dsl/http-client/src/test/java/com/example/loan/MessageConsumedTests.java delete mode 100644 samples/standalone/dsl/http-client/src/test/java/com/example/loan/TestControllerTests.java delete mode 100644 samples/standalone/dsl/http-client/src/test/resources/application-gradle.yaml delete mode 100644 samples/standalone/dsl/http-client/src/test/resources/application-test-repo.yaml delete mode 100644 samples/standalone/dsl/http-client/src/test/resources/application.yaml delete mode 100644 samples/standalone/dsl/http-client/src/test/resources/binary/request.pdf delete mode 100644 samples/standalone/dsl/http-client/src/test/resources/binary/response.pdf delete mode 100644 samples/standalone/dsl/http-client/src/test/resources/contractsAtRuntime/goodbyeWorld.groovy delete mode 100644 samples/standalone/dsl/http-server/.gitignore create mode 100644 samples/standalone/dsl/http-server/.gradle/8.1.1/checksums/checksums.lock create mode 100644 samples/standalone/dsl/http-server/.gradle/8.1.1/checksums/md5-checksums.bin create mode 100644 samples/standalone/dsl/http-server/.gradle/8.1.1/checksums/sha1-checksums.bin create mode 100644 samples/standalone/dsl/http-server/.gradle/8.1.1/dependencies-accessors/dependencies-accessors.lock create mode 100644 samples/standalone/dsl/http-server/.gradle/8.1.1/dependencies-accessors/gc.properties create mode 100644 samples/standalone/dsl/http-server/.gradle/8.1.1/fileChanges/last-build.bin create mode 100644 samples/standalone/dsl/http-server/.gradle/8.1.1/fileHashes/fileHashes.lock create mode 100644 samples/standalone/dsl/http-server/.gradle/8.1.1/gc.properties create mode 100644 samples/standalone/dsl/http-server/.gradle/8.3/checksums/checksums.lock create mode 100644 samples/standalone/dsl/http-server/.gradle/8.3/checksums/md5-checksums.bin create mode 100644 samples/standalone/dsl/http-server/.gradle/8.3/checksums/sha1-checksums.bin create mode 100644 samples/standalone/dsl/http-server/.gradle/8.3/dependencies-accessors/dependencies-accessors.lock create mode 100644 samples/standalone/dsl/http-server/.gradle/8.3/dependencies-accessors/gc.properties create mode 100644 samples/standalone/dsl/http-server/.gradle/8.3/executionHistory/executionHistory.bin create mode 100644 samples/standalone/dsl/http-server/.gradle/8.3/executionHistory/executionHistory.lock create mode 100644 samples/standalone/dsl/http-server/.gradle/8.3/fileChanges/last-build.bin create mode 100644 samples/standalone/dsl/http-server/.gradle/8.3/fileHashes/fileHashes.bin create mode 100644 samples/standalone/dsl/http-server/.gradle/8.3/fileHashes/fileHashes.lock create mode 100644 samples/standalone/dsl/http-server/.gradle/8.3/fileHashes/resourceHashesCache.bin create mode 100644 samples/standalone/dsl/http-server/.gradle/8.3/gc.properties create mode 100644 samples/standalone/dsl/http-server/.gradle/buildOutputCleanup/buildOutputCleanup.lock create mode 100644 samples/standalone/dsl/http-server/.gradle/buildOutputCleanup/cache.properties create mode 100644 samples/standalone/dsl/http-server/.gradle/buildOutputCleanup/outputFiles.bin create mode 100644 samples/standalone/dsl/http-server/.gradle/file-system.probe create mode 100644 samples/standalone/dsl/http-server/.gradle/vcs-1/gc.properties create mode 100644 samples/standalone/dsl/http-server/.idea/.gitignore create mode 100644 samples/standalone/dsl/http-server/.idea/codeStyles/Project.xml create mode 100644 samples/standalone/dsl/http-server/.idea/codeStyles/codeStyleConfig.xml create mode 100644 samples/standalone/dsl/http-server/.idea/compiler.xml create mode 100644 samples/standalone/dsl/http-server/.idea/encodings.xml create mode 100644 samples/standalone/dsl/http-server/.idea/jarRepositories.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__cglib_cglib_3_3_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__ch_qos_logback_logback_classic_1_4_5.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__ch_qos_logback_logback_core_1_4_5.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_classmate_1_5_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_annotations_2_14_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_core_2_14_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_databind_2_14_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_2_14_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jdk8_2_14_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jsr310_2_14_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_module_jackson_module_parameter_names_2_14_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__com_github_jknack_handlebars_4_3_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__com_github_tomakehurst_wiremock_jre8_standalone_2_35_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__com_ibm_icu_icu4j_4_6.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__com_jayway_jsonpath_json_path_2_7_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__com_rabbitmq_amqp_client_5_16_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__com_rackspace_eclipse_webtools_sourceediting_org_eclipse_wst_xml_xpath2_processor_2_1_100.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__com_toomuchcoding_jsonassert_jsonassert_0_6_2.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__com_vaadin_external_google_android_json_0_0_20131108_vaadin1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__commons_beanutils_commons_beanutils_1_9_4.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__commons_codec_commons_codec_1_15.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__commons_collections_commons_collections_3_2_2.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__commons_logging_commons_logging_1_2.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__dk_brics_automaton_1_12_4.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__edu_princeton_cup_java_cup_10k.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_micrometer_micrometer_commons_1_10_2.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_micrometer_micrometer_core_1_10_2.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_micrometer_micrometer_observation_1_10_2.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_incubator_netty_incubator_codec_classes_quic_0_0_34_Final.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_incubator_netty_incubator_codec_native_quic_linux_x86_64_0_0_34_Final.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_buffer_4_1_86_Final.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_codec_4_1_86_Final.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_codec_dns_4_1_86_Final.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_codec_http2_4_1_86_Final.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_codec_http_4_1_86_Final.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_codec_socks_4_1_86_Final.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_common_4_1_86_Final.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_handler_4_1_86_Final.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_handler_proxy_4_1_86_Final.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_resolver_4_1_86_Final.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_resolver_dns_4_1_86_Final.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_resolver_dns_classes_macos_4_1_86_Final.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_resolver_dns_native_macos_osx_x86_64_4_1_86_Final.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_transport_4_1_86_Final.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_transport_classes_epoll_4_1_86_Final.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_transport_native_epoll_linux_x86_64_4_1_86_Final.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_transport_native_unix_common_4_1_86_Final.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_projectreactor_netty_incubator_reactor_netty_incubator_quic_0_1_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_projectreactor_netty_reactor_netty_1_1_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_projectreactor_netty_reactor_netty_core_1_1_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_projectreactor_netty_reactor_netty_http_1_1_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_projectreactor_reactor_core_3_5_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_rest_assured_json_path_5_2_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_rest_assured_rest_assured_5_2_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_rest_assured_rest_assured_common_5_2_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_rest_assured_spring_commons_5_2_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_rest_assured_spring_mock_mvc_5_2_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__io_rest_assured_xml_path_5_2_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__jakarta_activation_jakarta_activation_api_2_1_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__jakarta_annotation_jakarta_annotation_api_2_1_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__jakarta_validation_jakarta_validation_api_3_0_2.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__jakarta_xml_bind_jakarta_xml_bind_api_4_0_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__javax_activation_javax_activation_api_1_2_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__javax_annotation_javax_annotation_api_1_3_2.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__javax_inject_javax_inject_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__net_bytebuddy_byte_buddy_1_12_20.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__net_bytebuddy_byte_buddy_agent_1_12_20.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__net_javacrumbs_json_unit_json_unit_assertj_2_32_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__net_javacrumbs_json_unit_json_unit_core_2_32_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__net_javacrumbs_json_unit_json_unit_json_path_2_32_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__net_jodah_typetools_0_6_2.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__net_minidev_accessors_smart_2_4_8.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__net_minidev_json_smart_2_4_8.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_commons_commons_lang3_3_12_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_commons_commons_text_1_10_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_groovy_groovy_4_0_6.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_groovy_groovy_json_4_0_6.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_groovy_groovy_nio_4_0_6.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_groovy_groovy_xml_4_0_6.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_httpcomponents_httpclient_4_5_14.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_httpcomponents_httpcore_4_4_16.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_httpcomponents_httpmime_4_5_14.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_logging_log4j_log4j_api_2_19_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_logging_log4j_log4j_to_slf4j_2_19_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_maven_resolver_maven_resolver_api_1_4_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_core_10_1_4.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_el_10_1_4.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_websocket_10_1_4.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apiguardian_apiguardian_api_1_1_2.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_assertj_assertj_core_3_23_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_ccil_cowan_tagsoup_tagsoup_1_2_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_hamcrest_hamcrest_2_2.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_hamcrest_hamcrest_core_2_2.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_hdrhistogram_HdrHistogram_2_1_12.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_hibernate_validator_hibernate_validator_8_0_0_Final.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_jboss_logging_jboss_logging_3_5_0_Final.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_jetbrains_annotations_13_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_jetbrains_kotlin_kotlin_stdlib_1_7_22.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_jetbrains_kotlin_kotlin_stdlib_common_1_7_22.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_jetbrains_kotlin_kotlin_stdlib_jdk7_1_7_22.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_jetbrains_kotlin_kotlin_stdlib_jdk8_1_7_22.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_5_9_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_api_5_9_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_engine_5_9_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_params_5_9_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_junit_platform_junit_platform_commons_1_9_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_junit_platform_junit_platform_engine_1_9_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_latencyutils_LatencyUtils_2_0_3.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_mockito_mockito_core_4_8_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_mockito_mockito_junit_jupiter_4_8_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_objenesis_objenesis_3_2.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_opentest4j_opentest4j_1_2_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_ow2_asm_asm_7_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_reactivestreams_reactive_streams_1_0_4.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_skyscreamer_jsonassert_1_5_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_slf4j_jul_to_slf4j_2_0_6.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_slf4j_slf4j_api_2_0_6.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_amqp_spring_amqp_3_0_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_amqp_spring_rabbit_3_0_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_3_0_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_actuator_3_0_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_actuator_autoconfigure_3_0_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_3_0_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_3_0_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_actuator_3_0_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_amqp_3_0_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_json_3_0_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_3_0_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_reactor_netty_3_0_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_test_3_0_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_tomcat_3_0_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_validation_3_0_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_web_3_0_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_webflux_3_0_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_3_0_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_autoconfigure_3_0_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_contract_shade_4_0_1_SNAPSHOT.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_contract_spec_4_0_1_SNAPSHOT.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_contract_spec_groovy_4_0_1_SNAPSHOT.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_contract_spec_java_4_0_1_SNAPSHOT.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_contract_verifier_4_0_0_SNAPSHOT.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_contract_verifier_4_0_1_SNAPSHOT.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_function_context_4_0_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_function_core_4_0_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_starter_contract_verifier_4_0_1_SNAPSHOT.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_starter_stream_rabbit_4_0_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_stream_4_0_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_stream_binder_rabbit_4_0_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_stream_binder_rabbit_core_4_0_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_stream_test_binder_4_0_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_integration_spring_integration_amqp_6_0_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_integration_spring_integration_core_6_0_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_integration_spring_integration_jmx_6_0_1.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_retry_spring_retry_2_0_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_aop_6_0_3.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_beans_6_0_3.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_context_6_0_3.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_core_6_0_3.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_expression_6_0_3.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_jcl_6_0_3.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_messaging_6_0_3.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_test_6_0_3.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_tx_6_0_3.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_web_6_0_3.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_webflux_6_0_3.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_webmvc_6_0_3.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_xmlunit_xmlunit_core_2_9_0.xml create mode 100644 samples/standalone/dsl/http-server/.idea/libraries/Maven__org_yaml_snakeyaml_1_33.xml create mode 100644 samples/standalone/dsl/http-server/.idea/misc.xml create mode 100644 samples/standalone/dsl/http-server/.idea/modules.xml create mode 100644 samples/standalone/dsl/http-server/.idea/sonarlint/issuestore/index.pb create mode 100644 samples/standalone/dsl/http-server/.idea/sonarlint/securityhotspotstore/index.pb create mode 100644 samples/standalone/dsl/http-server/.idea/vcs.xml delete mode 100644 samples/standalone/dsl/http-server/.mvn/jvm.config delete mode 100644 samples/standalone/dsl/http-server/.mvn/maven.config delete mode 100644 samples/standalone/dsl/http-server/.mvn/wrapper/MavenWrapperDownloader.java delete mode 100644 samples/standalone/dsl/http-server/.mvn/wrapper/maven-wrapper.jar delete mode 100644 samples/standalone/dsl/http-server/.mvn/wrapper/maven-wrapper.properties delete mode 100644 samples/standalone/dsl/http-server/README.adoc delete mode 100644 samples/standalone/dsl/http-server/build.gradle delete mode 100644 samples/standalone/dsl/http-server/gradle.properties delete mode 100644 samples/standalone/dsl/http-server/gradle/wrapper/gradle-wrapper.jar delete mode 100644 samples/standalone/dsl/http-server/gradle/wrapper/gradle-wrapper.properties delete mode 100755 samples/standalone/dsl/http-server/gradlew delete mode 100644 samples/standalone/dsl/http-server/gradlew.bat create mode 100644 samples/standalone/dsl/http-server/log.log delete mode 100755 samples/standalone/dsl/http-server/mvnw delete mode 100644 samples/standalone/dsl/http-server/mvnw.cmd delete mode 100644 samples/standalone/dsl/http-server/pom.xml delete mode 100644 samples/standalone/dsl/http-server/settings.gradle delete mode 100644 samples/standalone/dsl/http-server/src/main/java/com/example/fraud/Application.java delete mode 100644 samples/standalone/dsl/http-server/src/main/java/com/example/fraud/FooController.java delete mode 100644 samples/standalone/dsl/http-server/src/main/java/com/example/fraud/FraudDetectionController.java delete mode 100644 samples/standalone/dsl/http-server/src/main/java/com/example/fraud/FraudNameController.java delete mode 100644 samples/standalone/dsl/http-server/src/main/java/com/example/fraud/FraudStatsController.java delete mode 100644 samples/standalone/dsl/http-server/src/main/java/com/example/fraud/MessageSender.java delete mode 100644 samples/standalone/dsl/http-server/src/main/java/com/example/fraud/MessagingConfiguration.java delete mode 100644 samples/standalone/dsl/http-server/src/main/java/com/example/fraud/TestController.java delete mode 100644 samples/standalone/dsl/http-server/src/main/java/com/example/fraud/model/FraudCheck.java delete mode 100644 samples/standalone/dsl/http-server/src/main/java/com/example/fraud/model/FraudCheckResult.java delete mode 100644 samples/standalone/dsl/http-server/src/main/java/com/example/fraud/model/FraudCheckStatus.java delete mode 100644 samples/standalone/dsl/http-server/src/main/resources/application.properties delete mode 100644 samples/standalone/dsl/http-server/src/test/java/com/example/fraud/BinaryBase.java delete mode 100644 samples/standalone/dsl/http-server/src/test/java/com/example/fraud/FraudBase.java delete mode 100644 samples/standalone/dsl/http-server/src/test/java/com/example/fraud/FraudnameBase.java delete mode 100644 samples/standalone/dsl/http-server/src/test/java/com/example/fraud/MessagingBase.java delete mode 100644 samples/standalone/dsl/http-server/src/test/java/com/example/fraud/MultipartBase.java delete mode 100644 samples/standalone/dsl/http-server/src/test/java/com/example/fraud/TestBase.java delete mode 100644 samples/standalone/dsl/http-server/src/test/java/com/example/fraud/YmlFraudBase.java delete mode 100644 samples/standalone/dsl/http-server/src/test/java/com/example/fraud/YmlFraudnameBase.java delete mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/binary/request.pdf delete mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/binary/response.pdf delete mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/binary/shouldWorkWithBinaryPayload.groovy delete mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/fraud/shouldMarkClientAsFraud.groovy delete mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/fraud/shouldMarkClientAsNotFraud.groovy delete mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/fraud/shouldReturnFraudStats.groovy delete mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/fraudname/shouldReturnACookie.groovy delete mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/fraudname/shouldReturnAFraudForTheName.groovy delete mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/fraudname/shouldReturnNonFraudForTheName.groovy delete mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/messaging/output.pdf delete mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/messaging/shouldProduceValidSensorData.groovy delete mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/messaging/shouldReturnOkWhenServiceIsHealthy.yml delete mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/messaging/shouldWorkWithInputOutputBinary.groovy delete mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/multipart/shouldWorkForMultipartAsBytesWithContentType.groovy delete mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/multipart/shouldWorkForMultipartWithContentType.groovy delete mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/multipart/test.json delete mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/test/MyHttpContract.java delete mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/test/request.json delete mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/yml/fraud/shouldMarkClientAsFraud.yml delete mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/yml/fraud/shouldMarkClientAsNotFraud.yaml delete mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/yml/fraud/shouldReturnFraudStats.yml delete mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/yml/fraudname/shouldReturnAFraudForTheName.yml delete mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/yml/fraudname/shouldReturnNonFraudForTheName.yml delete mode 100644 samples/standalone/dsl/pom.xml delete mode 100755 samples/standalone/mvnw delete mode 100644 samples/standalone/mvnw.cmd delete mode 100644 samples/standalone/pom.xml create mode 100644 samples/standalone/restdocs/build.log delete mode 100644 samples/standalone/restdocs/http-client/.gitignore create mode 100644 samples/standalone/restdocs/http-client/.gradle/8.3/checksums/checksums.lock create mode 100644 samples/standalone/restdocs/http-client/.gradle/8.3/checksums/md5-checksums.bin create mode 100644 samples/standalone/restdocs/http-client/.gradle/8.3/checksums/sha1-checksums.bin create mode 100644 samples/standalone/restdocs/http-client/.gradle/8.3/dependencies-accessors/dependencies-accessors.lock create mode 100644 samples/standalone/restdocs/http-client/.gradle/8.3/dependencies-accessors/gc.properties create mode 100644 samples/standalone/restdocs/http-client/.gradle/8.3/executionHistory/executionHistory.bin create mode 100644 samples/standalone/restdocs/http-client/.gradle/8.3/executionHistory/executionHistory.lock create mode 100644 samples/standalone/restdocs/http-client/.gradle/8.3/fileChanges/last-build.bin create mode 100644 samples/standalone/restdocs/http-client/.gradle/8.3/fileHashes/fileHashes.bin create mode 100644 samples/standalone/restdocs/http-client/.gradle/8.3/fileHashes/fileHashes.lock create mode 100644 samples/standalone/restdocs/http-client/.gradle/8.3/fileHashes/resourceHashesCache.bin create mode 100644 samples/standalone/restdocs/http-client/.gradle/8.3/gc.properties create mode 100644 samples/standalone/restdocs/http-client/.gradle/buildOutputCleanup/buildOutputCleanup.lock create mode 100644 samples/standalone/restdocs/http-client/.gradle/buildOutputCleanup/cache.properties create mode 100644 samples/standalone/restdocs/http-client/.gradle/buildOutputCleanup/outputFiles.bin create mode 100644 samples/standalone/restdocs/http-client/.gradle/checksums/checksums.lock create mode 100644 samples/standalone/restdocs/http-client/.gradle/checksums/md5-checksums.bin create mode 100644 samples/standalone/restdocs/http-client/.gradle/checksums/sha1-checksums.bin create mode 100644 samples/standalone/restdocs/http-client/.gradle/file-system.probe create mode 100644 samples/standalone/restdocs/http-client/.gradle/vcs-1/gc.properties create mode 100644 samples/standalone/restdocs/http-client/.idea/.gitignore create mode 100644 samples/standalone/restdocs/http-client/.idea/compiler.xml create mode 100644 samples/standalone/restdocs/http-client/.idea/encodings.xml create mode 100644 samples/standalone/restdocs/http-client/.idea/jarRepositories.xml create mode 100644 samples/standalone/restdocs/http-client/.idea/misc.xml create mode 100644 samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/0/f/0f0eab2c174d28b70b02de758125b58bdbb2cb13 create mode 100644 samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/4/1/418b368109de47f2deab6ae6f859bba79503b690 create mode 100644 samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/4/4/442292b8a7efeabbe4cc176709b833b1792140ec create mode 100644 samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/8/4/8485b3d5dbc2b6f87bd101a3a996a5faab5574ea create mode 100644 samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/d/4/d4407a9ef49dcf7dd4b936e7fb4249f7579e0fbb create mode 100644 samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/f/0/f07866736216be0ee2aba49e392191aeae700a35 create mode 100644 samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/index.pb create mode 100644 samples/standalone/restdocs/http-client/.idea/vcs.xml delete mode 100644 samples/standalone/restdocs/http-client/.mvn/jvm.config delete mode 100644 samples/standalone/restdocs/http-client/.mvn/maven.config delete mode 100644 samples/standalone/restdocs/http-client/.mvn/wrapper/MavenWrapperDownloader.java delete mode 100644 samples/standalone/restdocs/http-client/.mvn/wrapper/maven-wrapper.jar delete mode 100644 samples/standalone/restdocs/http-client/.mvn/wrapper/maven-wrapper.properties delete mode 100644 samples/standalone/restdocs/http-client/README.adoc delete mode 100644 samples/standalone/restdocs/http-client/build.gradle delete mode 100644 samples/standalone/restdocs/http-client/gradle.properties delete mode 100644 samples/standalone/restdocs/http-client/gradle/wrapper/gradle-wrapper.jar delete mode 100644 samples/standalone/restdocs/http-client/gradle/wrapper/gradle-wrapper.properties delete mode 100755 samples/standalone/restdocs/http-client/gradlew delete mode 100644 samples/standalone/restdocs/http-client/gradlew.bat delete mode 100755 samples/standalone/restdocs/http-client/mvnw delete mode 100644 samples/standalone/restdocs/http-client/mvnw.cmd delete mode 100644 samples/standalone/restdocs/http-client/pom.xml delete mode 100644 samples/standalone/restdocs/http-client/settings.gradle delete mode 100644 samples/standalone/restdocs/http-client/src/main/java/com/example/loan/Application.java delete mode 100644 samples/standalone/restdocs/http-client/src/main/java/com/example/loan/LoanApplicationService.java delete mode 100644 samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/Client.java delete mode 100644 samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/FraudCheckStatus.java delete mode 100644 samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/FraudServiceRequest.java delete mode 100644 samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/FraudServiceResponse.java delete mode 100644 samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/LoanApplication.java delete mode 100644 samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/LoanApplicationResult.java delete mode 100644 samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/LoanApplicationStatus.java delete mode 100644 samples/standalone/restdocs/http-client/src/main/resources/application.yml delete mode 100644 samples/standalone/restdocs/http-client/src/test/java/com/example/loan/LoanApplicationServiceTests.java delete mode 100644 samples/standalone/restdocs/http-client/src/test/java/com/example/loan/LoanApplicationServiceusingStubRunnerTests.java delete mode 100644 samples/standalone/restdocs/http-client/src/test/java/com/example/loan/XmlServiceTests.java delete mode 100644 samples/standalone/restdocs/http-client/src/test/java/com/example/loan/XmlServiceUsingStubRunnerTests.java delete mode 100644 samples/standalone/restdocs/http-client/src/test/resources/application-gradle.yaml delete mode 100644 samples/standalone/restdocs/http-server/.gitignore create mode 100644 samples/standalone/restdocs/http-server/.gradle/8.3/checksums/checksums.lock create mode 100644 samples/standalone/restdocs/http-server/.gradle/8.3/checksums/md5-checksums.bin create mode 100644 samples/standalone/restdocs/http-server/.gradle/8.3/checksums/sha1-checksums.bin create mode 100644 samples/standalone/restdocs/http-server/.gradle/8.3/dependencies-accessors/dependencies-accessors.lock create mode 100644 samples/standalone/restdocs/http-server/.gradle/8.3/dependencies-accessors/gc.properties create mode 100644 samples/standalone/restdocs/http-server/.gradle/8.3/executionHistory/executionHistory.bin create mode 100644 samples/standalone/restdocs/http-server/.gradle/8.3/executionHistory/executionHistory.lock create mode 100644 samples/standalone/restdocs/http-server/.gradle/8.3/fileChanges/last-build.bin create mode 100644 samples/standalone/restdocs/http-server/.gradle/8.3/fileHashes/fileHashes.bin create mode 100644 samples/standalone/restdocs/http-server/.gradle/8.3/fileHashes/fileHashes.lock create mode 100644 samples/standalone/restdocs/http-server/.gradle/8.3/gc.properties create mode 100644 samples/standalone/restdocs/http-server/.gradle/buildOutputCleanup/buildOutputCleanup.lock create mode 100644 samples/standalone/restdocs/http-server/.gradle/buildOutputCleanup/cache.properties create mode 100644 samples/standalone/restdocs/http-server/.gradle/buildOutputCleanup/outputFiles.bin create mode 100644 samples/standalone/restdocs/http-server/.gradle/checksums/checksums.lock create mode 100644 samples/standalone/restdocs/http-server/.gradle/checksums/md5-checksums.bin create mode 100644 samples/standalone/restdocs/http-server/.gradle/checksums/sha1-checksums.bin create mode 100644 samples/standalone/restdocs/http-server/.gradle/file-system.probe create mode 100644 samples/standalone/restdocs/http-server/.gradle/vcs-1/gc.properties create mode 100644 samples/standalone/restdocs/http-server/.idea/.gitignore create mode 100644 samples/standalone/restdocs/http-server/.idea/compiler.xml create mode 100644 samples/standalone/restdocs/http-server/.idea/encodings.xml create mode 100644 samples/standalone/restdocs/http-server/.idea/jarRepositories.xml create mode 100644 samples/standalone/restdocs/http-server/.idea/misc.xml create mode 100644 samples/standalone/restdocs/http-server/.idea/sonarlint/issuestore/4/4/442292b8a7efeabbe4cc176709b833b1792140ec create mode 100644 samples/standalone/restdocs/http-server/.idea/sonarlint/issuestore/4/7/47243719dc78f8a57d390d73624d6c31feb69d10 create mode 100644 samples/standalone/restdocs/http-server/.idea/sonarlint/issuestore/c/e/cecf7cde4af07dd004c5c09953f0e7e7dbc86439 create mode 100644 samples/standalone/restdocs/http-server/.idea/sonarlint/issuestore/e/a/ea4a50232d6976a3ad6f2619cfb817ba6e474859 create mode 100644 samples/standalone/restdocs/http-server/.idea/sonarlint/issuestore/index.pb create mode 100644 samples/standalone/restdocs/http-server/.idea/vcs.xml delete mode 100644 samples/standalone/restdocs/http-server/.mvn/jvm.config delete mode 100644 samples/standalone/restdocs/http-server/.mvn/maven.config delete mode 100644 samples/standalone/restdocs/http-server/.mvn/wrapper/MavenWrapperDownloader.java delete mode 100644 samples/standalone/restdocs/http-server/.mvn/wrapper/maven-wrapper.jar delete mode 100644 samples/standalone/restdocs/http-server/.mvn/wrapper/maven-wrapper.properties delete mode 100644 samples/standalone/restdocs/http-server/README.adoc delete mode 100644 samples/standalone/restdocs/http-server/build.gradle delete mode 100644 samples/standalone/restdocs/http-server/gradle.properties delete mode 100644 samples/standalone/restdocs/http-server/gradle/wrapper/gradle-wrapper.jar delete mode 100644 samples/standalone/restdocs/http-server/gradle/wrapper/gradle-wrapper.properties delete mode 100755 samples/standalone/restdocs/http-server/gradlew delete mode 100644 samples/standalone/restdocs/http-server/gradlew.bat delete mode 100755 samples/standalone/restdocs/http-server/mvnw delete mode 100644 samples/standalone/restdocs/http-server/mvnw.cmd delete mode 100644 samples/standalone/restdocs/http-server/pom.xml delete mode 100644 samples/standalone/restdocs/http-server/settings.gradle delete mode 100644 samples/standalone/restdocs/http-server/src/assembly/stub.xml delete mode 100644 samples/standalone/restdocs/http-server/src/main/java/com/example/fraud/Application.java delete mode 100644 samples/standalone/restdocs/http-server/src/main/java/com/example/fraud/FraudDetectionController.java delete mode 100644 samples/standalone/restdocs/http-server/src/main/java/com/example/fraud/FraudDetectionXmlController.java delete mode 100644 samples/standalone/restdocs/http-server/src/main/java/com/example/fraud/model/FraudCheck.java delete mode 100644 samples/standalone/restdocs/http-server/src/main/java/com/example/fraud/model/FraudCheckResult.java delete mode 100644 samples/standalone/restdocs/http-server/src/main/java/com/example/fraud/model/FraudCheckStatus.java delete mode 100644 samples/standalone/restdocs/http-server/src/test/java/com/example/fraud/FraudBaseWithStandaloneSetup.java delete mode 100644 samples/standalone/restdocs/http-server/src/test/java/com/example/fraud/FraudBaseWithWebAppSetup.java delete mode 100644 samples/standalone/restdocs/http-server/src/test/java/com/example/fraud/StubGeneratorTests.java delete mode 100644 samples/standalone/restdocs/http-server/src/test/java/com/example/fraud/XmlStubGeneratorTests.java delete mode 100644 samples/standalone/restdocs/http-server/src/test/resources/contracts/standalone/shouldMarkClientAsFraud.groovy delete mode 100644 samples/standalone/restdocs/http-server/src/test/resources/contracts/webapp/shouldMarkClientAsNotFraud.groovy delete mode 100644 samples/standalone/restdocs/pom.xml create mode 100644 samples/standalone/webclient/build.log delete mode 100644 samples/standalone/webclient/http-client/.gitignore create mode 100644 samples/standalone/webclient/http-client/.gradle/8.3/checksums/checksums.lock create mode 100644 samples/standalone/webclient/http-client/.gradle/8.3/checksums/md5-checksums.bin create mode 100644 samples/standalone/webclient/http-client/.gradle/8.3/checksums/sha1-checksums.bin create mode 100644 samples/standalone/webclient/http-client/.gradle/8.3/dependencies-accessors/dependencies-accessors.lock create mode 100644 samples/standalone/webclient/http-client/.gradle/8.3/dependencies-accessors/gc.properties create mode 100644 samples/standalone/webclient/http-client/.gradle/8.3/executionHistory/executionHistory.bin create mode 100644 samples/standalone/webclient/http-client/.gradle/8.3/executionHistory/executionHistory.lock create mode 100644 samples/standalone/webclient/http-client/.gradle/8.3/fileChanges/last-build.bin create mode 100644 samples/standalone/webclient/http-client/.gradle/8.3/fileHashes/fileHashes.bin create mode 100644 samples/standalone/webclient/http-client/.gradle/8.3/fileHashes/fileHashes.lock create mode 100644 samples/standalone/webclient/http-client/.gradle/8.3/fileHashes/resourceHashesCache.bin create mode 100644 samples/standalone/webclient/http-client/.gradle/8.3/gc.properties create mode 100644 samples/standalone/webclient/http-client/.gradle/buildOutputCleanup/buildOutputCleanup.lock create mode 100644 samples/standalone/webclient/http-client/.gradle/buildOutputCleanup/cache.properties create mode 100644 samples/standalone/webclient/http-client/.gradle/buildOutputCleanup/outputFiles.bin create mode 100644 samples/standalone/webclient/http-client/.gradle/checksums/checksums.lock create mode 100644 samples/standalone/webclient/http-client/.gradle/checksums/md5-checksums.bin create mode 100644 samples/standalone/webclient/http-client/.gradle/checksums/sha1-checksums.bin create mode 100644 samples/standalone/webclient/http-client/.gradle/file-system.probe create mode 100644 samples/standalone/webclient/http-client/.gradle/vcs-1/gc.properties delete mode 100644 samples/standalone/webclient/http-client/.mvn/jvm.config delete mode 100644 samples/standalone/webclient/http-client/.mvn/maven.config delete mode 100644 samples/standalone/webclient/http-client/.mvn/wrapper/MavenWrapperDownloader.java delete mode 100644 samples/standalone/webclient/http-client/.mvn/wrapper/maven-wrapper.jar delete mode 100644 samples/standalone/webclient/http-client/.mvn/wrapper/maven-wrapper.properties delete mode 100644 samples/standalone/webclient/http-client/README.adoc delete mode 100644 samples/standalone/webclient/http-client/build.gradle delete mode 100644 samples/standalone/webclient/http-client/gradle.properties delete mode 100644 samples/standalone/webclient/http-client/gradle/wrapper/gradle-wrapper.jar delete mode 100644 samples/standalone/webclient/http-client/gradle/wrapper/gradle-wrapper.properties delete mode 100755 samples/standalone/webclient/http-client/gradlew delete mode 100644 samples/standalone/webclient/http-client/gradlew.bat delete mode 100755 samples/standalone/webclient/http-client/mvnw delete mode 100644 samples/standalone/webclient/http-client/mvnw.cmd delete mode 100644 samples/standalone/webclient/http-client/pom.xml delete mode 100644 samples/standalone/webclient/http-client/settings.gradle delete mode 100644 samples/standalone/webclient/http-client/src/main/java/com/example/loan/Application.java delete mode 100644 samples/standalone/webclient/http-client/src/main/java/com/example/loan/LoanApplicationService.java delete mode 100644 samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/Client.java delete mode 100644 samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/FraudCheckStatus.java delete mode 100644 samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/FraudServiceRequest.java delete mode 100644 samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/FraudServiceResponse.java delete mode 100644 samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/LoanApplication.java delete mode 100644 samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/LoanApplicationResult.java delete mode 100644 samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/LoanApplicationStatus.java delete mode 100644 samples/standalone/webclient/http-client/src/main/resources/application.yml delete mode 100644 samples/standalone/webclient/http-client/src/test/java/com/example/loan/LoanApplicationServiceTests.java delete mode 100644 samples/standalone/webclient/http-client/src/test/java/com/example/loan/LoanApplicationServiceusingStubRunnerGradleTests.java delete mode 100644 samples/standalone/webclient/http-client/src/test/java/com/example/loan/LoanApplicationServiceusingStubRunnerTests.java delete mode 100644 samples/standalone/webclient/http-client/src/test/resources/application-gradle.yaml delete mode 100644 samples/standalone/webclient/http-server/.gitignore create mode 100644 samples/standalone/webclient/http-server/.gradle/8.3/checksums/checksums.lock create mode 100644 samples/standalone/webclient/http-server/.gradle/8.3/checksums/md5-checksums.bin create mode 100644 samples/standalone/webclient/http-server/.gradle/8.3/checksums/sha1-checksums.bin create mode 100644 samples/standalone/webclient/http-server/.gradle/8.3/dependencies-accessors/dependencies-accessors.lock create mode 100644 samples/standalone/webclient/http-server/.gradle/8.3/dependencies-accessors/gc.properties create mode 100644 samples/standalone/webclient/http-server/.gradle/8.3/executionHistory/executionHistory.bin create mode 100644 samples/standalone/webclient/http-server/.gradle/8.3/executionHistory/executionHistory.lock create mode 100644 samples/standalone/webclient/http-server/.gradle/8.3/fileChanges/last-build.bin create mode 100644 samples/standalone/webclient/http-server/.gradle/8.3/fileHashes/fileHashes.bin create mode 100644 samples/standalone/webclient/http-server/.gradle/8.3/fileHashes/fileHashes.lock create mode 100644 samples/standalone/webclient/http-server/.gradle/8.3/gc.properties create mode 100644 samples/standalone/webclient/http-server/.gradle/buildOutputCleanup/buildOutputCleanup.lock create mode 100644 samples/standalone/webclient/http-server/.gradle/buildOutputCleanup/cache.properties create mode 100644 samples/standalone/webclient/http-server/.gradle/buildOutputCleanup/outputFiles.bin create mode 100644 samples/standalone/webclient/http-server/.gradle/checksums/checksums.lock create mode 100644 samples/standalone/webclient/http-server/.gradle/checksums/md5-checksums.bin create mode 100644 samples/standalone/webclient/http-server/.gradle/checksums/sha1-checksums.bin create mode 100644 samples/standalone/webclient/http-server/.gradle/file-system.probe create mode 100644 samples/standalone/webclient/http-server/.gradle/vcs-1/gc.properties create mode 100644 samples/standalone/webclient/http-server/.idea/.gitignore create mode 100644 samples/standalone/webclient/http-server/.idea/compiler.xml create mode 100644 samples/standalone/webclient/http-server/.idea/encodings.xml create mode 100644 samples/standalone/webclient/http-server/.idea/jarRepositories.xml create mode 100644 samples/standalone/webclient/http-server/.idea/misc.xml create mode 100644 samples/standalone/webclient/http-server/.idea/sonarlint/issuestore/4/4/442292b8a7efeabbe4cc176709b833b1792140ec create mode 100644 samples/standalone/webclient/http-server/.idea/sonarlint/issuestore/4/9/4933a334253a42a1b13f0397013f3267a154e096 create mode 100644 samples/standalone/webclient/http-server/.idea/sonarlint/issuestore/index.pb create mode 100644 samples/standalone/webclient/http-server/.idea/vcs.xml delete mode 100644 samples/standalone/webclient/http-server/.mvn/jvm.config delete mode 100644 samples/standalone/webclient/http-server/.mvn/maven.config delete mode 100644 samples/standalone/webclient/http-server/.mvn/wrapper/MavenWrapperDownloader.java delete mode 100644 samples/standalone/webclient/http-server/.mvn/wrapper/maven-wrapper.jar delete mode 100644 samples/standalone/webclient/http-server/.mvn/wrapper/maven-wrapper.properties delete mode 100644 samples/standalone/webclient/http-server/README.adoc delete mode 100644 samples/standalone/webclient/http-server/build.gradle delete mode 100644 samples/standalone/webclient/http-server/gradle.properties delete mode 100644 samples/standalone/webclient/http-server/gradle/wrapper/gradle-wrapper.jar delete mode 100644 samples/standalone/webclient/http-server/gradle/wrapper/gradle-wrapper.properties delete mode 100755 samples/standalone/webclient/http-server/gradlew delete mode 100644 samples/standalone/webclient/http-server/gradlew.bat delete mode 100755 samples/standalone/webclient/http-server/mvnw delete mode 100644 samples/standalone/webclient/http-server/mvnw.cmd delete mode 100644 samples/standalone/webclient/http-server/pom.xml delete mode 100644 samples/standalone/webclient/http-server/settings.gradle delete mode 100644 samples/standalone/webclient/http-server/src/assembly/stub.xml delete mode 100644 samples/standalone/webclient/http-server/src/main/java/com/example/fraud/Application.java delete mode 100644 samples/standalone/webclient/http-server/src/main/java/com/example/fraud/FraudDetectionController.java delete mode 100644 samples/standalone/webclient/http-server/src/main/java/com/example/fraud/model/FraudCheck.java delete mode 100644 samples/standalone/webclient/http-server/src/main/java/com/example/fraud/model/FraudCheckResult.java delete mode 100644 samples/standalone/webclient/http-server/src/main/java/com/example/fraud/model/FraudCheckStatus.java delete mode 100644 samples/standalone/webclient/http-server/src/main/resources/application.yml delete mode 100644 samples/standalone/webclient/http-server/src/test/java/com/example/fraud/StubGeneratorTests.java delete mode 100644 samples/standalone/webclient/pom.xml delete mode 100755 scripts/buildWithDocs.sh delete mode 100755 scripts/ciBuild.sh delete mode 100755 scripts/common.sh delete mode 100755 scripts/compileOnly.sh delete mode 100755 scripts/downloadDependencies.sh delete mode 100755 scripts/fastBuild.sh delete mode 100755 scripts/generateDocs.sh delete mode 100755 scripts/gradleOnly.sh delete mode 100755 scripts/integrationOnly.sh delete mode 100755 scripts/noIntegration.sh delete mode 100755 scripts/parallelBuild.sh delete mode 100755 scripts/runTests.sh delete mode 100755 scripts/updateWrappers.sh delete mode 100644 specs/README.adoc delete mode 100644 specs/pom.xml delete mode 100644 specs/spring-cloud-contract-spec-groovy/README.adoc delete mode 100644 specs/spring-cloud-contract-spec-groovy/pom.xml delete mode 100644 specs/spring-cloud-contract-spec-groovy/src/main/groovy/org/springframework/cloud/contract/spec/internal/GroovyDslPropertyConverter.java delete mode 100644 specs/spring-cloud-contract-spec-groovy/src/main/resources/META-INF/spring.factories delete mode 100644 specs/spring-cloud-contract-spec-groovy/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy delete mode 100644 specs/spring-cloud-contract-spec-java/README.adoc delete mode 100644 specs/spring-cloud-contract-spec-java/pom.xml delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/Contract.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/ContractConverter.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/ContractReader.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/ContractStorer.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/ContractTemplate.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/ContractVerifierException.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Body.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/BodyMatcher.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/BodyMatchers.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/CanBeDynamic.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ClientDslProperty.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ClientOutputMessage.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Common.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/CompositeContractTemplate.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ContractUtils.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Cookie.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Cookies.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/DslProperty.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/DslPropertyConverter.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ExecutionProperty.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/FromFileProperty.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/FromRequest.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/HandlebarsContractTemplate.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Header.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Headers.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/HttpHeaders.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/HttpMethods.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/HttpStatus.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Input.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/JSONCompareMode.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/MatchingStrategy.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/MatchingType.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/MatchingTypeValue.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/MatchingTypeValueHolder.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/MediaTypes.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/MessagingHeaders.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Multipart.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/NamedProperty.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/NotToEscapePattern.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/OptionalProperty.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/OutputMessage.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/PathBodyMatcher.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/PatternValueDslProperty.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/QueryParameter.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/QueryParameters.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/RandomStringGenerator.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/RegexCreatingProperty.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/RegexMatchingTypeValue.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/RegexPatterns.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/RegexProperty.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Request.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Response.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ResponseBodyMatchers.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ServerDslProperty.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ServerOutputMessage.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Url.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/UrlHelper.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/UrlPath.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/util/RegexpUtils.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/util/ValidateUtils.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/main/java/repackaged/nl/flotsam/xeger/Xeger.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/test/groovy/org/springframework/cloud/contract/spec/internal/HttpHeadersTests.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/test/groovy/org/springframework/cloud/contract/spec/internal/HttpMethodsTests.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/test/groovy/org/springframework/cloud/contract/spec/internal/MediaTypesTests.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/test/groovy/org/springframework/cloud/contract/spec/internal/MessagingHeadersTests.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/test/groovy/org/springframework/cloud/contract/spec/internal/RegexPropertyTests.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/test/groovy/repackaged/nl/flotsam/xeger/XegerTest.java delete mode 100644 specs/spring-cloud-contract-spec-java/src/test/groovy/repackaged/nl/flotsam/xeger/XegerUtilsTest.java delete mode 100644 specs/spring-cloud-contract-spec-kotlin/README.adoc delete mode 100644 specs/spring-cloud-contract-spec-kotlin/pom.xml delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/ContractDsl.kt delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/ContractDslExtensions.kt delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/BodyMatchersDsl.kt delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/CommonDsl.kt delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/ContractDslMarker.kt delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/CookiesDsl.kt delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/FromRequestDsl.kt delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/HeadersDsl.kt delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/InputDsl.kt delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/KotlinContractConverter.kt delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/MultipartDsl.kt delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/OutputMessageDsl.kt delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/RequestDsl.kt delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/ResponseBodyMatchersDsl.kt delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/ResponseDsl.kt delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/main/resources/META-INF/services/javax.script.ScriptEngineFactory delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/main/resources/META-INF/spring.factories delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/test/kotlin/org/springframework/cloud/contract/spec/ContractTests.kt delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/test/kotlin/org/springframework/cloud/contract/spec/internal/KotlinContractConverterTests.kt delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/multipart.kts delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/multipleDefinitions.kts delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/request.pdf delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/response.pdf delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/shouldWorkWithBinaryPayload.kts delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/singleDefinition.kts delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/test.json delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/unnamed_multiple.kts delete mode 100644 specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/unnamed_single.kts delete mode 100644 specs/spring-cloud-contract-spec/README.adoc delete mode 100644 specs/spring-cloud-contract-spec/pom.xml delete mode 100644 specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy delete mode 100644 specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/CookiesSpec.groovy delete mode 100644 specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/ExecutionPropertySpec.groovy delete mode 100644 specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/HttpStatusTests.java delete mode 100644 specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/InputSpec.groovy delete mode 100644 specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/MatchingTypeSpec.groovy delete mode 100644 specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/OutputMessageSpec.groovy delete mode 100644 specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/RegexPatternsSpec.groovy delete mode 100644 specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/RequestSpec.groovy delete mode 100644 specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/ResponseSpec.groovy delete mode 100644 spring-cloud-contract-dependencies/.factorypath delete mode 100644 spring-cloud-contract-dependencies/pom.xml create mode 100644 spring-cloud-contract-shade/dependency-reduced-pom.xml delete mode 100644 spring-cloud-contract-shade/pom.xml delete mode 100644 spring-cloud-contract-starters/pom.xml delete mode 100644 spring-cloud-contract-starters/spring-cloud-starter-contract-stub-runner-jetty/README.adoc delete mode 100644 spring-cloud-contract-starters/spring-cloud-starter-contract-stub-runner-jetty/pom.xml delete mode 100644 spring-cloud-contract-starters/spring-cloud-starter-contract-stub-runner/pom.xml delete mode 100644 spring-cloud-contract-starters/spring-cloud-starter-contract-verifier/pom.xml delete mode 100644 spring-cloud-contract-stub-runner-boot/.gitignore create mode 100644 spring-cloud-contract-stub-runner-boot/log.log delete mode 100644 spring-cloud-contract-stub-runner-boot/pom.xml delete mode 100644 spring-cloud-contract-stub-runner-boot/src/main/java/org/springframework/cloud/contract/stubrunner/server/StubRunnerBoot.java delete mode 100644 spring-cloud-contract-stub-runner-boot/src/main/resources/META-INF/thin-kafka.properties delete mode 100644 spring-cloud-contract-stub-runner-boot/src/main/resources/META-INF/thin-rabbit.properties delete mode 100644 spring-cloud-contract-stub-runner-boot/src/main/resources/application.yml delete mode 100644 spring-cloud-contract-stub-runner/.gitignore delete mode 100644 spring-cloud-contract-stub-runner/pom.xml delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherFactories.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherStubDownloader.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherStubDownloaderBuilder.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/Arguments.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AvailablePortScanner.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/BatchStubRunner.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/BatchStubRunnerFactory.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ClasspathStubProvider.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/CompositeStubDownloaderBuilder.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ContractDownloader.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ContractProjectUpdater.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/FileStubDownloader.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/GitRepo.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/HttpServerStub.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/HttpServerStubConfiguration.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/HttpServerStubConfigurer.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/MappingGenerator.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/MavenSettings.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/MessageNotMatchingException.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/NoOpHttpServerStub.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ProjectVersion.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ResourceResolver.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ResourceResolvingStubDownloader.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/RunningStubs.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ScmStubDownloaderBuilder.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubConfiguration.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubDownloader.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubDownloaderBuilder.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubDownloaderBuilderProvider.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubFinder.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubNotFoundException.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRepository.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunner.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerExecutor.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerFactory.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerOptions.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerOptionsBuilder.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerPropertyUtils.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunning.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubServer.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubTrigger.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/TemporaryFileStorage.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/ExceptionThrowingMessageVerifier.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/PortStubRunnerExtensionOptions.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/PortStubRunnerRuleOptions.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerExtension.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerExtensionOptions.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRule.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRuleOptions.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/provider/wiremock/StubRunnerWireMockTestExecutionListener.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStub.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStubConfigurer.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/EnableStubRunnerServer.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/HttpStubsController.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/StubRunnerBoot.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/StubRunnerServerConfiguration.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/TriggerController.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/AutoConfigureStubRunner.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfiguration.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/StubRunnerPort.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/StubRunnerPortBeanPostProcessor.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/StubRunnerProperties.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/ConditionalOnStubbedDiscoveryDisabled.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/ConditionalOnStubbedDiscoveryEnabled.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/StubMapperProperties.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerDiscoveryClient.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerReactiveDiscoveryClient.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerServiceInstance.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerSpringCloudAutoConfiguration.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/StubsRegistrar.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/consul/ConsulStubsRegistrar.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/consul/StubRunnerSpringCloudConsulAutoConfiguration.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/eureka/ConditionalOnEurekaEnabled.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/eureka/EurekaStubsRegistrar.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/eureka/StubRunnerSpringCloudEurekaAutoConfiguration.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/loadbalancer/SpringCloudLoadBalancerAutoConfiguration.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/zookeeper/StubRunnerSpringCloudZookeeperAutoConfiguration.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/zookeeper/ZookeeperStubsRegistrar.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/util/StubsParser.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/util/ZipCategory.java delete mode 100644 spring-cloud-contract-stub-runner/src/main/resources/META-INF/additional-spring-configuration-metadata.json delete mode 100644 spring-cloud-contract-stub-runner/src/main/resources/META-INF/spring.factories delete mode 100644 spring-cloud-contract-stub-runner/src/main/resources/META-INF/spring/org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner.imports delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/AetherStubDownloaderSpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/AvailablePortScannerSpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/BatchStubRunnerSpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/ContractDownloaderSpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/GitStubDownloaderPropertiesSpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/RunningStubsSpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubConfigurationSpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRepositorySpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerExecutorSpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerFactorySpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerOptionsBuilderSpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerPropertyUtilsSpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerSpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubServerSpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleCustomMsgVerifierSpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleCustomPortJUnitTest.java delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleExceptionThrowingSpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleJUnitTest.java delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleSpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/wiremock/TestWireMockExtensions.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStubAccessor.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStubSpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/server/StubRunnerBootSpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/serverexamples/StubRunnerBootConsulExample.java delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/serverexamples/StubRunnerBootEurekaExample.java delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/serverexamples/StubRunnerBootZookeeperExample.java delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfigurationSpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerOptionsBuilderSpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubMapperPropertiesSpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerSpringCloudAutoConfigurationSpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerSpringCloudReactiveAutoConfigurationSpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerStubsPerConsumerSpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerStubsPerConsumerWithConsumerNameSpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/consul/StubRunnerSpringCloudConsulAutoConfigurationSpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/util/ZipCategorySpec.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/AbstractGitTest.java delete mode 100644 spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/ClasspathStubProviderTest.java delete mode 100644 spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/CompositeStubDownloaderBuilderTests.java delete mode 100644 spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/ContractProjectUpdaterTest.java delete mode 100644 spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/FileStubDownloaderTests.java delete mode 100644 spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/GitRepoTests.java delete mode 100644 spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/GitStubDownloaderTests.java delete mode 100644 spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/StubDownloaderBuilderProviderTests.java delete mode 100644 spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/StubRepositoryTest.java delete mode 100644 spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/StubRunnerSliceTests.java delete mode 100644 spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/StubsStubDownloaderTests.java delete mode 100644 spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/TestCustomYamlContractConverter.java delete mode 100644 spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/TestUtils.java delete mode 100644 spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/issue1225/Issue1225Tests.java delete mode 100644 spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionCustomMessageVerifierTests.java delete mode 100644 spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionCustomPortTests.java delete mode 100644 spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionExceptionThrowingTests.java delete mode 100644 spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionTests.java delete mode 100644 spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5MethodExtensionTests.java delete mode 100644 spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/server/StubRunnerServerConfigurationTests.java delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/.m2/settings-security.xml delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/.m2/settings.xml delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/META-INF/spring.factories delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/anotherRepository/mappings/spring/cloud/bar/bar.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/anotherRepository/mappings/spring/cloud/foo/bar/foobar.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/anotherRepository/mappings/spring/cloud/foo/foo.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/anotherRepository/projects/brokers/brokers.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/anotherRepository/projects/brokers/nested/anotherDescriptor.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/anotherRepository/projects/descriptor.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/application-cloudtest.yml delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/application-eureka.yml delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/application-streamconsumer.yml delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/application-test-with-placeholders.yml delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/application-test.yml delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/application.yml delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/arbitrary.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/broken.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/customYamlRepository/contracts/custom.yml delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/file.zip delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/generateStubs/contracts/goodbye.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/generateStubs/contracts/goodbye_from_file.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/generateStubs/contracts/goodbye_response.txt delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/generateStubs/contracts/hello.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/generateStubs/contracts/hello.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/LICENSE.txt delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.10-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.10-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.10-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.10-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.10-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.10-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.11-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.11-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.11-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.11-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.11-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.11-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.5-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.5-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.5-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.5-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.5-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.5-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.6-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.6-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.6-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.6-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.6-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.6-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.7-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.7-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.7-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.7-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.7-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.7-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.8-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.8-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.8-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.8-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.8-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.8-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/foo.bar/bazService/0.0.1-SNAPSHOT/contracts/bazConsumer1/rest/shouldSayHello.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/foo.bar/bazService/0.0.1-SNAPSHOT/mappings/bazConsumer1/rest/shouldSayHello.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/README.adoc delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/COMMIT_EDITMSG delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/HEAD delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/config delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/description delete mode 100755 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/applypatch-msg.sample delete mode 100755 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/commit-msg.sample delete mode 100755 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/post-update.sample delete mode 100755 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/pre-applypatch.sample delete mode 100755 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/pre-commit.sample delete mode 100755 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/pre-push.sample delete mode 100755 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/pre-rebase.sample delete mode 100755 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/pre-receive.sample delete mode 100755 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/prepare-commit-msg.sample delete mode 100755 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/update.sample delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/index delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/info/exclude delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/logs/HEAD delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/logs/refs/heads/master delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/logs/refs/remotes/origin/HEAD delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/04/f59ff38f1c76629d41d71f38dcb87afecdf9ab delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/0a/124cc494496bf3574617f02e505975e8d64e5c delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/0b/b008b1d235cb760e13408f10662dda01027d1d delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/0f/c31c163430ef5913e1a85b3a6c4e36bcbf32e1 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/1e/bb28e0982e1e497fe57311c4f8f34bae6f382f delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/1e/c084220c52398ce8cd2f8235018019504030f2 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/2b/42d52aec21936e5578be5ea0e2fdb9c539ce88 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/35/c8489a4e3d4761ae82a8606ea82e0e52b05376 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/3b/d42890d5105a30abd82d0205b63cbf20a59e83 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/46/ea77fbb81bcd831368a980a2c296014be94bf8 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/49/c8705a4409b1a4bd0f767665632c6ae11b5b90 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/4d/48d4d56d4bf80700498dcb29d326c0ab35cb19 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/4e/5ffb7085c01081f98321985b6663f64939cdb2 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/57/4590052afef4af132f7b8c5b92682401635807 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/5b/0ae7cddbd14fc6ced6f87f4b9587afd6b0bd18 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/5f/25f6f934c0e7e5dcc18e1bd831dd288fa6ad8a delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/5f/8216428856a5d6240f82dda04f348ba8bb742c delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/61/9c03cba4276c76c43b9a307ed00f39dc44616e delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/61/fcad6942801c44ad275671c7d125efb564f799 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/62/589edd12a37dd28b6b6fed1e2d728ac9f05c8d delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/63/201c9f9cfbe294f3f314df8b9c94cfee88e622 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/6e/06f676c9ba4459c1feb922de8ee603ea6bebce delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/78/3688df3e22c6b8e1d8f58167baf4f511d369c5 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/83/1a7e732650ab7428f60d51ba7d9ea33c51cf26 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/90/126ac925d26698516838a646e286e037acd55e delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/95/f833faccac8775b5528e38f3c30b9036d5c538 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/9a/4d31b7e5ca02bf207e3b04b2312ee9585ee560 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/9e/5ec949f441e1828b21b7760ded76c1d42ea9bc delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/a1/84578130917b3bf6a6568f900f66c1ed0e72e1 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/b0/cdfa5512c23af490d213948c7bdcd76d59a93e delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/b4/fc3812c95e3f5eed2ac1964a131464293786aa delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/c4/25167fb2a107afddca629fad83f8603fe2c215 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/d2/5d733109a6de5ea294154f1612aaf5cb9ae06b delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/d2/ccedaea7b8739a11c17c91561cc2ace0a0a999 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/d7/2fbbffa2d0b1ea0707df4b533f3adf69383eaa delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/d9/ab57c99263dac1e164883dcb7e06c542b89906 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/fc/a3d789524348301d622344c8375d89b40f8b5d delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/fe/2d022c3d254c5c7a5a65783e6976fac499d9c6 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/pack/pack-36eb4e6b44a393bca412489cd42ac7cc572b42d3.idx delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/pack/pack-36eb4e6b44a393bca412489cd42ac7cc572b42d3.pack delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/packed-refs delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/refs/heads/master delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/refs/remotes/origin/HEAD delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/LICENSE.txt delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/latest/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/latest/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/latest/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/latest/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/latest/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/latest/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/release/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/release/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/release/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/release/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/release/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/release/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/foo.bar/bazService/0.0.1-SNAPSHOT/contracts/bazConsumer1/rest/shouldSayHello.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/foo.bar/bazService/0.0.1-SNAPSHOT/mappings/bazConsumer1/rest/shouldSayHello.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/README.adoc delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/COMMIT_EDITMSG delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/HEAD delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/config delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/description delete mode 100755 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/applypatch-msg.sample delete mode 100755 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/commit-msg.sample delete mode 100755 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/post-update.sample delete mode 100755 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/pre-applypatch.sample delete mode 100755 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/pre-commit.sample delete mode 100755 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/pre-push.sample delete mode 100755 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/pre-rebase.sample delete mode 100755 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/pre-receive.sample delete mode 100755 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/prepare-commit-msg.sample delete mode 100755 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/update.sample delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/index delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/info/exclude delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/logs/HEAD delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/logs/refs/heads/master delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/logs/refs/remotes/origin/HEAD delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/1e/c084220c52398ce8cd2f8235018019504030f2 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/2b/42d52aec21936e5578be5ea0e2fdb9c539ce88 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/3b/d42890d5105a30abd82d0205b63cbf20a59e83 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/3d/4a9b398121c61313558bd84a37637267539b25 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/51/326f92638a0342965bc511cbcc2eab61b41050 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/83/1a7e732650ab7428f60d51ba7d9ea33c51cf26 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/8d/d4290a6ccef367cde77cf95ec7449dca23d6bb delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/b4/fc3812c95e3f5eed2ac1964a131464293786aa delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/c7/e616f78096e2d77a0d908464bce9d415505961 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/f5/f3b2ddf93a179e1a0a93ccbf582d1e80648ce6 delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/pack/pack-36eb4e6b44a393bca412489cd42ac7cc572b42d3.idx delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/pack/pack-36eb4e6b44a393bca412489cd42ac7cc572b42d3.pack delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/packed-refs delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/refs/heads/master delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/refs/remotes/origin/HEAD delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/git_samples/sample_stubs/META-INF/com.example/hello-world/0.0.2/mappings/someMapping.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/logback.xml delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/0.0.1-SNAPSHOT/bootService-0.0.1-SNAPSHOT-stubs.jar delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/0.0.1-SNAPSHOT/bootService-0.0.1-SNAPSHOT.pom delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/maven-metadata.xml delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/0.0.1-SNAPSHOT/fraudDetectionServer-0.0.1-SNAPSHOT-stubs.jar delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/0.0.1-SNAPSHOT/fraudDetectionServer-0.0.1-SNAPSHOT.pom delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/maven-metadata.xml delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/loanIssuance/0.0.1-SNAPSHOT/loanIssuance-0.0.1-SNAPSHOT-stubs.jar delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/loanIssuance/0.0.1-SNAPSHOT/loanIssuance-0.0.1-SNAPSHOT.pom delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/loanIssuance/maven-metadata.xml delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/producerWithMultipleConsumers/0.0.1-SNAPSHOT/producerWithMultipleConsumers-0.0.1-SNAPSHOT-stubs.jar delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/producerWithMultipleConsumers/0.0.1-SNAPSHOT/producerWithMultipleConsumers-0.0.1-SNAPSHOT.pom delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/producerWithMultipleConsumers/maven-metadata.xml delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/messages/message.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/repository/contracts/contract1.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/repository/contracts/contract2.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/repository/httpcontract/contract1.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/lv/spring/cloud/bye/lv_bye.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/pl/spring/cloud/bye/pl_bye.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/pl/spring/cloud/bye/pl_overridden_bye.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/spring/cloud/bye/admin/admin.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/spring/cloud/bye/bye.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/spring/cloud/hello/README.md delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/spring/cloud/hello/admin/admin.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/spring/cloud/hello/hello.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/spring/cloud/ping/ping.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract1.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract2.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract3.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract4.groovy delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.bin delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.csv delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.xml delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/request.pdf delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/response.pdf delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/simple.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/simulation.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/transformers.json delete mode 100644 spring-cloud-contract-stub-runner/src/test/resources/zip/zip-malicious-traversal.zip delete mode 100644 spring-cloud-contract-tools/pom.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/pom.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/converter/ConversionContractVerifierException.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/converter/RecursiveFilesConverter.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/converter/RecursiveFilesConverterApplication.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/converter/StubGenerator.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/converter/StubGeneratorProvider.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/converter/StubPostProcessor.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/wiremock/DefaultWireMockStubPostProcessor.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverter.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockConverter.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/wiremock/WireMockMetaData.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/wiremock/WireMockStubPostProcessor.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/wiremock/WireMockToDslConverter.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/resources/META-INF/spring.factories delete mode 100755 spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/converter/RecursiveFilesConverterSpec.groovy delete mode 100755 spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverterSpec.groovy delete mode 100755 spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/WireMockToDslConverterSpec.groovy delete mode 100755 spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/WiremockScenarioConverterSpec.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/java/org/springframework/cloud/contract/verifier/wiremock/DefaultWireMockStubPostProcessorTests.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/dir3/Account creating.yml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/dir3/Test route.yml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/scenario/main_scenario/01_login.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/scenario/main_scenario/02_showCart.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/scenario/main_scenario/03_logout.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/1_scenario.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/2_scenario.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/dsl1.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/dsl1_list.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/dsl1_list2.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/dsl1b.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/scenario.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir2/dsl2.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dslRoot.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gitignore create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.3/checksums/checksums.lock create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.3/checksums/md5-checksums.bin create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.3/checksums/sha1-checksums.bin create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.3/dependencies-accessors/dependencies-accessors.lock create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.3/dependencies-accessors/gc.properties create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.3/executionHistory/executionHistory.bin create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.3/executionHistory/executionHistory.lock create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.3/fileChanges/last-build.bin create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.3/fileHashes/fileHashes.bin create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.3/fileHashes/fileHashes.lock create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.3/fileHashes/resourceHashesCache.bin create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.3/gc.properties create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.6.1/checksums/checksums.lock create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.6.1/checksums/md5-checksums.bin create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.6.1/checksums/sha1-checksums.bin create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.6.1/dependencies-accessors/dependencies-accessors.lock create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.6.1/dependencies-accessors/gc.properties create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.6.1/executionHistory/executionHistory.bin create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.6.1/executionHistory/executionHistory.lock create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.6.1/fileChanges/last-build.bin create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.6.1/fileHashes/fileHashes.bin create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.6.1/fileHashes/fileHashes.lock create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.6.1/fileHashes/resourceHashesCache.bin create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.6.1/gc.properties create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/checksums/checksums.lock create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/checksums/md5-checksums.bin create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/checksums/sha1-checksums.bin create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/checksums/sha256-checksums.bin create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/checksums/sha512-checksums.bin create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/dependencies-accessors/dependencies-accessors.lock create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/dependencies-accessors/gc.properties create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/executionHistory/executionHistory.bin create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/executionHistory/executionHistory.lock create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/fileChanges/last-build.bin create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/fileHashes/fileHashes.bin create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/fileHashes/fileHashes.lock create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/fileHashes/resourceHashesCache.bin create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/gc.properties create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/buildOutputCleanup/buildOutputCleanup.lock create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/buildOutputCleanup/cache.properties create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/buildOutputCleanup/outputFiles.bin create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/checksums/checksums.lock create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/checksums/md5-checksums.bin create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/checksums/sha1-checksums.bin create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/file-system.probe create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/vcs-1/gc.properties create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/.gitignore create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/codeStyles/Project.xml create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/codeStyles/codeStyleConfig.xml create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/compiler.xml create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/gradle.xml create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/jarRepositories.xml create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/misc.xml create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/sonarlint/issuestore/index.pb create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/sonarlint/securityhotspotstore/index.pb create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/uiDesigner.xml create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/vcs.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/build.gradle delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/gradle.properties delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/gradle/release.gradle delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/gradle/wrapper/gradle-wrapper.jar delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/gradle/wrapper/gradle-wrapper.properties delete mode 100755 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/gradlew delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/gradlew.bat delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/pom.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/ContractVerifierExtension.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/ContractsCopyTask.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/GenerateClientStubsFromDslTask.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/GenerateServerTestsTask.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/PublishStubsToScmTask.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/SpringCloudContractVerifierGradlePlugin.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/VersionExtractor.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/resources/META-INF/gradle-plugins/org.springframework.cloud.contract.properties delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/resources/META-INF/gradle-plugins/spring-cloud-contract.properties delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/groovy/org/springframework/cloud/contract/verifier/plugin/ContractVerifierIntegrationTest.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/groovy/org/springframework/cloud/contract/verifier/plugin/ContractVerifierKotlinIntegrationTest.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/groovy/org/springframework/cloud/contract/verifier/plugin/ContractVerifierTest.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/build.gradle delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/gradle.properties delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/gradle/wrapper/gradle-wrapper.jar delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/gradle/wrapper/gradle-wrapper.properties delete mode 100755 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/gradlew delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/gradlew.bat delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/repository/mappings/spring/cloud/twitter-places-analyzer/pairId/collerate_PlacesFrom_Tweet.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/repository/mappings/spring/cloud/twitter-places-analyzer/pairId/moreComplexVersion.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/settings.gradle delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/src/main/groovy/org/springframework/cloud/twitter/place/PairIdController.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/src/main/groovy/org/springframework/cloud/twitter/place/Tweet.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/src/test/groovy/org/springframework/cloud/contract/verifier/twitter/places/AcceptanceSpec.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/src/test/groovy/org/springframework/cloud/contract/verifier/twitter/places/BaseMockMvcSpec.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/src/test/resources/logback-test.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/build.gradle delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/mappings/fraudDetectionService/1_shouldMarkClientAsNotFraud.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/mappings/fraudDetectionService/2_shouldMarkClientAsFraud.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/Application.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/FraudDetectionController.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheck.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheckResult.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheckStatus.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/main/resources/application.yml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/test/groovy/org/springframework/cloud/MvcSpec.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/test/java/org/springframework/cloud/MvcTest.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/gradle.properties delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/gradle/wrapper/gradle-wrapper.jar delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/gradle/wrapper/gradle-wrapper.properties delete mode 100755 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/gradlew delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/gradlew.bat delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/Application.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/LoanApplicationService.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/Client.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheckStatus.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/FraudServiceRequest.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/FraudServiceResponse.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/LoanApplication.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/LoanApplicationResult.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/LoanApplicationStatus.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/resources/application.yml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/test/groovy/org/springframework/cloud/LoanApplicationServiceSpec.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/settings.gradle delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/build.gradle.kts delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/mappings/fraudDetectionService/1_shouldMarkClientAsNotFraud.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/mappings/fraudDetectionService/2_shouldMarkClientAsFraud.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/Application.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/FraudDetectionController.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheck.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheckResult.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheckStatus.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/main/resources/application.yml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/test/groovy/org/springframework/cloud/MvcSpec.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/test/java/org/springframework/cloud/MvcTest.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/gradle.properties delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/gradle/wrapper/gradle-wrapper.jar delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/gradle/wrapper/gradle-wrapper.properties delete mode 100755 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/gradlew delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/gradlew.bat delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/Application.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/LoanApplicationService.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/Client.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheckStatus.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/FraudServiceRequest.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/FraudServiceResponse.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/LoanApplication.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/LoanApplicationResult.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/LoanApplicationStatus.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/resources/application.yml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/test/groovy/org/springframework/cloud/LoanApplicationServiceSpec.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/settings.gradle.kts delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-gradle-portal-plugin/pom.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/.gitignore delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/pom.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/BaseClassMapping.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/ChangeDetector.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/ConvertMojo.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/CopyContracts.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/GenerateStubsMojo.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/GenerateTestsMojo.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/LeftOverPrevention.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/ManifestCreator.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/MavenContractsDownloader.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/PushStubsToScmMojo.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/RunMojo.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/stubrunner/AetherStubDownloaderFactory.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/stubrunner/LocalStubRunner.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/stubrunner/RemoteStubRunner.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/resources/META-INF/plexus/components.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/asciidoc/complex.adoc delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/asciidoc/configs.adoc delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/asciidoc/index.adoc delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/asciidoc/junit.adoc delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/asciidoc/spock.adoc delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/asciidoc/usage.adoc delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/site.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/maven/verifier/AbstractMojoTest.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/maven/verifier/ChangeDetectorTests.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/maven/verifier/MavenContractsDownloaderTests.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/maven/verifier/PluginUnitTest.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/stubrunner/InclusionPropertiesAccessor.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-baseclass-from-mappings/pom.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-baseclass-from-mappings/src/test/resources/contracts/com/hello/v1/Messaging.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-baseclass-from-mappings/src/test/resources/contracts/com/hello/v1/Sample.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-baseclass-from-mappings/src/test/resources/contracts/com/hello/v1/WithList.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-generated-baseclass/pom.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-generated-baseclass/src/test/resources/contracts/hello/v1/Messaging.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-generated-baseclass/src/test/resources/contracts/hello/v1/Sample.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-generated-baseclass/src/test/resources/contracts/hello/v1/WithList.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-remote-contracts/pom-with-repo.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-remote-contracts/pom.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic/pom.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic/src/test/resources/contracts/Messaging.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic/src/test/resources/contracts/Sample.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic/src/test/resources/contracts/WithList.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/common-repo/consumer1/Messaging.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/common-repo/consumer1/Sample.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/common-repo/consumer1/WithList.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/common-repo/pom.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-common-repo-with-messaging/pom.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-common-repo-with-messaging/src/test/java/com/example/services/TestBase.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/.gitignore delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/pom.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/main/java/com/blogspot/toomuchcoding/frauddetection/Application.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/main/java/com/blogspot/toomuchcoding/frauddetection/FraudDetectionController.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheck.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheckResult.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheckStatus.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/test/contracts/brokenContract.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/test/contracts/shouldMarkClientAsFraud.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/test/contracts/shouldMarkClientAsNotFraud.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/test/java/com/blogspot/toomuchcoding/frauddetection/BaseAccurest.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/test/java/com/blogspot/toomuchcoding/frauddetection/matchers/CustomMatchers.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-remote-contracts/pom.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/.gitignore delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/pom.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/main/java/com/blogspot/toomuchcoding/frauddetection/Application.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/main/java/com/blogspot/toomuchcoding/frauddetection/FraudDetectionController.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheck.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheckResult.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheckStatus.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/test/contracts/brokenContract.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/test/contracts/shouldMarkClientAsFraud.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/test/contracts/shouldMarkClientAsNotFraud.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/test/java/com/blogspot/toomuchcoding/frauddetection/BaseAccurest.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/test/java/com/blogspot/toomuchcoding/frauddetection/matchers/CustomMatchers.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/pom.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/generatedStubs/.gitignore delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/generatedStubs/pom.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/generatedStubs/target/stubs/contracts/Sample.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/generatedStubs/target/stubs/mappings/Sample.json delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/generatedStubsOnly/.gitignore delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/generatedStubsOnly/target/stubs/Sample.json delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/git-basic-remote-contracts/pom.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/multiple-contracts/pom.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/multiple-contracts/src/test/resources/contracts/com/hello/v1/WithList.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/pom.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/src/main/java/hello/Application.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/src/main/java/hello/Greeting.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/src/main/java/hello/GreetingController.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/src/test/java/hello/BaseAccurest.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/src/test/resources/contracts/greetings_ok.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/src/test/resources/contracts/greetings_with_default_value.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/pomless/Sample.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/pom.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/main/java/hello/Application.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/main/java/hello/Greeting.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/main/java/hello/GreetingController.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/main/java/hello/GreetingResponse.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/test/groovy/hello/BaseAccurest.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/test/resources/contracts/greetings_ok.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/test/resources/contracts/greetings_post_ok.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/test/resources/contracts/greetings_with_default_value.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/pom.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/src/main/java/hello/Application.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/src/main/java/hello/Greeting.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/src/main/java/hello/GreetingController.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/src/test/java/hello/BaseAccurest.java delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/src/test/resources/contracts/greetings_ok.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/src/test/resources/contracts/greetings_with_default_value.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/withStubs/pom.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/withStubs/src/test/resources/stubs/Sample.groovy delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/logback.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/contracts/0.0.1-SNAPSHOT/contracts-0.0.1-SNAPSHOT.jar delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/contracts/0.0.1-SNAPSHOT/contracts-0.0.1-SNAPSHOT.pom delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/contracts/0.0.1-SNAPSHOT/maven-metadata-local.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/contracts/1.0.4-SNAPSHOT/contracts-0.0.1-SNAPSHOT.pom delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/contracts/maven-metadata.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/services-contracts/1.0.4-SNAPSHOT/maven-metadata-local.xml delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/services-contracts/1.0.4-SNAPSHOT/services-contracts-1.0.4-SNAPSHOT.jar delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/services-contracts/1.0.4-SNAPSHOT/services-contracts-1.0.4-SNAPSHOT.pom delete mode 100644 spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/services-contracts/maven-metadata.xml delete mode 100644 spring-cloud-contract-verifier/pom.xml delete mode 100644 spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/BodyExtractor.groovy delete mode 100644 spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/ContentUtils.groovy delete mode 100644 spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/JsonToJsonPathsConverter.groovy delete mode 100644 spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/xml/XmlToXPathsConverter.groovy delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/FileSaver.java delete mode 100755 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/TestGenerator.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/TestGeneratorApplication.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/assertion/CollectionAssert.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/assertion/ContractCollectionAssert.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/assertion/SpringCloudContractAssertions.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/Acceptor.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BaseClassProvider.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BlockBuilder.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BodyAssertionLineCreator.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BodyMethodGeneration.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BodyMethodVisitor.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BodyParser.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BodyReader.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BodyThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ClassAnnotation.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ClassAnnotationsBuilder.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ClassBodyBuilder.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ClassMetaData.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ClassVerifier.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CommunicationType.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ComparisonBuilder.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ContentHelper.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CookieElementProcessor.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeAcceptor.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeBodyGiven.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeBodyParser.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeCookiesGiven.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeCookiesThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeFields.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeGiven.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeHeadersGiven.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeHeadersThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeMethodWithUrlGiven.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeQueryParamsGiven.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeRequestBuildGiven.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeRequestGiven.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeResponseWhen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeSchemeProtocolGiven.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeStaticImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeStatusCodeThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeWhen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomMultipartGiven.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/DefaultBaseClassProvider.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/DefaultClassMetadata.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/DefaultImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/DefaultJsonStaticImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/DefaultStaticImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ExplicitAcceptor.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ExplicitRequestGiven.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ExplicitResponseWhen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ExplicitRestAssuredImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ExplicitRestAssuredStaticImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/Field.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/FieldBuilder.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GeneratedClassDataForMethod.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GeneratedClassMetaData.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GeneratedTestClass.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GeneratedTestClassBuilder.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GenericBinaryBodyThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GenericHttpBodyThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GenericJsonBodyThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GenericTextBodyThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GenericXmlBodyThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/Given.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GroovyBodyParser.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GroovyClassMetaData.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GroovyComparisonBuilder.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/Imports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ImportsBuilder.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit4IgnoreImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit4IgnoreMethodAnnotation.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit4Imports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit4MethodAnnotation.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit4OrderClassAnnotation.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit4OrderImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit5IgnoreImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit5IgnoreMethodAnnotation.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit5Imports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit5MethodAnnotation.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit5OrderClassAnnotation.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit5OrderImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnitMethodMetadata.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaClassMetaData.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaJaxRsThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaJaxRsWhen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaMessagingBodyParser.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaMessagingWithBodyThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaMultipartGiven.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaRestAssuredGiven.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaRestAssuredThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaRestAssuredWhen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaTestGenerator.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsAcceptor.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsBodyParser.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsGiven.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsRequestCookiesWhen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsRequestHeadersWhen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsRequestInvokerWhen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsRequestMethodWhen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsRequestWhen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsResponseCookiesThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsResponseHeadersThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsStaticImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsStatusCodeThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsUrlPathWhen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsWhen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JsonBodyVerificationBuilder.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JsonPathImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingAssertThatThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingAssertThatWhen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingBodyParser.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingBodyThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingFields.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingHeadersThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingReceiveMessageThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingSpockNoMessageThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingStaticImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingTriggeredByWhen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingWhen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingWithBodyThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MetaDataBuilder.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodAcceptor.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodAnnotationBuilder.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodAnnotations.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodMetadata.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodMetadataBuilder.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodPostProcessor.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodPreProcessor.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodVisitor.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcAcceptor.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcAsyncWhen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcBodyGiven.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcCookiesGiven.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcHeadersGiven.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcQueryParamsWhen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcRequestGiven.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcResponseWhen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcRestAssuredImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcRestAssuredStaticImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcUrlWhen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/NameProvider.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/OurCallable.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/QueryParamsResolver.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredAcceptor.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredBodyParser.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredCookiesThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredGiven.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredHeadersThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredStatusCodeThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredWhen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SingleMethodBuilder.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SingleTestGenerator.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockExplicitMultipartGiven.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockIgnoreImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockIgnoreMethodAnnotation.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockJaxRsBodyParser.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockJaxRsThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockJaxRsWhen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMessagingBodyParser.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMessagingEmptyThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMessagingWithBodyThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMethodMetadata.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMockMvcMultipartGiven.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMockMvcRequestGiven.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMockMvcResponseWhen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockOrderClassAnnotation.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockOrderImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockRestAssuredBodyParser.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockRestAssuredGiven.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockRestAssuredThen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockRestAssuredWhen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockWebTestClientMultipartGiven.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SuppressWarningsClassAnnotation.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/TemplateUpdatingMethodPostProcessor.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/TestNGImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/TestNGMethodAnnotation.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/TestSideRequestTemplateModel.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/Then.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/UserImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/UserStaticImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/Visitor.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/WebTestClientAcceptor.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/WebTestClientRequestGiven.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/WebTestClientResponseWhen.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/WebTestClientRestAssured3StaticImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/WebTestClientRestAssuredImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/When.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/XmlBodyVerificationBuilder.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/XmlImports.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/handlebars/HandlebarsEscapeHelper.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/handlebars/HandlebarsJsonPathHelper.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/ContractVerifierConfigProperties.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/TestFramework.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/TestMode.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/framework/CustomDefinition.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/framework/JUnit5Definition.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/framework/JUnitDefinition.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/framework/SpockDefinition.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/framework/TestFrameworkDefinition.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/framework/TestNGDefinition.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/ContractsToYaml.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/ToYamlConverter.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/ToYamlConverterApplication.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/YamlContract.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/YamlToContracts.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/ContractVerifierMetadata.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/BaseWireMockStubStrategy.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/DefaultResponseTransformer.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/SpringCloudContractRequestMatcher.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockExtensions.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockRequestStubStrategy.java delete mode 100755 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockResponseStubStrategy.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockStubMapping.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockStubStrategy.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/XPathBodyMatcherToWireMockValuePatternConverter.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/file/ContractFileScanner.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/file/ContractMetadata.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/file/SingleContractMetadata.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/Body.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/ContractVerifierHttpMetaData.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/HttpVerifier.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/OkHttpHttpVerifier.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/Request.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/Response.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/MessageVerifierReceiver.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/MessageVerifierSender.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/amqp/AmqpMetadata.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/boot/AutoConfigureMessageVerifier.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/camel/CamelStubMessages.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/camel/ContractVerifierCamelConfiguration.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/camel/ContractVerifierCamelMessageBuilder.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/camel/StandaloneMetadata.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/integration/ContractVerifierIntegrationConfiguration.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/integration/ContractVerifierIntegrationMessageBuilder.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/integration/SpringIntegrationStubMessages.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierMessage.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierMessageMetadata.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierMessaging.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierObjectMapper.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/jms/ContractVerifierJmsConfiguration.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/jms/JmsStubMessages.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/kafka/KafkaMetadata.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/noop/NoOpContractVerifierAutoConfiguration.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/noop/NoOpStubMessages.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/ContractVerifierStreamAutoConfiguration.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/ContractVerifierStreamMessageBuilder.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/DefaultChannels.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/DestinationResolver.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/StreamInputDestinationMessageSender.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/StreamOutputDestinationMessageReceiver.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/StreamStubMessageSender.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/StreamStubMessages.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/util/ContractVerifierMessagingUtil.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/template/HandlebarsTemplateProcessor.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/template/TemplateProcessor.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/AssertionUtil.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/CloneUtils.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ContentType.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ContractScanner.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ContractVerifierDslConverter.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ContractVerifierUtil.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/DelegatingJsonVerifiable.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/DslParseException.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/FinishedDelegatingJsonVerifiable.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/JsonPaths.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/MapConverter.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/MetadataUtil.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/MethodBuffering.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/MethodBufferingJsonVerifiable.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/NamesUtil.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/RegexpBuilders.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ShouldTraverse.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/SpringCloudContractMetadata.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ToFileContractsTransformer.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/ArrayValueAssertion.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/DOMNamespaceContext.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/FieldAssertion.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/IteratingOverArray.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/ReadyToCheckAsserter.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XPathBuilder.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlArrayVerifiable.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlAsserter.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlAsserterConfiguration.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlAssertion.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlCachedObjects.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlReader.java delete mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlVerifiable.java delete mode 100644 spring-cloud-contract-verifier/src/main/resources/META-INF/spring/org.springframework.cloud.contract.verifier.messaging.boot.AutoConfigureMessageVerifier.imports delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/GeneratorScannerSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/MainTest.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/TestGeneratorTests.java delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/BlockBuilderTests.java delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/BookReturned.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ClassBuilderSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/GeneratedTestClassTests.java delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientMethodBuilderSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/JsonAssertTests.java delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilderSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MethodBuilderSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderWithMatchersSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/QueryParamsResolverSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGeneratorSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SpringTestMethodBodyBuildersSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/XmlMethodBodyBuilderSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/YamlMockMvcMethodBodyBuilderSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/messageResponse.json delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/DslToYamlContractConverterSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/JavaContractConverterSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverterSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/TestWireMockExtensions.groovy delete mode 100755 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockGroovyDslSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockRequestStubStrategySpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockResponseStubStrategySpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockStubMappingSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockStubVerifier.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockXmlStubStrategySpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScannerNewApiSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScannerSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/messaging/camel/ContractVerifierCamelMessageBuilderSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierObjectMapperSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/messaging/stream/ContractVerifierHelperForStreamTest.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/messaging/stream/StreamStubMessagesWithDestinationsSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/BodyExtractorSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/ContentUtilsSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/ContractVerifierDslConverterSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/JsonToJsonPathsConverterSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/NamesUtilSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/SyntaxChecker.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/ToFileContractsTransformerSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/xml/XPathSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/xml/XmlAssertionSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/xml/XmlToXPathsConverterSpec.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/assertion/CollectionAssertTests.java delete mode 100644 spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/builder/XmlBodyVerificationBuilderTest.java delete mode 100644 spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/dsl/ContractVerifierMetadataTests.java delete mode 100644 spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/dsl/wiremock/GraphQLRequestMatcherTests.java delete mode 100644 spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/dsl/wiremock/SpringCloudContractRequestMatcherTests.java delete mode 100644 spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/http/RequestTests.java delete mode 100644 spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/http/ResponseTests.java delete mode 100644 spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/amqp/AmqpMetadataTests.java delete mode 100644 spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/boot/AutoConfigureMessageVerifierTests.java delete mode 100644 spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/camel/ContractVerifierCamelConfigurationTests.java delete mode 100644 spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/integration/ContractVerifierIntegrationConfigurationTests.java delete mode 100644 spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/jms/ContractVerifierJmsConfigurationTests.java delete mode 100644 spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/jms/JmsStubMessagesTests.java delete mode 100644 spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/kafka/KafkaMetadataTests.java delete mode 100644 spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/noop/NoOpContractVerifierAutoConfigurationTests.java delete mode 100644 spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/stream/ContractVerifierStreamAutoConfigurationTests.java delete mode 100644 spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/util/ContractVerifierUtilTest.java delete mode 100644 spring-cloud-contract-verifier/src/test/resources/META-INF/spring.factories delete mode 100644 spring-cloud-contract-verifier/src/test/resources/application.properties delete mode 100644 spring-cloud-contract-verifier/src/test/resources/body_builder/request.pdf delete mode 100644 spring-cloud-contract-verifier/src/test/resources/body_builder/response.pdf delete mode 100644 spring-cloud-contract-verifier/src/test/resources/body_builder/worksWithPdf.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/charset/readFromFileWithCharset.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/charset/request.json delete mode 100644 spring-cloud-contract-verifier/src/test/resources/charset/response.json delete mode 100644 spring-cloud-contract-verifier/src/test/resources/classpath/readFromFile.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/classpath/request.json delete mode 100644 spring-cloud-contract-verifier/src/test/resources/classpath/request.xml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/classpath/response.json delete mode 100644 spring-cloud-contract-verifier/src/test/resources/contract.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/contract.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract.java delete mode 100644 spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_docs_examples.java delete mode 100644 spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_multipart.java delete mode 100644 spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_rest.java delete mode 100644 spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_rest_from_file.java delete mode 100644 spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_rest_from_pdf.java delete mode 100644 spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_rest_with_tags.java delete mode 100644 spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_xml.java delete mode 100644 spring-cloud-contract-verifier/src/test/resources/contractsToCompile/package_contract.java delete mode 100644 spring-cloud-contract-verifier/src/test/resources/contractsToCompile/request.json delete mode 100644 spring-cloud-contract-verifier/src/test/resources/contractsToCompile/request.pdf delete mode 100644 spring-cloud-contract-verifier/src/test/resources/contractsToCompile/response.json delete mode 100644 spring-cloud-contract-verifier/src/test/resources/contractsToCompile/response.pdf delete mode 100644 spring-cloud-contract-verifier/src/test/resources/directory/with/common-messaging/kafka-topics/coupon-collected/src/main/resources/contracts/rule-engine-daemon/messaging/couponCollectedEventV1.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/directory/with/common-messaging/kafka-topics/coupon-collected/src/main/resources/contracts/rule-engine-daemon/messaging/couponCollectedEventV2.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/directory/with/common-messaging/kafka-topics/coupon-sent/src/main/resources/contracts/rule-engine-daemon/messaging/couponSentEventSm.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/directory/with/common-messaging/reward-rules/src/main/resources/contracts/reward_rules/rest/admin/v1/shouldReturnBetRanges.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/directory/with/common-messaging/social-service/src/main/resources/contracts/coupons_new_backend/rest/shouldReturnEmptyFriendsWhenGetFriends.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/directory/with/common-messaging/social-service/src/main/resources/contracts/facebook_client/rest/shouldUpdateUserInfo.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/directory/with/custom/yml/custom.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/directory/with/mixed/contract.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/directory/with/mixed/dsl.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/directory/with/mixed/invalid.json delete mode 100644 spring-cloud-contract-verifier/src/test/resources/directory/with/name-with-hyphen/car-rental/diff.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/directory/with/scenario/01_login.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/directory/with/scenario/02_showCart.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/directory/with/scenario/03_logout.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/directory/with/stubs/different/diff.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/directory/with/stubs/other/different/diff.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/directory/with/stubs/other/other.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/directory/with/stubs/other/sample.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/directory/with/stubs/package/exceptions/test.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/directory/with/stubs/package/v1/exceptions/testv1.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/directory/with/stubs/package/v2/exceptions/testv2.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/dsl/basic/sampleDsl.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/getBody.json delete mode 100644 spring-cloud-contract-verifier/src/test/resources/kotlin/contract_docs_examples.kts delete mode 100644 spring-cloud-contract-verifier/src/test/resources/kotlin/contract_rest.kts delete mode 100644 spring-cloud-contract-verifier/src/test/resources/kotlin/contract_xml.kts delete mode 100644 spring-cloud-contract-verifier/src/test/resources/kotlin/multipart.kts delete mode 100644 spring-cloud-contract-verifier/src/test/resources/kotlin/readFromFile.kts delete mode 100644 spring-cloud-contract-verifier/src/test/resources/kotlin/request.json delete mode 100644 spring-cloud-contract-verifier/src/test/resources/kotlin/request.pdf delete mode 100644 spring-cloud-contract-verifier/src/test/resources/kotlin/response.json delete mode 100644 spring-cloud-contract-verifier/src/test/resources/kotlin/response.pdf delete mode 100644 spring-cloud-contract-verifier/src/test/resources/logback.xml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/main.json delete mode 100644 spring-cloud-contract-verifier/src/test/resources/messageResponse.json delete mode 100644 spring-cloud-contract-verifier/src/test/resources/multiple_contracts.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/prependFolderName/META-INF/1.0.0.SNAPSHOT/01_login.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/prependFolderName/META-INF/1.0.0.SNAPSHOT/3.0.0.SNAPSHOT/01_login.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/prependFolderName/META-INF/1.0.0.SNAPSHOT/3.0.0.SNAPSHOT/normal/01_login.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/prependFolderName/META-INF/1.0.0.SNAPSHOT/normal/01_login.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/prependFolderName/META-INF/2.0.0.SNAPSHOT/01_login.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/strange_[3.3.3]_directory/02_login.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/strange_[3.3.3]_directory/bar/03_login.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/strange_[3.3.3]_directory/foo/01_login.groovy delete mode 100644 spring-cloud-contract-verifier/src/test/resources/stubs/wiremocks/other/sample.json delete mode 100644 spring-cloud-contract-verifier/src/test/resources/stubs/wiremocks/sample.json delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/contract.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/contract_broken_request_headers.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/contract_broken_response_headers.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/contract_cookies.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/contract_from_file.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/contract_matchers.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/contract_matchers_url.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/contract_message.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/contract_message_matchers.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/contract_message_method.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/contract_message_scenario1.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/contract_messaging_pdf.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/contract_multipart.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/contract_pdf.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/contract_reference_request.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/contract_rest.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/contract_rest_named_xml.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/contract_rest_with_path.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/contract_rest_xml.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/issue1038.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/issue1052.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/multiple_contracts.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/oa3/openapi_petstore.yml delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/request.json delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/request.pdf delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/response.json delete mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/response.pdf delete mode 100644 spring-cloud-contract-wiremock/.gitignore delete mode 100644 spring-cloud-contract-wiremock/pom.xml delete mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/AutoConfigureHttpClient.java delete mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMock.java delete mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockApplicationListener.java delete mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockConfiguration.java delete mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockConfigurationCustomizer.java delete mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockRestServiceServer.java delete mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockRestTemplateConfiguration.java delete mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockSpring.java delete mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockStubMapping.java delete mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockTestExecutionListener.java delete mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/file/ResourcesFileSource.java delete mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/BasicMappingBuilder.java delete mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/ContractDslSnippet.java delete mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/ContractExchangeHandler.java delete mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/ContractResultHandler.java delete mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/DynamicPortPlaceholderInserterPreprocessor.java delete mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/JsonPathValue.java delete mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/SpringCloudContractRestDocs.java delete mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockRestAssuredConfiguration.java delete mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockRestDocs.java delete mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockRestDocsConfiguration.java delete mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockSnippet.java delete mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockVerifyHelper.java delete mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockWebTestClient.java delete mode 100644 spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockWebTestClientConfiguration.java delete mode 100644 spring-cloud-contract-wiremock/src/main/resources/META-INF/spring.factories delete mode 100644 spring-cloud-contract-wiremock/src/main/resources/META-INF/spring/org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs.imports delete mode 100644 spring-cloud-contract-wiremock/src/main/resources/org/springframework/restdocs/templates/asciidoctor/default-dsl-contract.snippet delete mode 100644 spring-cloud-contract-wiremock/src/main/resources/org/springframework/restdocs/templates/default-dsl-contract-only.snippet delete mode 100644 spring-cloud-contract-wiremock/src/main/resources/org/springframework/restdocs/templates/markdown/default-dsl-contract.snippet delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockAdditionalImportTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockApplicationTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockAutoStubsApplicationTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockConfigurationCustomizerTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockConfigurationInYamlTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockConfigurationMultipleCustomizerTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockDefaultSetupTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockFilesApplicationTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockFilesApplicationWithUrlResourceTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockFilesApplicationWithoutSlashTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockHttpsPortApplicationTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockOnlyHttpsPortApplicationTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockOnlyRandomPortHttpsApplicationTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockPortApplicationTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockRandomPortApplicationTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockRandomPortHttpsApplicationTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockRandomPortInheretedApplicationTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockSamePortApplicationTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockStubsAndFilesApplicationTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockStubsAndMultipleFilesApplicationTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockStubsApplicationTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockStubsApplicationWithSlashTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockWithResetAfterEachTestApplicationTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockWithResetAfterEachTestNestedApplicationTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/MetaAnnotationWithResetAfterEachTestApplicationTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WireMockStubMappingTest.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockHttpsServerApplicationTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockMockServerApplicationTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerApplicationTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerRestAssuredApplicationTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerRestDocsApplicationTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerRestDocsHypermediaApplicationTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerRestDocsMatcherApplicationTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerWebTestClientApplicationTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockTestsApplication.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/file/ResourcesFileSourceTest.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/issue399/NotOrderedCustomizerTest.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/issue399/OrderedCustomizerTest.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/issue399/SpringContractWiremockIssueDemoApplication.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/Client.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/FirstTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/FraudCheckStatus.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/FraudServiceRequest.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/FraudServiceResponse.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/LoanApplication.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/SecondTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/staticInit/ClientProperties.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/staticInit/RestTemplateConfiguration.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/staticInit/TimeoutApplication.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/staticInit/WebClient.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/staticInit/WebClientTest.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/restdocs/ContractDslSnippetTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockSnippetTests.java delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/__files/hello.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/application-customfoo.yml delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/application.yml delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/custom-from-yml/__files/hello-custom.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/custom-from-yml/mappings/custom-test-endpoint.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/custom/hello.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/example-mappings/shouldMarkClientAsFraud.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/example-mappings/shouldMarkClientAsNotFraud.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/files/__files/hello.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/files_banner/__files/response-bannerList-error.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/files_banner/__files/response-bannerList-success.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/files_notice/__files/response-noticeList-error.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/files_notice/__files/response-noticeList-success.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/io.stubs/mappings/link.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/io.stubs/mappings/resource.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/jarfiles/module-banner-test-fixtures.jar delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/mappings/accept.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/mappings/body-matches-equaltojson.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/mappings/body-matches-equaltoxml.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/mappings/body-matches-jsonpath.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/mappings/body-matches-regex.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/mappings/body-matches-xpath.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/mappings/header-contains.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/mappings/header-matches-precise.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/mappings/header-matches.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/mappings/poster.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-base64-body.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-body-file.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-content-type.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-empty-path.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-high-priority.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-json-body.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-low-priority.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/mappings/resource-without-content-type.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/mappings/resource.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/mappings/url-matches.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/mappings/url-path-pattern.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/mappings/url-simple-path-pattern-with-leading-slash.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/mappings/url-simple-path-pattern-without-leading-slash.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/root/__files/hello.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/root/mappings/accept.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/root/mappings/resource-with-body-file.json delete mode 100644 spring-cloud-contract-wiremock/src/test/resources/root/mappings/url-matches.json delete mode 100644 src/checkstyle/checkstyle-suppressions.xml create mode 100644 supplemental-ui/partials/nav-search.hbs create mode 100644 supplemental-ui/partials/search.hbs delete mode 100644 tests/pom.xml delete mode 100644 tests/samples-messaging-amqp/pom.xml delete mode 100644 tests/samples-messaging-amqp/src/main/java/com/example/AmqpMessagingApplication.java delete mode 100644 tests/samples-messaging-amqp/src/main/java/com/example/Book.java delete mode 100644 tests/samples-messaging-amqp/src/main/java/com/example/Issue178ListenerConfiguration.java delete mode 100644 tests/samples-messaging-amqp/src/main/java/com/example/MessagePublisher.java delete mode 100644 tests/samples-messaging-amqp/src/main/java/com/example/RabbitManager.java delete mode 100644 tests/samples-messaging-amqp/src/test/groovy/com/example/AmqpMessagingApplicationSpec.groovy delete mode 100644 tests/samples-messaging-amqp/src/test/resources/application.yml delete mode 100644 tests/samples-messaging-camel/.springBeans create mode 100644 tests/samples-messaging-camel/log.log delete mode 100644 tests/samples-messaging-camel/pom.xml delete mode 100644 tests/samples-messaging-camel/src/main/java/com/example/BookReturned.java delete mode 100644 tests/samples-messaging-camel/src/main/java/com/example/BookRouteConfiguration.java delete mode 100644 tests/samples-messaging-camel/src/main/java/com/example/BookService.java delete mode 100644 tests/samples-messaging-camel/src/main/java/com/example/CamelMessagingApplication.java delete mode 100644 tests/samples-messaging-camel/src/test/groovy/com/example/CamelMessagingApplicationSpec.groovy delete mode 100644 tests/samples-messaging-camel/src/test/resources/logback-test.xml delete mode 100644 tests/samples-messaging-integration/.springBeans delete mode 100644 tests/samples-messaging-integration/pom.xml delete mode 100644 tests/samples-messaging-integration/src/main/java/com/example/BookDeleted.java delete mode 100644 tests/samples-messaging-integration/src/main/java/com/example/BookListener.java delete mode 100644 tests/samples-messaging-integration/src/main/java/com/example/BookReturned.java delete mode 100644 tests/samples-messaging-integration/src/main/java/com/example/BookService.java delete mode 100644 tests/samples-messaging-integration/src/main/java/com/example/IntegrationMessagingApplication.java delete mode 100644 tests/samples-messaging-integration/src/main/resources/integration-context.xml delete mode 100644 tests/samples-messaging-integration/src/test/groovy/com/example/IntegrationMessagingApplicationSpec.groovy delete mode 100644 tests/samples-messaging-jms/.springBeans delete mode 100644 tests/samples-messaging-jms/pom.xml delete mode 100644 tests/samples-messaging-jms/src/main/java/com/example/BookDeleted.java delete mode 100644 tests/samples-messaging-jms/src/main/java/com/example/BookReturned.java delete mode 100644 tests/samples-messaging-jms/src/main/java/com/example/BookService.java delete mode 100644 tests/samples-messaging-jms/src/main/java/com/example/JmsMessagingApplication.java delete mode 100644 tests/samples-messaging-jms/src/test/groovy/com/example/JmsMessagingApplicationSpec.groovy delete mode 100644 tests/samples-messaging-jms/src/test/resources/application.yml delete mode 100644 tests/spring-cloud-contract-stub-runner-amqp/pom.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-amqp/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/amqp/AmqpMessagingApplication.java delete mode 100644 tests/spring-cloud-contract-stub-runner-amqp/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/amqp/MessageSubscriber.java delete mode 100644 tests/spring-cloud-contract-stub-runner-amqp/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/amqp/MessageSubscriberRabbitListener.java delete mode 100644 tests/spring-cloud-contract-stub-runner-amqp/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/amqp/Person.java delete mode 100644 tests/spring-cloud-contract-stub-runner-amqp/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/amqp/AmqpStubRunnerRabbitListenerSpec.groovy delete mode 100644 tests/spring-cloud-contract-stub-runner-amqp/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/amqp/AmqpStubRunnerSpec.groovy delete mode 100644 tests/spring-cloud-contract-stub-runner-amqp/src/test/resources/application.yml delete mode 100644 tests/spring-cloud-contract-stub-runner-amqp/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/amqp/spring-cloud-contract-amqp-test/0.4.0-SNAPSHOT/maven-metadata-local.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-amqp/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/amqp/spring-cloud-contract-amqp-test/0.4.0-SNAPSHOT/spring-cloud-contract-amqp-test-0.4.0-SNAPSHOT-stubs.jar delete mode 100644 tests/spring-cloud-contract-stub-runner-amqp/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/amqp/spring-cloud-contract-amqp-test/0.4.0-SNAPSHOT/spring-cloud-contract-amqp-test-0.4.0-SNAPSHOT.pom delete mode 100644 tests/spring-cloud-contract-stub-runner-amqp/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/amqp/spring-cloud-contract-amqp-test/maven-metadata-local.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-amqp/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/amqp/spring-cloud-contract-amqp-test/maven-metadata.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-eureka/pom.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/eureka/StubRunnerSpringCloudEurekaAutoConfigurationSpec.groovy delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/application.yml delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/logback.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/0.0.1-SNAPSHOT/bootService-0.0.1-SNAPSHOT-stubs.jar delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/0.0.1-SNAPSHOT/bootService-0.0.1-SNAPSHOT.pom delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/maven-metadata.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/0.0.1-SNAPSHOT/fraudDetectionServer-0.0.1-SNAPSHOT-stubs.jar delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/0.0.1-SNAPSHOT/fraudDetectionServer-0.0.1-SNAPSHOT.pom delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/maven-metadata.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/loanIssuance/0.0.1-SNAPSHOT/loanIssuance-0.0.1-SNAPSHOT-stubs.jar delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/loanIssuance/0.0.1-SNAPSHOT/loanIssuance-0.0.1-SNAPSHOT.pom delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/loanIssuance/maven-metadata.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-zookeeper/pom.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/zookeeper/StubRunnerSpringCloudZookeeperAutoConfigurationSpec.groovy delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/application.yml delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/logback.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/0.0.1-SNAPSHOT/bootService-0.0.1-SNAPSHOT-stubs.jar delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/0.0.1-SNAPSHOT/bootService-0.0.1-SNAPSHOT.pom delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/maven-metadata.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/0.0.1-SNAPSHOT/fraudDetectionServer-0.0.1-SNAPSHOT-stubs.jar delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/0.0.1-SNAPSHOT/fraudDetectionServer-0.0.1-SNAPSHOT.pom delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/maven-metadata.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/loanIssuance/0.0.1-SNAPSHOT/loanIssuance-0.0.1-SNAPSHOT-stubs.jar delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/loanIssuance/0.0.1-SNAPSHOT/loanIssuance-0.0.1-SNAPSHOT.pom delete mode 100644 tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/loanIssuance/maven-metadata.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-context-path/pom.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/Application.java delete mode 100644 tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/LoanApplicationService.java delete mode 100644 tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/Client.java delete mode 100644 tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/FraudCheckStatus.java delete mode 100644 tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/FraudServiceRequest.java delete mode 100644 tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/FraudServiceResponse.java delete mode 100644 tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/LoanApplication.java delete mode 100644 tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/LoanApplicationResult.java delete mode 100644 tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/LoanApplicationStatus.java delete mode 100644 tests/spring-cloud-contract-stub-runner-context-path/src/main/resources/application.yml delete mode 100644 tests/spring-cloud-contract-stub-runner-context-path/src/test/java/com/example/loan/FailFastLoanApplicationServiceTests.java delete mode 100644 tests/spring-cloud-contract-stub-runner-context-path/src/test/java/com/example/loan/LoanApplicationServiceTests.java delete mode 100644 tests/spring-cloud-contract-stub-runner-context-path/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/contextPathFraudDetectionServer/0.0.1-SNAPSHOT/contextPathFraudDetectionServer-0.0.1-SNAPSHOT-stubs.jar delete mode 100644 tests/spring-cloud-contract-stub-runner-context-path/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/contextPathFraudDetectionServer/0.0.1-SNAPSHOT/contextPathFraudDetectionServer-0.0.1-SNAPSHOT.pom delete mode 100644 tests/spring-cloud-contract-stub-runner-context-path/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/contextPathFraudDetectionServer/maven-metadata.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-integration/pom.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-integration/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/BookReturned.groovy delete mode 100644 tests/spring-cloud-contract-stub-runner-integration/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/IntegrationStubRunnerSpec.groovy delete mode 100644 tests/spring-cloud-contract-stub-runner-integration/src/test/resources/application.yml delete mode 100644 tests/spring-cloud-contract-stub-runner-integration/src/test/resources/integration-context.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/0.0.1-SNAPSHOT/integrationService-0.0.1-SNAPSHOT-stubs.jar delete mode 100644 tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/0.0.1-SNAPSHOT/integrationService-0.0.1-SNAPSHOT.pom delete mode 100644 tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/0.0.1-SNAPSHOT/maven-metadata-local.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/maven-metadata-local.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/maven-metadata.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-jms/pom.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-jms/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/jms/BookReturned.groovy delete mode 100644 tests/spring-cloud-contract-stub-runner-jms/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/jms/JmsStubRunnerSpec.groovy delete mode 100644 tests/spring-cloud-contract-stub-runner-jms/src/test/resources/application.yml delete mode 100644 tests/spring-cloud-contract-stub-runner-jms/src/test/resources/stubs/bookReturned1.groovy delete mode 100644 tests/spring-cloud-contract-stub-runner-kafka/pom.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-kafka/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/kafka/BookReturned.groovy delete mode 100644 tests/spring-cloud-contract-stub-runner-kafka/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/kafka/KafkaStubRunnerSpec.groovy delete mode 100644 tests/spring-cloud-contract-stub-runner-kafka/src/test/resources/application.yml delete mode 100644 tests/spring-cloud-contract-stub-runner-kafka/src/test/resources/stubs/bookReturned1.groovy delete mode 100644 tests/spring-cloud-contract-stub-runner-moco-contract-jar/pom.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-moco-contract-jar/src/main/resources/META-INF/com.example/fraudDetectionServerMoco/1.0.0/contracts/nested/contract2.groovy delete mode 100644 tests/spring-cloud-contract-stub-runner-moco-contract-jar/src/main/resources/META-INF/com.example/fraudDetectionServerMoco/1.0.0/mappings/nested/shouldSayBye.json delete mode 100644 tests/spring-cloud-contract-stub-runner-moco-contract-jar/src/main/resources/META-INF/com.example/fraudDetectionServerMoco/1.0.0/mappings/shouldSayHello.json delete mode 100644 tests/spring-cloud-contract-stub-runner-moco-contract-jar/src/main/resources/contracts/com.example/fraudDetectionServerMoco/nested/contract3.groovy delete mode 100644 tests/spring-cloud-contract-stub-runner-moco-contract-jar/src/main/resources/mappings/com.example/fraudDetectionServerMoco/nested/shouldSayBye2.json delete mode 100644 tests/spring-cloud-contract-stub-runner-moco-contract-jar/src/main/resources/mappings/shouldSayHello2.json delete mode 100644 tests/spring-cloud-contract-stub-runner-moco/pom.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-moco/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/moco/MocoHttpServerStub.groovy delete mode 100644 tests/spring-cloud-contract-stub-runner-moco/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/moco/MocoHttpServerStubSpec.groovy delete mode 100644 tests/spring-cloud-contract-stub-runner-moco/src/test/resources/META-INF/spring.factories delete mode 100644 tests/spring-cloud-contract-stub-runner-moco/src/test/resources/application-test.yaml delete mode 100644 tests/spring-cloud-contract-stub-runner-moco/src/test/resources/application.yml delete mode 100644 tests/spring-cloud-contract-stub-runner-moco/src/test/resources/logback.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-stream/pom.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/BookReturned.groovy delete mode 100644 tests/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy delete mode 100644 tests/spring-cloud-contract-stub-runner-stream/src/test/resources/application.yml delete mode 100644 tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/0.0.1-SNAPSHOT/maven-metadata-local.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/0.0.1-SNAPSHOT/streamService-0.0.1-SNAPSHOT-stubs.jar delete mode 100644 tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/0.0.1-SNAPSHOT/streamService-0.0.1-SNAPSHOT.pom delete mode 100644 tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/maven-metadata-local.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/maven-metadata.xml delete mode 100644 tests/spring-cloud-contract-stub-runner-stream/src/test/resources/request.pdf delete mode 100644 tests/spring-cloud-contract-stub-runner-stream/src/test/resources/response.pdf diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index ce69db0a99..0000000000 --- a/.editorconfig +++ /dev/null @@ -1,29 +0,0 @@ -root = true - -[*.java] -indent_style = tab -indent_size = 4 -continuation_indent_size = 8 - -[*.groovy] -indent_style = tab -indent_size = 4 -continuation_indent_size = 8 - -[*.kt] -indent_style = tab -indent_size = 4 -continuation_indent_size = 8 - -[*.xml] -indent_style = tab -indent_size = 4 -continuation_indent_size = 8 - -[*.yml] -indent_style = space -indent_size = 2 - -[*.yaml] -indent_style = space -indent_size = 2 diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md deleted file mode 100644 index 9eeac3b093..0000000000 --- a/.github/CONTRIBUTING.md +++ /dev/null @@ -1,45 +0,0 @@ - -# Contributing - -Spring Cloud is released under the non-restrictive Apache 2.0 license, -and follows a very standard Github development process, using Github -tracker for issues and merging pull requests into master. If you want -to contribute even something trivial please do not hesitate, but -follow the guidelines below. - -## Sign the Contributor License Agreement -Before we accept a non-trivial patch or pull request we will need you to sign the -[Contributor License Agreement](https://cla.pivotal.io/sign/spring). -Signing the contributor's agreement does not grant anyone commit rights to the main -repository, but it does mean that we can accept your contributions, and you will get an -author credit if we do. Active contributors might be asked to join the core team, and -given the ability to merge pull requests. - -## Code of Conduct -This project adheres to the Contributor Covenant [code of -conduct](https://github.com/spring-cloud/spring-cloud-build/blob/main/docs/src/main/asciidoc/code-of-conduct.adoc). By participating, you are expected to uphold this code. Please report -unacceptable behavior to spring-code-of-conduct@pivotal.io. - -## Code Conventions and Housekeeping -None of these is essential for a pull request, but they will all help. They can also be -added after the original pull request but before a merge. - -* Use the Spring Framework code format conventions. If you use Eclipse - you can import formatter settings using the - `eclipse-code-formatter.xml` file from the - [Spring Cloud Build](https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/main/spring-cloud-dependencies-parent/eclipse-code-formatter.xml) project. If using IntelliJ, you can use the - [Eclipse Code Formatter Plugin](https://plugins.jetbrains.com/plugin/6546) to import the same file. -* Make sure all new `.java` files to have a simple Javadoc class comment with at least an - `@author` tag identifying you, and preferably at least a paragraph on what the class is - for. -* Add the ASF license header comment to all new `.java` files (copy from existing files - in the project) -* Add yourself as an `@author` to the .java files that you modify substantially (more - than cosmetic changes). -* Add some Javadocs and, if you change the namespace, some XSD doc elements. -* A few unit tests would help a lot as well -- someone has to do it. -* If no-one else is using your branch, please rebase it against the current master (or - other target branch in the main project). -* When writing a commit message please follow [these conventions](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html), - if you are fixing an existing issue please add `Fixes gh-XXXX` at the end of the commit - message (where XXXX is the issue number). diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 0bc5ef4fa3..0000000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,20 +0,0 @@ - diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index aeafef9d32..0000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: '' - ---- - -**Describe the bug** -Please provide details of the problem, including the version of Spring Cloud that you -are using. - -**Sample** -If possible, please provide a test case or sample application that reproduces -the problem. This makes it much easier for us to diagnose the problem and to verify that -we have fixed it. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index bbcbbe7d61..0000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 203f3c889b..0000000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,6 +0,0 @@ -version: 2 -updates: -- package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" diff --git a/.github/workflows/codeql.yaml b/.github/workflows/codeql.yaml deleted file mode 100644 index 0b58baec64..0000000000 --- a/.github/workflows/codeql.yaml +++ /dev/null @@ -1,49 +0,0 @@ -name: "Code Scanning - Action" - -on: - pull_request: - push: - -jobs: - CodeQL-Build: - # CodeQL runs on ubuntu-latest, windows-latest, and macos-latest - runs-on: ubuntu-latest - - permissions: - # required for all workflows - security-events: write - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Set up JDK - uses: actions/setup-java@v3 - with: - distribution: 'temurin' - java-version: 17 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - # Override language selection by uncommenting this and choosing your languages - # with: - # languages: go, javascript, csharp, python, cpp, java - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below). - # - name: Autobuild - # uses: github/codeql-action/autobuild@v2 - - # â„¹ï¸ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - # âœï¸ If the Autobuild fails above, remove it and uncomment the following - # three lines and modify them (or add more) to build your code if your - # project uses a compiled language - - - run: | - ./mvnw clean install -B -U -Pspring -DskipTests - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml new file mode 100644 index 0000000000..7a8535cec6 --- /dev/null +++ b/.github/workflows/deploy-docs.yml @@ -0,0 +1,53 @@ +name: Deploy Docs +run-name: ${{ format('{0} ({1})', github.workflow, github.event.inputs.build-refname || 'all') }} +on: + workflow_dispatch: + inputs: + build-refname: + description: Enter git refname to build (e.g., 5.7.x). + required: false + push: + branches: docs-build +env: + GRADLE_ENTERPRISE_SECRET_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }} +permissions: + contents: write +jobs: + build: + if: github.repository_owner == 'spring-cloud' + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 5 + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'temurin' + - name: Set up refname build + if: github.event.inputs.build-refname + run: | + git fetch --depth 1 https://github.com/$GITHUB_REPOSITORY ${{ github.event.inputs.build-refname }} + export BUILD_REFNAME=${{ github.event.inputs.build-refname }} + echo "BUILD_REFNAME=$BUILD_REFNAME" >> $GITHUB_ENV + export BUILD_VERSION=$(git cat-file --textconv FETCH_HEAD:pom.xml | python3 -c "import xml.etree.ElementTree as xml; from sys import stdin; print(xml.parse(stdin).getroot().find('{http://maven.apache.org/POM/4.0.0}version').text)") + echo BUILD_VERSION=$BUILD_VERSION >> $GITHUB_ENV + - name: Run Antora + run: | + ./mvnw --no-transfer-progress -B antora + - name: Publish Docs + uses: spring-io/spring-doc-actions/rsync-antora-reference@v0.0.11 + with: + docs-username: ${{ secrets.DOCS_USERNAME }} + docs-host: ${{ secrets.DOCS_HOST }} + docs-ssh-key: ${{ secrets.DOCS_SSH_KEY }} + docs-ssh-host-key: ${{ secrets.DOCS_SSH_HOST_KEY }} + site-path: target/antora/site + - name: Bust Cloudflare Cache + uses: spring-io/spring-doc-actions/bust-cloudflare-antora-cache@v0.0.11 + with: + context-root: spring-cloud-contract + cloudflare-zone-id: ${{ secrets.CLOUDFLARE_ZONE_ID }} + cloudflare-cache-token: ${{ secrets.CLOUDFLARE_CACHE_TOKEN }} diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml deleted file mode 100644 index 6abbd16d0b..0000000000 --- a/.github/workflows/maven.yml +++ /dev/null @@ -1,32 +0,0 @@ -# This workflow will build a Java project with Maven -# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven - -name: Build - -on: - push: - branches: [ main, 3.1.x, 3.0.x ] - pull_request: - branches: [ main, 3.1.x, 3.0.x ] - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - name: Set up JDK - uses: actions/setup-java@v3 - with: - distribution: 'temurin' - java-version: 17 - - name: Cache local Maven repository - uses: actions/cache@v3 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven- - - name: Build with Maven - run: ./mvnw clean install -B -U -Pspring,integration,docs diff --git a/.gitignore b/.gitignore index 052b287229..6be8a4a166 100644 --- a/.gitignore +++ b/.gitignore @@ -1,46 +1,22 @@ -*~ -#* -*# -.#* -.factorypath -.classpath -.project +target/ .settings/ -.sts4-cache/ -target/ -build/ -bin/ -.gradle/ - -*.class -.attach* - -# Mobile Tools for Java (J2ME) -.mtj.tmp/ - -# Package Files # -*.war -*.ear -*.versionsBackup - -# virtual machine crash logs, see https://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* - -*.class -*.iml - -.idea/ -.gradle/ -target/ -build/ -out/ - -hs_err_pid* +.project +.classpath +*.orig +.springBeans +.factorypath +.sts4-cache +.ant-targets-build.xml +src/ant/.ant-targets-upload-dist.xml +*.sonar4clipse* .DS_Store -*.log -interpolated-settings.xml -interpolated-pom.xml -dependency-reduced-pom.xml - -.vscode/ -.flattened-pom.xml +*.iml +*.ipr +*.iws +/.idea/ +*.graphml +node +node_modules +build +package.json +package-lock.json diff --git a/.mvn/maven.config b/.mvn/maven.config deleted file mode 100644 index a682990566..0000000000 --- a/.mvn/maven.config +++ /dev/null @@ -1 +0,0 @@ --P spring diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar index c1dd12f17644411d6e840bd5a10c6ecda0175f18..2cc7d4a55c0cd0092912bf49ae38b3a9e3fd0054 100644 GIT binary patch literal 50710 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 EfAhh=DF6Tf literal 58727 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%0ANsA|A3-jj|r`KAo%oTajX3>^E` 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 YM{}PByk10KD_nuQ4E7Du?}+~TKh4V)`~Uy| diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index 015dfe6821..642d572ce9 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1,18 +1,2 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.3/apache-maven-3.8.3-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/.sdkmanrc b/.sdkmanrc deleted file mode 100644 index 415f90832f..0000000000 --- a/.sdkmanrc +++ /dev/null @@ -1,3 +0,0 @@ -# Enable auto-env through the sdkman_auto_env config -# Add key=value pairs of SDKs to use below -java=17.0.1-tem diff --git a/.settings.xml b/.settings.xml deleted file mode 100644 index 97c7a2cc95..0000000000 --- a/.settings.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - - repo.spring.io - ${env.CI_DEPLOY_USERNAME} - ${env.CI_DEPLOY_PASSWORD} - - - - - - spring - - true - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - - - - ide - - true - - - - diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 8d50b18f32..0000000000 --- a/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ -Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - diff --git a/README.adoc b/README.adoc index 40a6c4eb2a..6ecf6bdfc2 100644 --- a/README.adoc +++ b/README.adoc @@ -1,392 +1,23 @@ -//// -DO NOT EDIT THIS FILE. IT WAS GENERATED. -Manual changes to this file will be lost when it is generated again. -Edit the files in the src/main/asciidoc/ directory instead. -//// += Spring Cloud Contract Docs Build +You're currently viewing the Antora playbook branch. +The playbook branch hosts the docs build that is used to build and publish the production docs site. -== Spring Cloud Contract +The Spring Cloud Contract reference docs are built using https://antora.org[Antora]. +This README covers how to build the docs in a software branch as well as how to build the production docs site locally. -You always need confidence when pushing new features into a new application or service in -a distributed system. To that end, this project provides support for consumer-driven -contracts and service schemas in Spring applications, covering a range of options for -writing tests, publishing them as assets, and asserting that a contract is kept by -producers and consumers -- for both HTTP and message-based interactions. - -== Project page - -You can read more about Spring Cloud Contract by going to https://spring.io/projects/spring-cloud-contract[the project page] - -== Contributing - -:spring-cloud-build-branch: master - -Spring Cloud is released under the non-restrictive Apache 2.0 license, -and follows a very standard Github development process, using Github -tracker for issues and merging pull requests into master. If you want -to contribute even something trivial please do not hesitate, but -follow the guidelines below. - -=== Sign the Contributor License Agreement -Before we accept a non-trivial patch or pull request we will need you to sign the -https://cla.pivotal.io/sign/spring[Contributor License Agreement]. -Signing the contributor's agreement does not grant anyone commit rights to the main -repository, but it does mean that we can accept your contributions, and you will get an -author credit if we do. Active contributors might be asked to join the core team, and -given the ability to merge pull requests. - -=== Code of Conduct -This project adheres to the Contributor Covenant https://github.com/spring-cloud/spring-cloud-build/blob/master/docs/src/main/asciidoc/code-of-conduct.adoc[code of -conduct]. By participating, you are expected to uphold this code. Please report -unacceptable behavior to spring-code-of-conduct@pivotal.io. - -=== Code Conventions and Housekeeping -None of these is essential for a pull request, but they will all help. They can also be -added after the original pull request but before a merge. - -* Use the Spring Framework code format conventions. If you use Eclipse - you can import formatter settings using the - `eclipse-code-formatter.xml` file from the - https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-dependencies-parent/eclipse-code-formatter.xml[Spring - Cloud Build] project. If using IntelliJ, you can use the - https://plugins.jetbrains.com/plugin/6546[Eclipse Code Formatter - Plugin] to import the same file. -* Make sure all new `.java` files to have a simple Javadoc class comment with at least an - `@author` tag identifying you, and preferably at least a paragraph on what the class is - for. -* Add the ASF license header comment to all new `.java` files (copy from existing files - in the project) -* Add yourself as an `@author` to the .java files that you modify substantially (more - than cosmetic changes). -* Add some Javadocs and, if you change the namespace, some XSD doc elements. -* A few unit tests would help a lot as well -- someone has to do it. -* If no-one else is using your branch, please rebase it against the current master (or - other target branch in the main project). -* When writing a commit message please follow https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html[these conventions], - if you are fixing an existing issue please add `Fixes gh-XXXX` at the end of the commit - message (where XXXX is the issue number). - -=== Checkstyle - -Spring Cloud Build comes with a set of checkstyle rules. You can find them in the `spring-cloud-build-tools` module. The most notable files under the module are: - -.spring-cloud-build-tools/ ----- -└── src -    ├── checkstyle -    │   └── checkstyle-suppressions.xml <3> -    └── main -    └── resources -    ├── checkstyle-header.txt <2> -    └── checkstyle.xml <1> ----- -<1> Default Checkstyle rules -<2> File header setup -<3> Default suppression rules - -==== Checkstyle configuration - -Checkstyle rules are *disabled by default*. To add checkstyle to your project just define the following properties and plugins. - -.pom.xml ----- - -true <1> - true - <2> - true - <3> - - - - - <4> - io.spring.javaformat - spring-javaformat-maven-plugin - - <5> - org.apache.maven.plugins - maven-checkstyle-plugin - - - - - - <5> - org.apache.maven.plugins - maven-checkstyle-plugin - - - - ----- -<1> Fails the build upon Checkstyle errors -<2> Fails the build upon Checkstyle violations -<3> Checkstyle analyzes also the test sources -<4> Add the Spring Java Format plugin that will reformat your code to pass most of the Checkstyle formatting rules -<5> Add checkstyle plugin to your build and reporting phases - -If you need to suppress some rules (e.g. line length needs to be longer), then it's enough for you to define a file under `${project.root}/src/checkstyle/checkstyle-suppressions.xml` with your suppressions. Example: - -.projectRoot/src/checkstyle/checkstyle-suppresions.xml ----- - - - - - - ----- - -It's advisable to copy the `${spring-cloud-build.rootFolder}/.editorconfig` and `${spring-cloud-build.rootFolder}/.springformat` to your project. That way, some default formatting rules will be applied. You can do so by running this script: - -```bash -$ curl https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/.editorconfig -o .editorconfig -$ touch .springformat -``` - -=== IDE setup - -==== Intellij IDEA - -In order to setup Intellij you should import our coding conventions, inspection profiles and set up the checkstyle plugin. -The following files can be found in the https://github.com/spring-cloud/spring-cloud-build/tree/master/spring-cloud-build-tools[Spring Cloud Build] project. - -.spring-cloud-build-tools/ ----- -└── src -    ├── checkstyle -    │   └── checkstyle-suppressions.xml <3> -    └── main -    └── resources -    ├── checkstyle-header.txt <2> -    ├── checkstyle.xml <1> -    └── intellij -       ├── Intellij_Project_Defaults.xml <4> -       └── Intellij_Spring_Boot_Java_Conventions.xml <5> ----- -<1> Default Checkstyle rules -<2> File header setup -<3> Default suppression rules -<4> Project defaults for Intellij that apply most of Checkstyle rules -<5> Project style conventions for Intellij that apply most of Checkstyle rules - -.Code style - -image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/{spring-cloud-build-branch}/docs/src/main/asciidoc/images/intellij-code-style.png[Code style] - -Go to `File` -> `Settings` -> `Editor` -> `Code style`. There click on the icon next to the `Scheme` section. There, click on the `Import Scheme` value and pick the `Intellij IDEA code style XML` option. Import the `spring-cloud-build-tools/src/main/resources/intellij/Intellij_Spring_Boot_Java_Conventions.xml` file. - -.Inspection profiles - -image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/{spring-cloud-build-branch}/docs/src/main/asciidoc/images/intellij-inspections.png[Code style] - -Go to `File` -> `Settings` -> `Editor` -> `Inspections`. There click on the icon next to the `Profile` section. There, click on the `Import Profile` and import the `spring-cloud-build-tools/src/main/resources/intellij/Intellij_Project_Defaults.xml` file. - -.Checkstyle - -To have Intellij work with Checkstyle, you have to install the `Checkstyle` plugin. It's advisable to also install the `Assertions2Assertj` to automatically convert the JUnit assertions - -image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/{spring-cloud-build-branch}/docs/src/main/asciidoc/images/intellij-checkstyle.png[Checkstyle] - -Go to `File` -> `Settings` -> `Other settings` -> `Checkstyle`. There click on the `+` icon in the `Configuration file` section. There, you'll have to define where the checkstyle rules should be picked from. In the image above, we've picked the rules from the cloned Spring Cloud Build repository. However, you can point to the Spring Cloud Build's GitHub repository (e.g. for the `checkstyle.xml` : `https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/main/resources/checkstyle.xml`). We need to provide the following variables: - -- `checkstyle.header.file` - please point it to the Spring Cloud Build's, `spring-cloud-build-tools/src/main/resources/checkstyle-header.txt` file either in your cloned repo or via the `https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/main/resources/checkstyle-header.txt` URL. -- `checkstyle.suppressions.file` - default suppressions. Please point it to the Spring Cloud Build's, `spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml` file either in your cloned repo or via the `https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml` URL. -- `checkstyle.additional.suppressions.file` - this variable corresponds to suppressions in your local project. E.g. you're working on `spring-cloud-contract`. Then point to the `project-root/src/checkstyle/checkstyle-suppressions.xml` folder. Example for `spring-cloud-contract` would be: `/home/username/spring-cloud-contract/src/checkstyle/checkstyle-suppressions.xml`. - -IMPORTANT: Remember to set the `Scan Scope` to `All sources` since we apply checkstyle rules for production and test sources. - -=== Duplicate Finder - -Spring Cloud Build brings along the `basepom:duplicate-finder-maven-plugin`, that enables flagging duplicate and conflicting classes and resources on the java classpath. - -==== Duplicate Finder configuration - -Duplicate finder is *enabled by default* and will run in the `verify` phase of your Maven build, but it will only take effect in your project if you add the `duplicate-finder-maven-plugin` to the `build` section of the projecst's `pom.xml`. - -.pom.xml -[source,xml] ----- - - - - org.basepom.maven - duplicate-finder-maven-plugin - - - ----- - -For other properties, we have set defaults as listed in the https://github.com/basepom/duplicate-finder-maven-plugin/wiki[plugin documentation]. - -You can easily override them but setting the value of the selected property prefixed with `duplicate-finder-maven-plugin`. For example, set `duplicate-finder-maven-plugin.skip` to `true` in order to skip duplicates check in your build. - -If you need to add `ignoredClassPatterns` or `ignoredResourcePatterns` to your setup, make sure to add them in the plugin configuration section of your project: - -[source,xml] ----- - - - - org.basepom.maven - duplicate-finder-maven-plugin - - - org.joda.time.base.BaseDateTime - .*module-info - - - changelog.txt - - - - - - - ----- - - -== How to Build Spring Cloud Contract - -=== Cloning the repository on Windows - -While cloning this project on Windows, some files in the git repository may exceed the Windows maximum file path limit of 255 characters, which may -result in an incorrectly (probably partially) checked out repository. - -To resolve this issue, you can set the `core.longPaths` attribute to `true` or clone the Spring Cloud Contract repository. - -To set the `core.longPaths` attribute to `true`, you have three options: - -- Change it for all users of the machine (doing so requires administrator privileges): +== Building the Site +You can build the entire site by invoking the following on the docs-build branch and then viewing the site at `target/site/index.html` [source,bash] ---- -git config --system core.longPaths true -git clone https://github.com/spring-cloud/spring-cloud-contract.git +./mvnw antora ---- -- Change it for the current user (no administrative privileges required): +== Building a Specific Branch [source,bash] ---- -git config --global core.longPaths true -git clone https://github.com/spring-cloud/spring-cloud-contract.git +./mvnw antora ---- - -- Change for just this repository (administrative privileges depend on where the repository is being cloned to): - -[source,bash] ----- -git clone -c core.longPaths=true https://github.com/spring-cloud/spring-cloud-contract.git ----- - -IMPORTANT: You need to have all the necessary Groovy plugins -installed for your IDE to properly resolve the sources. For example, in -Intellij IDEA, having both the Eclipse Groovy Compiler Plugin and the GMavenPlus Intellij -Plugin results in properly imported project. - -IMPORTANT: Spring Cloud Contract builds Docker images. Remember to -have Docker installed. - -IMPORTANT: If you want to run the build in offline mode, you must have Maven 3.5.2+ installed. - -=== Project structure - -The following listing shows the Spring Cloud Contract folder structure: - -``` -├── config -├── docker -├── samples -├── scripts -├── specs -├── spring-cloud-contract-dependencies -├── spring-cloud-contract-shade -├── spring-cloud-contract-starters -├── spring-cloud-contract-stub-runner -├── spring-cloud-contract-stub-runner-boot -├── spring-cloud-contract-tools -├── spring-cloud-contract-verifier -├── spring-cloud-contract-wiremock -└── tests -``` - -The following list describes each of the top-level folders in the project structure: - -- `config`: Folder contains setup for Spring Cloud Release Tools automated release process -- `docker`: Folder contains docker images -- `samples`: Folder contains test samples together with standalone ones used also to build documentation -- `scripts`: Contains scripts to build and test `Spring Cloud Contract` with Maven, Gradle and standalone projects -- `specs`: Contains specifications for the Contract DSL. -- `spring-cloud-contract-dependencies`: Contains Spring Cloud Contract BOM -- `spring-cloud-contract-shade`: Shaded dependencies used by the plugins -- `spring-cloud-contract-starters`: Contains Spring Cloud Contract Starters -- `spring-cloud-contract-spec`: Contains specification modules (contains concept of a Contract) -- `spring-cloud-contract-stub-runner`: Contains Stub Runner related modules -- `spring-cloud-contract-stub-runner-boot`: Contains Stub Runner Boot app -- `spring-cloud-contract-tools`: Gradle and Maven plugin for `Spring Cloud Contract Verifier` -- `spring-cloud-contract-verifier`: Core of the `Spring Cloud Contract Verifier` functionality -- `spring-cloud-contract-wiremock`: All WireMock related functionality -- `tests`: Integration tests for different messaging technologies - -=== Commands - -To build the core functionality together with the Maven Plugin, you can run the following -command: - -``` -./mvnw clean install -P integration -``` - -Calling that function builds the core, the Maven plugin, and the Gradle plugin and runs -end-to_end tests on the -standalone samples in the proper order (both for Maven and Gradle). - -To build only the Gradle Plugin, you can run the following commands: - -``` -cd spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin -./gradlew clean build -``` - -=== Helpful scripts - -We provide a couple of helpful scripts to build the project. - -To build the project in parallel (by default, it uses four cores, but you can change it), -run the following command: - -``` -./scripts/parallelBuild.sh -``` - -To use eight 8 cores, run the following command: - -``` -CORES=8 ./scripts/parallelBuild.sh -``` - -To build the project without any integration tests (by default, this uses one core), run -the following command: - -``` -./scripts/noIntegration.sh -``` - -To use eight cores, run the following command: - -``` -CORES=8 ./scripts/noIntegration.sh -``` - -To generate the documentation (for both the root project and the maven plugin), run the -following command: - -``` -./scripts/generateDocs.sh -``` diff --git a/docs/antora-playbook.yml b/antora-playbook.yml similarity index 61% rename from docs/antora-playbook.yml rename to antora-playbook.yml index 9a70e676ca..c4cef4bacf 100644 --- a/docs/antora-playbook.yml +++ b/antora-playbook.yml @@ -6,38 +6,39 @@ antora: - '@antora/collector-extension' - '@antora/atlas-extension' - require: '@springio/antora-extensions/root-component-extension' - root_component_name: 'PROJECT_WITHOUT_SPRING' - # FIXME: Run antora once using this extension to migrate to the Asciidoc Tabs syntax - # and then remove this extension - - require: '@springio/antora-extensions/tabs-migration-extension' - unwrap_example_block: always - save_result: true + root_component_name: 'cloud-contract' site: - title: PROJECT_FULL_NAME - url: https://docs.spring.io/PROJECT_NAME/reference/ + title: Spring Cloud Contract + url: https://docs.spring.io/spring-cloud-contract/reference + robots: allow +git: + ensure_git_suffix: false content: sources: - - url: ./.. - branches: HEAD + - url: https://github.com/spring-cloud/spring-cloud-contract + # Refname matching: + # https://docs.antora.org/antora/latest/playbook/content-refname-matching/ + branches: [ main ] + tags: [ '({4..9}).+({1..9}).+({0..9})?(-{RC,M}+({0..9}))', '!4.1.0-M1' ] start_path: docs - worktrees: true asciidoc: attributes: page-stackoverflow-url: https://stackoverflow.com/tags/spring-cloud page-pagination: '' hide-uri-scheme: '@' tabs-sync-option: '@' - chomp: 'all' extensions: - '@asciidoctor/tabs' - '@springio/asciidoctor-extensions' - sourcemap: true urls: + latest_version_segment_strategy: redirect:to latest_version_segment: '' + redirect_facility: httpd +ui: + bundle: + url: https://github.com/spring-io/antora-ui-spring/releases/download/v0.3.5/ui-bundle.zip + snapshot: true runtime: log: failure_level: warn format: pretty -ui: - bundle: - url: https://github.com/spring-io/antora-ui-spring/releases/download/v0.3.5/ui-bundle.zip diff --git a/asciidoctor.css b/asciidoctor.css deleted file mode 100644 index dd1495848b..0000000000 --- a/asciidoctor.css +++ /dev/null @@ -1,2011 +0,0 @@ -/* Asciidoctor default stylesheet | MIT License | https://asciidoctor.org */ -/* Remove the comments around the @import statement below when using this as a custom stylesheet */ -/*@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic|Noto+Serif:400,400italic,700,700italic|Droid+Sans+Mono:400";*/ -article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section, summary { - display: block -} - -audio, canvas, video { - display: inline-block -} - -audio:not([controls]) { - display: none; - height: 0 -} - -[hidden], template { - display: none -} - -script { - display: none !important -} - -html { - font-family: sans-serif; - -ms-text-size-adjust: 100%; - -webkit-text-size-adjust: 100% -} - -body { - margin: 0 -} - -a { - background: transparent -} - -a:focus { - outline: thin dotted -} - -a:active, a:hover { - outline: 0 -} - -h1 { - font-size: 2em; - margin: .67em 0 -} - -abbr[title] { - border-bottom: 1px dotted -} - -b, strong { - font-weight: bold -} - -dfn { - font-style: italic -} - -hr { - -moz-box-sizing: content-box; - box-sizing: content-box; - height: 0 -} - -mark { - background: #ff0; - color: #000 -} - -code, kbd, pre, samp { - font-family: monospace; - font-size: 1em -} - -pre { - white-space: pre-wrap -} - -q { - quotes: "\201C" "\201D" "\2018" "\2019" -} - -small { - font-size: 80% -} - -sub, sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline -} - -sup { - top: -.5em -} - -sub { - bottom: -.25em -} - -img { - border: 0 -} - -svg:not(:root) { - overflow: hidden -} - -figure { - margin: 0 -} - -fieldset { - border: 1px solid silver; - margin: 0 2px; - padding: .35em .625em .75em -} - -legend { - border: 0; - padding: 0 -} - -button, input, select, textarea { - font-family: inherit; - font-size: 100%; - margin: 0 -} - -button, input { - line-height: normal -} - -button, select { - text-transform: none -} - -button, html input[type="button"], input[type="reset"], input[type="submit"] { - -webkit-appearance: button; - cursor: pointer -} - -button[disabled], html input[disabled] { - cursor: default -} - -input[type="checkbox"], input[type="radio"] { - box-sizing: border-box; - padding: 0 -} - -input[type="search"] { - -webkit-appearance: textfield; - -moz-box-sizing: content-box; - -webkit-box-sizing: content-box; - box-sizing: content-box -} - -input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { - -webkit-appearance: none -} - -button::-moz-focus-inner, input::-moz-focus-inner { - border: 0; - padding: 0 -} - -textarea { - overflow: auto; - vertical-align: top -} - -table { - border-collapse: collapse; - border-spacing: 0 -} - -*, *:before, *:after { - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box -} - -html, body { - font-size: 100% -} - -body { - background: #fff; - color: rgba(0, 0, 0, .8); - padding: 0; - margin: 0; - font-family: "Noto Serif", "DejaVu Serif", serif; - font-weight: 400; - font-style: normal; - line-height: 1; - position: relative; - cursor: auto -} - -a:hover { - cursor: pointer -} - -img, object, embed { - max-width: 100%; - height: auto -} - -object, embed { - height: 100% -} - -img { - -ms-interpolation-mode: bicubic -} - -#map_canvas img, #map_canvas embed, #map_canvas object, .map_canvas img, .map_canvas embed, .map_canvas object { - max-width: none !important -} - -.left { - float: left !important -} - -.right { - float: right !important -} - -.text-left { - text-align: left !important -} - -.text-right { - text-align: right !important -} - -.text-center { - text-align: center !important -} - -.text-justify { - text-align: justify !important -} - -.hide { - display: none -} - -.antialiased, body { - -webkit-font-smoothing: antialiased -} - -img { - display: inline-block; - vertical-align: middle -} - -textarea { - height: auto; - min-height: 50px -} - -select { - width: 100% -} - -p.lead, .paragraph.lead > p, #preamble > .sectionbody > .paragraph:first-of-type p { - font-size: 1.21875em; - line-height: 1.6 -} - -.subheader, .admonitionblock td.content > .title, .audioblock > .title, .exampleblock > .title, .imageblock > .title, .listingblock > .title, .literalblock > .title, .stemblock > .title, .openblock > .title, .paragraph > .title, .quoteblock > .title, table.tableblock > .title, .verseblock > .title, .videoblock > .title, .dlist > .title, .olist > .title, .ulist > .title, .qlist > .title, .hdlist > .title { - line-height: 1.45; - color: #7a2518; - font-weight: 400; - margin-top: 0; - margin-bottom: .25em -} - -div, dl, dt, dd, ul, ol, li, h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6, pre, form, p, blockquote, th, td { - margin: 0; - padding: 0; - direction: ltr -} - -a { - color: #2156a5; - text-decoration: underline; - line-height: inherit -} - -a:hover, a:focus { - color: #1d4b8f -} - -a img { - border: none -} - -p { - font-family: inherit; - font-weight: 400; - font-size: 1em; - line-height: 1.6; - margin-bottom: 1.25em; - text-rendering: optimizeLegibility -} - -p aside { - font-size: .875em; - line-height: 1.35; - font-style: italic -} - -h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { - font-family: "Open Sans", "DejaVu Sans", sans-serif; - font-weight: 300; - font-style: normal; - color: #ba3925; - text-rendering: optimizeLegibility; - margin-top: 1em; - margin-bottom: .5em; - line-height: 1.0125em -} - -h1 small, h2 small, h3 small, #toctitle small, .sidebarblock > .content > .title small, h4 small, h5 small, h6 small { - font-size: 60%; - color: #e99b8f; - line-height: 0 -} - -h1 { - font-size: 2.125em -} - -h2 { - font-size: 1.6875em -} - -h3, #toctitle, .sidebarblock > .content > .title { - font-size: 1.375em -} - -h4, h5 { - font-size: 1.125em -} - -h6 { - font-size: 1em -} - -hr { - border: solid #ddddd8; - border-width: 1px 0 0; - clear: both; - margin: 1.25em 0 1.1875em; - height: 0 -} - -em, i { - font-style: italic; - line-height: inherit -} - -strong, b { - font-weight: bold; - line-height: inherit -} - -small { - font-size: 60%; - line-height: inherit -} - -code { - font-family: "Droid Sans Mono", "DejaVu Sans Mono", monospace; - font-weight: 400; - color: rgba(0, 0, 0, .9) -} - -ul, ol, dl { - font-size: 1em; - line-height: 1.6; - margin-bottom: 1.25em; - list-style-position: outside; - font-family: inherit -} - -ul, ol, ul.no-bullet, ol.no-bullet { - margin-left: 1.5em -} - -ul li ul, ul li ol { - margin-left: 1.25em; - margin-bottom: 0; - font-size: 1em -} - -ul.square li ul, ul.circle li ul, ul.disc li ul { - list-style: inherit -} - -ul.square { - list-style-type: square -} - -ul.circle { - list-style-type: circle -} - -ul.disc { - list-style-type: disc -} - -ul.no-bullet { - list-style: none -} - -ol li ul, ol li ol { - margin-left: 1.25em; - margin-bottom: 0 -} - -dl dt { - margin-bottom: .3125em; - font-weight: bold -} - -dl dd { - margin-bottom: 1.25em -} - -abbr, acronym { - text-transform: uppercase; - font-size: 90%; - color: rgba(0, 0, 0, .8); - border-bottom: 1px dotted #ddd; - cursor: help -} - -abbr { - text-transform: none -} - -blockquote { - margin: 0 0 1.25em; - padding: .5625em 1.25em 0 1.1875em; - border-left: 1px solid #ddd -} - -blockquote cite { - display: block; - font-size: .9375em; - color: rgba(0, 0, 0, .6) -} - -blockquote cite:before { - content: "\2014 \0020" -} - -blockquote cite a, blockquote cite a:visited { - color: rgba(0, 0, 0, .6) -} - -blockquote, blockquote p { - line-height: 1.6; - color: rgba(0, 0, 0, .85) -} - -@media only screen and (min-width: 768px) { - h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { - line-height: 1.2 - } - - h1 { - font-size: 2.75em - } - - h2 { - font-size: 2.3125em - } - - h3, #toctitle, .sidebarblock > .content > .title { - font-size: 1.6875em - } - - h4 { - font-size: 1.4375em - } -} - -table { - background: #fff; - margin-bottom: 1.25em; - border: solid 1px #dedede -} - -table thead, table tfoot { - background: #f7f8f7; - font-weight: bold -} - -table thead tr th, table thead tr td, table tfoot tr th, table tfoot tr td { - padding: .5em .625em .625em; - font-size: inherit; - color: rgba(0, 0, 0, .8); - text-align: left -} - -table tr th, table tr td { - padding: .5625em .625em; - font-size: inherit; - color: rgba(0, 0, 0, .8) -} - -table tr.even, table tr.alt, table tr:nth-of-type(even) { - background: #f8f8f7 -} - -table thead tr th, table tfoot tr th, table tbody tr td, table tr td, table tfoot tr td { - display: table-cell; - line-height: 1.6 -} - -h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { - line-height: 1.2; - word-spacing: -.05em -} - -h1 strong, h2 strong, h3 strong, #toctitle strong, .sidebarblock > .content > .title strong, h4 strong, h5 strong, h6 strong { - font-weight: 400 -} - -.clearfix:before, .clearfix:after, .float-group:before, .float-group:after { - content: " "; - display: table -} - -.clearfix:after, .float-group:after { - clear: both -} - -*:not(pre) > code { - font-size: .9375em; - font-style: normal !important; - letter-spacing: 0; - padding: .1em .5ex; - word-spacing: -.15em; - background-color: #f7f7f8; - -webkit-border-radius: 4px; - border-radius: 4px; - line-height: 1.45; - text-rendering: optimizeSpeed -} - -pre, pre > code { - line-height: 1.45; - color: rgba(0, 0, 0, .9); - font-family: "Droid Sans Mono", "DejaVu Sans Mono", monospace; - font-weight: 400; - text-rendering: optimizeSpeed -} - -.keyseq { - color: rgba(51, 51, 51, .8) -} - -kbd { - display: inline-block; - color: rgba(0, 0, 0, .8); - font-size: .75em; - line-height: 1.4; - background-color: #f7f7f7; - border: 1px solid #ccc; - -webkit-border-radius: 3px; - border-radius: 3px; - -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, .2), 0 0 0 .1em white inset; - box-shadow: 0 1px 0 rgba(0, 0, 0, .2), 0 0 0 .1em #fff inset; - margin: -.15em .15em 0 .15em; - padding: .2em .6em .2em .5em; - vertical-align: middle; - white-space: nowrap -} - -.keyseq kbd:first-child { - margin-left: 0 -} - -.keyseq kbd:last-child { - margin-right: 0 -} - -.menuseq, .menu { - color: rgba(0, 0, 0, .8) -} - -b.button:before, b.button:after { - position: relative; - top: -1px; - font-weight: 400 -} - -b.button:before { - content: "["; - padding: 0 3px 0 2px -} - -b.button:after { - content: "]"; - padding: 0 2px 0 3px -} - -p a > code:hover { - color: rgba(0, 0, 0, .9) -} - -#header, #content, #footnotes, #footer { - width: 100%; - margin-left: auto; - margin-right: auto; - margin-top: 0; - margin-bottom: 0; - max-width: 62.5em; - *zoom: 1; - position: relative; - padding-left: .9375em; - padding-right: .9375em -} - -#header:before, #header:after, #content:before, #content:after, #footnotes:before, #footnotes:after, #footer:before, #footer:after { - content: " "; - display: table -} - -#header:after, #content:after, #footnotes:after, #footer:after { - clear: both -} - -#content { - margin-top: 1.25em -} - -#content:before { - content: none -} - -#header > h1:first-child { - color: rgba(0, 0, 0, .85); - margin-top: 2.25rem; - margin-bottom: 0 -} - -#header > h1:first-child + #toc { - margin-top: 8px; - border-top: 1px solid #ddddd8 -} - -#header > h1:only-child, body.toc2 #header > h1:nth-last-child(2) { - border-bottom: 1px solid #ddddd8; - padding-bottom: 8px -} - -#header .details { - border-bottom: 1px solid #ddddd8; - line-height: 1.45; - padding-top: .25em; - padding-bottom: .25em; - padding-left: .25em; - color: rgba(0, 0, 0, .6); - display: -ms-flexbox; - display: -webkit-flex; - display: flex; - -ms-flex-flow: row wrap; - -webkit-flex-flow: row wrap; - flex-flow: row wrap -} - -#header .details span:first-child { - margin-left: -.125em -} - -#header .details span.email a { - color: rgba(0, 0, 0, .85) -} - -#header .details br { - display: none -} - -#header .details br + span:before { - content: "\00a0\2013\00a0" -} - -#header .details br + span.author:before { - content: "\00a0\22c5\00a0"; - color: rgba(0, 0, 0, .85) -} - -#header .details br + span#revremark:before { - content: "\00a0|\00a0" -} - -#header #revnumber { - text-transform: capitalize -} - -#header #revnumber:after { - content: "\00a0" -} - -#content > h1:first-child:not([class]) { - color: rgba(0, 0, 0, .85); - border-bottom: 1px solid #ddddd8; - padding-bottom: 8px; - margin-top: 0; - padding-top: 1rem; - margin-bottom: 1.25rem -} - -#toc { - border-bottom: 1px solid #efefed; - padding-bottom: .5em -} - -#toc > ul { - margin-left: .125em -} - -#toc ul.sectlevel0 > li > a { - font-style: italic -} - -#toc ul.sectlevel0 ul.sectlevel1 { - margin: .5em 0 -} - -#toc ul { - font-family: "Open Sans", "DejaVu Sans", sans-serif; - list-style-type: none -} - -#toc a { - text-decoration: none -} - -#toc a:active { - text-decoration: underline -} - -#toctitle { - color: #7a2518; - font-size: 1.2em -} - -@media only screen and (min-width: 768px) { - #toctitle { - font-size: 1.375em - } - - body.toc2 { - padding-left: 15em; - padding-right: 0 - } - - #toc.toc2 { - margin-top: 0 !important; - background-color: #f8f8f7; - position: fixed; - width: 15em; - left: 0; - top: 0; - border-right: 1px solid #efefed; - border-top-width: 0 !important; - border-bottom-width: 0 !important; - z-index: 1000; - padding: 1.25em 1em; - height: 100%; - overflow: auto - } - - #toc.toc2 #toctitle { - margin-top: 0; - font-size: 1.2em - } - - #toc.toc2 > ul { - font-size: .9em; - margin-bottom: 0 - } - - #toc.toc2 ul ul { - margin-left: 0; - padding-left: 1em - } - - #toc.toc2 ul.sectlevel0 ul.sectlevel1 { - padding-left: 0; - margin-top: .5em; - margin-bottom: .5em - } - - body.toc2.toc-right { - padding-left: 0; - padding-right: 15em - } - - body.toc2.toc-right #toc.toc2 { - border-right-width: 0; - border-left: 1px solid #efefed; - left: auto; - right: 0 - } -} - -@media only screen and (min-width: 1280px) { - body.toc2 { - padding-left: 20em; - padding-right: 0 - } - - #toc.toc2 { - width: 20em - } - - #toc.toc2 #toctitle { - font-size: 1.375em - } - - #toc.toc2 > ul { - font-size: .95em - } - - #toc.toc2 ul ul { - padding-left: 1.25em - } - - body.toc2.toc-right { - padding-left: 0; - padding-right: 20em - } -} - -#content #toc { - border-style: solid; - border-width: 1px; - border-color: #e0e0dc; - margin-bottom: 1.25em; - padding: 1.25em; - background: #f8f8f7; - -webkit-border-radius: 4px; - border-radius: 4px -} - -#content #toc > :first-child { - margin-top: 0 -} - -#content #toc > :last-child { - margin-bottom: 0 -} - -#footer { - max-width: 100%; - background-color: rgba(0, 0, 0, .8); - padding: 1.25em -} - -#footer-text { - color: rgba(255, 255, 255, .8); - line-height: 1.44 -} - -.sect1 { - padding-bottom: .625em -} - -@media only screen and (min-width: 768px) { - .sect1 { - padding-bottom: 1.25em - } -} - -.sect1 + .sect1 { - border-top: 1px solid #efefed -} - -#content h1 > a.anchor, h2 > a.anchor, h3 > a.anchor, #toctitle > a.anchor, .sidebarblock > .content > .title > a.anchor, h4 > a.anchor, h5 > a.anchor, h6 > a.anchor { - position: absolute; - z-index: 1001; - width: 1.5ex; - margin-left: -1.5ex; - display: block; - text-decoration: none !important; - visibility: hidden; - text-align: center; - font-weight: 400 -} - -#content h1 > a.anchor:before, h2 > a.anchor:before, h3 > a.anchor:before, #toctitle > a.anchor:before, .sidebarblock > .content > .title > a.anchor:before, h4 > a.anchor:before, h5 > a.anchor:before, h6 > a.anchor:before { - content: "\00A7"; - font-size: .85em; - display: block; - padding-top: .1em -} - -#content h1:hover > a.anchor, #content h1 > a.anchor:hover, h2:hover > a.anchor, h2 > a.anchor:hover, h3:hover > a.anchor, #toctitle:hover > a.anchor, .sidebarblock > .content > .title:hover > a.anchor, h3 > a.anchor:hover, #toctitle > a.anchor:hover, .sidebarblock > .content > .title > a.anchor:hover, h4:hover > a.anchor, h4 > a.anchor:hover, h5:hover > a.anchor, h5 > a.anchor:hover, h6:hover > a.anchor, h6 > a.anchor:hover { - visibility: visible -} - -#content h1 > a.link, h2 > a.link, h3 > a.link, #toctitle > a.link, .sidebarblock > .content > .title > a.link, h4 > a.link, h5 > a.link, h6 > a.link { - color: #ba3925; - text-decoration: none -} - -#content h1 > a.link:hover, h2 > a.link:hover, h3 > a.link:hover, #toctitle > a.link:hover, .sidebarblock > .content > .title > a.link:hover, h4 > a.link:hover, h5 > a.link:hover, h6 > a.link:hover { - color: #a53221 -} - -.audioblock, .imageblock, .literalblock, .listingblock, .stemblock, .videoblock { - margin-bottom: 1.25em -} - -.admonitionblock td.content > .title, .audioblock > .title, .exampleblock > .title, .imageblock > .title, .listingblock > .title, .literalblock > .title, .stemblock > .title, .openblock > .title, .paragraph > .title, .quoteblock > .title, table.tableblock > .title, .verseblock > .title, .videoblock > .title, .dlist > .title, .olist > .title, .ulist > .title, .qlist > .title, .hdlist > .title { - text-rendering: optimizeLegibility; - text-align: left; - font-family: "Noto Serif", "DejaVu Serif", serif; - font-size: 1rem; - font-style: italic -} - -table.tableblock > caption.title { - white-space: nowrap; - overflow: visible; - max-width: 0 -} - -.paragraph.lead > p, #preamble > .sectionbody > .paragraph:first-of-type p { - color: rgba(0, 0, 0, .85) -} - -table.tableblock #preamble > .sectionbody > .paragraph:first-of-type p { - font-size: inherit -} - -.admonitionblock > table { - border-collapse: separate; - border: 0; - background: none; - width: 100% -} - -.admonitionblock > table td.icon { - text-align: center; - width: 80px -} - -.admonitionblock > table td.icon img { - max-width: none -} - -.admonitionblock > table td.icon .title { - font-weight: bold; - font-family: "Open Sans", "DejaVu Sans", sans-serif; - text-transform: uppercase -} - -.admonitionblock > table td.content { - padding-left: 1.125em; - padding-right: 1.25em; - border-left: 1px solid #ddddd8; - color: rgba(0, 0, 0, .6) -} - -.admonitionblock > table td.content > :last-child > :last-child { - margin-bottom: 0 -} - -.exampleblock > .content { - border-style: solid; - border-width: 1px; - border-color: #e6e6e6; - margin-bottom: 1.25em; - padding: 1.25em; - background: #fff; - -webkit-border-radius: 4px; - border-radius: 4px -} - -.exampleblock > .content > :first-child { - margin-top: 0 -} - -.exampleblock > .content > :last-child { - margin-bottom: 0 -} - -.sidebarblock { - border-style: solid; - border-width: 1px; - border-color: #e0e0dc; - margin-bottom: 1.25em; - padding: 1.25em; - background: #f8f8f7; - -webkit-border-radius: 4px; - border-radius: 4px -} - -.sidebarblock > :first-child { - margin-top: 0 -} - -.sidebarblock > :last-child { - margin-bottom: 0 -} - -.sidebarblock > .content > .title { - color: #7a2518; - margin-top: 0; - text-align: center -} - -.exampleblock > .content > :last-child > :last-child, .exampleblock > .content .olist > ol > li:last-child > :last-child, .exampleblock > .content .ulist > ul > li:last-child > :last-child, .exampleblock > .content .qlist > ol > li:last-child > :last-child, .sidebarblock > .content > :last-child > :last-child, .sidebarblock > .content .olist > ol > li:last-child > :last-child, .sidebarblock > .content .ulist > ul > li:last-child > :last-child, .sidebarblock > .content .qlist > ol > li:last-child > :last-child { - margin-bottom: 0 -} - -.literalblock pre, .listingblock pre:not(.highlight), .listingblock pre[class="highlight"], .listingblock pre[class^="highlight "], .listingblock pre.CodeRay, .listingblock pre.prettyprint { - background: #f7f7f8 -} - -.sidebarblock .literalblock pre, .sidebarblock .listingblock pre:not(.highlight), .sidebarblock .listingblock pre[class="highlight"], .sidebarblock .listingblock pre[class^="highlight "], .sidebarblock .listingblock pre.CodeRay, .sidebarblock .listingblock pre.prettyprint { - background: #f2f1f1 -} - -.literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { - -webkit-border-radius: 4px; - border-radius: 4px; - word-wrap: break-word; - padding: 1em; - font-size: .8125em -} - -.literalblock pre.nowrap, .literalblock pre[class].nowrap, .listingblock pre.nowrap, .listingblock pre[class].nowrap { - overflow-x: auto; - white-space: pre; - word-wrap: normal -} - -@media only screen and (min-width: 768px) { - .literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { - font-size: .90625em - } -} - -@media only screen and (min-width: 1280px) { - .literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { - font-size: 1em - } -} - -.literalblock.output pre { - color: #f7f7f8; - background-color: rgba(0, 0, 0, .9) -} - -.listingblock pre.highlightjs { - padding: 0 -} - -.listingblock pre.highlightjs > code { - padding: 1em; - -webkit-border-radius: 4px; - border-radius: 4px -} - -.listingblock pre.prettyprint { - border-width: 0 -} - -.listingblock > .content { - position: relative -} - -.listingblock code[data-lang]:before { - display: none; - content: attr(data-lang); - position: absolute; - font-size: .75em; - top: .425rem; - right: .5rem; - line-height: 1; - text-transform: uppercase; - color: #999 -} - -.listingblock:hover code[data-lang]:before { - display: block -} - -.listingblock.terminal pre .command:before { - content: attr(data-prompt); - padding-right: .5em; - color: #999 -} - -.listingblock.terminal pre .command:not([data-prompt]):before { - content: "$" -} - -table.pyhltable { - border-collapse: separate; - border: 0; - margin-bottom: 0; - background: none -} - -table.pyhltable td { - vertical-align: top; - padding-top: 0; - padding-bottom: 0 -} - -table.pyhltable td.code { - padding-left: .75em; - padding-right: 0 -} - -pre.pygments .lineno, table.pyhltable td:not(.code) { - color: #999; - padding-left: 0; - padding-right: .5em; - border-right: 1px solid #ddddd8 -} - -pre.pygments .lineno { - display: inline-block; - margin-right: .25em -} - -table.pyhltable .linenodiv { - background: none !important; - padding-right: 0 !important -} - -.quoteblock { - margin: 0 1em 1.25em 1.5em; - display: table -} - -.quoteblock > .title { - margin-left: -1.5em; - margin-bottom: .75em -} - -.quoteblock blockquote, .quoteblock blockquote p { - color: rgba(0, 0, 0, .85); - font-size: 1.15rem; - line-height: 1.75; - word-spacing: .1em; - letter-spacing: 0; - font-style: italic; - text-align: justify -} - -.quoteblock blockquote { - margin: 0; - padding: 0; - border: 0 -} - -.quoteblock blockquote:before { - content: "\201c"; - float: left; - font-size: 2.75em; - font-weight: bold; - line-height: .6em; - margin-left: -.6em; - color: #7a2518; - text-shadow: 0 1px 2px rgba(0, 0, 0, .1) -} - -.quoteblock blockquote > .paragraph:last-child p { - margin-bottom: 0 -} - -.quoteblock .attribution { - margin-top: .5em; - margin-right: .5ex; - text-align: right -} - -.quoteblock .quoteblock { - margin-left: 0; - margin-right: 0; - padding: .5em 0; - border-left: 3px solid rgba(0, 0, 0, .6) -} - -.quoteblock .quoteblock blockquote { - padding: 0 0 0 .75em -} - -.quoteblock .quoteblock blockquote:before { - display: none -} - -.verseblock { - margin: 0 1em 1.25em 1em -} - -.verseblock pre { - font-family: "Open Sans", "DejaVu Sans", sans; - font-size: 1.15rem; - color: rgba(0, 0, 0, .85); - font-weight: 300; - text-rendering: optimizeLegibility -} - -.verseblock pre strong { - font-weight: 400 -} - -.verseblock .attribution { - margin-top: 1.25rem; - margin-left: .5ex -} - -.quoteblock .attribution, .verseblock .attribution { - font-size: .9375em; - line-height: 1.45; - font-style: italic -} - -.quoteblock .attribution br, .verseblock .attribution br { - display: none -} - -.quoteblock .attribution cite, .verseblock .attribution cite { - display: block; - letter-spacing: -.05em; - color: rgba(0, 0, 0, .6) -} - -.quoteblock.abstract { - margin: 0 0 1.25em 0; - display: block -} - -.quoteblock.abstract blockquote, .quoteblock.abstract blockquote p { - text-align: left; - word-spacing: 0 -} - -.quoteblock.abstract blockquote:before, .quoteblock.abstract blockquote p:first-of-type:before { - display: none -} - -table.tableblock { - max-width: 100%; - border-collapse: separate -} - -table.tableblock td > .paragraph:last-child p > p:last-child, table.tableblock th > p:last-child, table.tableblock td > p:last-child { - margin-bottom: 0 -} - -table.spread { - width: 100% -} - -table.tableblock, th.tableblock, td.tableblock { - border: 0 solid #dedede -} - -table.grid-all th.tableblock, table.grid-all td.tableblock { - border-width: 0 1px 1px 0 -} - -table.grid-all tfoot > tr > th.tableblock, table.grid-all tfoot > tr > td.tableblock { - border-width: 1px 1px 0 0 -} - -table.grid-cols th.tableblock, table.grid-cols td.tableblock { - border-width: 0 1px 0 0 -} - -table.grid-all * > tr > .tableblock:last-child, table.grid-cols * > tr > .tableblock:last-child { - border-right-width: 0 -} - -table.grid-rows th.tableblock, table.grid-rows td.tableblock { - border-width: 0 0 1px 0 -} - -table.grid-all tbody > tr:last-child > th.tableblock, table.grid-all tbody > tr:last-child > td.tableblock, table.grid-all thead:last-child > tr > th.tableblock, table.grid-rows tbody > tr:last-child > th.tableblock, table.grid-rows tbody > tr:last-child > td.tableblock, table.grid-rows thead:last-child > tr > th.tableblock { - border-bottom-width: 0 -} - -table.grid-rows tfoot > tr > th.tableblock, table.grid-rows tfoot > tr > td.tableblock { - border-width: 1px 0 0 0 -} - -table.frame-all { - border-width: 1px -} - -table.frame-sides { - border-width: 0 1px -} - -table.frame-topbot { - border-width: 1px 0 -} - -th.halign-left, td.halign-left { - text-align: left -} - -th.halign-right, td.halign-right { - text-align: right -} - -th.halign-center, td.halign-center { - text-align: center -} - -th.valign-top, td.valign-top { - vertical-align: top -} - -th.valign-bottom, td.valign-bottom { - vertical-align: bottom -} - -th.valign-middle, td.valign-middle { - vertical-align: middle -} - -table thead th, table tfoot th { - font-weight: bold -} - -tbody tr th { - display: table-cell; - line-height: 1.6; - background: #f7f8f7 -} - -tbody tr th, tbody tr th p, tfoot tr th, tfoot tr th p { - color: rgba(0, 0, 0, .8); - font-weight: bold -} - -p.tableblock > code:only-child { - background: none; - padding: 0 -} - -p.tableblock { - font-size: 1em -} - -td > div.verse { - white-space: pre -} - -ol { - margin-left: 1.75em -} - -ul li ol { - margin-left: 1.5em -} - -dl dd { - margin-left: 1.125em -} - -dl dd:last-child, dl dd:last-child > :last-child { - margin-bottom: 0 -} - -ol > li p, ul > li p, ul dd, ol dd, .olist .olist, .ulist .ulist, .ulist .olist, .olist .ulist { - margin-bottom: .625em -} - -ul.unstyled, ol.unnumbered, ul.checklist, ul.none { - list-style-type: none -} - -ul.unstyled, ol.unnumbered, ul.checklist { - margin-left: .625em -} - -ul.checklist li > p:first-child > .fa-check-square-o:first-child, ul.checklist li > p:first-child > input[type="checkbox"]:first-child { - margin-right: .25em -} - -ul.checklist li > p:first-child > input[type="checkbox"]:first-child { - position: relative; - top: 1px -} - -ul.inline { - margin: 0 auto .625em auto; - margin-left: -1.375em; - margin-right: 0; - padding: 0; - list-style: none; - overflow: hidden -} - -ul.inline > li { - list-style: none; - float: left; - margin-left: 1.375em; - display: block -} - -ul.inline > li > * { - display: block -} - -.unstyled dl dt { - font-weight: 400; - font-style: normal -} - -ol.arabic { - list-style-type: decimal -} - -ol.decimal { - list-style-type: decimal-leading-zero -} - -ol.loweralpha { - list-style-type: lower-alpha -} - -ol.upperalpha { - list-style-type: upper-alpha -} - -ol.lowerroman { - list-style-type: lower-roman -} - -ol.upperroman { - list-style-type: upper-roman -} - -ol.lowergreek { - list-style-type: lower-greek -} - -.hdlist > table, .colist > table { - border: 0; - background: none -} - -.hdlist > table > tbody > tr, .colist > table > tbody > tr { - background: none -} - -td.hdlist1 { - padding-right: .75em; - font-weight: bold -} - -td.hdlist1, td.hdlist2 { - vertical-align: top -} - -.literalblock + .colist, .listingblock + .colist { - margin-top: -.5em -} - -.colist > table tr > td:first-of-type { - padding: 0 .75em; - line-height: 1 -} - -.colist > table tr > td:last-of-type { - padding: .25em 0 -} - -.thumb, .th { - line-height: 0; - display: inline-block; - border: solid 4px #fff; - -webkit-box-shadow: 0 0 0 1px #ddd; - box-shadow: 0 0 0 1px #ddd -} - -.imageblock.left, .imageblock[style*="float: left"] { - margin: .25em .625em 1.25em 0 -} - -.imageblock.right, .imageblock[style*="float: right"] { - margin: .25em 0 1.25em .625em -} - -.imageblock > .title { - margin-bottom: 0 -} - -.imageblock.thumb, .imageblock.th { - border-width: 6px -} - -.imageblock.thumb > .title, .imageblock.th > .title { - padding: 0 .125em -} - -.image.left, .image.right { - margin-top: .25em; - margin-bottom: .25em; - display: inline-block; - line-height: 0 -} - -.image.left { - margin-right: .625em -} - -.image.right { - margin-left: .625em -} - -a.image { - text-decoration: none -} - -span.footnote, span.footnoteref { - vertical-align: super; - font-size: .875em -} - -span.footnote a, span.footnoteref a { - text-decoration: none -} - -span.footnote a:active, span.footnoteref a:active { - text-decoration: underline -} - -#footnotes { - padding-top: .75em; - padding-bottom: .75em; - margin-bottom: .625em -} - -#footnotes hr { - width: 20%; - min-width: 6.25em; - margin: -.25em 0 .75em 0; - border-width: 1px 0 0 0 -} - -#footnotes .footnote { - padding: 0 .375em; - line-height: 1.3; - font-size: .875em; - margin-left: 1.2em; - text-indent: -1.2em; - margin-bottom: .2em -} - -#footnotes .footnote a:first-of-type { - font-weight: bold; - text-decoration: none -} - -#footnotes .footnote:last-of-type { - margin-bottom: 0 -} - -#content #footnotes { - margin-top: -.625em; - margin-bottom: 0; - padding: .75em 0 -} - -.gist .file-data > table { - border: 0; - background: #fff; - width: 100%; - margin-bottom: 0 -} - -.gist .file-data > table td.line-data { - width: 99% -} - -div.unbreakable { - page-break-inside: avoid -} - -.big { - font-size: larger -} - -.small { - font-size: smaller -} - -.underline { - text-decoration: underline -} - -.overline { - text-decoration: overline -} - -.line-through { - text-decoration: line-through -} - -.aqua { - color: #00bfbf -} - -.aqua-background { - background-color: #00fafa -} - -.black { - color: #000 -} - -.black-background { - background-color: #000 -} - -.blue { - color: #0000bf -} - -.blue-background { - background-color: #0000fa -} - -.fuchsia { - color: #bf00bf -} - -.fuchsia-background { - background-color: #fa00fa -} - -.gray { - color: #606060 -} - -.gray-background { - background-color: #7d7d7d -} - -.green { - color: #006000 -} - -.green-background { - background-color: #007d00 -} - -.lime { - color: #00bf00 -} - -.lime-background { - background-color: #00fa00 -} - -.maroon { - color: #600000 -} - -.maroon-background { - background-color: #7d0000 -} - -.navy { - color: #000060 -} - -.navy-background { - background-color: #00007d -} - -.olive { - color: #606000 -} - -.olive-background { - background-color: #7d7d00 -} - -.purple { - color: #600060 -} - -.purple-background { - background-color: #7d007d -} - -.red { - color: #bf0000 -} - -.red-background { - background-color: #fa0000 -} - -.silver { - color: #909090 -} - -.silver-background { - background-color: #bcbcbc -} - -.teal { - color: #006060 -} - -.teal-background { - background-color: #007d7d -} - -.white { - color: #bfbfbf -} - -.white-background { - background-color: #fafafa -} - -.yellow { - color: #bfbf00 -} - -.yellow-background { - background-color: #fafa00 -} - -span.icon > .fa { - cursor: default -} - -.admonitionblock td.icon [class^="fa icon-"] { - font-size: 2.5em; - text-shadow: 1px 1px 2px rgba(0, 0, 0, .5); - cursor: default -} - -.admonitionblock td.icon .icon-note:before { - content: "\f05a"; - color: #19407c -} - -.admonitionblock td.icon .icon-tip:before { - content: "\f0eb"; - text-shadow: 1px 1px 2px rgba(155, 155, 0, .8); - color: #111 -} - -.admonitionblock td.icon .icon-warning:before { - content: "\f071"; - color: #bf6900 -} - -.admonitionblock td.icon .icon-caution:before { - content: "\f06d"; - color: #bf3400 -} - -.admonitionblock td.icon .icon-important:before { - content: "\f06a"; - color: #bf0000 -} - -.conum[data-value] { - display: inline-block; - color: #fff !important; - background-color: rgba(0, 0, 0, .8); - -webkit-border-radius: 100px; - border-radius: 100px; - text-align: center; - font-size: .75em; - width: 1.67em; - height: 1.67em; - line-height: 1.67em; - font-family: "Open Sans", "DejaVu Sans", sans-serif; - font-style: normal; - font-weight: bold -} - -.conum[data-value] * { - color: #fff !important -} - -.conum[data-value] + b { - display: none -} - -.conum[data-value]:after { - content: attr(data-value) -} - -pre .conum[data-value] { - position: relative; - top: -.125em -} - -b.conum * { - color: inherit !important -} - -.conum:not([data-value]):empty { - display: none -} - -h1, h2 { - letter-spacing: -.01em -} - -dt, th.tableblock, td.content { - text-rendering: optimizeLegibility -} - -p, td.content { - letter-spacing: -.01em -} - -p strong, td.content strong { - letter-spacing: -.005em -} - -p, blockquote, dt, td.content { - font-size: 1.0625rem -} - -p { - margin-bottom: 1.25rem -} - -.sidebarblock p, .sidebarblock dt, .sidebarblock td.content, p.tableblock { - font-size: 1em -} - -.exampleblock > .content { - background-color: #fffef7; - border-color: #e0e0dc; - -webkit-box-shadow: 0 1px 4px #e0e0dc; - box-shadow: 0 1px 4px #e0e0dc -} - -.print-only { - display: none !important -} - -@media print { - @page { - margin: 1.25cm .75cm - } - - * { - -webkit-box-shadow: none !important; - box-shadow: none !important; - text-shadow: none !important - } - - a { - color: inherit !important; - text-decoration: underline !important - } - - a.bare, a[href^="#"], a[href^="mailto:"] { - text-decoration: none !important - } - - a[href^="http:"]:not(.bare):after, a[href^="https:"]:not(.bare):after { - content: "(" attr(href) ")"; - display: inline-block; - font-size: .875em; - padding-left: .25em - } - - abbr[title]:after { - content: " (" attr(title) ")" - } - - pre, blockquote, tr, img { - page-break-inside: avoid - } - - thead { - display: table-header-group - } - - img { - max-width: 100% !important - } - - p, blockquote, dt, td.content { - font-size: 1em; - orphans: 3; - widows: 3 - } - - h2, h3, #toctitle, .sidebarblock > .content > .title { - page-break-after: avoid - } - - #toc, .sidebarblock, .exampleblock > .content { - background: none !important - } - - #toc { - border-bottom: 1px solid #ddddd8 !important; - padding-bottom: 0 !important - } - - .sect1 { - padding-bottom: 0 !important - } - - .sect1 + .sect1 { - border: 0 !important - } - - #header > h1:first-child { - margin-top: 1.25rem - } - - body.book #header { - text-align: center - } - - body.book #header > h1:first-child { - border: 0 !important; - margin: 2.5em 0 1em 0 - } - - body.book #header .details { - border: 0 !important; - display: block; - padding: 0 !important - } - - body.book #header .details span:first-child { - margin-left: 0 !important - } - - body.book #header .details br { - display: block - } - - body.book #header .details br + span:before { - content: none !important - } - - body.book #toc { - border: 0 !important; - text-align: left !important; - padding: 0 !important; - margin: 0 !important - } - - body.book #toc, body.book #preamble, body.book h1.sect0, body.book .sect1 > h2 { - page-break-before: always - } - - .listingblock code[data-lang]:before { - display: block - } - - #footer { - background: none !important; - padding: 0 .9375em - } - - #footer-text { - color: rgba(0, 0, 0, .6) !important; - font-size: .9em - } - - .hide-on-print { - display: none !important - } - - .print-only { - display: block !important - } - - .hide-for-print { - display: none !important - } - - .show-for-print { - display: inherit !important - } -} diff --git a/config/releaser.yml b/config/releaser.yml deleted file mode 100644 index 19daad1dce..0000000000 --- a/config/releaser.yml +++ /dev/null @@ -1,5 +0,0 @@ -releaser.maven.buildCommand: ./scripts/noIntegration.sh {{systemProps}} -releaser.maven.deployCommand: ./mvnw deploy -DskipTests -B -Pfast,deploy -Dgradle.publish-plugins.task=-Phello=world {{systemProps}} -releaser.gradle.gradlePropsSubstitution: - verifierVersion: spring-cloud-contract - bootVersion: spring-boot diff --git a/docker/pom.xml b/docker/pom.xml deleted file mode 100644 index 1ed2a272eb..0000000000 --- a/docker/pom.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - 4.0.0 - - - org.springframework.cloud - spring-cloud-contract-parent - 4.1.0-SNAPSHOT - .. - - - spring-cloud-contract-docker-parent - pom - 4.1.0-SNAPSHOT - Spring Cloud Contract Docker Parent - Spring Cloud Contract Docker Parent - - - springcloud - - - - - skip - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - - - - maven-deploy-plugin - 2.8.2 - - true - - - - - - diff --git a/docker/spring-cloud-contract-docker/Dockerfile b/docker/spring-cloud-contract-docker/Dockerfile deleted file mode 100644 index cfd5083044..0000000000 --- a/docker/spring-cloud-contract-docker/Dockerfile +++ /dev/null @@ -1,45 +0,0 @@ -FROM ubuntu:20.04 - -ARG SDKMAN_JAVA_INSTALLATION=17.0.1-tem - -LABEL Author="Marcin Grzejszczak " -LABEL Author="Bastian Doetsch " - -RUN apt-get update && apt-get install -y curl \ - unzip \ - zip \ - && apt-get clean - -RUN useradd -u1000 -m scc - -# Install sdkman and java -COPY sdkman/ /usr/local/bin/ -RUN chmod +x /usr/local/bin/sdkman-wrapper.sh - -# provide output & contract directories and change owner to scc -RUN mkdir -p /contracts -RUN mkdir -p /spring-cloud-contract-output -RUN mkdir -p /spring-cloud-contract -RUN chown -R scc:scc /contracts -RUN chown -R scc:scc /spring-cloud-contract-output /spring-cloud-contract -RUN chown -R scc:scc /spring-cloud-contract - -USER scc -RUN curl -s https://get.sdkman.io/ | bash -COPY --chown=scc:scc sdkman.config /home/scc/.sdkman/etc/config -RUN bash -c "source /home/scc/.sdkman/bin/sdkman-init.sh" -RUN bash -c "sdkman-wrapper.sh install java ${SDKMAN_JAVA_INSTALLATION}" -ENV JAVA_HOME /home/scc/.sdkman/candidates/java/current/ -ENV PATH "${PATH}:${JAVA_HOME}/bin" - -# Spring Cloud Contract -COPY --chown=scc:scc project /spring-cloud-contract/ -WORKDIR /spring-cloud-contract/ - -# Let's copy the downloaded deps to .m2 and the gradle cache -COPY --chown=scc:scc target/maven_dependencies /home/scc/.m2/repository/ -COPY --chown=scc:scc target/gradle_dependencies /home/scc/.gradle/ - -# Let's download gradle wrapper if for some reason it hasn't been downloaded -RUN ./gradlew clean resolveDependencies build --stacktrace -x copyOutput || echo "Expected to fail" -CMD ["./build.sh"] diff --git a/docker/spring-cloud-contract-docker/build_adocs.sh b/docker/spring-cloud-contract-docker/build_adocs.sh deleted file mode 100755 index 2b337b3d31..0000000000 --- a/docker/spring-cloud-contract-docker/build_adocs.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -set -e - -CURRENT_DIR="$( pwd )" -ADOC_OUTPUT_DIR="${CURRENT_DIR}/target/adoc/" -pushd project - mkdir -p "${ADOC_OUTPUT_DIR}" - ./gradlew dumpAllProps - cp "$( pwd )/build/props.adoc" "${ADOC_OUTPUT_DIR}/" - cp "$( pwd )/build/appProps.adoc" "${ADOC_OUTPUT_DIR}/" -popd diff --git a/docker/spring-cloud-contract-docker/get_dependencies.sh b/docker/spring-cloud-contract-docker/get_dependencies.sh deleted file mode 100755 index 30aacef4fb..0000000000 --- a/docker/spring-cloud-contract-docker/get_dependencies.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash - -set -e - -WRAPPER_VERSION="8.3" -GRADLE_BIN_DIR="gradle-${WRAPPER_VERSION}-bin" -GRADLE_WRAPPER_DIR="${HOME}/.gradle/wrapper/dists/${GRADLE_BIN_DIR}" -CURRENT_DIR="$( pwd )" -GRADLE_OUTPUT_DIR="${CURRENT_DIR}/target/gradle_dependencies/" -pushd project - rm -rf .gradle - ./gradlew wrapper --gradle-version "${WRAPPER_VERSION}" - ./gradlew clean resolveDependencies build -g "${GRADLE_OUTPUT_DIR}" -x copyOutput || echo "Expected to fail the build" - if [ -d "${GRADLE_WRAPPER_DIR}" ]; then - echo "Copying Gradle Wrapper version [${WRAPPER_VERSION}]" - mkdir -p "${GRADLE_OUTPUT_DIR}/wrapper/dists/" - cp -r "${GRADLE_WRAPPER_DIR}" "${GRADLE_OUTPUT_DIR}/wrapper/dists/" - else - echo "Gradle Wrapper [${GRADLE_WRAPPER_DIR}] not found. Will not copy it" - fi -popd - -./build_adocs.sh - -pushd project - rm -rf build -popd diff --git a/docker/spring-cloud-contract-docker/pom.xml b/docker/spring-cloud-contract-docker/pom.xml deleted file mode 100644 index 40837bb45e..0000000000 --- a/docker/spring-cloud-contract-docker/pom.xml +++ /dev/null @@ -1,231 +0,0 @@ - - - 4.0.0 - - 1.0.8.RELEASE - 4.2.5 - 17.0.1-tem - - - - org.springframework.cloud - spring-cloud-contract-docker-parent - 4.1.0-SNAPSHOT - .. - - - spring-cloud-contract-docker - pom - 4.1.0-SNAPSHOT - Spring Cloud Contract Docker - Spring Cloud Contract Docker - - - - org.springframework.cloud - spring-cloud-contract-dependencies - ${project.version} - pom - runtime - - - - org.apache.groovy - groovy - compile - - - org.apache.groovy - groovy-ant - compile - - - org.apache.groovy - groovy-groovydoc - compile - - - org.springframework.cloud - spring-cloud-starter-contract-verifier - compile - - - org.springframework.cloud - spring-cloud-contract-gradle-plugin - runtime - - - org.springframework.cloud - spring-cloud-contract-wiremock - compile - - - org.springframework.cloud - spring-cloud-contract-spec - compile - - - org.springframework.cloud - spring-cloud-contract-tools - ${project.version} - pom - runtime - - - org.springframework.cloud - spring-cloud-contract-spec-java - compile - - - org.springframework.cloud - spring-cloud-contract-spec-groovy - compile - - - org.springframework.cloud - spring-cloud-contract-spec-kotlin - compile - - - org.springframework.cloud - spring-cloud-contract-verifier - compile - - - org.springframework.cloud - spring-cloud-contract-converters - compile - - - org.springframework.cloud - spring-cloud-contract-stub-runner - compile - - - org.springframework.cloud - spring-cloud-contract-stub-runner-boot - compile - - - org.springframework.cloud - spring-cloud-contract-shade - compile - - - org.springframework.cloud - spring-cloud-starter-contract-stub-runner - compile - - - org.springframework.cloud - spring-cloud-starter-contract-stub-runner-jetty - compile - - - org.springframework.cloud - spring-cloud-contract-maven-plugin - compile - - - io.spring.gradle - dependency-management-plugin - ${dependency-management-plugin.version} - runtime - - - org.springframework.cloud - spring-cloud-build - ${spring-cloud-build.version} - pom - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-dependencies - package - - copy-dependencies - - - - ${project.build.directory}/maven_dependencies - - false - true - true - true - true - false - - - - - - org.codehaus.mojo - exec-maven-plugin - ${exec-maven-plugin.version} - - - gradle - package - - ./get_dependencies.sh - - - exec - - - - - - com.spotify - dockerfile-maven-plugin - 1.4.13 - - - default - - build - push - - - - - ${docker.registry.organization}/spring-cloud-contract - - ${project.version} - ${env.DOCKER_HUB_USERNAME} - ${env.DOCKER_HUB_PASSWORD} - - true - - - ${sdkman-java-installation.version} - - - - - org.codehaus.plexus - plexus-archiver - ${plexus-archiver.version} - - - - - - diff --git a/docker/spring-cloud-contract-docker/project/.gradle/7.5.1/checksums/checksums.lock b/docker/spring-cloud-contract-docker/project/.gradle/7.5.1/checksums/checksums.lock new file mode 100644 index 0000000000000000000000000000000000000000..c7e0c7aa34e4d46ac0ba3be5ed36bafdedc2da11 GIT binary patch literal 17 VcmZSnc);n6Wxz2p1~6b`1pqkF1Wo_| literal 0 HcmV?d00001 diff --git a/docker/spring-cloud-contract-docker/project/.gradle/7.5.1/checksums/md5-checksums.bin b/docker/spring-cloud-contract-docker/project/.gradle/7.5.1/checksums/md5-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..64c95f431208d725b92c7be9734df35150515f09 GIT binary patch literal 24797 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 A$p8QV literal 0 HcmV?d00001 diff --git a/docker/spring-cloud-contract-docker/project/.gradle/7.5.1/checksums/sha1-checksums.bin b/docker/spring-cloud-contract-docker/project/.gradle/7.5.1/checksums/sha1-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..667d2f31475999af0362dbe89f7b429d08d71d1d GIT binary patch literal 25571 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 literal 0 HcmV?d00001 diff --git a/.springformat b/docker/spring-cloud-contract-docker/project/.gradle/7.5.1/dependencies-accessors/gc.properties similarity index 100% rename from .springformat rename to docker/spring-cloud-contract-docker/project/.gradle/7.5.1/dependencies-accessors/gc.properties diff --git a/docker/spring-cloud-contract-docker/project/.gradle/7.5.1/fileChanges/last-build.bin b/docker/spring-cloud-contract-docker/project/.gradle/7.5.1/fileChanges/last-build.bin new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/docker/spring-cloud-contract-docker/project/.gradle/7.5.1/fileHashes/fileHashes.bin b/docker/spring-cloud-contract-docker/project/.gradle/7.5.1/fileHashes/fileHashes.bin new file mode 100644 index 0000000000000000000000000000000000000000..650a480997834e23641797bb29b65ffb5ef88754 GIT binary patch literal 18947 zcmeI(-Ahwp90%~nFv7_B*48EnYZR4QQ^c3@1!kEpg_y8zN+Z&XVBIJbDhqUwYXd^zC6e0d5}8)fqV~~?csZV-*b3AyWDn) z5Ow-GKgiah+*)D<0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fWUSUFw>3fW}8vx z?~oR0*9j@uLl-Hw%BAYDJZmnyY@8S0AM`fb&5ys_pJRF5N0HkXyGL%gEzf!0F7kj| z_xJRSZ-L)uMC8*)XZ@W!V^4TqF7mg%!O4cyr4oLhF_C}L=7i1|2NwDKRgr6}?sdfr ztFG~RgUH(wQB95eTQ#3g5xID$`A>EYuMmI$1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOL~wAy7oOafF`xr87O*)3EAL zsUCU#4<{^%%Y%d@S+gQG{*QpHVLEi|-^Rl42O5|6(yPqL(Ki=I4eL^4uW>D#P7*TM z?3Xt(LND!i`)|F^Zgp6SjK`Z;BdXhMBPx# literal 0 HcmV?d00001 diff --git a/docker/spring-cloud-contract-docker/project/.gradle/8.3/checksums/md5-checksums.bin b/docker/spring-cloud-contract-docker/project/.gradle/8.3/checksums/md5-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..f2db6959ce4360aec8f00b09b666ec484c6b6c39 GIT binary patch literal 25497 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 literal 0 HcmV?d00001 diff --git a/docker/spring-cloud-contract-docker/project/.gradle/8.3/checksums/sha1-checksums.bin b/docker/spring-cloud-contract-docker/project/.gradle/8.3/checksums/sha1-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..b9c3c09746ac71df678727538d4ad2dc61fe672d GIT binary patch literal 26057 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 literal 0 HcmV?d00001 diff --git a/docker/spring-cloud-contract-docker/project/.gradle/8.3/fileChanges/last-build.bin b/docker/spring-cloud-contract-docker/project/.gradle/8.3/fileChanges/last-build.bin new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/docker/spring-cloud-contract-docker/project/.gradle/8.3/fileHashes/fileHashes.bin b/docker/spring-cloud-contract-docker/project/.gradle/8.3/fileHashes/fileHashes.bin new file mode 100644 index 0000000000000000000000000000000000000000..e9c68bfd63aa857ed329f4ad5250b5d6c9246c9a GIT binary patch literal 19147 zcmeI(Ye-X300;1Enqj5+m`ep?PO+(_hOaUwsF_|}gu$Yq2cnXw1!W|et7L_1No88r zW@@F0jA{vnBxDasdkrN*rBb2H!WD#8Hk)?mITx|}y$|ufu6--XEz5MS7Wm`1L+e6oTNS@lq=bFLNx}&uP4{2V==dHC; z%f|bL0eYP}K5t*$X)IniafjyX`TS+s;}(VUNHo1pBcH#K_?pt#^MiE$UOsmWbU(f+ zJ9dcVX_xtYg;QRQUv!Cy=JtFpiNAJaa!vdpdi?}Gms+}1Y}@Z3I)4wJr~cG`?W^<8 zqIndbADA+GC)a*RBsuHE=lmzb*s&Mj(P)#fL2yFOvY))2ANKHN-( zsorH2Hrz~InwpAJuY7W}1rhAJoupxw&Nl4AY`gdWTH~WSX0&2!zvO|`aCmvAo0V&5 z^NL(5XB*6-FT#e&JTV!S)S7%Z-9@R(PRXH-v!vk}AZ)~lt1@2q78?8I>5|H|%9ZmQ zE)K%Rkbc}EQ;b|1n+~dyja}ssZFeQ2Yy2n|HX3w>*aS~~O8dKCVa*e9UR*;Z%Q(H6 z+!f<3Y~-tz=Q6G7Nf-Of{?=zN+UOcxq#-U9HUjtW3x7H+bCfGi1jSttO_7FwJ83M5 z6gJN6I9Og3+%s&@=Z=f)KPA(~G18d)ENoo4m#=xWt<|(W;7M6WwEf%p4aOpDob-Jk aqAiK+oaz2vERW3XpbZ0A!;kyUg#H0O!BiCh literal 0 HcmV?d00001 diff --git a/docker/spring-cloud-contract-docker/project/.gradle/8.3/fileHashes/fileHashes.lock b/docker/spring-cloud-contract-docker/project/.gradle/8.3/fileHashes/fileHashes.lock new file mode 100644 index 0000000000000000000000000000000000000000..72f6f750e7f86e9dcb4078178ba5cb05e2922596 GIT binary patch literal 17 UcmZRcoLKv$GIE100|ZC_05mBCFaQ7m literal 0 HcmV?d00001 diff --git a/docker/spring-cloud-contract-docker/project/.gradle/8.3/fileHashes/resourceHashesCache.bin b/docker/spring-cloud-contract-docker/project/.gradle/8.3/fileHashes/resourceHashesCache.bin new file mode 100644 index 0000000000000000000000000000000000000000..0aafb4515666a363fa674e75ea0d3866550d9584 GIT binary patch literal 18599 zcmeI%p-V$S90%}+V?~5*L3j%qWkEz3Hp^s!m@EdHXfer}e}K$k)u2oag8za{76%qV zG>E~ruplOx$ui&Ly~hx pXMc8FHcmcI+x?*4ep|W^N5{WAn#0F#CD(mw9qv>=@@Ly|$2U3fRC53T literal 0 HcmV?d00001 diff --git a/spring-cloud-contract-stub-runner/src/test/resources/emptyrepo/.gitkeep b/docker/spring-cloud-contract-docker/project/.gradle/8.3/gc.properties similarity index 100% rename from spring-cloud-contract-stub-runner/src/test/resources/emptyrepo/.gitkeep rename to docker/spring-cloud-contract-docker/project/.gradle/8.3/gc.properties diff --git a/docker/spring-cloud-contract-docker/project/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/docker/spring-cloud-contract-docker/project/.gradle/buildOutputCleanup/buildOutputCleanup.lock new file mode 100644 index 0000000000000000000000000000000000000000..80f0593cd8f1e737e933384fd1362746a67ddf10 GIT binary patch literal 17 UcmZSfymjaI#;sc|7$Cp{07J$FnE(I) literal 0 HcmV?d00001 diff --git a/docker/spring-cloud-contract-docker/project/.gradle/buildOutputCleanup/cache.properties b/docker/spring-cloud-contract-docker/project/.gradle/buildOutputCleanup/cache.properties new file mode 100644 index 0000000000..6abff7f80f --- /dev/null +++ b/docker/spring-cloud-contract-docker/project/.gradle/buildOutputCleanup/cache.properties @@ -0,0 +1,2 @@ +#Wed Sep 06 14:28:25 CEST 2023 +gradle.version=8.3 diff --git a/docker/spring-cloud-contract-docker/project/.gradle/buildOutputCleanup/outputFiles.bin b/docker/spring-cloud-contract-docker/project/.gradle/buildOutputCleanup/outputFiles.bin new file mode 100644 index 0000000000000000000000000000000000000000..c083ce394a85b1349ef81eaef3e2f768db77a396 GIT binary patch literal 18749 zcmeI%O(=tL9KiAa9B61}QBzuZPaKpeP9}$K<)oE%k<4Loak0{rSjl}QP24ErBrOh< zgNv{e7ca4kgWc9@d3)yh|443fkiJhn&-3s5{GO-h`COkqrJVLxy{XTw@^i@w0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009L4i-6zwkYe*=oUH}wo+qZi&}H3so2S` zdD*ii{|^=$$}cC^+)>>#(wBC&?duya5#2|n@7*SbGOoap?g!G-XW7G^V9aZFZ;|xp z?0n!nG}ol(7o=N4oBm$kV}4lAsnf_q+jebsxbeDB(xu!F6s^{I(Yjelb-o#V0 zp0ASbnZ3HMws(x^`GJp~ji)bG>!jaH57v+S?i^i%dOj?D;$c6TNUfCUo|G2&=d1z%23Y~{ literal 0 HcmV?d00001 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/fake/.gitkeep b/docker/spring-cloud-contract-docker/project/.gradle/vcs-1/gc.properties similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/fake/.gitkeep rename to docker/spring-cloud-contract-docker/project/.gradle/vcs-1/gc.properties diff --git a/docker/spring-cloud-contract-docker/project/.idea/.gitignore b/docker/spring-cloud-contract-docker/project/.idea/.gitignore new file mode 100644 index 0000000000..13566b81b0 --- /dev/null +++ b/docker/spring-cloud-contract-docker/project/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/docker/spring-cloud-contract-docker/project/.idea/codeStyles/Project.xml b/docker/spring-cloud-contract-docker/project/.idea/codeStyles/Project.xml new file mode 100644 index 0000000000..17c6134ebd --- /dev/null +++ b/docker/spring-cloud-contract-docker/project/.idea/codeStyles/Project.xml @@ -0,0 +1,89 @@ + + + + + \ No newline at end of file diff --git a/docker/spring-cloud-contract-docker/project/.idea/codeStyles/codeStyleConfig.xml b/docker/spring-cloud-contract-docker/project/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000000..0adac017fe --- /dev/null +++ b/docker/spring-cloud-contract-docker/project/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/docker/spring-cloud-contract-docker/project/.idea/compiler.xml b/docker/spring-cloud-contract-docker/project/.idea/compiler.xml new file mode 100644 index 0000000000..b589d56e9f --- /dev/null +++ b/docker/spring-cloud-contract-docker/project/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/docker/spring-cloud-contract-docker/project/.idea/gradle.xml b/docker/spring-cloud-contract-docker/project/.idea/gradle.xml new file mode 100644 index 0000000000..c40aef8ac6 --- /dev/null +++ b/docker/spring-cloud-contract-docker/project/.idea/gradle.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/docker/spring-cloud-contract-docker/project/.idea/jarRepositories.xml b/docker/spring-cloud-contract-docker/project/.idea/jarRepositories.xml new file mode 100644 index 0000000000..49bd6f6e98 --- /dev/null +++ b/docker/spring-cloud-contract-docker/project/.idea/jarRepositories.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docker/spring-cloud-contract-docker/project/.idea/misc.xml b/docker/spring-cloud-contract-docker/project/.idea/misc.xml new file mode 100644 index 0000000000..f1854e4b53 --- /dev/null +++ b/docker/spring-cloud-contract-docker/project/.idea/misc.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/mappings/.gitkeep b/docker/spring-cloud-contract-docker/project/.idea/sonarlint/issuestore/5/9/59f81c123b3abbcb97274545796dd18706c3e106 similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/mappings/.gitkeep rename to docker/spring-cloud-contract-docker/project/.idea/sonarlint/issuestore/5/9/59f81c123b3abbcb97274545796dd18706c3e106 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/mappings/.gitkeep b/docker/spring-cloud-contract-docker/project/.idea/sonarlint/issuestore/f/0/f07866736216be0ee2aba49e392191aeae700a35 similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/mappings/.gitkeep rename to docker/spring-cloud-contract-docker/project/.idea/sonarlint/issuestore/f/0/f07866736216be0ee2aba49e392191aeae700a35 diff --git a/docker/spring-cloud-contract-docker/project/.idea/sonarlint/issuestore/index.pb b/docker/spring-cloud-contract-docker/project/.idea/sonarlint/issuestore/index.pb new file mode 100644 index 0000000000..6b9b0e4f40 --- /dev/null +++ b/docker/spring-cloud-contract-docker/project/.idea/sonarlint/issuestore/index.pb @@ -0,0 +1,5 @@ + +8 +build.sh,5/9/59f81c123b3abbcb97274545796dd18706c3e106 +< + build.gradle,f/0/f07866736216be0ee2aba49e392191aeae700a35 \ No newline at end of file diff --git a/docker/spring-cloud-contract-docker/project/.idea/vcs.xml b/docker/spring-cloud-contract-docker/project/.idea/vcs.xml new file mode 100644 index 0000000000..c2365ab11f --- /dev/null +++ b/docker/spring-cloud-contract-docker/project/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/docker/spring-cloud-contract-docker/project/README.adoc b/docker/spring-cloud-contract-docker/project/README.adoc deleted file mode 100644 index 1aed4cdfa0..0000000000 --- a/docker/spring-cloud-contract-docker/project/README.adoc +++ /dev/null @@ -1,24 +0,0 @@ -# Spring Cloud Contract Verifier Docker Project - -## Developer tips - -### Environment variables -In order to use a new environment variable inside the Gradle script, you need to add it to the `envVars` map together with a description and a default value. Otherwise, any attempt to resolve such an environment variable will lead to an exception being thrown. - -If you're referencing any environment variables from inside the Java code please follow the following convention. - -```java -/** - * Some description. - **/ -@Value("${ENV_VAR_NAME:defaultValue}") -String envVar; -``` - -If you provide Javadocs, we will automatically parse any `@Value` annotated fields and build a table of environment variables with description and default values. - -### Customizing the gradle build - -You can provide a customized `gradle.build` to be run in the container by mounting your customized build file as a volume when running the container: - -`docker run -v :/spring-cloud-contract/build.gradle springcloud/spring-cloud-contract:` diff --git a/docker/spring-cloud-contract-docker/project/build.gradle b/docker/spring-cloud-contract-docker/project/build.gradle deleted file mode 100644 index dc5c77042f..0000000000 --- a/docker/spring-cloud-contract-docker/project/build.gradle +++ /dev/null @@ -1,269 +0,0 @@ -import contracts.DocsFromSources - -buildscript { - repositories { - mavenLocal() - mavenCentral() - if ("${verifierVersion}".contains("SNAPSHOT")) { - maven { url "https://repo.spring.io/snapshot" } - } else if ("${verifierVersion}".contains("M") || "${verifierVersion}".contains("RC")) { - maven { url "https://repo.spring.io/milestone" } - } - } - - dependencies { - classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}" - classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:${verifierVersion}" - } -} - -Map envVars = [ - PROJECT_GROUP: new EnvVar("Your project's group ID", "com.example"), - PROJECT_VERSION: new EnvVar("Your project's version", "0.0.1-SNAPSHOT"), - PROJECT_NAME: new EnvVar("Your project's artifact id", "example"), - STANDALONE_PROTOCOL: new EnvVar("For standalone version, which additional protocol should be added", ""), - PRODUCER_STUBS_CLASSIFIER: new EnvVar("Archive classifier used for generated producer stubs", "stubs"), - FAIL_ON_NO_CONTRACTS: new EnvVar("Should the build fail if there are no contracts present?", false), - REPO_WITH_BINARIES_URL: new EnvVar("URL of your Artifact Manager (defaults to the default URL of https://jfrog.com/artifactory/[Artifactory] when running locally)", "http://localhost:8081/artifactory/libs-release-local"), - REPO_WITH_BINARIES_USERNAME: new EnvVar("(optional) Username when the Artifact Manager is secured", "admin"), - REPO_WITH_BINARIES_PASSWORD: new EnvVar("(optional) Password when the Artifact Manager is secured", "password"), - REPO_ALLOW_INSECURE_PROTOCOL: new EnvVar("(optional) If allows to publish artifacts to Artifact Manager over insecure HTTP", "false"), - PUBLISH_ARTIFACTS: new EnvVar("If set to `true`, publishes the artifact to binary storage", "true"), - PUBLISH_ARTIFACTS_OFFLINE: new EnvVar("If set to `true`, publishes the artifacts to local m2", "false"), - EXTERNAL_CONTRACTS_GROUP_ID: new EnvVar("Group ID of the project with contracts", "com.example"), - EXTERNAL_CONTRACTS_ARTIFACT_ID: new EnvVar("Artifact ID of the project with contracts", ""), - EXTERNAL_CONTRACTS_CLASSIFIER: new EnvVar("Classifier of the project with contracts", ""), - EXTERNAL_CONTRACTS_VERSION: new EnvVar("Version of the project with contracts. Defautls to an equivalent of picking the latest", "+"), - EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_URL: new EnvVar("URL of your Artifact Manager. It defaults to the value of `REPO_WITH_BINARIES_URL` environment variable and if that is not set, it defaults to `http://localhost:8081/artifactory/libs-release-local`", ""), - EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_USERNAME: new EnvVar("(optional) Username if the `EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_URL` requires authentication. It defaults to `REPO_WITH_BINARIES_USERNAME`. If that is not set, it defaults to `admin", ""), - EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_PASSWORD: new EnvVar("(optional) Password if the `EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_URL` requires authentication. It defaults to `REPO_WITH_BINARIES_PASSWORD, If that is not set, it defaults to `password", ""), - EXTERNAL_CONTRACTS_PATH: new EnvVar("Path to contracts for the given project, inside the project with contracts. Defaults to slash-separated `EXTERNAL_CONTRACTS_GROUP_ID` concatenated with `/` and `EXTERNAL_CONTRACTS_ARTIFACT_ID. For example,\n" + - "for group id `cat-server-side.dog` and artifact ID `fish`, would result in `cat/dog/fish` for the contracts path.", ""), - EXTERNAL_CONTRACTS_WORK_OFFLINE: new EnvVar("If set to `true`, retrieves the artifact with contracts from the container's `.m2`. Mount your local `.m2` as a volume available at the container's `/root/.m2` path", "false"), - PUBLISH_STUBS_TO_SCM: new EnvVar("If set to `true` will run the task to publish stubs to scm", false), - MESSAGING_TYPE: new EnvVar("Type of messaging. Can be either [rabbit] or [kafka].", ""), - DEBUG: new EnvVar("(Docker Image only) Applicable for Docker Image - turns on debug mode for the Gradle build", "false"), - ADDITIONAL_FLAGS: new EnvVar("(Docker Image only) Additional flags to be passed to the Gradle build", ""), -] - -group = getProp(envVars, "PROJECT_GROUP") ?: 'com.example' -version = getProp(envVars, "PROJECT_VERSION") ?: '0.0.1-SNAPSHOT' - -repositories { - mavenLocal() - mavenCentral() - if ("${verifierVersion}".contains("SNAPSHOT")) { - maven { url "https://repo.spring.io/snapshot" } - } else if ("${verifierVersion}".contains("M") || "${verifierVersion}".contains("RC")) { - maven { url "https://repo.spring.io/milestone" } - } -} - -apply plugin: 'groovy' -apply plugin: "io.spring.dependency-management" -apply plugin: "org.springframework.boot" -apply plugin: 'spring-cloud-contract' -apply plugin: 'maven-publish' - -bootJar.enabled = false - -class EnvVar { - final Object defaultValue - final String description - - EnvVar(String description, Object defaultValue) { - this.defaultValue = defaultValue - this.description = description - } - - boolean equals(o) { - if (this.is(o)) { - return true - } - if (getClass() != o.class) { - return false - } - EnvVar envVar = (EnvVar) o - if (defaultValue != envVar.defaultValue) { - return false - } - if (description != envVar.description) { - return false - } - return true - } - - int hashCode() { - int result - result = (defaultValue != null ? defaultValue.hashCode() : 0) - result = 31 * result + (description != null ? description.hashCode() : 0) - return result - } -} - -dependencies { - testImplementation(platform("org.springframework.cloud:spring-cloud-contract-dependencies:${verifierVersion}")) - testImplementation(platform("org.apache.camel.springboot:camel-spring-boot-dependencies:${camelVersion}")) - - testImplementation("org.springframework.boot:spring-boot-starter-web") - testImplementation("org.springframework.cloud:spring-cloud-starter-contract-verifier") - testImplementation("org.springframework.amqp:spring-rabbit") - testImplementation("org.apache.camel.springboot:camel-spring-boot-starter") - testImplementation("org.apache.camel.springboot:camel-kafka-starter") - testImplementation("org.apache.camel.springboot:camel-rabbitmq-starter") - if (getProp(envVars, "STANDALONE_PROTOCOL")) { - testImplementation("org.apache.camel.springboot:camel-${getProp(envVars, "STANDALONE_PROTOCOL")}-starter") - } -} - -contractTest { - useJUnitPlatform() - if (getProp(envVars, "MESSAGING_TYPE") != "") { - systemProperty("spring.profiles.active", "messagingtype") - } else if (getProp(envVars, "STANDALONE_PROTOCOL") != "") { - systemProperty("spring.profiles.active", "standalone") - } - testLogging { - exceptionFormat = 'full' - afterSuite { desc, result -> - if (!desc.parent) { - println "Results: (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)" - if (result.testCount == 0) { - throw new IllegalStateException("No tests were found. Failing the build") - } - } - } - } -} - -contracts { - baseClassForTests = "contracts.ContractTestsBase" - testMode = "EXPLICIT" - stubsSuffix = getProp(envVars, "PRODUCER_STUBS_CLASSIFIER") ?: "stubs" - failOnNoContracts = Boolean.parseBoolean(getProp(envVars, "FAIL_ON_NO_CONTRACTS") ?: "false") - if (getProp(envVars, "EXTERNAL_CONTRACTS_ARTIFACT_ID")) { - logger. - lifecycle("Will use an artifact with contracts [${getProp(envVars, "EXTERNAL_CONTRACTS_GROUP_ID")}:${getProp(envVars, "EXTERNAL_CONTRACTS_ARTIFACT_ID")}]") - // tests - contracts from an artifact - contractsPath = getProp(envVars, "EXTERNAL_CONTRACTS_PATH") ?: "" - if (!Boolean.parseBoolean(getProp(envVars, "EXTERNAL_CONTRACTS_WORK_OFFLINE").toString())) { - contractRepository { - repositoryUrl = getProp(envVars, 'EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_URL') ?: - getProp(envVars, 'REPO_WITH_BINARIES_URL') ?: 'http://localhost:8081/artifactory/libs-release-local' - username = getProp(envVars, 'EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_USERNAME') ?: - getProp(envVars, 'REPO_WITH_BINARIES_USERNAME') ?: 'admin' - password = getProp(envVars, 'EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_PASSWORD') ?: - getProp(envVars, 'REPO_WITH_BINARIES_PASSWORD') ?: 'password' - } - } - contractDependency { - groupId = getProp(envVars, "EXTERNAL_CONTRACTS_GROUP_ID") ?: "com.example" - artifactId = getProp(envVars, "EXTERNAL_CONTRACTS_ARTIFACT_ID") - delegate.classifier = getProp(envVars, "EXTERNAL_CONTRACTS_CLASSIFIER") ?: "" - delegate.version = getProp(envVars, "EXTERNAL_CONTRACTS_VERSION") ?: "+" - } - contractsMode = Boolean. - parseBoolean(getProp(envVars, "EXTERNAL_CONTRACTS_WORK_OFFLINE")) ? "LOCAL" : "REMOTE" - } - else { - logger.lifecycle("Will use contracts from the mounted [/contracts] folder") - // tests - contracts in this repo - contractsDslDir = new File("/contracts") - } -} - -task cleanOutput(type: Delete) { - def dirName = "/spring-cloud-contract-output" - file(dirName).list().each { - f -> delete "${dirName}/${f}" - } -} - -task copyOutput(type: Copy) { - dependsOn("cleanOutput") - from 'build' - into '/spring-cloud-contract-output' -} - -test { - finalizedBy("copyOutput") -} - -publishing { - publications { - maven(MavenPublication) { - artifact verifierStubsJar - } - } - repositories { - maven { - allowInsecureProtocol Boolean.parseBoolean(getProp(envVars, 'REPO_ALLOW_INSECURE_PROTOCOL') ?: "false") - url getProp(envVars, 'REPO_WITH_BINARIES_URL') ?: 'http://localhost:8081/artifactory/libs-release-local' - credentials { - username getProp(envVars, 'REPO_WITH_BINARIES_USERNAME') ?: 'admin' - password getProp(envVars, 'REPO_WITH_BINARIES_PASSWORD') ?: 'password' - } - } - } -} - -// explicitly disable artifacts publication -boolean publishEnabled = Boolean.parseBoolean(getProp(envVars, "PUBLISH_ARTIFACTS") ?: "true") -boolean publishOffline = Boolean.parseBoolean(getProp(envVars, "PUBLISH_ARTIFACTS_OFFLINE") ?: "false") -publish.setEnabled(publishEnabled) -publishToMavenLocal.setEnabled(publishOffline) - -gradle.taskGraph.whenReady { graph -> - graph.allTasks. - findAll { it.name.startsWith("publish") && "publishStubsToScm" != it.name }*. - setEnabled(publishEnabled) - graph.allTasks. - findAll { it.name.startsWith("publish") && it.name.endsWith("ToMavenLocal") }*.setEnabled(publishOffline) -} - -if (Boolean.parseBoolean(getProp(envVars, "PUBLISH_STUBS_TO_SCM") ?: "false")) { - publish.dependsOn("publishStubsToScm") -} - -String getProp(Map envVars, String propName) { - if (!envVars.containsKey(propName)) { - throw new IllegalStateException("You've referenced a property with name [${propName}] but it's not in the list of accepatble props ${envVars.keySet()}") - } - return hasProperty(propName) ? - (getProperty(propName) ?: System.properties[propName]) : System.properties[propName] ?: - System.getenv(propName) ?: envVars.get(propName)?.defaultValue -} - -task resolveDependencies { - description "Pre-downloads *most* dependencies" - doLast { - configurations.getAsMap().each { name, config -> - println "Retrieving dependencies for $name" - try { - config.files - } - catch (e) { - project.logger.info e.message // some cannot be resolved, silently skip them - } - } - } -} - -task dumpAllProps() { - doLast { - // TODO: Parse the java code for env vars - File output = new File("build", "props.adoc") - if (!output.exists()) { - output.parentFile.mkdirs() - output.createNewFile() - } - String table = """\ -.Docker environment variables -|=== -|Name | Description | Default -""" - output.text = table + envVars.sort().collect { '|' + it.key + '|' + it.value.description + '|' + it.value.defaultValue }.join("\n") + "\n|===" - - new DocsFromSources(project).buildApplicationEnvVars() - } -} diff --git a/docker/spring-cloud-contract-docker/project/build.sh b/docker/spring-cloud-contract-docker/project/build.sh deleted file mode 100755 index 007e993eef..0000000000 --- a/docker/spring-cloud-contract-docker/project/build.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -set -o errexit -set -o errtrace -set -o nounset -set -o pipefail - -export PROJECT_NAME="${PROJECT_NAME:-example}" -export DEBUG="${DEBUG:-false}" -echo "Setting project name to [${PROJECT_NAME}]" -echo "rootProject.name='${PROJECT_NAME}'" >> settings.gradle -echo "Running the build" -export ADDITIONAL_FLAGS="${ADDITIONAL_FLAGS:-}" -if [[ "${DEBUG}" == "true" ]]; then - ADDITIONAL_FLAGS="${ADDITIONAL_FLAGS} --debug" -fi -./gradlew clean build publishToMavenLocal publish --stacktrace ${ADDITIONAL_FLAGS} diff --git a/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.2/executionHistory/executionHistory.bin b/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.2/executionHistory/executionHistory.bin new file mode 100644 index 0000000000000000000000000000000000000000..abf26f7f77f8fc6de289b1267ce4fa69c7b0277e GIT binary patch literal 31363 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 literal 0 HcmV?d00001 diff --git a/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.2/executionHistory/executionHistory.lock b/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.2/executionHistory/executionHistory.lock new file mode 100644 index 0000000000000000000000000000000000000000..e3599eade01efd85ddbff6b30c3615ae7fe3298a GIT binary patch literal 17 UcmZSHq&x5K(|hb686dz406!xIQvd(} literal 0 HcmV?d00001 diff --git a/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.3.3/executionHistory/executionHistory.bin b/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.3.3/executionHistory/executionHistory.bin new file mode 100644 index 0000000000000000000000000000000000000000..920090b0e81685a644cde671cfea8280e58846fa GIT binary patch literal 31752 zcmeI23tSY{9>-^P5nq)tfBrHA3BXz{KZyOu-~JVTg9IP}NB|Om1Rw!O01|)%AOT1K5`Y9C0Z0H6fCL}` zNB|Om1R#O`7Xk^OBR$NW2^cOCzVw=hAVK$mFCx*4XRjB(>eI!XJu$-i{vh)BkN_kA2|xmn03-kjKmw2e zBmfCO0+0YC00}?>kN_kA2|xmn03-kjKmw2eBmfCO0+0YC00}?>kN_kA33!q~D1!W> z6nu(=Pe~@9mC1xD>3Ot56{^mfr{;-}kjyNVLT}d8`!-U|uqo0MmQZO(DWRjJJi(=L zQYE9+Q6Oa!VIU&S-{;CmCBqUtsloy((HCkr_vjkYCB1-4nt4C^mptVmV=8DZkz_fF zp}Up1=n|Az@^TX8)8nFJW99~j=V%#~UPG`HpXrCxI#i)(o@8l4BTY4Er7|*^&};aq zwz6?LQt8m2XZ~3>s^R3)@3N%bGpFtzfRxyuDy8UTk~P&NrxCmwUB>8mppWxI-gRis zot%YQthuy9W3KQDEf2IZXCv4YuIEZ?s)|(TQ&3wW)4!I7`XO((D?uhywUl)mvvQ{f zETyET$4?;*qz1{i79eRQqoU{(q{x<%!IQKwN-~P&kOFIRGC^r#X*tU>EShUeWY{#3 zy$JX()(WtyUG-7+qHf~L9G`A^o|McWm3p2~Xh>vzTlrunn9$lXh3RG<*{K9YM`{R; zL)KYq+A}S)4#~4-v80A1I1(w~7(J^bg^?zBNOQAMxSG+DxRzj*6pgc_j=?z{3ouKR8b+^@C>fe(2_=uK7-bsCww)=lWSSeq&C7VM ziqw&`3Je=Xa=4OEs==RdX{a<5Pa$d2w1g$*qLNgC?qs4ZqpirbVsL4Yb2%2}) zq5k@8P0qnluN^5)AdVF#Z4kA1N(aX)^pr+LvW{}{9(keqSeZzdKo=^OJiOze=$41% zfJwjt%`*+XQ^>j-QOj%rFDOslzh`SRArL54y- zT~{Q!;UP7t978(_xv}AqkwNGxjrj2VgVe@e6Fs)3X^L^wv3#%i_0zA_J^jHaeQE~x zr=Rec4ldnkn)LLoU4>8DAERnK`&s3htv`5dn((AnrvZzIbEJ|zXzP@nX;+fQMOQ33 z6&Y0Jv1tNyIBmImayRwKDf)TO$?j(-PTq7R#$&^ip>-Ob5mif;B}Nb5wQAf!>T1$O zO~((9V0q}kxeWGvU~mijTW~ly5>1D)|FpWna`leKukn{|R?Je+9l!IZF}#MNB^<8; zN3E~F&+qA)+go(UvyxI(Y2i+S4%JO>iC%ak=eoYEtg`6B2`>m5LCqh;Yl<=pt! zPkeT#@xI4uI{t*T3>r%&Ye*&UB&NCWZT;|H_8H@}d+YN07dsgo!C!bR`tc z@q`9!e&7xxQIG_%YaC7Aqjz4Z`S@b)34NT8A?EA-Z;LLuOe1ZG$ztayo?$a_aE-xJ z6%5DW$>1xAvkbw3+o$!fBvr-ZA<~c#V1h?c;7;n8A#uzwud9aUn##q+JAWNLf9%-4 zCo*^5W9z`IZ@YED-gj^PNng?Dqo;3H1Z@vg;6=;|(G#8hs)9w`Ka89ZWH|llx#EHU zk{R+neo?`4E5b&^98W23Jc9?EyY_mq_Z4{MqJ(8%TW~1*Y)kM>pSQY1wvOaFhYD|A z*0BA<=6rEs*Eqk){fE^KoHgWlrxN3}dm~nG9Z!FBuC(;pOV=mHWZ&A>d6anX{))96 zO3Kai-IDN_`0~v+&JvIPO{F+rq_H78(HR>*HEwvb^47KfTlSWDlFA=Q@#2jhTXAW8 ztvdE|Y~JP%!@ouwQ#z9t@AwulV?pnpGgi$$(-IXr+^6iou}&hxQ>UPlg99ti-Zt=M z*@v04=Lc?ViY(sy_fp~HWWlan+IqWm%*mg2_gg+-cGXw;o?_9y3Qw)rHXJ?JI$6$` zm;B@9d!C7mrK3GVX-Ws6H3w*QhU<2JrWO!<>I{Ce@v3Cwv z>c>o)U9GEFTY5%W+c{Kp_$u}_;K@Bn4%zH6a;*$-XNlS-Y&(5AVyUPtb zT3bA4{`^S)AMsJh`9gMGasdwoEUk$_>6ZwfLJjS3-w*RU za$wo|{N-QvBUflbqesuiW_%mK`eYCN;rzg93x|%MUT=#RA!wT6O`g+fETbejj$wts z7^K7+9-&|uo&&K9I#Wc25bc1hw&s~5CQNB7feRMIYQ&jhC^+<>v+MUB10r-RlM1}e zxasA29IM1R@X>-O4_w&cacgh|hszix7sWDKiwxj_H4tLVZ)rr|=Ks~~+SIGduJ4XY z$D?KK*Fb-8b`W={ddx54z{mCV)o*t7(dyIoeHiW{{E6lU5yD7qig#qe)K6+ zfwyVE)hzh8L5vO{0sPd6i$U{Oi!`yuO(8BI;KamPAdalCu|wCo;2s<-HI+xOBbS?Q zjf||3zdQMXgmtP3r14a1<3)VaFto^}inT)c!v)VZe8FvN96R~()uR%g%rjM35{Tx? zX+t8xTFZUEIQ)EmV&mf<416cE&py991*URWdWjM2BXQ!-<9v>sndDnDb5=6Lx2S=)f zcip^rX+nIIWK^D(X?+n3MI(OW$2t_M3dKD?x z>iA3{@)9kv)emv&XpvK%t*gtY%Hty>(J@hl&iR&3mpiArb?47^+gXLJ<94=!@Vj)~ zxsY4u?PDBr*D($O0j-uXwsqV-)*#nytU=m6ciKMIAwu6=$J&(G{#b{Auw$38UYbSe z!bXV1IkpiB?&6&T9d!-#@Q@*4x7twDZc`ld#OCj2)Y!GST98(gM(k$Npc`z4(A_FE zbh6HvjVLkZYHXq9ckPO~%BSA$h@%lG#$1g+bd6oVV@cFIE6UC6#P-FWKfq##rwm>6 z8zcTpkA2f+$v`-@(Dde)Wh W!CT0tlR>`cOa|g2iC`c02>cztB|BgM literal 0 HcmV?d00001 diff --git a/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.3.3/executionHistory/executionHistory.lock b/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.3.3/executionHistory/executionHistory.lock new file mode 100644 index 0000000000000000000000000000000000000000..f35862e40c3a877f110d0512b3ce475f3afa03dc GIT binary patch literal 17 TcmZR+EXb6~o3G`{00B|}9XtY5 literal 0 HcmV?d00001 diff --git a/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.3/executionHistory/executionHistory.bin b/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.3/executionHistory/executionHistory.bin new file mode 100644 index 0000000000000000000000000000000000000000..75330ced473f016766a54fb0f9180fd650ee1c18 GIT binary patch literal 41634 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 P@=W`yidQPpR#DS%7 zazO1Q3iEH#vdf|<|L56$&(qS5ZhHUf_x!$no<2SOUe~8dl1zrUvZU0?O^r+lAbFf-S;^Pbyg&9D4&K^7mE5D|>M7@L@s1|~2q1s} z0tg_000IagfB*srAbRzjhz>I`*oM54t5uGh%EFN0MLBXhQN?^SkA3wzlhU zI+u(meYXAOo~p?mXSrxyUL;$RAv3+TZY^m$U--EH_RUUhMRx~=7KdL%>&z=!+Pw7E g!`G94`ZRz3`O*Hao2WYsxH5`GD-sZ`>{z1p1EqO@^#A|> literal 0 HcmV?d00001 diff --git a/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.4.1/dependencies-accessors/dependencies-accessors.lock b/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.4.1/dependencies-accessors/dependencies-accessors.lock new file mode 100644 index 0000000000000000000000000000000000000000..693d24ef12790eba078377ed796de420c7cd79bb GIT binary patch literal 17 TcmZR6w6Wy&9F?kU1}FdkJDmiJ literal 0 HcmV?d00001 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/common-repo/target/IgnoreMe.groovy b/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.4.1/dependencies-accessors/gc.properties similarity index 100% rename from spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/common-repo/target/IgnoreMe.groovy rename to docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.4.1/dependencies-accessors/gc.properties diff --git a/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.4.1/executionHistory/executionHistory.bin b/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.4.1/executionHistory/executionHistory.bin new file mode 100644 index 0000000000000000000000000000000000000000..8efb9a112f538655b5750262b545b716f3179b98 GIT binary patch literal 41970 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 P@=W`yidQPpR#DS%7 zazO1Q3iEH#vdf|<|L56$&(qS5ZhHUf_x!$no<2SOUe~8dl1zrUvZU0?O^r+lAbFf-S;^Pbyg&9D4&K^7mE5D|>M7@L@s1|~2q1s} z0tg_000IagfB*srAbRzjhz>I`*oM54t5uGh%EFN0MLBXhQN?^SkA3wzlhU zI+u(meYXAOo~p?mXSrxyUL;$RAv3+TZY^m$U--EH_RUUhMRx~=7KdL%>&z=!+Pw7E g!`G94`ZRz3`O*Hao2WYsxH5`GD-sZ`>{z1p1EqO@^#A|> literal 0 HcmV?d00001 diff --git a/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.5.1/dependencies-accessors/dependencies-accessors.lock b/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.5.1/dependencies-accessors/dependencies-accessors.lock new file mode 100644 index 0000000000000000000000000000000000000000..92776a10fd868e51bfe9a62c89cf2ea7458a2a65 GIT binary patch literal 17 TcmZR6bpP|lGhG|w8K3|FOM3;+ literal 0 HcmV?d00001 diff --git a/tests/spring-cloud-contract-stub-runner-integration/.jdk8 b/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.5.1/dependencies-accessors/gc.properties similarity index 100% rename from tests/spring-cloud-contract-stub-runner-integration/.jdk8 rename to docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.5.1/dependencies-accessors/gc.properties diff --git a/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.5.1/executionHistory/executionHistory.bin b/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.5.1/executionHistory/executionHistory.bin new file mode 100644 index 0000000000000000000000000000000000000000..efe3302cb4647a61f15ef22cf00dfc15eb06301f GIT binary patch literal 31507 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 literal 0 HcmV?d00001 diff --git a/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.5.1/gc.properties b/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/7.5.1/gc.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/8.3/executionHistory/executionHistory.bin b/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/8.3/executionHistory/executionHistory.bin new file mode 100644 index 0000000000000000000000000000000000000000..6c3478d3e83e855d696102575873edcdbd8f5225 GIT binary patch literal 29963 zcmeI22~-o;8pmf6RH{AgP^+T07OeVENy1W!R$FC@vM3f%+uEm2k|7KvGwIAE3g_9D zhoV%dCsq%{?W=+-wJ5G#)VhQ1b7{5qsP9fD+aw5&u-Nm?<(xp6d++~# z_c!1D=DYV!B!YNjk1aol{ilolEBpotKmw2eBmfCO0+0YC00}?>kN_kA2|xmn03-kj zKmw2eBmfCO0{<@r#)5%#6b9q%FX6vDKLtSoo&{edlF2{cUO3aEolrb7%zAzhaV9pt z?5peJh3l#Q*6Y^4;Ch%)27f~WkN_kA2|xmn03-kjKmw2eBmfCO0+0YC00}?>kN_kA z2|xmn03-kjKmw2eBmfCO0+0YC00}?>kN_kA2|xmn03-kjKmw2eBmfCO0+2vk5(q{R z-;3aLmj9G$ST@*{VoFJ4)Iq^?N{Buqgw<$pz4kT1CeO~uW}4B;wG6J&5pvu>$~l}( zW94dEZy>>y7~F(M2;V0~5^9>kIYNW|SlxMg-*5faWX#Wwt4f&v0BsSKm-15Wy)jiquPEvA`;s}Pqb@E6e88_;cv_@P@j3XG9q^T~bOT$TPZzAnj1{vD81(uQWhQx_=Grh5^Wg|Ve zNDwp{>0lB%n`!_z*lTJ1hVi#JnlczU)(hF%c-NxAo7=ezN z+Eu~4NhTO`OJWSprJ%ED1AjMw8*Fpv&NT{HB0#)Q+o3b(Krr7TXpJ9C7^7u7eQLd` zAyh^!YO7@a*COhLtZvYRNWQ71u8aGXi#o8>lAGn@2os@0=2|Ndl$zF%lolznU75-e z6hA*BNrpuVt(TK=QWsA}F$~S1dA5r*lP0lO0sqBY0X7^)mG-I)&|Bizk40HdOeNGt z4p-?2q^!Pj;1g!ZHU=c6W`voh3rhxZQVB+4WC+yOn)gh>2}Xfn8ll5k7Adhx+Y2qu zi{x927(z$jEP)iVw2@I0yi~5d>^24O1FckB8Aoy z3O&xKNlIaP@F>){I)z{rgXF;qEkP0Hr;JQ^D9KWBhE-U;1J{&+N^)>biY5K#`TK@x zy~w-$bC2cTJ$^#+wUaojNz>yL5T`UG2=$-?LB`yVj#PnvY1))73zi4S149MTAkWNu z+Y%%>{a#r#=idqao|Wu(QxvB-k?@^vC*JHp?J6tO7Y8RQvBQ!h?h3P<%1G)o1S8Vl zx;#gz^NRLgI}2f2E-Y0fE*LBJo+*B6^*>pS@!EfOhjXXADb}9CFim z{x)!=UaWpbonQXK}pcX-cF#`ebNL!tvi`6fVo`Im~{doar+Ca+!kg(5Tn-mObp;MdL7VW{+*X~ID5iv)EoiQ z1%Aeg>^^YJGkni&D&gvbn8e%N^R;fH2EyXW+392Xhr1u%tH=p?e=xE1MNhYhOx25t z6tAoJG9b=4wDW+1-L>(ji<<7*d_XpU5D2C_NWb}s1431R5Uj48A6eJEV1Cw`%%dUI z3s-lOR5sQ3(r8XcQZkm)fOseiln=H_Zyr*2`^>iG740WJRQYboE0?v{!Bz|= zRg)I#sK0Mo-TW(uUg^<0=DtTzpWz-Ypg+h_zi8j<9ggkZG3@fF9@XLF4}Ku2ZYmqg z1Cyj!4%dOH1QHyXioii|w?9BP_PcZVQ62Hwf|Ra_>C@}Jm)vmbMIWSK2m{TM9L=OF zKz^o3RnaV~NCsaC1w-R3$SB^Z2u`7>Gd25{?)%?T+3qLC>o{;>{f$t9ZJsS^y@3U5rY?(|4lhiOP|MlYRAAcp1 z=H0yaYv)#yZPD}zyZ%$p3yYpnx62Ex>f$|o#r@V*cXl=RQ!{MChSD2XO~+oVE4qYl z+gl#miqb8Z^I;u^ZJFnrf25@S>LFV$O}M<|ud3~oO=9QIb$YJ4n~!?iH>#dBeLOZb z$L_|oTQX0@3YB-(zCle{ds3E(T;E$+)~ezylmcTZ{+EXITR)%-oqp@Xq{=CeT1(g6 z5G78mvGVGH@Amb7bRj2gY3IEg;~xLTWX0J!7E$=ezQJj;24{V??!x|2dp+E>wh>u( z9j(440Cpj}d)K$aGIsUW6n0(4W)`-pxVzrww7S6J{7*<0_?{fvb>-tz(Hk?2t)=Vk z4HU0gu%9bV^*`W)E{^^E^1&4k3Kq1IY?CABlNUl*z^bDWr(UfYJ%ipg`g7^`HLa=L zQcEms*ZN7upVs&3Mx39sEINAUffin1Vc)zQn|=R-Uo?3mDu|JPJ{aF(%PUM48r)@v z*NiF5jw1p7wMBcHoGdl8xWX1suUr^>o&3kTsM33X;y1#ZukNt4!o~+@?pzY;>-+M^ z?H{f23G;4+g%yUrIdk%+MR(W7>{BAs-nqH^M%yi`urs$-bT3(nA9!I?`Qb_BVUL^F zcas)Xm{(Qhtg^W|$9oW;=z^mM{~a5D(VOv@;a7XL_n43T!V{`(d(=2Z(ZWg47=~68 zEK4)|fdo=&-D_6SG{8W=hi>?;7Q>)-RVo-|oxHC*|Sjl7?HLwPH7ERqHXYu*w6~ z)ti_8FzjNMZ|=d}Skim9Vp7j_+Fs#*jUE!a$LKL%19r*4I-cJ;0B0kB1lR;XersJL z&8!vX^8&D4Z|2MsM?SH!Ll-#V?h`0C*GI6by1Vy7BDO|ti+yfviDm>bXVLe^R|GB} zfEGD5u{H?pTKIO&ckCCZ-;DJs7&P{8LWAiqp?Oi1X&la2>s`qTy*hW?X`j8l*Q9sb z=k>6_EPV5MDS~|?9d~EAN7eb5_SLx)7qsUub$n~go!mY>N?-2r`lAu|E5>=Ow0f@X zY(wyrcq0c6VeM>>x32pNY;86ugn7g&>Y0po@?bpiHG59J6I|dm!!vkeNYvaskHyyU zq!2hbhHxH6<21RU+vQVb3W(&Irpa20|jq)Tm`RsbUX<@ zRs5&XS3Qu<$l7{OSXD*}Z2nSOa4O9-a5#xJt-13tbkDiq?4L>Ju`?jvgP7vEsbO>8 zBMnhbO>!cmlyPB6QIW;qT#rl!@hJiXbRZm&!taoC((JKGO4*=%>$@G|%f)=p1Y;tU z;LVmKa0mq+9(n_d7J*31fa7#E2_7YUSv&*0TCxxv4s!hAIv-%bxo0AOOw5rc0xfhX z;e#aq=#plZI9?^0F$AM0%>!kT#g0WrgN{`5XB&y&QN$72bkCJeAd>kvZz5gl&59l! z5jQq6s?;L`c?Z`7_GJr&8+gvB zsH8Ai^k}7B*jz3~P%dulGPtHfSR~SO#$X4|n*vJf10k;Dg2I0PgPwT*gX+Ox_XAKW zhTzbnT+?g>4)=;5;uHKJ=t;wOxLx4I5GOy#&L9o1zb28+wqXwRc>Giz{q{TyMeSL@ zskR8$E@_C}7U!IgpDg@K4pNsS1YKrJU7pma<}WrF>rkB2BeeX9LlK%BdD;VUOxvWG zbJ~U$+wB+Cd^$<3OQLwMEhm`pHiLORgKgSUk$(Qivfw5C9vwYAB)8^vTNnZ!#=^3# zejBi}m-ZJ{*A9N;;>_D!yFbG%vWKD|B+nL>Kzv8rgd3l`f!B@{qryf58f|eZA)qX j1Q@~6vc~4)4`U;WPSw5o@X(R%mFE05Q^u#a9nbw2wG%n~ literal 0 HcmV?d00001 diff --git a/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/8.3/executionHistory/executionHistory.lock b/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/8.3/executionHistory/executionHistory.lock new file mode 100644 index 0000000000000000000000000000000000000000..81d2aaba3feead27a1cd102a33bb8307de580c16 GIT binary patch literal 17 TcmZRc!?;Q^#v`AP0Rq?nAm### literal 0 HcmV?d00001 diff --git a/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/buildOutputCleanup/buildOutputCleanup.lock new file mode 100644 index 0000000000000000000000000000000000000000..cf4e5090844beeb176eb460927c125a68c5a1908 GIT binary patch literal 17 VcmZQRJ-c~93-jI}1~6b+4gfZj1k3;c literal 0 HcmV?d00001 diff --git a/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/buildOutputCleanup/cache.properties b/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/buildOutputCleanup/cache.properties new file mode 100644 index 0000000000..6a2b4d3e85 --- /dev/null +++ b/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/buildOutputCleanup/cache.properties @@ -0,0 +1,2 @@ +#Wed Sep 06 14:28:19 CEST 2023 +gradle.version=8.3 diff --git a/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/buildOutputCleanup/outputFiles.bin b/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/buildOutputCleanup/outputFiles.bin new file mode 100644 index 0000000000000000000000000000000000000000..7ae9e89b2ce68fd1bea9699edb0eb7c066183b61 GIT binary patch literal 18965 zcmeI%O-K}B7{Kw_^-#K&TNJE)m{1U9ln@;{>>(+bnS!E4Xr<6B4@M-BDAaaPi#7?Q zO%PZ5An9wPAc_(f3M=xmMt12SS(IC3gcL2p($_5WJV?i)F7h9k*_Z!3^TPYP?nc81 z_gLvpxp?3_>b zDb}vPhT&~--|<8M0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ u0R#|0009ILKmY**5cpGpway3m&h5$FxyS6^iW8<~`F|(2&=d1((23P^_ literal 0 HcmV?d00001 diff --git a/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/noVersion/buildSrc.lock b/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/noVersion/buildSrc.lock new file mode 100644 index 0000000000000000000000000000000000000000..35a038769b15c0935bb3cd038f5cc1de7579f128 GIT binary patch literal 2 JcmZQ%0000400IC2 literal 0 HcmV?d00001 diff --git a/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/vcs-1/gc.properties b/docker/spring-cloud-contract-docker/project/buildSrc/.gradle/vcs-1/gc.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docker/spring-cloud-contract-docker/project/buildSrc/build.gradle b/docker/spring-cloud-contract-docker/project/buildSrc/build.gradle deleted file mode 100644 index 6b3fe7015f..0000000000 --- a/docker/spring-cloud-contract-docker/project/buildSrc/build.gradle +++ /dev/null @@ -1,21 +0,0 @@ -repositories { - mavenLocal() - mavenCentral() - maven { url "https://repo.spring.io/snapshot" } - maven { url "https://repo.spring.io/milestone" } -// maven { url "https://repo.spring.io/release" } -} - -ext { - roasterVersion = "2.22.3.Final" - junit5Version = "5.6.2" -} - -dependencies { - implementation "org.jboss.forge.roaster:roaster-api:${roasterVersion}" - implementation "org.jboss.forge.roaster:roaster-jdt:${roasterVersion}" -} - -test { - useJUnitPlatform() -} diff --git a/docker/spring-cloud-contract-docker/project/buildSrc/src/main/java/contracts/DocsFromSources.java b/docker/spring-cloud-contract-docker/project/buildSrc/src/main/java/contracts/DocsFromSources.java deleted file mode 100644 index 1d1e2aa168..0000000000 --- a/docker/spring-cloud-contract-docker/project/buildSrc/src/main/java/contracts/DocsFromSources.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts; - -import java.io.File; -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.FileVisitor; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; - -import org.gradle.api.Project; -import org.jboss.forge.roaster.Roaster; -import org.jboss.forge.roaster.model.JavaUnit; -import org.jboss.forge.roaster.model.source.AnnotationSource; -import org.jboss.forge.roaster.model.source.FieldSource; -import org.jboss.forge.roaster.model.source.JavaClassSource; -import org.jboss.forge.roaster.model.source.JavaDocSource; - -public class DocsFromSources { - - private static final String ADOC_HEADER = - ".Docker environment variables - read at runtime\n" - + "|===\n" - + "|Name | Description | Default\n"; - - private final Project project; - - public DocsFromSources(Project project) { - this.project = project; - } - - public void buildApplicationEnvVars() { - Path path = new File(rootDir(), sourcePath()).toPath(); - List envVars = new ArrayList<>(); - FileVisitor fv = new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) - throws IOException { - if (!file.toString().endsWith(".java")) { - info("Skipping [" + file.toString() + "]"); - return FileVisitResult.CONTINUE; - } - JavaUnit unit = Roaster.parseUnit(Files.newInputStream(file)); - JavaClassSource myClass = unit.getGoverningType(); - info("Checking [" + myClass.getName() + "]"); - List> fields = myClass.getFields(); - for (FieldSource field : fields) { - List> annotations = field.getAnnotations(); - for (AnnotationSource annotation : annotations) { - if ("org.springframework.beans.factory.annotation.Value".equals(annotation.getQualifiedName())) { - info("Field [" + field.getName() + "] has @Value annotation"); - JavaDocSource> javaDoc = field.getJavaDoc(); - String description = javaDoc.getFullText(); - // ${foo:asd} - String annotationValue = annotation.getStringValue(); - // foo:asd - annotationValue = annotationValue.substring(2, annotationValue.length() - 1); - String[] parsed = annotationValue.split(":"); - String defaultValue = ""; - String name = parsed[0]; - if (parsed.length == 2) { - defaultValue = parsed[1]; - } - envVars.add(new EnvVar(name, description, defaultValue)); - } - } - } - info("Found [" + envVars.size() + "] env var field entries"); - return FileVisitResult.CONTINUE; - } - }; - - try { - Files.walkFileTree(path, fv); - Path output = new File(rootDir(), "build/appProps.adoc").toPath(); - StringBuilder stringBuilder = new StringBuilder().append(ADOC_HEADER); - Collections.sort(envVars); - envVars.forEach(envVar -> stringBuilder.append(envVar.toString()).append("\n")); - stringBuilder.append("|==="); - Files.write(output, stringBuilder.toString().getBytes()); - } - catch (IOException e) { - throw new IllegalStateException(e); - } - } - - String sourcePath() { - return "src/test/java/contracts"; - } - - File rootDir() { - return project.getRootDir(); - } - - void info(String log) { - this.project.getLogger().info(log); - } -} - -class EnvVar implements Comparable { - final String name; - final String description; - final String defaultValue; - - EnvVar(String name, String description, String defaultValue) { - this.name = name; - this.description = description; - this.defaultValue = defaultValue; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - EnvVar envVar = (EnvVar) o; - return Objects.equals(name, envVar.name) && - Objects.equals(description, envVar.description) && - Objects.equals(defaultValue, envVar.defaultValue); - } - - @Override - public int hashCode() { - return Objects.hash(name, description, defaultValue); - } - - @Override - public int compareTo(EnvVar o) { - return name.compareTo(o.name); - } - - @Override - public String toString() { - return "|" + name + "|" + description + "|" + defaultValue; - } -} \ No newline at end of file diff --git a/docker/spring-cloud-contract-docker/project/gradle.properties b/docker/spring-cloud-contract-docker/project/gradle.properties deleted file mode 100644 index fedc2636e7..0000000000 --- a/docker/spring-cloud-contract-docker/project/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -org.gradle.daemon=false -verifierVersion=4.1.0-SNAPSHOT -springBootVersion=3.2.0-SNAPSHOT -camelVersion=3.11.0 diff --git a/docker/spring-cloud-contract-docker/project/gradle/wrapper/gradle-wrapper.jar b/docker/spring-cloud-contract-docker/project/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 7f93135c49b765f8051ef9d0a6055ff8e46073d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63721 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鯊%1Et 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⁢ zv5o9#E7!G0XmdzfsS{efPNi`1b44~SZ4Z8fuX!I}#8g+(wxzQwUT#Xb2(tbY1+EUhGKoT@KEU9Ktl>_0 z%bjDJg;#*gtJZv!-Zs`?^}v5eKmnbjqlvnSzE@_SP|LG_PJ6CYU+6zY6>92%E+ z=j@TZf-iW4(%U{lnYxQA;7Q!b;^brF8n0D>)`q5>|WDDXLrqYU_tKN2>=#@~OE7grMnNh?UOz-O~6 z6%rHy{#h9K0AT+lDC7q4{hw^|q6*Ry;;L%Q@)Ga}$60_q%D)rv(CtS$CQbpq9|y1e zRSrN4;$Jyl{m5bZw`$8TGvb}(LpY{-cQ)fcyJv7l3S52TLXVDsphtv&aPuDk1OzCA z4A^QtC(!11`IsNx_HnSy?>EKpHJWT^wmS~hc^p^zIIh@9f6U@I2 zC=Mve{j2^)mS#U$e{@Q?SO6%LDsXz@SY+=cK_QMmXBIU)j!$ajc-zLx3V60EXJ!qC zi<%2x8Q24YN+&8U@CIlN zrZkcT9yh%LrlGS9`G)KdP(@9Eo-AQz@8GEFWcb7U=a0H^ZVbLmz{+&M7W(nXJ4sN8 zJLR7eeK(K8`2-}j(T7JsO`L!+CvbueT%izanm-^A1Dn{`1Nw`9P?cq;7no+XfC`K(GO9?O^5zNIt4M+M8LM0=7Gz8UA@Z0N+lg+cX)NfazRu z5D)~HA^(u%w^cz+@2@_#S|u>GpB+j4KzQ^&Wcl9f z&hG#bCA(Yk0D&t&aJE^xME^&E-&xGHhXn%}psEIj641H+Nl-}boj;)Zt*t(4wZ5DN z@GXF$bL=&pBq-#vkTkh>7hl%K5|3 z{`Vn9b$iR-SoGENp}bn4;fR3>9sA%X2@1L3aE9yTra;Wb#_`xWwLSLdfu+PAu+o3| zGVnpzPr=ch{uuoHjtw7+_!L_2;knQ!DuDl0R`|%jr+}jFzXtrHIKc323?JO{l&;VF z*L1+}JU7%QJOg|5|Tc|D8fN zJORAg=_vsy{ak|o);@)Yh8Lkcg@$FG3k@ep36BRa^>~UmnRPziS>Z=`Jb2x*Q#`%A zU*i3&Vg?TluO@X0O;r2Jl6LKLUOVhSqg1*qOt^|8*c7 zo(298@+r$k_wQNGHv{|$tW(T8L+4_`FQ{kEW5Jgg{yf7ey4ss_(SNKfz(N9lx&a;< je(UuV8hP?p&}TPdm1I$XmG#(RzlD&B2izSj9sl%y5~4qc diff --git a/docker/spring-cloud-contract-docker/project/gradle/wrapper/gradle-wrapper.properties b/docker/spring-cloud-contract-docker/project/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index ac72c34e8a..0000000000 --- a/docker/spring-cloud-contract-docker/project/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/docker/spring-cloud-contract-docker/project/gradlew b/docker/spring-cloud-contract-docker/project/gradlew deleted file mode 100755 index 0adc8e1a53..0000000000 --- a/docker/spring-cloud-contract-docker/project/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/docker/spring-cloud-contract-docker/project/gradlew.bat b/docker/spring-cloud-contract-docker/project/gradlew.bat deleted file mode 100644 index 6689b85bee..0000000000 --- a/docker/spring-cloud-contract-docker/project/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/docker/spring-cloud-contract-docker/project/src/test/java/contracts/ContractTestsBase.java b/docker/spring-cloud-contract-docker/project/src/test/java/contracts/ContractTestsBase.java deleted file mode 100644 index 7606736283..0000000000 --- a/docker/spring-cloud-contract-docker/project/src/test/java/contracts/ContractTestsBase.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts; - -import java.time.Duration; -import java.util.concurrent.TimeUnit; - -import io.restassured.RestAssured; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.TestInfo; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.cloud.contract.verifier.converter.YamlContract; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver; -import org.springframework.cloud.contract.verifier.messaging.amqp.AmqpMetadata; -import org.springframework.cloud.contract.verifier.messaging.boot.AutoConfigureMessageVerifier; -import org.springframework.cloud.contract.verifier.messaging.camel.StandaloneMetadata; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessageMetadata; -import org.springframework.cloud.contract.verifier.util.ContractVerifierUtil; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.util.StringUtils; -import org.springframework.web.client.RestTemplate; - -/** - * @author Marcin Grzejszczak - */ -@SpringBootTest(classes = ContractTestsBase.Config.class, webEnvironment = SpringBootTest.WebEnvironment.NONE) -@AutoConfigureMessageVerifier -public abstract class ContractTestsBase { - - private static final Logger log = LoggerFactory.getLogger(ContractTestsBase.class); - - /** - * URL at which the application is running. - */ - @Value("${APPLICATION_BASE_URL}") - String url; - - /** - * Optional username to access the application. - */ - @Value("${APPLICATION_USERNAME:}") - String username; - - /** - * Optional password to access the application. - */ - @Value("${APPLICATION_PASSWORD:}") - String password; - - /** - * Timeout to connect to the application to trigger a message. - */ - @Value("${MESSAGING_TRIGGER_CONNECT_TIMEOUT:5000}") - Integer connectTimeout; - - /** - * Timeout to read the response from the application to trigger a message. - */ - @Value("${MESSAGING_TRIGGER_READ_TIMEOUT:5000}") - Integer readTimeout; - - /** - * Defines the messaging type when dealing with message based contracts. - */ - @Value("${MESSAGING_TYPE:}") - String messagingType; - - @Autowired - MessageVerifierReceiver messageVerifier; - - @BeforeEach - public void setup(TestInfo testInfo) { - RestAssured.baseURI = this.url; - if (StringUtils.hasText(this.username)) { - RestAssured.authentication = RestAssured.basic(this.username, this.password); - } - setupMessagingFromContract(testInfo); - } - - private void setupMessagingFromContract(TestInfo testInfo) { - try { - YamlContract contract = ContractVerifierUtil.contract(this, testInfo.getDisplayName()); - setupMessagingIfPresent(contract); - } catch (Exception e) { - log.warn("An exception occurred while trying to setup messaging from contract", e); - } - } - - private void setupMessagingIfPresent(YamlContract contract) { - if (contract.input == null && contract.outputMessage == null) { - return; - } - setupAmqpIfPresent(contract); - setupStandaloneIfPresent(contract); - } - - private void setupAmqpIfPresent(YamlContract contract) { - AmqpMetadata amqpMetadata = AmqpMetadata.fromMetadata(contract.metadata); - if (isMessagingType("rabbit") && hasDeclaredOutputQueue(amqpMetadata) || isMessagingType("kafka")) { - log.info("First will try to receive a message to setup the connection with the broker"); - if (contract.outputMessage != null && StringUtils.hasText(contract.outputMessage.sentTo)){ - setupConnection(contract.outputMessage.sentTo, contract); - } - } - } - - private void setupStandaloneIfPresent(YamlContract contract) { - StandaloneMetadata metadata = StandaloneMetadata.fromMetadata(contract.metadata); - if (StringUtils.hasText(metadata.getSetup().getOptions())) { - log.info("First will try to receive a message to setup the connection with the broker"); - setMessageType(contract, ContractVerifierMessageMetadata.MessageType.SETUP); - setupConnection(metadata.getSetup().getOptions(), contract); - } - } - - private void setMessageType(YamlContract contract, - ContractVerifierMessageMetadata.MessageType output) { - contract.metadata.put(ContractVerifierMessageMetadata.METADATA_KEY, - new ContractVerifierMessageMetadata(output)); - } - - private void setupConnection(String destination, YamlContract contract) { - if (!StringUtils.hasText(destination)) { - return; - } - log.info("Setting up destination [{}]", destination); - this.messageVerifier.receive(destination, 100, TimeUnit.MILLISECONDS, contract); - } - - private boolean hasDeclaredOutputQueue(AmqpMetadata amqpMetadata) { - return StringUtils.hasText(amqpMetadata.getOutputMessage().getConnectToBroker().getDeclareQueueWithName()); - } - - private boolean isMessagingType(String rabbit) { - return rabbit.equalsIgnoreCase(this.messagingType); - } - - public void triggerMessage(String label) { - String url = this.url + "/springcloudcontract/" + label; - log.info("Will send a request to [{}] in order to trigger a message", url); - restTemplate().postForObject(url, "", String.class); - } - - private RestTemplate restTemplate() { - RestTemplateBuilder builder = new RestTemplateBuilder() - .setConnectTimeout(Duration.ofMillis(this.connectTimeout)) - .setReadTimeout(Duration.ofMillis(this.readTimeout)); - if (StringUtils.hasText(this.username)) { - builder = builder.basicAuthentication(this.username, this.password); - } - return builder.build(); - } - - @Configuration - @Import(MessagingAutoConfig.class) - @EnableAutoConfiguration - protected static class Config { - - } - -} diff --git a/docker/spring-cloud-contract-docker/project/src/test/java/contracts/MessagingAutoConfig.java b/docker/spring-cloud-contract-docker/project/src/test/java/contracts/MessagingAutoConfig.java deleted file mode 100644 index 2491dffb61..0000000000 --- a/docker/spring-cloud-contract-docker/project/src/test/java/contracts/MessagingAutoConfig.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts; - -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import org.apache.camel.ConsumerTemplate; -import org.apache.camel.Exchange; -import org.apache.camel.Message; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.amqp.core.MessageProperties; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cloud.contract.verifier.converter.YamlContract; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender; -import org.springframework.cloud.contract.verifier.messaging.amqp.AmqpMetadata; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessageMetadata; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging; -import org.springframework.cloud.contract.verifier.messaging.kafka.KafkaMetadata; -import org.springframework.cloud.contract.verifier.messaging.noop.NoOpStubMessages; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import org.springframework.util.StringUtils; - -/** - * @author Marcin Grzejszczak - */ -@Configuration -@ConditionalOnProperty("MESSAGING_TYPE") -@Profile("messagingtype") -public class MessagingAutoConfig { - - /** - * Type of messaging. Can be either [rabbit] or [kafka]. - */ - @Value("${MESSAGING_TYPE:}") - String messagingType; - - /** - * For RabbitMQ - brokers addresses. - */ - @Value("${SPRING_RABBITMQ_ADDRESSES:}") - String springRabbitmqAddresses; - - /** - * For Kafka - brokers addresses. - */ - @Value("${SPRING_KAFKA_BOOTSTRAP_SERVERS:}") - String springKafkaBootstrapServers; - - @Bean - public ContractVerifierMessaging contractVerifierMessaging(MessageVerifierReceiver receiver) { - return new ContractVerifierCamelHelper(new NoOpStubMessages(), receiver); - } - - @Bean - MessageVerifierReceiver manualMessageVerifier(ConsumerTemplate consumerTemplate) { - return new MessageVerifierReceiver() { - - private final Logger log = LoggerFactory.getLogger(MessageVerifierReceiver.class); - - @Override - public Message receive(String destination, long timeout, TimeUnit timeUnit, YamlContract yamlContract) { - String uri = messagingType() + "://" + destination + additionalOptions(yamlContract); - log.info("Camel URI [{}]", uri); - Exchange exchange = consumerTemplate.receive(uri, timeUnit.toMillis(timeout)); - if (exchange == null) { - return null; - } - return exchange.getMessage(); - } - - private String messagingType() { - if (messagingType.equalsIgnoreCase("kafka")) { - return "kafka"; - } - return "rabbitmq"; - } - - private String additionalOptions(YamlContract contract) { - if (contract == null) { - return ""; - } - if (messagingType.equalsIgnoreCase("kafka")) { - return setKafkaOpts(contract); - } - return setRabbitOpts(contract); - } - - private String setKafkaOpts(YamlContract contract) { - String opts = defaultOpts(contract); - KafkaMetadata metadata = KafkaMetadata.fromMetadata(contract.metadata); - ContractVerifierMessageMetadata messageMetadata = ContractVerifierMessageMetadata.fromMetadata(contract.metadata); - if (inputMessage(messageMetadata) && StringUtils.hasText(metadata.getInput().getConnectToBroker().getAdditionalOptions())) { - return opts + "&" + metadata.getInput().getConnectToBroker().getAdditionalOptions(); - } - else if (StringUtils.hasText(metadata.getOutputMessage().getConnectToBroker().getAdditionalOptions())) { - return opts + "&" + metadata.getOutputMessage().getConnectToBroker().getAdditionalOptions(); - } - return opts; - } - - private String defaultOpts(YamlContract contract) { - String consumerGroup = sameConsumerGroupForSameContract(contract); - return "?brokers=" + getRequiredProperty("SPRING_KAFKA_BOOTSTRAP_SERVERS", springKafkaBootstrapServers) + "&autoOffsetReset=latest&groupId=" + consumerGroup + "&shutdownTimeout=5"; - } - - private String sameConsumerGroupForSameContract(YamlContract contract) { - return contract.input.hashCode() + "_" + contract.outputMessage.hashCode(); - } - - private String setRabbitOpts(YamlContract contract) { - String opts = "?addresses=" + getRequiredProperty("SPRING_RABBITMQ_ADDRESSES", springRabbitmqAddresses); - AmqpMetadata metadata = AmqpMetadata.fromMetadata(contract.metadata); - ContractVerifierMessageMetadata messageMetadata = ContractVerifierMessageMetadata.fromMetadata(contract.metadata); - if (inputMessage(messageMetadata) && StringUtils.hasText(metadata.getInput().getConnectToBroker().getAdditionalOptions())) { - return opts + "&" + metadata.getInput().getConnectToBroker().getAdditionalOptions(); - } - else if (StringUtils.hasText(metadata.getOutputMessage().getConnectToBroker().getAdditionalOptions())) { - return opts + "&" + metadata.getOutputMessage().getConnectToBroker().getAdditionalOptions(); - } - return defaultOpts(opts, metadata, messageMetadata); - } - - private String getRequiredProperty(String name, String value) { - if (!StringUtils.hasText(value)) { - throw new IllegalStateException("The property [" + name + "] must not be empty!"); - } - return value; - } - - private boolean inputMessage(ContractVerifierMessageMetadata messageMetadata) { - return messageMetadata.getMessageType() == ContractVerifierMessageMetadata.MessageType.INPUT; - } - - private String defaultOpts(String opts, AmqpMetadata amqpMetadata, ContractVerifierMessageMetadata messageMetadata) { - AmqpMetadata.ConnectToBroker connectToBroker = inputMessage(messageMetadata) ? amqpMetadata.getInput().getConnectToBroker() : amqpMetadata.getOutputMessage().getConnectToBroker(); - MessageProperties messageProperties = inputMessage(messageMetadata) ? amqpMetadata.getInput().getMessageProperties() : amqpMetadata.getOutputMessage().getMessageProperties(); - if (StringUtils.hasText(connectToBroker.getDeclareQueueWithName())) { - opts = opts + "&queue=" + connectToBroker.getDeclareQueueWithName(); - } - if (messageProperties != null && StringUtils.hasText(messageProperties.getReceivedRoutingKey())) { - opts = opts + "&routingKey=" + messageProperties.getReceivedRoutingKey(); - } - return opts; - } - - @Override - public Message receive(String destination, YamlContract yamlContract) { - return receive(destination, 5, TimeUnit.SECONDS, yamlContract); - } - - }; - } - -} - -class ContractVerifierCamelHelper extends ContractVerifierMessaging { - - ContractVerifierCamelHelper(MessageVerifierSender sender, MessageVerifierReceiver receiver) { - super(sender, receiver); - } - - @Override - protected ContractVerifierMessage convert(Message receive) { - if (receive == null) { - return null; - } - return new ContractVerifierMessage(receive.getBody(), receive.getHeaders()); - } - -} diff --git a/docker/spring-cloud-contract-docker/project/src/test/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/docker/spring-cloud-contract-docker/project/src/test/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index 45330bbdc5..0000000000 --- a/docker/spring-cloud-contract-docker/project/src/test/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1 +0,0 @@ -contracts.MessagingAutoConfig diff --git a/docker/spring-cloud-contract-docker/project/src/test/resources/application-messagingtype.yml b/docker/spring-cloud-contract-docker/project/src/test/resources/application-messagingtype.yml deleted file mode 100644 index 462cdc5878..0000000000 --- a/docker/spring-cloud-contract-docker/project/src/test/resources/application-messagingtype.yml +++ /dev/null @@ -1 +0,0 @@ -stubrunner.camel.enabled: false \ No newline at end of file diff --git a/docker/spring-cloud-contract-docker/sdkman.config b/docker/spring-cloud-contract-docker/sdkman.config deleted file mode 100644 index b6578f6f4b..0000000000 --- a/docker/spring-cloud-contract-docker/sdkman.config +++ /dev/null @@ -1,8 +0,0 @@ -# make gvm non-interactive, great for CI environments -sdkman_auto_answer=true - -# don't prompt user to selfupdate on new shell -sdkman_suggestive_selfupdate=false - -# don't perform automatic selfupdates -sdkman_auto_selfupdate=false \ No newline at end of file diff --git a/docker/spring-cloud-contract-docker/sdkman/sdkman-wrapper.sh b/docker/spring-cloud-contract-docker/sdkman/sdkman-wrapper.sh deleted file mode 100755 index 673ffaaf78..0000000000 --- a/docker/spring-cloud-contract-docker/sdkman/sdkman-wrapper.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -# A quick wrapper to source the gvm env and run it -# This is used to run gvm in Dockerfile RUN commands -# since the RUN commands does not use interactive shells - -[[ -s "/home/scc/.sdkman/bin/sdkman-init.sh" ]] && source "/home/scc/.sdkman/bin/sdkman-init.sh" && sdk $@ diff --git a/docker/spring-cloud-contract-stub-runner-docker/Dockerfile b/docker/spring-cloud-contract-stub-runner-docker/Dockerfile deleted file mode 100644 index 509f6148b1..0000000000 --- a/docker/spring-cloud-contract-stub-runner-docker/Dockerfile +++ /dev/null @@ -1,40 +0,0 @@ -FROM ubuntu:20.04 - -ARG SDKMAN_JAVA_INSTALLATION=17.0.1-tem -ARG THIN_REPO=https://repo.spring.io/snapshot - -LABEL Author="Marcin Grzejszczak " -LABEL Author="Bastian Doetsch " - -RUN apt-get update && apt-get install -y curl \ - unzip \ - zip \ - && apt-get clean - -RUN useradd -u1000 -m scc - -# Install sdkman and java -COPY sdkman/ /usr/local/bin/ -RUN chmod +x /usr/local/bin/sdkman-wrapper.sh - -USER scc -WORKDIR /home/scc - -RUN curl -s https://get.sdkman.io/ | bash -COPY --chown=scc sdkman.config /home/scc/.sdkman/etc/config -RUN bash -c "source /home/scc/.sdkman/bin/sdkman-init.sh" -RUN bash -c "sdkman-wrapper.sh install java ${SDKMAN_JAVA_INSTALLATION}" -ENV JAVA_HOME /home/scc/.sdkman/candidates/java/current/ -ENV PATH "${PATH}:${JAVA_HOME}/bin" - -# Spring Cloud Contract -ENV SERVER_PORT 8750 -VOLUME /tmp -COPY --chown=scc:scc target/maven_dependencies /home/scc/.m2/repository/ -COPY --chown=scc:scc target/libs/stub-runner-boot.jar stub-runner-boot.jar -RUN echo "Fetching dependencies, please wait..." -RUN java -Dthin.dryrun=true -jar stub-runner-boot.jar --thin.repo=${THIN_REPO} -RUN java -Dthin.dryrun=true -jar stub-runner-boot.jar --thin.profile=rabbit --thin.repo=${THIN_REPO} -RUN java -Dthin.dryrun=true -jar stub-runner-boot.jar --thin.profile=kafka --thin.repo=${THIN_REPO} -COPY --chown=scc:scc run.sh run.sh -ENTRYPOINT ["./run.sh"] diff --git a/docker/spring-cloud-contract-stub-runner-docker/log.log b/docker/spring-cloud-contract-stub-runner-docker/log.log new file mode 100644 index 0000000000..713025d269 --- /dev/null +++ b/docker/spring-cloud-contract-stub-runner-docker/log.log @@ -0,0 +1,176 @@ +[INFO] Scanning for projects... +[INFO] +[INFO] --< org.springframework.cloud:spring-cloud-contract-stub-runner-docker >-- +[INFO] Building Spring Cloud Contract Stub Runner Docker 4.0.0-SNAPSHOT +[INFO] --------------------------------[ pom ]--------------------------------- +[INFO] +[INFO] --- maven-dependency-plugin:3.1.2:tree (default-cli) @ spring-cloud-contract-stub-runner-docker --- +[INFO] org.springframework.cloud:spring-cloud-contract-stub-runner-docker:pom:4.0.0-SNAPSHOT +[INFO] +- org.springframework.cloud:spring-cloud-contract-parent:pom:4.0.0-SNAPSHOT:runtime +[INFO] +- org.springframework.cloud:spring-cloud-commons-dependencies:pom:4.0.0-SNAPSHOT:runtime +[INFO] +- org.springframework.cloud:spring-cloud-contract-dependencies:pom:4.0.0-SNAPSHOT:runtime +[INFO] +- org.springframework.cloud:spring-cloud-netflix-dependencies:pom:4.0.0-SNAPSHOT:runtime +[INFO] +- org.springframework.cloud:spring-cloud-zookeeper-dependencies:pom:4.0.0-SNAPSHOT:runtime +[INFO] +- org.springframework.cloud:spring-cloud-consul-dependencies:pom:4.0.0-SNAPSHOT:runtime +[INFO] +- org.springframework.cloud:spring-cloud-stream-dependencies:pom:4.0.0-SNAPSHOT:runtime +[INFO] +- org.springframework.cloud:spring-cloud-contract-stub-runner-boot:jar:4.0.0-SNAPSHOT:compile +[INFO] | +- org.springframework.cloud:spring-cloud-starter-contract-stub-runner:jar:4.0.0-SNAPSHOT:compile +[INFO] | | +- org.springframework.cloud:spring-cloud-contract-stub-runner:jar:4.0.0-SNAPSHOT:compile +[INFO] | | | +- org.springframework.cloud:spring-cloud-contract-verifier:jar:4.0.0-SNAPSHOT:compile +[INFO] | | | | +- javax.inject:javax.inject:jar:1:compile +[INFO] | | | | +- com.toomuchcoding.jsonassert:jsonassert:jar:0.6.2:compile +[INFO] | | | | +- com.rackspace.eclipse.webtools.sourceediting:org.eclipse.wst.xml.xpath2.processor:jar:2.1.100:compile +[INFO] | | | | | +- edu.princeton.cup:java-cup:jar:10k:compile +[INFO] | | | | | \- com.ibm.icu:icu4j:jar:4.6:compile +[INFO] | | | | +- org.apache.groovy:groovy-nio:jar:4.0.0:compile +[INFO] | | | | +- org.apache.groovy:groovy-json:jar:4.0.0:compile +[INFO] | | | | +- org.apache.groovy:groovy-xml:jar:4.0.0:compile +[INFO] | | | | +- com.github.jknack:handlebars:jar:4.3.0:compile +[INFO] | | | | +- commons-beanutils:commons-beanutils:jar:1.9.4:compile +[INFO] | | | | | +- commons-logging:commons-logging:jar:1.2:compile +[INFO] | | | | | \- commons-collections:commons-collections:jar:3.2.2:compile +[INFO] | | | | +- com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:jar:2.14.0-rc3:compile +[INFO] | | | | +- net.javacrumbs.json-unit:json-unit-assertj:jar:2.32.0:compile +[INFO] | | | | | +- net.javacrumbs.json-unit:json-unit-core:jar:2.32.0:compile +[INFO] | | | | | | \- org.hamcrest:hamcrest-core:jar:1.3:test +[INFO] | | | | | \- net.javacrumbs.json-unit:json-unit-json-path:jar:2.32.0:compile +[INFO] | | | | \- org.junit.jupiter:junit-jupiter-api:jar:5.9.1:compile +[INFO] | | | | +- org.opentest4j:opentest4j:jar:1.2.0:compile +[INFO] | | | | +- org.junit.platform:junit-platform-commons:jar:1.9.1:compile +[INFO] | | | | \- org.apiguardian:apiguardian-api:jar:1.1.2:compile +[INFO] | | | +- org.springframework.cloud:spring-cloud-contract-shade:jar:4.0.0-SNAPSHOT:compile +[INFO] | | | +- org.springframework.cloud:spring-cloud-contract-converters:jar:4.0.0-SNAPSHOT:compile +[INFO] | | | +- org.springframework.cloud:spring-cloud-contract-spec:jar:4.0.0-SNAPSHOT:compile +[INFO] | | | | \- org.springframework.cloud:spring-cloud-contract-spec-groovy:jar:4.0.0-SNAPSHOT:compile +[INFO] | | | +- org.eclipse.jgit:org.eclipse.jgit:jar:6.1.0.202203080745-r:compile +[INFO] | | | | \- com.googlecode.javaewah:JavaEWAH:jar:1.1.13:compile +[INFO] | | | +- org.eclipse.jgit:org.eclipse.jgit.ssh.jsch:jar:6.1.0.202203080745-r:compile +[INFO] | | | | +- com.jcraft:jsch:jar:0.1.55:compile +[INFO] | | | | \- com.jcraft:jzlib:jar:1.1.1:compile +[INFO] | | | +- com.jcraft:jsch.agentproxy.sshagent:jar:0.0.9:compile +[INFO] | | | | \- com.jcraft:jsch.agentproxy.core:jar:0.0.9:compile +[INFO] | | | +- com.jcraft:jsch.agentproxy.jsch:jar:0.0.9:compile +[INFO] | | | \- com.jcraft:jsch.agentproxy.usocket-jna:jar:0.0.9:compile +[INFO] | | | \- net.java.dev.jna:jna-platform:jar:4.1.0:compile +[INFO] | | +- org.springframework.boot:spring-boot-starter-test:jar:3.0.0-RC2:compile +[INFO] | | | +- org.springframework.boot:spring-boot-test:jar:3.0.0-RC2:compile +[INFO] | | | +- org.springframework.boot:spring-boot-test-autoconfigure:jar:3.0.0-RC2:compile +[INFO] | | | +- com.jayway.jsonpath:json-path:jar:2.7.0:compile +[INFO] | | | | \- net.minidev:json-smart:jar:2.4.8:compile +[INFO] | | | | \- net.minidev:accessors-smart:jar:2.4.8:compile +[INFO] | | | | \- org.ow2.asm:asm:jar:9.1:compile +[INFO] | | | +- jakarta.xml.bind:jakarta.xml.bind-api:jar:4.0.0:compile +[INFO] | | | | \- jakarta.activation:jakarta.activation-api:jar:2.1.0:compile +[INFO] | | | +- org.assertj:assertj-core:jar:3.23.1:compile +[INFO] | | | | \- net.bytebuddy:byte-buddy:jar:1.12.18:compile +[INFO] | | | +- org.hamcrest:hamcrest:jar:2.2:compile +[INFO] | | | +- org.junit.jupiter:junit-jupiter:jar:5.9.1:compile +[INFO] | | | | +- org.junit.jupiter:junit-jupiter-params:jar:5.9.1:compile +[INFO] | | | | \- org.junit.jupiter:junit-jupiter-engine:jar:5.9.1:runtime +[INFO] | | | | \- org.junit.platform:junit-platform-engine:jar:1.9.1:runtime +[INFO] | | | +- org.mockito:mockito-core:jar:2.23.0:test +[INFO] | | | | +- net.bytebuddy:byte-buddy-agent:jar:1.12.18:test +[INFO] | | | | \- org.objenesis:objenesis:jar:2.6:test +[INFO] | | | +- org.mockito:mockito-junit-jupiter:jar:4.8.1:compile +[INFO] | | | +- org.skyscreamer:jsonassert:jar:1.5.1:compile +[INFO] | | | | \- com.vaadin.external.google:android-json:jar:0.0.20131108.vaadin1:compile +[INFO] | | | +- org.springframework:spring-core:jar:6.0.0-RC4:compile +[INFO] | | | +- org.springframework:spring-test:jar:6.0.0-RC4:compile +[INFO] | | | \- org.xmlunit:xmlunit-core:jar:2.9.0:compile +[INFO] | | +- org.springframework.cloud:spring-cloud-contract-wiremock:jar:4.0.0-SNAPSHOT:compile +[INFO] | | | +- jakarta.servlet:jakarta.servlet-api:jar:6.0.0:compile +[INFO] | | | +- com.github.tomakehurst:wiremock-jre8-standalone:jar:2.35.0:compile +[INFO] | | | +- org.apache.httpcomponents.client5:httpclient5:jar:5.1.3:compile +[INFO] | | | | +- org.apache.httpcomponents.core5:httpcore5:jar:5.1.4:compile +[INFO] | | | | +- org.apache.httpcomponents.core5:httpcore5-h2:jar:5.1.4:compile +[INFO] | | | | \- commons-codec:commons-codec:jar:1.15:compile +[INFO] | | | \- org.springframework.cloud:spring-cloud-test-support:jar:4.0.0-SNAPSHOT:compile +[INFO] | | | +- org.apache.maven.resolver:maven-resolver-connector-basic:jar:1.4.1:compile +[INFO] | | | | +- org.apache.maven.resolver:maven-resolver-spi:jar:1.4.1:compile +[INFO] | | | | \- org.apache.maven.resolver:maven-resolver-util:jar:1.4.1:compile +[INFO] | | | +- org.apache.maven.resolver:maven-resolver-impl:jar:1.4.1:compile +[INFO] | | | +- org.apache.maven:maven-resolver-provider:jar:3.6.3:compile +[INFO] | | | | +- org.apache.maven:maven-model:jar:3.6.3:compile +[INFO] | | | | +- org.apache.maven:maven-model-builder:jar:3.6.3:compile +[INFO] | | | | | +- org.codehaus.plexus:plexus-interpolation:jar:1.25:compile +[INFO] | | | | | +- org.apache.maven:maven-artifact:jar:3.6.3:compile +[INFO] | | | | | \- org.apache.maven:maven-builder-support:jar:3.6.3:compile +[INFO] | | | | \- org.apache.maven:maven-repository-metadata:jar:3.6.3:compile +[INFO] | | | \- org.apache.maven.resolver:maven-resolver-transport-http:jar:1.4.1:compile +[INFO] | | | +- org.apache.httpcomponents:httpclient:jar:4.5.13:compile +[INFO] | | | \- org.apache.httpcomponents:httpcore:jar:4.4.15:compile +[INFO] | | +- org.apache.maven.resolver:maven-resolver-api:jar:1.4.1:compile +[INFO] | | \- org.sonatype.sisu:sisu-inject-plexus:jar:2.6.0:compile +[INFO] | | +- org.codehaus.plexus:plexus-component-annotations:jar:1.7.1:compile +[INFO] | | +- org.codehaus.plexus:plexus-classworlds:jar:2.5.2:compile +[INFO] | | +- org.codehaus.plexus:plexus-utils:jar:3.0.18:compile +[INFO] | | +- org.sonatype.sisu:sisu-inject-bean:jar:2.6.0:compile +[INFO] | | | +- javax.enterprise:cdi-api:jar:1.0:compile +[INFO] | | | | \- javax.annotation:jsr250-api:jar:1.0:compile +[INFO] | | | +- org.sonatype.sisu:sisu-guice:jar:no_aop:3.2.6:compile +[INFO] | | | | \- com.google.guava:guava:jar:16.0.1:compile +[INFO] | | | \- org.eclipse.sisu:org.eclipse.sisu.inject:jar:0.3.3:compile +[INFO] | | \- org.eclipse.sisu:org.eclipse.sisu.plexus:jar:0.3.3:compile +[INFO] | +- org.springframework.cloud:spring-cloud-contract-spec-kotlin:jar:4.0.0-SNAPSHOT:compile +[INFO] | | +- org.springframework.cloud:spring-cloud-contract-spec-java:jar:4.0.0-SNAPSHOT:compile +[INFO] | | | +- org.apache.groovy:groovy:jar:4.0.0:compile +[INFO] | | | +- dk.brics:automaton:jar:1.12-4:compile +[INFO] | | | +- org.apache.commons:commons-text:jar:1.10.0:compile +[INFO] | | | | \- org.apache.commons:commons-lang3:jar:3.12.0:compile +[INFO] | | | \- org.springframework:spring-jcl:jar:6.0.0-RC4:compile +[INFO] | | +- org.jetbrains.kotlin:kotlin-stdlib-jdk8:jar:1.6.21:compile +[INFO] | | | +- org.jetbrains.kotlin:kotlin-stdlib:jar:1.6.21:compile +[INFO] | | | | +- org.jetbrains.kotlin:kotlin-stdlib-common:jar:1.6.21:compile +[INFO] | | | | \- org.jetbrains:annotations:jar:13.0:compile +[INFO] | | | \- org.jetbrains.kotlin:kotlin-stdlib-jdk7:jar:1.6.21:compile +[INFO] | | +- org.jetbrains.kotlin:kotlin-compiler-embeddable:jar:1.6.21:compile +[INFO] | | | +- org.jetbrains.kotlin:kotlin-script-runtime:jar:1.6.21:compile +[INFO] | | | +- org.jetbrains.kotlin:kotlin-reflect:jar:1.6.21:runtime +[INFO] | | | +- org.jetbrains.kotlin:kotlin-daemon-embeddable:jar:1.6.21:runtime +[INFO] | | | +- org.jetbrains.intellij.deps:trove4j:jar:1.0.20200330:compile +[INFO] | | | \- net.java.dev.jna:jna:jar:5.6.0:compile +[INFO] | | +- org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:jar:1.6.21:compile +[INFO] | | | \- org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:jar:1.6.21:runtime +[INFO] | | | \- org.jetbrains.kotlin:kotlin-scripting-common:jar:1.6.21:compile +[INFO] | | \- org.jetbrains.kotlin:kotlin-script-util:jar:1.6.21:compile +[INFO] | | +- org.jetbrains.kotlin:kotlin-scripting-jvm:jar:1.6.21:compile +[INFO] | | \- org.jetbrains.kotlin:kotlin-daemon-client:jar:1.6.21:compile +[INFO] | | \- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:jar:1.6.4:compile +[INFO] | \- org.springframework.boot:spring-boot-starter-web:jar:3.0.0-RC2:compile +[INFO] | +- org.springframework.boot:spring-boot-starter:jar:3.0.0-RC2:compile +[INFO] | | +- org.springframework.boot:spring-boot:jar:3.0.0-RC2:compile +[INFO] | | +- org.springframework.boot:spring-boot-autoconfigure:jar:3.0.0-RC2:compile +[INFO] | | +- org.springframework.boot:spring-boot-starter-logging:jar:3.0.0-RC2:compile +[INFO] | | | +- ch.qos.logback:logback-classic:jar:1.4.4:compile +[INFO] | | | | \- ch.qos.logback:logback-core:jar:1.4.4:compile +[INFO] | | | +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.19.0:compile +[INFO] | | | | \- org.apache.logging.log4j:log4j-api:jar:2.19.0:compile +[INFO] | | | \- org.slf4j:jul-to-slf4j:jar:2.0.3:compile +[INFO] | | +- jakarta.annotation:jakarta.annotation-api:jar:2.1.1:compile +[INFO] | | \- org.yaml:snakeyaml:jar:1.33:compile +[INFO] | +- org.springframework.boot:spring-boot-starter-json:jar:3.0.0-RC2:compile +[INFO] | | +- com.fasterxml.jackson.core:jackson-databind:jar:2.14.0-rc3:compile +[INFO] | | | +- com.fasterxml.jackson.core:jackson-annotations:jar:2.14.0-rc3:compile +[INFO] | | | \- com.fasterxml.jackson.core:jackson-core:jar:2.14.0-rc3:compile +[INFO] | | +- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.14.0-rc3:compile +[INFO] | | +- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.14.0-rc3:compile +[INFO] | | \- com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.14.0-rc3:compile +[INFO] | +- org.springframework.boot:spring-boot-starter-tomcat:jar:3.0.0-RC2:compile +[INFO] | | +- org.apache.tomcat.embed:tomcat-embed-core:jar:10.1.1:compile +[INFO] | | +- org.apache.tomcat.embed:tomcat-embed-el:jar:10.1.1:compile +[INFO] | | \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:10.1.1:compile +[INFO] | +- org.springframework:spring-web:jar:6.0.0-RC4:compile +[INFO] | | +- org.springframework:spring-beans:jar:6.0.0-RC4:compile +[INFO] | | \- io.micrometer:micrometer-observation:jar:1.10.0:compile +[INFO] | | \- io.micrometer:micrometer-commons:jar:1.10.0:compile +[INFO] | \- org.springframework:spring-webmvc:jar:6.0.0-RC4:compile +[INFO] | +- org.springframework:spring-aop:jar:6.0.0-RC4:compile +[INFO] | +- org.springframework:spring-context:jar:6.0.0-RC4:compile +[INFO] | \- org.springframework:spring-expression:jar:6.0.0-RC4:compile +[INFO] \- org.slf4j:slf4j-api:jar:2.0.3:compile +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ +[INFO] Total time: 0.694 s +[INFO] Finished at: 2022-11-16T14:05:27+01:00 +[INFO] ------------------------------------------------------------------------ diff --git a/docker/spring-cloud-contract-stub-runner-docker/pom.xml b/docker/spring-cloud-contract-stub-runner-docker/pom.xml deleted file mode 100644 index d85f56a027..0000000000 --- a/docker/spring-cloud-contract-stub-runner-docker/pom.xml +++ /dev/null @@ -1,301 +0,0 @@ - - - 4.0.0 - - - org.springframework.cloud - spring-cloud-contract-docker-parent - 4.1.0-SNAPSHOT - .. - - - spring-cloud-contract-stub-runner-docker - pom - 4.1.0-SNAPSHOT - Spring Cloud Contract Stub Runner Docker - Spring Cloud Contract Stub Runner Docker - - - https://repo.spring.io/snapshot - - - - - - org.springframework.cloud - spring-cloud-contract-parent - ${project.version} - pom - runtime - - - org.springframework.cloud - spring-cloud-commons-dependencies - ${spring-cloud-commons.version} - pom - runtime - - - org.springframework.cloud - spring-cloud-contract-dependencies - ${project.version} - pom - runtime - - - org.springframework.cloud - spring-cloud-netflix-dependencies - ${spring-cloud-netflix.version} - pom - runtime - - - org.springframework.cloud - spring-cloud-zookeeper-dependencies - ${spring-cloud-zookeeper.version} - pom - runtime - - - org.springframework.cloud - spring-cloud-consul-dependencies - ${spring-cloud-consul.version} - pom - runtime - - - org.springframework.cloud - spring-cloud-stream-dependencies - ${spring-cloud-stream.version} - pom - runtime - - - org.springframework.cloud - spring-cloud-dependencies-parent - ${spring-cloud-build.version} - pom - runtime - - - org.springframework.cloud - spring-cloud-build-dependencies - ${spring-cloud-build.version} - pom - runtime - - - org.springframework.boot.experimental - spring-boot-thin-layout - ${thin-jar.version} - - - org.springframework.boot.experimental - spring-boot-thin-launcher - ${thin-jar.version} - exec - - - - - org.springframework.cloud - spring-cloud-contract-stub-runner-boot - compile - - - org.springframework.cloud - spring-cloud-contract-wiremock - compile - - - org.springframework.cloud - spring-cloud-contract-tools - ${project.version} - pom - runtime - - - org.springframework.cloud - spring-cloud-contract-spec - compile - - - org.springframework.cloud - spring-cloud-contract-spec-java - compile - - - org.springframework.cloud - spring-cloud-contract-spec-groovy - compile - - - org.springframework.cloud - spring-cloud-contract-spec-kotlin - compile - - - org.springframework.cloud - spring-cloud-contract-verifier - compile - - - org.springframework.cloud - spring-cloud-contract-converters - compile - - - org.springframework.cloud - spring-cloud-contract-stub-runner - compile - - - org.springframework.cloud - spring-cloud-contract-shade - compile - - - org.springframework.cloud - spring-cloud-starter-contract-verifier - compile - - - org.springframework.cloud - spring-cloud-starter-contract-stub-runner - compile - - - org.springframework.cloud - spring-cloud-starter-contract-stub-runner-jetty - compile - - - org.springframework.boot.experimental - spring-boot-thin-launcher - ${thin-jar.version} - exec - compile - - - - - org.slf4j - slf4j-api - ${slf4j.version} - compile - - - org.springframework.cloud - spring-cloud-build - ${spring-cloud-build.version} - pom - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-all-dependencies - package - - copy-dependencies - - - - ${project.build.directory}/maven_dependencies - - false - true - true - true - true - false - - - - copy-dependencies - package - - copy - - - - - ${project.groupId} - spring-cloud-contract-stub-runner-boot - - ${project.version} - jar - true - ${project.build.directory}/libs - - stub-runner-boot.jar - - - - - - - - com.spotify - dockerfile-maven-plugin - 1.4.13 - - - default - - build - push - - - - - - ${docker.registry.organization}/spring-cloud-contract-stub-runner - - ${project.version} - ${env.DOCKER_HUB_USERNAME} - ${env.DOCKER_HUB_PASSWORD} - - ${thin.repo} - - - - - org.codehaus.plexus - plexus-archiver - 3.6.0 - - - - - - - - milestone - - https://repo.spring.io/milestone - - - - central - - https://repo.maven.apache.org/maven2 - - - - diff --git a/docker/spring-cloud-contract-stub-runner-docker/run.sh b/docker/spring-cloud-contract-stub-runner-docker/run.sh deleted file mode 100755 index 53c0252dbe..0000000000 --- a/docker/spring-cloud-contract-stub-runner-docker/run.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -set -o errexit -set -o errtrace -set -o nounset -set -o pipefail - -echo "Running Spring Cloud Contract Stub Runner" -ADDITIONAL_OPTS="${ADDITIONAL_OPTS:-}" -MESSAGING_TYPE="${MESSAGING_TYPE:-}" - -if [[ "${MESSAGING_TYPE}" != "" ]]; then - echo "Messaging type passed, will active thin profile [${MESSAGING_TYPE}]" - ADDITIONAL_OPTS="${ADDITIONAL_OPTS} --thin.profile=${MESSAGING_TYPE}" -fi - -echo "Please wait for the dependencies to be downloaded..." -java -Djava.security.egd=file:/dev/./urandom -jar /home/scc/stub-runner-boot.jar ${ADDITIONAL_OPTS} diff --git a/docker/spring-cloud-contract-stub-runner-docker/sdkman.config b/docker/spring-cloud-contract-stub-runner-docker/sdkman.config deleted file mode 100644 index b6578f6f4b..0000000000 --- a/docker/spring-cloud-contract-stub-runner-docker/sdkman.config +++ /dev/null @@ -1,8 +0,0 @@ -# make gvm non-interactive, great for CI environments -sdkman_auto_answer=true - -# don't prompt user to selfupdate on new shell -sdkman_suggestive_selfupdate=false - -# don't perform automatic selfupdates -sdkman_auto_selfupdate=false \ No newline at end of file diff --git a/docker/spring-cloud-contract-stub-runner-docker/sdkman/sdkman-wrapper.sh b/docker/spring-cloud-contract-stub-runner-docker/sdkman/sdkman-wrapper.sh deleted file mode 100755 index 673ffaaf78..0000000000 --- a/docker/spring-cloud-contract-stub-runner-docker/sdkman/sdkman-wrapper.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -# A quick wrapper to source the gvm env and run it -# This is used to run gvm in Dockerfile RUN commands -# since the RUN commands does not use interactive shells - -[[ -s "/home/scc/.sdkman/bin/sdkman-init.sh" ]] && source "/home/scc/.sdkman/bin/sdkman-init.sh" && sdk $@ diff --git a/docs/.github/workflows/deploy-docs.yml b/docs/.github/workflows/deploy-docs.yml deleted file mode 100644 index be4b92dfc0..0000000000 --- a/docs/.github/workflows/deploy-docs.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Deploy Docs -on: - push: - branches-ignore: [ gh-pages ] - tags: '**' - repository_dispatch: - types: request-build-reference # legacy - #schedule: - #- cron: '0 10 * * *' # Once per day at 10am UTC - workflow_dispatch: -permissions: - actions: write -jobs: - build: - runs-on: ubuntu-latest - # if: github.repository_owner == 'spring-cloud' - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - ref: docs-build - fetch-depth: 1 - - name: Dispatch (partial build) - if: github.ref_type == 'branch' - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD) -f build-refname=${{ github.ref_name }} - - name: Dispatch (full build) - if: github.ref_type == 'tag' - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD) diff --git a/docs/antora.yml b/docs/antora.yml deleted file mode 100644 index 15b346da04..0000000000 --- a/docs/antora.yml +++ /dev/null @@ -1,12 +0,0 @@ -name: PROJECT_WITHOUT_SPRING -version: true -title: PROJECT_NAME -nav: - - modules/ROOT/nav.adoc -ext: - collector: - run: - command: ./mvnw --no-transfer-progress -B process-resources -Pdocs -pl docs -Dantora-maven-plugin.phase=none -Dgenerate-docs.phase=none -Dgenerate-readme.phase=none -Dgenerate-cloud-resources.phase=none -Dmaven-dependency-plugin-for-docs.phase=none -Dmaven-dependency-plugin-for-docs-classes.phase=none -DskipTests - local: true - scan: - dir: ./target/classes/antora-resources/ diff --git a/docs/modules/ROOT/assets/images/Deps.png b/docs/modules/ROOT/assets/images/Deps.png deleted file mode 100644 index 1426814308101b8ccf6ef95fd195e37c0a180392..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37192 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 A(f|Me diff --git a/docs/modules/ROOT/assets/images/Stubs1.png b/docs/modules/ROOT/assets/images/Stubs1.png deleted file mode 100644 index ebadfdb91014284b917367e3d9c9c8a137da3993..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35170 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 diff --git a/docs/modules/ROOT/assets/images/start_spring_io_dependencies.png b/docs/modules/ROOT/assets/images/start_spring_io_dependencies.png deleted file mode 100644 index 0b4784234b8118859f476bdc0aa908b63a1136e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 347308 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�P7>c8|nmWH@sJ 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%0Dv?AJbBFAdp6l%~@$e)!}LaZi$}Yob}O7q4}E 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
omEMx;XC*w+_GfbLVbr$D&}6) z~`ztu?@@8<{rnj-b{fU$$AwTOO_cs_=QIjIKx46UR_Gu?QE;Vgp#EaBPW}>>MnNJ+&AYxIuju;!2aA0$;ZdUELW9s ze=(9yyKK#>6&8yv`MrrnST4nOVVzUUMW@ixU$Pw&-Tlo(qXX%j)uO;5f`DDt*}i3P zD6FI4pie=(HF;{E$mB^MAz!W+=7j*@wkCC)%8`m!3Ta)*D%V#!C|BG=(4xhT`AB6< z>42#%w;_TnpK|`rNW+PP5t$#%!CA(lyzXKHRPU0AKMtZ!OQYI=7Lehm-KkK$p&K$H5Iycv@LHCIm#fNV4ZYKvinBJ$)qHqUkhKxhEm^rLr$t>LGBm0m zA)qkQ7>fbnSE2>UGmCT-ub01Lt*8Nnw$Tqv<)cz9O$2OxQ##tbQe_`@1MzJW*1ObD zZt!^^>?13Leagm^LwKZ6zEBs90_?M}=J~C1I(k?(G=oJdRP#AcTJ|Lv^9c9WZ zt!Bf8J_y=+bC@SKt$a(=g(b!?X7{=WF=kfl&)^Aa8c-AP^$~4UA*S~d*#qGeZ2tAD zvs~?hJ&;hQ08h<9I(Ev{2AMa?fpS+|MBkaE?M*{}5Klscu@d7K(`bvbRN%f*CM metadata = metadataClasses(); - File doc = new File(this.rootPath, "target/metadata.adoc"); - StringBuilder sb = adocWithMetadata(metadata); - Files.write(doc.toPath(), sb.toString().getBytes()); - log.info("Produced adoc with all metadata!"); - } - - private StringBuilder adocWithMetadata(List metadata) throws Exception { - YAMLMapper mapper = new YAMLMapper(); - mapper.enable(SerializationFeature.INDENT_OUTPUT); - mapper.disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER); - StringBuilder sb = new StringBuilder(); - for (Class metadatum : metadata) { - Constructor constructor = null; - try { - constructor = metadatum.getDeclaredConstructor(null); - } - catch (Exception ex) { - log.warn("Failed to find a no-args constructor for matadatum [" + metadatum + "]", ex); - continue; - } - Object instance = constructor.newInstance(); - SpringCloudContractMetadata newInstance = (SpringCloudContractMetadata) instance; - String description = newInstance.description(); - String key = newInstance.key(); - List additionalClasses = classesToLookAt(metadatum, newInstance); - // @formatter:off - sb - .append("[[metadata-").append(key).append("]]\n") - .append("##### Metadata `").append(key).append("`\n\n") - .append("* key: `").append(key).append("`").append("\n") - .append("* description:\n\n").append(description).append("\n\n") - .append("Example:\n\n") - .append("```yaml\n").append(mapper.writeValueAsString(newInstance)).append("\n```\n\n") - // To make the schema collapsable - .append("+++
+++\nClick here to expand the JSON schema:\n+++
+++\n") - .append("```json\n").append(generateJsonSchemaForClass(metadatum)).append("\n```\n") - .append("+++
+++\n\n") - .append("If you are interested in learning more about the types and its properties, check out the following classes:\n\n") - .append(additionalClasses.stream().map(aClass -> "* `" + aClass.getName() + "`").collect(Collectors.joining("\n"))) - .append("\n\n"); - // @formatter:on - } - return sb; - } - - private List classesToLookAt(Class metadatum, SpringCloudContractMetadata newInstance) { - List additionalClasses = new ArrayList<>(); - additionalClasses.add(metadatum); - additionalClasses.addAll(newInstance.additionalClassesToLookAt()); - return additionalClasses; - } - - private List metadataClasses() throws ClassNotFoundException { - BeanDefinitionRegistry bdr = new SimpleBeanDefinitionRegistry(); - ClassPathBeanDefinitionScanner s = new ClassPathBeanDefinitionScanner(bdr, false); - TypeFilter tf = new AssignableTypeFilter(SpringCloudContractMetadata.class); - s.addIncludeFilter(tf); - String basePackage = "org.springframework.cloud.contract"; - s.scan(basePackage); - String[] beans = bdr.getBeanDefinitionNames(); - List metadata = new ArrayList<>(); - for (String bean : beans) { - BeanDefinition beanDefinition = bdr.getBeanDefinition(bean); - String beanClassName = beanDefinition.getBeanClassName(); - if (beanClassName != null && !beanClassName.contains(basePackage)) { - continue; - } - metadata.add(Class.forName(beanClassName)); - } - return metadata; - } - -} diff --git a/docs/src/test/java/org/springframework/cloud/contract/docs/AdditionalResourcesGenerationTests.java b/docs/src/test/java/org/springframework/cloud/contract/docs/AdditionalResourcesGenerationTests.java deleted file mode 100644 index b4eab03696..0000000000 --- a/docs/src/test/java/org/springframework/cloud/contract/docs/AdditionalResourcesGenerationTests.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.docs; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.util.Collection; - -import org.assertj.core.api.BDDAssertions; -import org.junit.jupiter.api.Test; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.verifier.converter.YamlContractConverter; - -class AdditionalResourcesGenerationTests { - - // @formatter:off - private static final String CONTRACT = "description: Some description\n" - + "name: some name\n" - + "priority: 8\n" - + "ignored: true\n" - + "inProgress: true\n" - + "request:\n" - + " method: PUT\n" - + " url: /foo\n" - + " queryParameters:\n" - + " a: b\n" - + " b: c\n" - + " headers:\n" - + " foo: bar\n" - + " fooReq: baz\n" - + " cookies:\n" - + " foo: bar\n" - + " fooReq: baz\n" - + " body:\n" - + " foo: bar\n" - + " matchers:\n" - + " body:\n" - + " - path: $.foo\n" - + " type: by_regex\n" - + " value: bar\n" - + " headers:\n" - + " - key: foo\n" - + " regex: bar\n" - + "response:\n" - + " status: 200\n" - + " fixedDelayMilliseconds: 1000\n" - + " headers:\n" - + " foo2: bar\n" - + " foo3: foo33\n" - + " fooRes: baz\n" - + " body:\n" - + " foo2: bar\n" - + " foo3: baz\n" - + " nullValue: null\n" - + " matchers:\n" - + " body:\n" - + " - path: $.foo2\n" - + " type: by_regex\n" - + " value: bar\n" - + " - path: $.foo3\n" - + " type: by_command\n" - + " value: executeMe($it)\n" - + " - path: $.nullValue\n" - + " type: by_null\n" - + " value: null\n" - + " headers:\n" - + " - key: foo2\n" - + " regex: bar\n" - + " - key: foo3\n" - + " command: andMeToo($it)\n" - + " cookies:\n" - + " - key: foo2\n" - + " regex: bar\n" - + " - key: foo3\n" - + " predefined:\n"; - // @formatter:on - - @Test - void should_convert_yaml_to_contract() throws IOException { - File ymlFile = new File("target/contract.yml"); - Files.write(ymlFile.toPath(), CONTRACT.getBytes()); - - Collection contracts = new YamlContractConverter().convertFrom(ymlFile); - - BDDAssertions.then(contracts).isNotEmpty(); - } - -} diff --git a/docs/src/test/resources/contract.yml b/docs/src/test/resources/contract.yml deleted file mode 100644 index 761e688201..0000000000 --- a/docs/src/test/resources/contract.yml +++ /dev/null @@ -1,72 +0,0 @@ -description: Some description -name: some name -priority: 8 -ignored: true -inProgress: true -request: - method: PUT - url: /foo - queryParameters: - a: b - b: c - headers: - foo: bar - fooReq: baz - cookies: - foo: bar - fooReq: baz - body: - foo: bar - matchers: - body: - - path: $.foo - type: by_regex - value: bar - headers: - - key: foo - regex: bar -response: - status: 200 - fixedDelayMilliseconds: 1000 - headers: - foo2: bar - foo3: foo33 - fooRes: baz - body: - foo2: bar - foo3: baz - nullValue: null - matchers: - body: - - path: $.foo2 - type: by_regex - value: bar - - path: $.foo3 - type: by_command - value: executeMe($it) - - path: $.nullValue - type: by_null - value: null - headers: - - key: foo2 - regex: bar - - key: foo3 - command: andMeToo($it) - cookies: - - key: foo2 - regex: bar - - key: foo3 - predefined: -metadata: - wiremock: - stubMapping: - "postServeActions": { - "webhook": { - "headers": { - "Content-Type": "application/json" - }, - "method": "POST", - "body": "{ \"result\": \"SUCCESS\" }", - "url": "http://localhost:56299/callback" - } - } diff --git a/ideas.md b/ideas.md deleted file mode 100644 index 9d3aa2b7f5..0000000000 --- a/ideas.md +++ /dev/null @@ -1,17 +0,0 @@ -# Spring Cloud Contract - -Feature ideas: - -- [x] Move DSL and stub runner code over from [Accurest](https://github.com/Codearte/accurest) -- [x] Spring Restdocs generators -- [ ] RAML generators -- [ ] Named scenarios for modelling sequences of request-response with state changes -- [x] Wiremock support for Spring Boot apps -- [x] Wiremock mock servers using `MockRestServiceServer` (from Spring Test) -- [x] POJO-based contracts (packaging DTOs and stub declarations from the producer) -- [ ] Sample messages packaged and injectable into Spring Cloud Stream consumer tests -- [x] `DiscoveryClient` support so backends can be stubbed or mocked transparently (declaratively) -- [ ] Actuator endpoints that verify the state of contracts supported by the host service -- [x] Something to make PACT easier to use in Spring Boot apps? -- [ ] Support [Citrus](https://citrusframework.org/) users (somehow?) -- [x] Schema registries for binary formats like protobuf, thrift, avro - Stream does it diff --git a/log.log b/log.log new file mode 100644 index 0000000000..a3c5c04523 --- /dev/null +++ b/log.log @@ -0,0 +1,116 @@ +[INFO] Processing build on daemon 1c467fe4 +[INFO] Scanning for projects... +[WARN] +[WARN] Some problems were encountered while building the effective model for org.springframework.cloud:spring-cloud-contract-docs:jar:4.0.4-SNAPSHOT +[WARN] 'build.plugins.plugin.version' for org.codehaus.mojo:build-helper-maven-plugin is missing. @ line 29, column 12 +[WARN] +[WARN] Some problems were encountered while building the effective model for org.springframework.cloud:spring-cloud-contract-verifier:jar:4.0.4-SNAPSHOT +[WARN] 'build.plugins.plugin.version' for org.codehaus.mojo:build-helper-maven-plugin is missing. @ line 320, column 12 +[WARN] +[WARN] It is highly recommended to fix these problems because they threaten the stability of your build. +[WARN] +[WARN] For this reason, future Maven versions might no longer support building such malformed projects. +[WARN] +[INFO] BuildTimeEventSpy is registered. +[INFO] Downloading from spring-releases: https://repo.spring.io/release/org/codehaus/mojo/flatten-maven-plugin/maven-metadata.xml +[WARN] Could not transfer metadata org.codehaus.mojo:flatten-maven-plugin/maven-metadata.xml from/to spring-releases (https://repo.spring.io/release): authentication failed for https://repo.spring.io/release/org/codehaus/mojo/flatten-maven-plugin/maven-metadata.xml, status: 401 Unauthorized +[INFO] +[INFO] Using the SmartBuilder implementation with a thread count of 15 +[INFO] Task segments : [dependency:tree] +[INFO] Build maximum degree of concurrency is 15 +[INFO] Total number of projects is 1 +[INFO] +[INFO] ----< org.springframework.cloud:spring-cloud-contract-spec-kotlin >----- +[INFO] Building Spring Cloud Contract Spec Kotlin 4.0.4-SNAPSHOT +[INFO] --------------------------------[ jar ]--------------------------------- +[INFO] Downloading from spring-releases: https://repo.spring.io/release/org/slf4j/slf4j-api/maven-metadata.xml +[INFO] Downloading from maven-restlet: https://maven.restlet.org/org/slf4j/slf4j-api/maven-metadata.xml +[WARN] Could not transfer metadata org.slf4j:slf4j-api/maven-metadata.xml from/to spring-releases (https://repo.spring.io/release): authentication failed for https://repo.spring.io/release/org/slf4j/slf4j-api/maven-metadata.xml, status: 401 Unauthorized +[WARN] Could not transfer metadata org.slf4j:slf4j-api/maven-metadata.xml from/to maven-restlet (https://maven.restlet.org): transfer failed for https://maven.restlet.org/org/slf4j/slf4j-api/maven-metadata.xml +[WARN] org.slf4j:slf4j-api/maven-metadata.xml failed to transfer from https://repo.spring.io/release during a previous attempt. This failure was cached in the local repository and resolution will not be reattempted until the update interval of spring-releases has elapsed or updates are forced. Original error: Could not transfer metadata org.slf4j:slf4j-api/maven-metadata.xml from/to spring-releases (https://repo.spring.io/release): authentication failed for https://repo.spring.io/release/org/slf4j/slf4j-api/maven-metadata.xml, status: 401 Unauthorized +[WARN] org.slf4j:slf4j-api/maven-metadata.xml failed to transfer from https://maven.restlet.org during a previous attempt. This failure was cached in the local repository and resolution will not be reattempted until the update interval of maven-restlet has elapsed or updates are forced. Original error: Could not transfer metadata org.slf4j:slf4j-api/maven-metadata.xml from/to maven-restlet (https://maven.restlet.org): transfer failed for https://maven.restlet.org/org/slf4j/slf4j-api/maven-metadata.xml +[INFO] +[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ spring-cloud-contract-spec-kotlin --- +[WARN] The artifact xml-apis:xml-apis:jar:2.0.2 has been relocated to xml-apis:xml-apis:jar:1.0.b2 +[WARN] org.slf4j:slf4j-api/maven-metadata.xml failed to transfer from https://repo.spring.io/release during a previous attempt. This failure was cached in the local repository and resolution will not be reattempted until the update interval of spring-releases has elapsed or updates are forced. Original error: Could not transfer metadata org.slf4j:slf4j-api/maven-metadata.xml from/to spring-releases (https://repo.spring.io/release): authentication failed for https://repo.spring.io/release/org/slf4j/slf4j-api/maven-metadata.xml, status: 401 Unauthorized +[WARN] org.slf4j:slf4j-api/maven-metadata.xml failed to transfer from https://maven.restlet.org during a previous attempt. This failure was cached in the local repository and resolution will not be reattempted until the update interval of maven-restlet has elapsed or updates are forced. Original error: Could not transfer metadata org.slf4j:slf4j-api/maven-metadata.xml from/to maven-restlet (https://maven.restlet.org): transfer failed for https://maven.restlet.org/org/slf4j/slf4j-api/maven-metadata.xml +[WARN] org.slf4j:slf4j-api/maven-metadata.xml failed to transfer from https://repo.spring.io/release during a previous attempt. This failure was cached in the local repository and resolution will not be reattempted until the update interval of spring-releases has elapsed or updates are forced. Original error: Could not transfer metadata org.slf4j:slf4j-api/maven-metadata.xml from/to spring-releases (https://repo.spring.io/release): authentication failed for https://repo.spring.io/release/org/slf4j/slf4j-api/maven-metadata.xml, status: 401 Unauthorized +[WARN] org.slf4j:slf4j-api/maven-metadata.xml failed to transfer from https://maven.restlet.org during a previous attempt. This failure was cached in the local repository and resolution will not be reattempted until the update interval of maven-restlet has elapsed or updates are forced. Original error: Could not transfer metadata org.slf4j:slf4j-api/maven-metadata.xml from/to maven-restlet (https://maven.restlet.org): transfer failed for https://maven.restlet.org/org/slf4j/slf4j-api/maven-metadata.xml +[INFO] org.springframework.cloud:spring-cloud-contract-spec-kotlin:jar:4.0.4-SNAPSHOT +[INFO] +- org.springframework.cloud:spring-cloud-contract-spec-java:jar:4.0.4-SNAPSHOT:compile +[INFO] | +- org.apache.groovy:groovy:jar:4.0.0:compile +[INFO] | +- org.springframework:spring-core:jar:6.0.9:compile +[INFO] | +- dk.brics:automaton:jar:1.12-4:compile +[INFO] | +- org.apache.commons:commons-text:jar:1.10.0:compile +[INFO] | | \- org.apache.commons:commons-lang3:jar:3.12.0:compile +[INFO] | \- org.springframework:spring-jcl:jar:6.0.9:compile +[INFO] +- org.jetbrains.kotlin:kotlin-stdlib-jdk8:jar:1.8.22:compile +[INFO] | +- org.jetbrains.kotlin:kotlin-stdlib:jar:1.8.22:compile +[INFO] | | +- org.jetbrains.kotlin:kotlin-stdlib-common:jar:1.8.22:compile +[INFO] | | \- org.jetbrains:annotations:jar:13.0:compile +[INFO] | \- org.jetbrains.kotlin:kotlin-stdlib-jdk7:jar:1.8.22:compile +[INFO] +- org.jetbrains.kotlin:kotlin-compiler-embeddable:jar:1.8.22:compile +[INFO] | +- org.jetbrains.kotlin:kotlin-script-runtime:jar:1.8.22:compile +[INFO] | +- org.jetbrains.kotlin:kotlin-reflect:jar:1.8.22:runtime +[INFO] | +- org.jetbrains.kotlin:kotlin-daemon-embeddable:jar:1.8.22:runtime +[INFO] | +- org.jetbrains.intellij.deps:trove4j:jar:1.0.20200330:compile +[INFO] | \- net.java.dev.jna:jna:jar:5.6.0:runtime +[INFO] +- org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:jar:1.8.22:compile +[INFO] | \- org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:jar:1.8.22:runtime +[INFO] | \- org.jetbrains.kotlin:kotlin-scripting-common:jar:1.8.22:compile +[INFO] +- org.jetbrains.kotlin:kotlin-script-util:jar:1.8.22:compile +[INFO] | +- org.jetbrains.kotlin:kotlin-scripting-jvm:jar:1.8.22:compile +[INFO] | \- org.jetbrains.kotlin:kotlin-daemon-client:jar:1.8.22:compile +[INFO] | \- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:jar:1.6.4:compile +[INFO] +- org.springframework.boot:spring-boot-starter-test:jar:3.0.7:test +[INFO] | +- org.springframework.boot:spring-boot-starter:jar:3.0.7:test +[INFO] | | +- org.springframework.boot:spring-boot:jar:3.0.7:test +[INFO] | | | \- org.springframework:spring-context:jar:6.0.9:test +[INFO] | | | +- org.springframework:spring-aop:jar:6.0.9:test +[INFO] | | | +- org.springframework:spring-beans:jar:6.0.9:test +[INFO] | | | \- org.springframework:spring-expression:jar:6.0.9:test +[INFO] | | +- org.springframework.boot:spring-boot-autoconfigure:jar:3.0.7:test +[INFO] | | +- org.springframework.boot:spring-boot-starter-logging:jar:3.0.7:test +[INFO] | | | +- ch.qos.logback:logback-classic:jar:1.4.7:test +[INFO] | | | | \- ch.qos.logback:logback-core:jar:1.4.7:test +[INFO] | | | +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.19.0:test +[INFO] | | | | \- org.apache.logging.log4j:log4j-api:jar:2.19.0:test +[INFO] | | | \- org.slf4j:jul-to-slf4j:jar:2.0.7:test +[INFO] | | +- jakarta.annotation:jakarta.annotation-api:jar:2.1.1:test +[INFO] | | \- org.yaml:snakeyaml:jar:1.33:test +[INFO] | +- org.springframework.boot:spring-boot-test:jar:3.0.7:test +[INFO] | +- org.springframework.boot:spring-boot-test-autoconfigure:jar:3.0.7:test +[INFO] | +- com.jayway.jsonpath:json-path:jar:2.7.0:test +[INFO] | | +- net.minidev:json-smart:jar:2.4.11:test +[INFO] | | | \- net.minidev:accessors-smart:jar:2.4.11:test +[INFO] | | | \- org.ow2.asm:asm:jar:9.3:test +[INFO] | | \- org.slf4j:slf4j-api:jar:2.0.7:provided (version selected from constraint [2.0.0,)) +[INFO] | +- jakarta.xml.bind:jakarta.xml.bind-api:jar:4.0.0:test +[INFO] | | \- jakarta.activation:jakarta.activation-api:jar:2.1.2:test +[INFO] | +- org.assertj:assertj-core:jar:3.23.1:test +[INFO] | | \- net.bytebuddy:byte-buddy:jar:1.12.23:test +[INFO] | +- org.hamcrest:hamcrest:jar:2.2:test +[INFO] | +- org.junit.jupiter:junit-jupiter:jar:5.9.3:test +[INFO] | | +- org.junit.jupiter:junit-jupiter-api:jar:5.9.3:test +[INFO] | | | +- org.opentest4j:opentest4j:jar:1.2.0:test +[INFO] | | | +- org.junit.platform:junit-platform-commons:jar:1.9.3:test +[INFO] | | | \- org.apiguardian:apiguardian-api:jar:1.1.2:test +[INFO] | | +- org.junit.jupiter:junit-jupiter-params:jar:5.9.3:test +[INFO] | | \- org.junit.jupiter:junit-jupiter-engine:jar:5.9.3:test +[INFO] | | \- org.junit.platform:junit-platform-engine:jar:1.9.3:test +[INFO] | +- org.mockito:mockito-core:jar:2.23.0:test +[INFO] | | +- net.bytebuddy:byte-buddy-agent:jar:1.12.23:test +[INFO] | | \- org.objenesis:objenesis:jar:2.6:test +[INFO] | +- org.mockito:mockito-junit-jupiter:jar:4.8.1:test +[INFO] | +- org.skyscreamer:jsonassert:jar:1.5.1:test +[INFO] | | \- com.vaadin.external.google:android-json:jar:0.0.20131108.vaadin1:test +[INFO] | +- org.springframework:spring-test:jar:6.0.9:test +[INFO] | \- org.xmlunit:xmlunit-core:jar:2.9.1:test +[INFO] \- org.jetbrains.kotlin:kotlin-test:jar:1.8.22:test +[INFO] Segment walltime 0 s, segment projects service time 0 s, effective/maximum degree of concurrency 1.00/15 +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ +[INFO] Total time: 1.574 s (Wall Clock) +[INFO] Finished at: 2023-07-05T14:44:53+02:00 +[INFO] ------------------------------------------------------------------------ diff --git a/mvnw b/mvnw index 5643201c7d..41c0f0c23d 100755 --- a/mvnw +++ b/mvnw @@ -36,10 +36,6 @@ if [ -z "$MAVEN_SKIP_RC" ] ; then - if [ -f /usr/local/etc/mavenrc ] ; then - . /usr/local/etc/mavenrc - fi - if [ -f /etc/mavenrc ] ; then . /etc/mavenrc fi @@ -149,7 +145,7 @@ if [ -z "$JAVACMD" ] ; then JAVACMD="$JAVA_HOME/bin/java" fi else - JAVACMD="`\\unset -f command; \\command -v java`" + JAVACMD="`which java`" fi fi @@ -216,9 +212,9 @@ else echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." fi if [ -n "$MVNW_REPOURL" ]; then - jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" else - jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" fi while IFS="=" read key value; do case "$key" in (wrapperUrl) jarUrl="$value"; break ;; @@ -237,9 +233,9 @@ else echo "Found wget ... using wget" fi if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + wget "$jarUrl" -O "$wrapperJarPath" else - wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" fi elif command -v curl > /dev/null; then if [ "$MVNW_VERBOSE" = true ]; then @@ -309,8 +305,6 @@ WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain exec "$JAVACMD" \ $MAVEN_OPTS \ - $MAVEN_DEBUG_OPTS \ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" \ - "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd index 23b7079a3d..86115719e5 100644 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -1,188 +1,182 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* -if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% ^ - %JVM_CONFIG_MAVEN_PROPS% ^ - %MAVEN_OPTS% ^ - %MAVEN_DEBUG_OPTS% ^ - -classpath %WRAPPER_JAR% ^ - "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ - %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" -if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%"=="on" pause - -if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% - -cmd /C exit /B %ERROR_CODE% +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml index deac7315fc..438d5d457e 100644 --- a/pom.xml +++ b/pom.xml @@ -1,527 +1,15 @@ - - + + + 4.0.0 - - org.springframework.cloud - spring-cloud-build - 4.1.0-SNAPSHOT - - - - spring-cloud-contract-parent - pom - 4.1.0-SNAPSHOT - - Spring Cloud Contract - Spring Cloud Contract - - https://github.com/spring-cloud/spring-cloud-contract - - 2016 - - - - 3.19.0 - 0.0.9 - 4.1.0-SNAPSHOT - 4.1.0-SNAPSHOT - 4.1.0-SNAPSHOT - 4.1.0-SNAPSHOT - 4.1.0-SNAPSHOT - 4.1.0-SNAPSHOT - 5.0.4 - 3.3.0 - 2.3-groovy-4.0 - 0.2.2 - 1.10.0 - 4.3.1 - 6.3.0.202209071007-r - 1 - 2.32.0 - 5.2.1 - [2.0.0,) - 1.0.30.RELEASE - - 5.9.1 - 5.9.1 - 1.13.0 - 3.0.0-M7 - 4.2.0 - 2.26.0 - 1.17.5 - - - 4.0.0 - - 3.6.3 - 1.6 - - 1.4.1 - 2.1.100 - 2.12.2 - 0.8.8 - 1.6.0 - 1.3.0 - - 1.8.22 - 1.9.4 - 2.6.0 - - false - false - - - - spring-cloud-contract-dependencies - - - docs - spring-cloud-contract-shade - spring-cloud-contract-wiremock - spring-cloud-contract-verifier - specs - spring-cloud-contract-stub-runner - spring-cloud-contract-starters - spring-cloud-contract-tools - spring-cloud-contract-stub-runner-boot - tests - samples - - - - - - org.springframework.cloud - spring-cloud-commons-dependencies - ${spring-cloud-commons.version} - pom - import - - - io.rest-assured - rest-assured-bom - ${rest-assured.version} - pom - import - - - org.apache.camel.springboot - camel-spring-boot-starter - ${camel.version} - - - org.apache.camel - camel-spring - ${camel.version} - - - org.apache.camel.springboot - camel-spring-boot - ${camel.version} - - - org.apache.camel.springboot - camel-rabbitmq-starter - ${camel.version} - - - org.apache.camel.springboot - camel-direct-starter - ${camel.version} - - - org.apache.camel.springboot - camel-bean-starter - ${camel.version} - - - org.apache.camel.springboot - camel-jackson-starter - ${camel.version} - - - org.apache.camel - camel-core - ${camel.version} - - - org.apache.camel - camel-kafka - ${camel.version} - - - org.apache.camel - camel-jackson - ${camel.version} - - - org.apache.camel - camel-jms - ${camel.version} - - - org.apache.camel - camel-activemq - ${camel.version} - - - org.apache.activemq - artemis-jms-server - ${artemis.version} - - - net.sf.jopt-simple - jopt-simple - ${jopt-simple.version} - - - cglib - cglib - ${cglib.version} - - - org.spockframework - spock-spring - ${spock-spring.version} - - - org.apache.groovy - groovy-all - - - org.apache.groovy - groovy - - - - - org.spockframework - spock-core - ${spock-spring.version} - - - org.apache.groovy - groovy-all - - - org.apache.groovy - groovy - - - - - org.spockframework - spock-junit4 - ${spock-spring.version} - - - io.specto - hoverfly-junit - ${hoverfly-junit.version} - - - org.apache.commons - commons-text - ${commons-text.version} - - - com.github.jknack - handlebars - ${handlebars.version} - - - javax.inject - javax.inject - ${javax-inject.version} - - - - - org.eclipse.jgit - org.eclipse.jgit - ${jgit.version} - - - org.eclipse.jgit - org.eclipse.jgit.ssh.jsch - ${jgit.version} - - - - com.jcraft - jsch.agentproxy.sshagent - ${jsch-agent.version} - - - com.jcraft - jsch.agentproxy.jsch - ${jsch-agent.version} - - - com.jcraft - jsch.agentproxy.usocket-jna - ${jsch-agent.version} - - - - org.springframework.cloud - spring-cloud-contract-dependencies - ${project.version} - pom - import - - - org.springframework.cloud - spring-cloud-netflix-dependencies - ${spring-cloud-netflix.version} - pom - import - - - org.springframework.cloud - spring-cloud-stream-dependencies - ${spring-cloud-stream.version} - pom - import - - - org.springframework.cloud - spring-cloud-zookeeper-dependencies - ${spring-cloud-zookeeper.version} - pom - import - - - org.springframework.cloud - spring-cloud-consul-dependencies - ${spring-cloud-consul.version} - pom - import - - - - org.apache.groovy - groovy - ${groovy.version} - - - org.apache.groovy - groovy-ant - ${groovy.version} - - - org.apache.groovy - groovy-bsf - ${groovy.version} - - - org.apache.groovy - groovy-console - ${groovy.version} - - - org.apache.groovy - groovy-docgenerator - ${groovy.version} - - - org.apache.groovy - groovy-groovydoc - ${groovy.version} - - - org.apache.groovy - groovy-groovysh - ${groovy.version} - - - org.apache.groovy - groovy-jmx - ${groovy.version} - - - org.apache.groovy - groovy-json - ${groovy.version} - - - org.apache.groovy - groovy-jsr223 - ${groovy.version} - - - org.apache.groovy - groovy-nio - ${groovy.version} - - - org.apache.groovy - groovy-servlet - ${groovy.version} - - - org.apache.groovy - groovy-sql - ${groovy.version} - - - org.apache.groovy - groovy-swing - ${groovy.version} - - - org.apache.groovy - groovy-templates - ${groovy.version} - - - org.apache.groovy - groovy-test - ${groovy.version} - - - org.apache.groovy - groovy-testng - ${groovy.version} - - - org.apache.groovy - groovy-xml - ${groovy.version} - - - org.apache.maven - maven-resolver-provider - ${maven.version} - - - org.apache.maven - maven-embedder - ${maven.version} - - - org.apache.maven - maven-artifact - ${maven.version} - - - org.apache.maven - maven-settings-builder - ${maven.version} - - - org.sonatype.sisu - sisu-inject-plexus - ${sisu-inject-plexus.version} - - - org.apache.maven.resolver - maven-resolver - ${maven.resolver.version} - import - pom - - - com.rackspace.eclipse.webtools.sourceediting - org.eclipse.wst.xml.xpath2.processor - ${xpath2.processor.version} - - - xerces - xercesImpl - ${xerces.version} - - - - org.jetbrains.kotlin - kotlin-bom - ${contract.kotlin.version} - import - pom - - - org.jetbrains.kotlin - kotlin-scripting-compiler-embeddable - ${contract.kotlin.version} - - - org.jetbrains.kotlin - kotlin-daemon-embeddable - ${contract.kotlin.version} - - - org.jetbrains.kotlin - kotlin-compiler-embeddable - ${contract.kotlin.version} - - - - - org.slf4j - slf4j-api - ${slf4j.version} - provided - - - org.slf4j - slf4j-simple - ${slf4j.version} - provided - - - org.awaitility - awaitility - ${awaitility.version} - - - org.apache.activemq - artemis-junit - ${artemis.version} - - - org.testcontainers - rabbitmq - ${testcontainers.version} - - - org.testcontainers - junit-jupiter - ${testcontainers.version} - - - - - - Spring - https://spring.io/ - - - - - mariuszs - Mariusz Smykula - mariuszs@gmail.com - - - marcingrzejszczak - Marcin Grzejszczak - mgrzejszczak@vmware.com - - - dsyer - David Syer - dsyer@vmware.com - - - OlgaMaciaszek - Olga Maciaszek-Sharma - omaciaszeksharma@vmware.com - - + org.springframework.cloud + spring-cloud-contract-docs-build + 0.0.1-SNAPSHOT + Spring Cloud Contract Docs Build + Builds Spring Cloud Contract Docs. + https://spring.io/projects/spring-cloud-contract scm:git:https://github.com/spring-cloud/spring-cloud-contract.git @@ -529,211 +17,54 @@ scm:git:git@github.com:spring-cloud/spring-cloud-contract.git https://github.com/spring-cloud/spring-cloud-contract - HEAD - - GitHub https://github.com/spring-cloud/spring-cloud-contract/issues - - Github Actions - https://github.com/spring-cloud/spring-cloud-contract/actions - + + 0.0.3 + + - - - - org.codehaus.mojo - flatten-maven-plugin - 1.5.0 - - - org.apache.maven.plugins - maven-surefire-plugin - ${maven-surefire-plugin.version} - - - **/*Spec.* - **/*Tests.* - **/*Test.* - - plain - true - - - - org.codehaus.gmavenplus - gmavenplus-plugin - ${gmavenplus-plugin.version} - - - - addSources - addTestSources - compile - compileTests - - - - - - - org.apache.maven.plugins - maven-clean-plugin - 3.1.0 + io.spring.maven.antora + antora-maven-plugin + ${io.spring.maven.antora-version} + true - - - target - - + + + + + + + 9d489079e5ec46dbb238909fee5c9c29 + WB1FQYI187 + springcloudcontract + - - io.spring.javaformat - spring-javaformat-maven-plugin - - - org.apache.maven.plugins - maven-checkstyle-plugin - - - - - org.apache.maven.plugins - maven-checkstyle-plugin - - - - - - - sonatype-snapshots - https://oss.sonatype.org/content/repositories/snapshots/ + spring-snapshot + https://repo.spring.io/snapshot true + + false + - netflix-candidates - Netflix Candidates - https://artifactory-oss.prod.netflix.net/artifactory/maven-oss-candidates - - false - + spring-milestone + https://repo.spring.io/milestone - - - spring - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - false - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - false - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - - - sonar - - - - org.jacoco - jacoco-maven-plugin - ${jacoco-maven-plugin.version} - - - pre-unit-test - - prepare-agent - - - surefireArgLine - ${project.build.directory}/jacoco.exec - - - - - post-unit-test - test - - report - - - - ${project.build.directory}/jacoco.exec - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - ${surefireArgLine} - ${surefireArgLine} - - - - - - - diff --git a/samples/pom.xml b/samples/pom.xml deleted file mode 100644 index fd567fe06b..0000000000 --- a/samples/pom.xml +++ /dev/null @@ -1,137 +0,0 @@ - - - 4.0.0 - - - org.springframework.cloud - spring-cloud-contract-parent - 4.1.0-SNAPSHOT - .. - - - spring-cloud-contract-samples - pom - 4.1.0-SNAPSHOT - Spring Cloud Contract Samples - Spring Cloud Contract Samples - - - ${basedir}/.. - - - - - org.springframework.cloud - spring-cloud-contract-stub-runner - test - - - org.springframework.cloud - spring-cloud-contract-maven-plugin - test - - - org.springframework.cloud - spring-cloud-contract-gradle-plugin - test - - - - - - - maven-deploy-plugin - 2.8.2 - - true - - - - - - - - integration - - - - - org.apache.maven.plugins - maven-invoker-plugin - 3.2.1 - - src/it/settings.xml - standalone - ${skipTests} - true - - integration - - - contracts/pom.xml - */pom.xml - dsl/pom.xml - restdocs/pom.xml - webclient/pom.xml - - - clean - install - - - - - integration - - run - - - - - - - - - windows - - - - - org.apache.maven.plugins - maven-invoker-plugin - 3.2.1 - - src/it/settings.xml - standalone - ${skipTests} - true - - windows - - - */pom.xml - - - clean - install - - - - - integration - - run - - - - - - - - - - diff --git a/samples/src/it/settings.xml b/samples/src/it/settings.xml deleted file mode 100644 index 5329c60576..0000000000 --- a/samples/src/it/settings.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - integration - - true - - - - it-repo - - true - - - - local.central - @localRepositoryUrl@ - - true - - - true - - - - - - local.central - @localRepositoryUrl@ - - true - - - true - - - - - - diff --git a/samples/standalone/.idea/.gitignore b/samples/standalone/.idea/.gitignore new file mode 100644 index 0000000000..13566b81b0 --- /dev/null +++ b/samples/standalone/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/samples/standalone/.idea/codeStyles/Project.xml b/samples/standalone/.idea/codeStyles/Project.xml new file mode 100644 index 0000000000..17c6134ebd --- /dev/null +++ b/samples/standalone/.idea/codeStyles/Project.xml @@ -0,0 +1,89 @@ + + + + + \ No newline at end of file diff --git a/samples/standalone/.idea/codeStyles/codeStyleConfig.xml b/samples/standalone/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000000..0adac017fe --- /dev/null +++ b/samples/standalone/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/samples/standalone/.idea/compiler.xml b/samples/standalone/.idea/compiler.xml new file mode 100644 index 0000000000..0b45b73471 --- /dev/null +++ b/samples/standalone/.idea/compiler.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/.idea/encodings.xml b/samples/standalone/.idea/encodings.xml new file mode 100644 index 0000000000..80683df66b --- /dev/null +++ b/samples/standalone/.idea/encodings.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/.idea/jarRepositories.xml b/samples/standalone/.idea/jarRepositories.xml new file mode 100644 index 0000000000..097facbe13 --- /dev/null +++ b/samples/standalone/.idea/jarRepositories.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/.idea/misc.xml b/samples/standalone/.idea/misc.xml new file mode 100644 index 0000000000..44185bb907 --- /dev/null +++ b/samples/standalone/.idea/misc.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/.idea/sonarlint/issuestore/index.pb b/samples/standalone/.idea/sonarlint/issuestore/index.pb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/standalone/.idea/vcs.xml b/samples/standalone/.idea/vcs.xml new file mode 100644 index 0000000000..b2bdec2d71 --- /dev/null +++ b/samples/standalone/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/samples/standalone/.mvn/jvm.config b/samples/standalone/.mvn/jvm.config deleted file mode 100644 index 0e7dabeff6..0000000000 --- a/samples/standalone/.mvn/jvm.config +++ /dev/null @@ -1 +0,0 @@ --Xmx1024m -XX:CICompilerCount=1 -XX:TieredStopAtLevel=1 -Djava.security.egd=file:/dev/./urandom \ No newline at end of file diff --git a/samples/standalone/.mvn/maven.config b/samples/standalone/.mvn/maven.config deleted file mode 100644 index a682990566..0000000000 --- a/samples/standalone/.mvn/maven.config +++ /dev/null @@ -1 +0,0 @@ --P spring diff --git a/samples/standalone/.mvn/wrapper/MavenWrapperDownloader.java b/samples/standalone/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index b901097f2d..0000000000 --- a/samples/standalone/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2007-present 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. - */ -import java.net.*; -import java.io.*; -import java.nio.channels.*; -import java.util.Properties; - -public class MavenWrapperDownloader { - - private static final String WRAPPER_VERSION = "0.5.6"; - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" - + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if(mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if(mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if(!outputFile.getParentFile().exists()) { - if(!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { - String username = System.getenv("MVNW_USERNAME"); - char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); - Authenticator.setDefault(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(username, password); - } - }); - } - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/samples/standalone/.mvn/wrapper/maven-wrapper.jar b/samples/standalone/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index c1dd12f17644411d6e840bd5a10c6ecda0175f18..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58727 zcmb5W18`>1vNjyPv28mO+cqb*Z6_1kwr$(?#I}=(ZGUs`Jr}3`|DLbDUA3!L?dtC8 zUiH*ktDo+@6r@4HP=SCTA%WmZqm^Ro`Ls)bfPkcdfq?#g1(Fq27W^S8Cq^$TC?_c< zs-#ROD;6C)1wFuk7<3)nGuR^#!H;n&3*IjzXg+s8Z_S!!E0jUq(`}Itt=YdYa5Z_s z&e>2={87knpF*PKNzU;lsbk#P(l^WBvb$yEz)z+nYH43pKodrDkMp@h?;n{;K}hl>Fb^ zqx}C0|D7kg|Cj~3f7hn_zkAE}|6t|cZT|S5Hvb#3nc~C14u5UI{6#F<|FkJ0svs&S zA}S{=DXLT*BM1$`2rK%`D@vEw9l9%*=92X_2g?Fwfi=6Zfpr7+<~sgP#Bav+Df2ts zwtu~70zhqV?mrzM)}r7mMS`Hk_)NrI5K%CTtQtDxqw5iv5F0!ksIon{qqpPVnU?ds zN$|Vm{MHKEReUy>1kVfT-$3))Js0p2W_LFy3cjjZ7za0R zPdBH>y&pb0vr1|ckDpt2p$IQhwnPs5G*^b-y}sg4W!ALn}a`pY0JIa$H0$eV2T8WjWD= zWaENacQhlTyK4O!+aOXBurVR2k$eb8HVTCxy-bcHlZ4Xr!`juLAL#?t6|Ba!g9G4I zSwIt2Lla>C?C4wAZ8cKsZl9-Yd3kqE`%!5HlGdJJaFw0mu#--&**L-i|BcIdc3B$;0FC;FbE-dunVZ; zdIQ=tPKH4iJQQ=$5BeEMLov_Hn>gXib|9nOr}>eZt@B4W^m~>Zp#xhn1dax+?hS!AchWJ4makWZs@dQUeXQ zsI2+425_{X@t2KN zIbqec#)Jg5==VY3^YBeJ2B+%~^Y8|;F!mE8d(`UgNl2B9o>Ir5)qbBr)a?f%nrP zQyW(>FYPZjCVKDOU;Bw#PqPF1CCvp)dGdA&57a5hD&*vIc)jA)Z-!y5pS{5W6%#prH16zgD8s zexvpF#a|=*acp>L^lZ(PT)GiA8BJL-9!r8S$ZvXRKMVtiGe`+!@O%j<1!@msc177U zTDy>WOZu)W5anPrweQyjIu3IJC|ngdjZofGbdW&oj^DJlC7$;|xafB45evT|WBgGf-b|9y0J`fe0W-vw6xh}` z=(Tnq(-K0O{;VUcKe2y63{HXc+`R_#HLwnZ0rzWO*b#VeSuC4NG!H_ApCypbt1qx( z6y7Q$5(JOpQ&pTkc^0f}A0Kq*?;g9lEfzeE?5e2MBNZB)^8W1)YgdjsVyN+I9EZlh z3l}*}*)cFl=dOq|DvF=!ui$V%XhGQ%bDn3PK9 zV%{Y|VkAdt^d9~y4laGDqSwLd@pOnS&^@sI7}YTIb@El1&^_sq+{yAGf0|rq5TMp# z6d~;uAZ(fY3(eH=+rcbItl2=u6mf|P{lD4kiRCv;>GtFaHR3gim?WU9RjHmFZLm+m z+j<}_exaOQ1a}=K#voc~En+Mk_<(L!?1e#Uay~|H5q)LjD*yE6xFYQ-Wx{^iH1@pP zC0De#D6I26&W{;J40sZB!=%{c?XdO?YQvnTMA3TwfhAm@bvkX*(x?JTs*dFDv^=2X z284}AK)1nRn+8(Q2P?f)e>0~;NUI9%p%fnv1wBVpoXL+9OE`Vv1Y7=+nub$o7AN>y zB?R(^G8PYcMk4bxe7XItq@48QqWKb8fa*i9-N)=wdU-Q^=}!nFgTr_uT=Z=9pq z`{7!$U|+fnXFcsJ4GNm3JQQCN+G85k$)ZLhF{NbIy{REj84}Zt;0fe#>MARW)AoSb zrBpwF37ZVBMd>wZn_hAadI*xu8)Y#`aMbwRIA2n^-OS~M58_@j?#P1|PXJ1XBC9{4 zT^8*|xu<@(JlSOT*ILrVGr+7$nZN`Z3GxJJO@nY&mHsv^^duAh*lCu5q+S6zWA+`- z%^*y#)O7ko_RwGJl;bcEpP03FOrhlLWs`V_OUCrR-g>NJz*pN|itmN6O@Hw05Zq;Xtif%+sp4Py0{<7<^c zeoHHhRq>2EtYy9~2dZywm&OSk`u2ECWh6dJY?;fT-3-$U`!c(o$&hhPC%$~fT&bw3 zyj+8aXD;G!p*>BC6rpvx#6!|Qaic;KEv5>`Y+R(6F^1eIeYG6d1q3D3OL{7%7iw3R zwO)W7gMh27ASSB>-=OfP(YrKqBTNFv4hL@Im~~ombbSu44p~VoH$H-6+L_JW>Amkl zhDU~|r77?raaxD!-c$Ta?WAAi{w3T}YV=+S?1HQGC0+{Bny_^b+4Jum}oW4c=$ z#?D<}Ds{#d5v`L`${Pee;W84X*osNQ96xsKp^EAzuUh9#&zDX=eqdAp$UY)EGrkU% z(6m35n=46B$TNnejNSlih_!<)Iu@K!PW5S@Ya^0OK+EMWM=1w=GUKW^(r59U%i?d zzbo?|V4tDWGHHsrAQ}}ma#<`9r=M8%XF#%a=@Hn(p3wFBlkZ2L@8=*@J-^zuyF0aN zzJ7f!Jf8I+^6Tt$e+IIh zb80@?7y#Iz3w-0VEjgbHurqI>$qj<@n916)&O340!_5W9DtwR)P5mk6v2ljyK*DG5 zYjzE~m`>tq8HYXl%1JJ%e-%BqV4kRdPUZB1Cm$BQZr(fzp_@rn_W+;GwI$?L2Y4;b z)}c5D$#LT}2W8Si<`EHKIa_X+>+2PF(C*u~F=8E!jL(=IdQxY40%|( zoNg2Z&Aob@LEui-lJ#@)Ts)tE0_!*3{Uk)r{;-IZpX`N4mZX`#E|A;viQWImB6flI z?M_|xHCXV$5LOY-!U1_O1k;OWa=EchwlDCK4xHwBW2jE-6&%}og+9NILu${v10Z^Z#* zap|)B9a-AMU~>$r)3&|dQuP#MA$jnw54w*Ax~*_$iikp+j^OR8I5Fo<_UR#B-c>$? zeg)=;w^sGeAMi<3RGDRj$jA30Qq$e|zf2z;JyQ}tkU)ZI_k6tY%(`#AvL)p)iYXUy z5W9Su3NJ8mVyy)WqzFSk&vZM!;kUh8dVeA-myqcV%;xUne`PbHCPpvH?br`U2Y&dM zV!nJ!^n%`!H&!QSlpzLWnZpgi;#P0OAleH+<CfLa?&o|kyw1}W%6Pij zp$Vv5=;Z0LFN|j9i&9>zqX>*VnV3h#>n!2L?5gO6HJS3~kpy5G zYAVPMaB-FJOk3@OrxL(*-O~OB9^d{!G0K>wlzXuBm*$&%p1O#6SQ*?Q0CETLQ->XpfkW7< zj&Nep(}eAH1u$wWFvLV*lA{JOltP_%xKXC*a8DB&;{fD&2bATy>rC^kFY+$hFS7us;Y) zy_H?cv9XTHYz<4C<0b`WKC#{nJ15{F=oaq3x5}sYApT?Po+(Cmmo#dHZFO^{M#d~d znRT=TFATGVO%z_FNG-@G;9az|udZ>t@5l+A-K)BUWFn_|T#K3=d3EXRNqHyi#>;hX z*JQ`pT3#&tH>25laFlL6Rllu(seA*OboEd%rxMtz3@5v-+{qDP9&BcoS$2fgjgvp$ zc8!3=p0p@Ee1$u{Gg}Kkxg@M*qgZfYLlnD88{uwG1T?zxCbBR+x(RK$JB(eWJH#~; zZoY6L+esVRV?-*QmRCG}h`rB*Lv=uE%URF@+#l-g!Artx>Y9D;&G=jY2n2`J z{6-J%WX~Glx*QBmOOJ(RDRIzhfk&ibsm1t&&7aU{1P3U0uM%F2zJb4~50uby_ng+# zN)O9lK=dkJpxsUo7u8|e`Y~mmbxOTDn0i!i;d;ml#orN(Lc=j+n422NoSnlH6?0<0?th-qB7u}`5My%#?ES}>@RldOQz}WILz<$+cN~&ET zwUI01HCB((TyU$Ej8bxsE8oLmT-c7gA1Js?Iq`QMzIHV|)v)n2 zT_L(9x5%8*wU(C`VapaHoicWcm|0X@9TiNtbc|<4N6_H1F6&qgEEj=vjegFt;hC7- zLG7_=vedRFZ6Chbw!{#EpAlM?-sc#pc<~j#537n)M%RT)|L}y(ggi_-SLpsE3qi3V z=EEASxc>a{Su)jXcRS41Z@Mxk&0B7B<(?Izt5wpyyIBO|-M}ex8BhbIgi*X4 zDZ+Yk1<6&=PoZ=U-!9`!?sBVpYF#Y!JK<`fx}bXN651o0VVaW;t6ASVF@gq-mIDV_)?F^>rq1XX0NYy~(G=I6x%Fi5C2rMtvs z%P`g2>0{xLUy~#ye)%QAz^NkD5GUyPYl}K#;e-~UQ96`I$U0D!sMdQ>;%+c0h>k*Y z)sD1mi_@|rZnQ+zbWq~QxFlBQXj8WEY7NKaOYjUxAkGB8S#;l@b^C?;twRKl=mt0< zazifrBs`(q7_r14u1ZS`66VmsLpV>b5U!ktX>g4Nq~VPq6`%`3iCdr(>nS~uxxylU z>h(2p$XPJVh9BDpRLLzTDlNdp+oq8sOUlJ#{6boG`k)bwnsw5iy@#d{f_De-I|}vx6evw;ch97=;kLvM)-DBGwl6%fA%JItoMeyqjCR*_5Q70yd!KN zh=>ek8>f#~^6CJR0DXp0;7ifZjjSGBn}Cl{HeX!$iXMbtAU$F+;`%A<3TqbN#PCM& z&ueq$cB%pu2oMm_-@*aYzgn9`OiT@2ter*d+-$Aw42(@2Ng4mKG%M-IqX?q%3R|_( zN|&n$e1L#Ev=YMX5F53!O%))qDG3D(0rsOHblk;9ghWyqEOpg)mC$OduqpHAuIxr_>*|zy+|=EmOFn zFM+Ni%@CymLS-3vRWn=rVk?oZEz0V#y356IE6HR5#>7EigxZ05=cA|4<_tC8jyBJ| zgg!^kNwP7S^ooIj6riI9x`jFeQfRr4JCPumr<82M zto$j^Qb~MPmJ-|*2u{o7?yI8BI``zDaOCg2tG_5X;w<|uj5%oDthnLx-l4l)fmUGx z6N^jR|DC);yLi4q-ztTkf>*U$@2^w5(lhxu=OC|=WuTTp^!?2Nn27R`2FY_ zLHY-zFS}r+4|XyZw9b0D3)DmS!Gr+-LSdI}m{@-gL%^8CFSIYL?UZaCVd)2VI3|ay zwue39zshVrB+s2lp*};!gm<79@0HkjhgF^>`UhoR9Mi`aI#V#fI@x&1K3f&^8kaq% zkHVg$CTBoaGqEjrL)k*Y!rtiD2iQLYZ%|B}oBl8GHvR%n>HiIQN*+$mCN>I=c7H2N z&K4$4e@E^ff-cVHCbrHNMh4Dy|2Q;M{{xu|DYjeaRh2FK5QK!bG_K`kbBk$l$S4UF zq?F-%7UrX_Q?9M)a#WvcZ^R-fzJB5IFP>3uEoeCAAhN5W-ELRB&zsCnWY6#E?!)E56Pe+bxHjGF6;R9Hps)+t092-bf4 z_Wieg+0u5JL++k)#i0r?l`9*k)3ZlHOeMJ1DTdx9E1J2@BtdD3qX;&S_wMExOGv$T zl^T%oxb+)vq6vJvR`8{+YOsc@8}wSXpoK%v0k@8X*04Se3<8f)rE|fRXAoT!$6MdrKSuzeK@L*yug?MQs8oTbofqW)Df# zC2J3irHAaX_e~SGlBoRhEW`W6Z}&YX|5IMfzskAt{B*m z*w=3i!;x5Gfgc~>y9fPXFAPMhO@Si}SQESjh`P|dlV5HPRo7j(hV=$o8UMIT7~7+k z*@Sd>f%#{ARweJYhQs~ECpHie!~YXL|FJA;KS4m|CKFnT{fN`Ws>N?CcV@(>7WMPYN} z1}Wg+XU2(Yjpq7PJ|aSn;THEZ{4s8*@N!dz&bjys_Zk7%HiD+56;cF26`-a zEIo!B(T|L*uMXUvqJs&54`^@sUMtH-i~rOM9%$xGXTpmow$DxI>E5!csP zAHe|);0w%`I<==_Zw9t$e}?R+lIu%|`coRum(1p~*+20mBc?Z=$+z<0n&qS0-}|L4 zrgq|(U*eB%l3nfC=U1Y?(Tf@0x8bhdtsU2w&Y-WvyzkiyJ>GZqUP6c+<_p0`ZOnIK z#a~ynuzRWxO6c;S@*}B1pTjLJQHi(+EuE2;gG*p^Fq%6UoE1x95(^BY$H$$soSf=vpJ)_3E zp&$l=SiNaeoNLAK8x%XaHp3-So@F7 z3NMRRa@%k+Z$a%yb25ud&>Cdcb<+}n>=jZ`91)a z{wcA(j$%z#RoyB|&Z+B4%7Pe*No`pAX0Y;Ju4$wvJE{VF*Qej8C}uVF=xFpG^rY6Y+9mcz$T9^x(VP3uY>G3Zt&eU{pF*Bu<4j9MPbi4NMC=Z$kS6DMW9yN#vhM&1gd1t}8m(*YY9 zh2@s)$1p4yYT`~lYmU>>wKu+DhlnI1#Xn4(Rnv_qidPQHW=w3ZU!w3(@jO*f;4;h? zMH0!08(4=lT}#QA=eR(ZtW1=~llQij7)L6n#?5iY_p>|_mLalXYRH!x#Y?KHyzPB^ z6P3YRD}{ou%9T%|nOpP_??P;Rmra7$Q*Jz-f?42PF_y>d)+0Q^)o5h8@7S=je}xG# z2_?AdFP^t{IZHWK)9+EE_aPtTBahhUcWIQ7Awz?NK)ck2n-a$gplnd4OKbJ;;tvIu zH4vAexlK2f22gTALq5PZ&vfFqqERVT{G_d`X)eGI%+?5k6lRiHoo*Vc?ie6dx75_t z6hmd#0?OB9*OKD7A~P$e-TTv3^aCdZys6@`vq%Vi_D8>=`t&q9`Jn1=M#ktSC>SO3 z1V?vuIlQs6+{aHDHL?BB&3baSv;y#07}(xll9vs9K_vs2f9gC9Biy+9DxS77=)c z6dMbuokO-L*Te5JUSO$MmhIuFJRGR&9cDf)@y5OQu&Q$h@SW-yU&XQd9;_x;l z<`{S&Hnl!5U@%I~5p)BZspK894y7kVQE7&?t7Z|OOlnrCkvEf7$J5dR?0;Jt6oANc zMnb_Xjky|2ID#fhIB2hs-48Er>*M?56YFnjC)ixiCes%fgT?C|1tQupZ0Jon>yr|j z6M66rC(=;vw^orAMk!I1z|k}1Ox9qOILGJFxU*ZrMSfCe?)wByP=U73z+@Pfbcndc=VzYvSUnUy z+-B+_n`=f>kS8QBPwk+aD()=#IqkdxHPQMJ93{JGhP=48oRkmJyQ@i$pk(L&(p6<0 zC9ZEdO*i+t`;%(Ctae(SjV<@i%r5aune9)T4{hdzv33Uo9*K=V18S$6VVm^wgEteF za0zCLO(9~!U9_z@Qrh&rS|L0xG}RWoE1jXiEsrTgIF4qf#{0rl zE}|NGrvYLMtoORV&FWaFadDNCjMt|U8ba8|z&3tvd)s7KQ!Od*Kqe(48&C7=V;?`SQV)Qc?6L^k_vNUPbJ>>!5J?sDYm5kR&h_RZk)MfZ1 znOpQ|T;Me(%mdBJR$sbEmp3!HKDDSmMDnVpeo{S13l#9e6OImR$UPzjd-eCwmMwyT zm5~g6DIbY<_!8;xEUHdT(r_OQ<6QCE9Jy|QLoS>d(B zW6GRzX)~&Mx}})ITysFzl5_6JM*~ciBfVP(WF_r zY>z4gw&AxB%UV3Y{Y6z*t*o!p@~#u3X_t{Q9Us8ar8_9?N% zN&M~6y%2R(mAZ~@Tg1Oapt?vDr&fHuJ=V$wXstq|)eIG_4lB#@eU>fniJh zwJY<8yH5(+SSQ=$Y=-$2f$@^Ak#~kaR^NYFsi{XGlFCvK(eu{S$J(owIv17|p-%0O zL-@NyUg!rx0$Uh~JIeMX6JJE>*t<7vS9ev#^{AGyc;uio_-Je1?u#mA8+JVczhA2( zhD!koe;9$`Qgaxlcly4rdQ1VlmEHUhHe9TwduB+hm3wH2o27edh?|vrY{=;1Doy4& zIhP)IDd91@{`QQqVya(ASth4}6OY z-9BQj2d-%+-N7jO8!$QPq%o$9Fy8ja{4WT$gRP+b=Q1I48g-g|iLNjbhYtoNiR*d- z{sB}~8j*6*C3eM8JQj5Jn?mD#Gd*CrVEIDicLJ-4gBqUwLA-bp58UXko;M|ql+i5` zym-&U5BIS9@iPg#fFbuXCHrprSQKRU0#@yd%qrX1hhs*85R}~hahfFDq=e@bX))mf zWH%mXxMx|h5YhrTy;P_Xi_IDH*m6TYv>|hPX*_-XTW0G9iu!PqonQneKKaCVvvF^% zgBMDpN7!N?|G5t`v{neLaCFB{OyIl>qJQ_^0MJXQ zY2%-si~ej?F^%ytIIHU(pqT+3d+|IQ{ss#!c91R{2l*00e3ry!ha|XIsR%!q=E^Fal`6Oxu`K0fmPM?P6ZgzH7|TVQhl;l2 z)2w0L9CsN-(adU5YsuUw19OY_X69-!=7MIJ^(rUNr@#9l6aB8isAL^M{n2oD0FAHk97;X* z-INjZ5li`a|NYNt9gL2WbKT!`?%?lB^)J)9|025nBcBtEmWBRXQwi21EGg8>!tU>6Wf}S3p!>7vHNFSQR zgC>pb^&OHhRQD~7Q|gh5lV)F6i++k4Hp_F2L2WrcxH&@wK}QgVDg+y~o0gZ=$j&^W zz1aP8*cvnEJ#ffCK!Kz{K>yYW`@fc8ByF9X4XmyIv+h!?4&$YKl*~`ToalM{=Z_#^ zUs<1Do+PA*XaH;&0GW^tDjrctWKPmCF-qo7jGL)MK=XP*vt@O4wN1Y!8o`{DN|Rh) znK?nvyU&`ATc@U*l}=@+D*@l^gYOj&6SE|$n{UvyPwaiRQ_ua2?{Vfa|E~uqV$BhH z^QNqA*9F@*1dA`FLbnq;=+9KC@9Mel*>6i_@oVab95LHpTE)*t@BS>}tZ#9A^X7nP z3mIo+6TpvS$peMe@&=g5EQF9Mi9*W@Q`sYs=% z`J{3llzn$q;2G1{N!-#oTfQDY`8>C|n=Fu=iTk443Ld>>^fIr4-!R3U5_^ftd>VU> zij_ix{`V$I#k6!Oy2-z#QFSZkEPrXWsYyFURAo`Kl$LkN>@A?_);LE0rZIkmjb6T$ zvhc#L-Cv^4Ex*AIo=KQn!)A4;7K`pu-E+atrm@Cpmpl3e>)t(yo4gGOX18pL#xceU zbVB`#5_@(k{4LAygT1m#@(7*7f5zqB)HWH#TCrVLd9}j6Q>?p7HX{avFSb?Msb>Jg z9Q9DChze~0Psl!h0E6mcWh?ky! z$p#@LxUe(TR5sW2tMb#pS1ng@>w3o|r~-o4m&00p$wiWQ5Sh-vx2cv5nemM~Fl1Pn z@3ALEM#_3h4-XQ&z$#6X&r~U-&ge+HK6$)-`hqPj0tb|+kaKy*LS5@a9aSk!=WAEB z7cI`gaUSauMkEbg?nl0$44TYIwTngwzvUu0v0_OhpV;%$5Qgg&)WZm^FN=PNstTzW z5<}$*L;zrw>a$bG5r`q?DRc%V$RwwnGIe?m&(9mClc}9i#aHUKPLdt96(pMxt5u`F zsVoku+IC|TC;_C5rEU!}Gu*`2zKnDQ`WtOc3i#v}_9p>fW{L4(`pY;?uq z$`&LvOMMbLsPDYP*x|AVrmCRaI$UB?QoO(7mlBcHC};gA=!meK)IsI~PL0y1&{Dfm6! zxIajDc1$a0s>QG%WID%>A#`iA+J8HaAGsH z+1JH=+eX5F(AjmZGk|`7}Gpl#jvD6_Z!&{*kn@WkECV-~Ja@tmSR|e_L@9?N9 z3hyyry*D0!XyQh_V=8-SnJco#P{XBd1+7<5S3FA)2dFlkJY!1OO&M7z9uO?$#hp8K z><}uQS-^-B;u7Z^QD!7#V;QFmx0m%{^xtl3ZvPyZdi;^O&c;sNC4CHxzvvOB8&uHl zBN;-lu+P=jNn`2k$=vE0JzL{v67psMe_cb$LsmVfxA?yG z^q7lR00E@Ud3)mBPnT0KM~pwzZiBREupva^PE3~e zBgQ9oh@kcTk2)px3Hv^VzTtMzCG?*X(TDZ1MJ6zx{v- z;$oo46L#QNjk*1przHSQn~Ba#>3BG8`L)xla=P{Ql8aZ!A^Z6rPv%&@SnTI7FhdzT z-x7FR0{9HZg8Bd(puRlmXB(tB?&pxM&<=cA-;RT5}8rI%~CSUsR^{Dr%I2WAQghoqE5 zeQ874(T`vBC+r2Mi(w`h|d zA4x%EfH35I?h933@ic#u`b+%b+T?h=<}m@x_~!>o35p|cvIkkw07W=Ny7YcgssA_^ z|KJQrnu||Nu9@b|xC#C5?8Pin=q|UB?`CTw&AW0b)lKxZVYrBw+whPwZJCl}G&w9r zr7qsqm>f2u_6F@FhZU0%1Ioc3X7bMP%by_Z?hds`Q+&3P9-_AX+3CZ=@n!y7udAV2 zp{GT6;VL4-#t0l_h~?J^;trk1kxNAn8jdoaqgM2+mL&?tVy{I)e`HT9#Tr}HKnAfO zAJZ82j0+49)E0+=x%#1_D;sKu#W>~5HZV6AnZfC`v#unnm=hLTtGWz+21|p)uV+0= zDOyrLYI2^g8m3wtm-=pf^6N4ebLJbV%x`J8yd1!3Avqgg6|ar z=EM0KdG6a2L4YK~_kgr6w5OA;dvw0WPFhMF7`I5vD}#giMbMzRotEs&-q z^ji&t1A?l%UJezWv?>ijh|$1^UCJYXJwLX#IH}_1K@sAR!*q@j(({4#DfT|nj}p7M zFBU=FwOSI=xng>2lYo5*J9K3yZPwv(=7kbl8Xv0biOba>vik>6!sfwnH(pglq1mD-GrQi8H*AmfY*J7&;hny2F zupR}4@kzq+K*BE%5$iX5nQzayWTCLJ^xTam-EEIH-L2;huPSy;32KLb>>4 z#l$W^Sx7Q5j+Sy*E;1eSQQuHHWOT;1#LjoYpL!-{7W3SP4*MXf z<~>V7^&sY|9XSw`B<^9fTGQLPEtj=;<#x^=;O9f2{oR+{Ef^oZ z@N>P$>mypv%_#=lBSIr_5sn zBF-F_WgYS81vyW6$M;D_PoE&%OkNV1&-q+qgg~`A7s}>S`}cn#E$2m z%aeUXwNA(^3tP=;y5%pk#5Yz&H#AD`Jph-xjvZm_3KZ|J>_NR@croB^RUT~K;Exu5%wC}1D4nov3+@b8 zKyU5jYuQ*ZpTK23xXzpN51kB+r*ktnQJ7kee-gP+Ij0J_#rFTS4Gux;pkVB;n(c=6 zMks#)ZuXUcnN>UKDJ-IP-u2de1-AKdHxRZDUGkp)0Q#U$EPKlSLQSlnq)OsCour)+ zIXh@3d!ImInH7VrmR>p8p4%n;Tf6l2jx1qjJu>e3kf5aTzU)&910nXa-g0xn$tFa& z2qZ7UAl*@5o=PAh`6L${6S-0?pe3thPB4pahffb$#nL8ncN(Nyos`}r{%{g64Ji^= zK8BIywT0-g4VrhTt}n~Y;3?FGL74h?EG*QfQy0A8u>BtXuI{C-BYu*$o^}U1)z;8d zVN(ssw?oCbebREPD~I$-t7}`_5{{<0d10So7Pc2%EREdpMWIJI&$|rq<0!LL+BQM4 zn7)cq=qy|8YzdO(?NOsVRk{rW)@e7g^S~r^SCawzq3kj#u(5@C!PKCK0cCy zT@Tey2IeDYafA2~1{gyvaIT^a-Yo9kx!W#P-k6DfasKEgFji`hkzrmJ#JU^Yb%Nc~ zc)+cIfTBA#N0moyxZ~K!`^<>*Nzv-cjOKR(kUa4AkAG#vtWpaD=!Ku&;(D#(>$&~B zI?V}e8@p%s(G|8L+B)&xE<({g^M`#TwqdB=+oP|5pF3Z8u>VA!=w6k)zc6w2=?Q2` zYCjX|)fRKI1gNj{-8ymwDOI5Mx8oNp2JJHG3dGJGg!vK>$ji?n>5qG)`6lEfc&0uV z)te%G&Q1rN;+7EPr-n8LpNz6C6N0*v{_iIbta7OTukSY zt5r@sO!)rjh0aAmShx zd3=DJ3c(pJXGXzIh?#RR_*krI1q)H$FJ#dwIvz);mn;w6Rlw+>LEq4CN6pP4AI;!Y zk-sQ?O=i1Mp5lZX3yka>p+XCraM+a!1)`F`h^cG>0)f0OApGe(^cz-WoOno-Y(EeB zVBy3=Yj}ak7OBj~V259{&B`~tbJCxeVy@OEE|ke4O2=TwIvf-=;Xt_l)y`wuQ-9#D z(xD-!k+2KQzr`l$7dLvWf*$c8=#(`40h6d$m6%!SB1JzK+tYQihGQEwR*-!cM>#LD>x_J*w(LZbcvHW@LTjM?RSN z0@Z*4$Bw~Ki3W|JRI-r3aMSepJNv;mo|5yDfqNLHQ55&A>H5>_V9<_R!Ip`7^ylX=D<5 zr40z>BKiC@4{wSUswebDlvprK4SK2!)w4KkfX~jY9!W|xUKGTVn}g@0fG94sSJGV- z9@a~d2gf5s>8XT@`If?Oway5SNZS!L5=jpB8mceuf2Nd%aK2Zt|2FVcg8~7O{VPgI z#?H*_Kl!9!B}MrK1=O!Aw&faUBluA0v#gWVlAmZt;QN7KC<$;;%p`lmn@d(yu9scs zVjomrund9+p!|LWCOoZ`ur5QXPFJtfr_b5%&Ajig2dI6}s&Fy~t^j}()~4WEpAPL= zTj^d;OoZTUf?weuf2m?|R-7 z*C4M6ZhWF(F@2}nsp85rOqt+!+uZz3$ReX#{MP5-r6b`ztXDWl$_mcjFn*{sEx7f*O(ck+ou8_?~a_2Ztsq6qB|SPw26k!tLk{Q~Rz z$(8F1B;zK-#>AmmDC7;;_!;g&CU7a?qiIT=6Ts0cbUNMT6yPRH9~g zS%x{(kxYd=D&GKCkx;N21sU;OI8@4vLg2}L>Lb{Qv`B*O0*j>yJd#`R5ypf^lp<7V zCc|+>fYgvG`ROo>HK+FAqlDm81MS>&?n2E-(;N7}oF>3T9}4^PhY=Gm`9i(DPpuS- zq)>2qz!TmZ6q8;&M?@B;p1uG6RM_Y8zyId{-~XQD_}bXL{Jp7w`)~IR{l5a2?7!Vg zp!OfP4E$Ty_-K3VY!wdGj%2RL%QPHTL)uKfO5Am5<$`5 zHCBtvI~7q-ochU`=NJF*pPx@^IhAk&ZEA>w$%oPGc-}6~ywV~3-0{>*sb=|ruD{y$ ze%@-m`u28vKDaf*_rmN`tzQT>&2ltg-lofR8~c;p;E@`zK!1lkgi?JR0 z+<61+rEupp7F=mB=Ch?HwEjuQm}1KOh=o@ zMbI}0J>5}!koi&v9?!B?4FJR88jvyXR_v{YDm}C)lp@2G2{a{~6V5CwSrp6vHQsfb-U<{SSrQ zhjRbS;qlDTA&TQ2#?M(4xsRXFZ^;3A+_yLw>o-9GJ5sgsauB`LnB-hGo9sJ~tJ`Q>=X7sVmg<=Fcv=JDe*DjP-SK-0mJ7)>I zaLDLOU*I}4@cro&?@C`hH3tiXmN`!(&>@S2bFyAvI&axlSgd=!4IOi#+W;sS>lQ28 zd}q&dew9=x;5l0kK@1y9JgKWMv9!I`*C;((P>8C@JJRGwP5EL;JAPHi5fI|4MqlLU z^4D!~w+OIklt7dx3^!m6Be{Lp55j{5gSGgJz=hlNd@tt_I>UG(GP5s^O{jFU;m~l0 zfd`QdE~0Ym=6+XN*P`i0ogbgAJVjD9#%eBYJGIbDZ4s(f-KRE_>8D1Dv*kgO1~NSn zigx8f+VcA_xS)V-O^qrs&N9(}L!_3HAcegFfzVAntKxmhgOtsb4k6qHOpGWq6Q0RS zZO=EomYL%;nKgmFqxD<68tSGFOEM^u0M(;;2m1#4GvSsz2$jawEJDNWrrCrbO<}g~ zkM6516erswSi_yWuyR}}+h!VY?-F!&Y5Z!Z`tkJz&`8AyQ=-mEXxkQ%abc`V1s>DE zLXd7!Q6C)`7#dmZ4Lm?>CTlyTOslb(wZbi|6|Pl5fFq3y^VIzE4DALm=q$pK>-WM> z@ETsJj5=7=*4 z#Q8(b#+V=~6Gxl?$xq|?@_yQJ2+hAYmuTj0F76c(B8K%;DPhGGWr)cY>SQS>s7%O- zr6Ml8h`}klA=1&wvbFMqk}6fml`4A%G=o@K@8LHifs$)}wD?ix~Id@9-`;?+I7 zOhQN(D)j=^%EHN16(Z3@mMRM5=V)_z(6y^1b?@Bn6m>LUW7}?nupv*6MUVPSjf!Ym zMPo5YoD~t(`-c9w)tV%RX*mYjAn;5MIsD?0L&NQ#IY`9k5}Fr#5{CeTr)O|C2fRhY z4zq(ltHY2X)P*f?yM#RY75m8c<%{Y?5feq6xvdMWrNuqnR%(o(uo8i|36NaN<#FnT ze-_O*q0DXqR>^*1sAnsz$Ueqe5*AD@Htx?pWR*RP=0#!NjnaE-Gq3oUM~Kc9MO+o6 z7qc6wsBxp7GXx+hwEunnebz!|CX&`z{>loyCFSF-zg za}zec;B1H7rhGMDfn+t9n*wt|C_0-MM~XO*wx7-`@9~-%t?IegrHM(6oVSG^u?q`T zO<+YuVbO2fonR-MCa6@aND4dBy^~awRZcp!&=v+#kH@4jYvxt=)zsHV0;47XjlvDC8M1hSV zm!GB(KGLwSd{F-?dmMAe%W0oxkgDv8ivbs__S{*1U}yQ=tsqHJYI9)jduSKr<63$> zp;a-B^6Hg3OLUPi1UwHnptVSH=_Km$SXrCM2w8P z%F#Boi&CcZ5vAGjR1axw&YNh~Q%)VDYUDZ6f^0;>W7_sZr&QvRWc2v~p^PqkA%m=S zCwFUg2bNM(DaY>=TLmOLaDW&uH;Za?8BAwQo4+Xy4KXX;Z}@D5+}m)U#o?3UF}+(@jr$M4ja*`Y9gy~Y`0 z6Aex1*3ng@2er)@{%E9a3A;cts9cAor=RWt7ege)z=$O3$d5CX&hORZ3htL>jj5qT zW#KGQ;AZ|YbS0fvG~Y)CvVwXnBLJkSps7d~v;cj$D3w=rB9Tx>a&4>(x00yz!o*SOd*M!yIwx;NgqW?(ysFv8XLxs6Lrh8-F`3FO$}V{Avztc4qmZ zoz&YQR`*wWy_^&k-ifJ&N8Qh=E-fH6e}-}0C{h~hYS6L^lP>=pLOmjN-z4eQL27!6 zIe2E}knE;dxIJ_!>Mt|vXj%uGY=I^8(q<4zJy~Q@_^p@JUNiGPr!oUHfL~dw9t7C4I9$7RnG5p9wBpdw^)PtGwLmaQM=KYe z;Dfw@%nquH^nOI6gjP+K@B~0g1+WROmv1sk1tV@SUr>YvK7mxV3$HR4WeQ2&Y-{q~ z4PAR&mPOEsTbo~mRwg&EJE2Dj?TOZPO_@Z|HZX9-6NA!%Pb3h;G3F5J+30BoT8-PU z_kbx`I>&nWEMtfv(-m>LzC}s6q%VdBUVI_GUv3@^6SMkEBeVjWplD5y58LyJhikp4VLHhyf?n%gk0PBr(PZ3 z+V`qF971_d@rCO8p#7*#L0^v$DH>-qB!gy@ut`3 zy3cQ8*t@@{V7F*ti(u{G4i55*xY9Erw3{JZ8T4QPjo5b{n=&z4P^}wxA;x85^fwmD z6mEq9o;kx<5VneT_c-VUqa|zLe+BFgskp_;A)b>&EDmmP7Gx#nU-T@;O+(&&n7ljK zqK7&yV!`FIJAI+SaA6y=-H=tT`zWvBlaed!3X^_Lucc%Q=kuiG%65@@6IeG}e@`ieesOL} zKHBJBso6u&7gzlrpB%_yy<>TFwDI>}Ec|Gieb4=0fGwY|3YGW2Dq46=a1 zVo`Vi%yz+L9)9hbb%FLTC@-G(lODgJ(f&WmSCK9zV3-IV7XI<{2j}ms_Vmb!os)06 zhVIZPZF)hW--kWTCyDVRd2T&t|P&aDrtO5kzXy<*A+5$k7$>4+y%;% znYN-t#1^#}Z6d+ahj*Gzor+@kBD7@f|IGNR$4U=Y0J2#D2)YSxUCtiC1weJg zLp0Q&JFrt|In8!~1?fY0?=fPyaqPy$iQXJDhHP>N%B42Yck`Qz-OM_~GMuWow)>=Q z0pCCC7d0Z^Ipx29`}P3;?b{dO?7z0e{L|O*Z}nxi>X|RL8XAw$1eOLKd5j@f{RQ~Y zG?7$`hy@s7IoRF2@KA%2ZM6{ru9T5Gj)iDCz};VvlG$WuT+>_wCTS~J6`I9D{nsrU z2;X#OyopBgo778Q>D%_E>rMN~Po~d5H<`8|Zcv}F`xL5~NCVLX4Wkg007HhMgj9Pa z94$km3A+F&LzOJlpeFR*j+Y%M!Qm42ziH~cKM&3b;15s)ycD@3_tL-dk{+xP@J7#o z-)bYa-gd2esfy<&-nrj>1{1^_L>j&(MA1#WNPg3UD?reL*}V{ag{b!uT755x>mfbZ z0PzwF+kx91`qqOn`1>xw@801XAJlH>{`~|pyi6J;3s=cTOfelA&K5HX#gBp6s<|r5 zjSSj+CU*-TulqlnlP`}?)JkJ_7fg){;bRlXf+&^e8CWwFqGY@SZ=%NmLCXpYb+}7* z$4k}%iFUi^kBdeJg^kHt)f~<;Ovlz!9frq20cIj>2eIcG(dh57ry;^E^2T)E_8#;_9iJT>4sdCB_db|zO?Z^*lBN zNCs~f+Jkx%EUgkN2-xFF?B%TMr4#)%wq?-~+Nh;g9=n3tM>i5ZcH&nkVcPXgYRjG@ zf(Y7WN@hGV7o0bjx_2@bthJ`hjXXpfaes_(lWIw!(QK_nkyqj?{j#uFKpNVpV@h?7_WC3~&%)xHR1kKo`Cypj15#%0m z-o0GXem63g^|IltM?eZV=b+Z2e8&Z1%{0;*zmFc62mNqLTy$Y_c|9HiH0l>K z+mAx7DVYoHhXfdCE8Bs@j=t0f*uM++Idd25BgIm`Ad;I_{$mO?W%=JF82blr8rl>yMk6?pM z^tMluJ-ckG_}OkxP91t2o>CQ_O8^VZn$s$M_APWIXBGBq0Lt^YrTD5(Vwe2ta4y#DEYa(W~=eLOy7rD^%Vd$kL27M)MSpwgoP3P{ z!yS$zc|uP{yzaIqCwE!AfYNS;KW|OdP1Q%!LZviA0e^WDsIS5#= z!B{TW)VB)VHg{LoS#W7i6W>*sFz!qr^YS0t2kh90y=Je5{p>8)~D@dLS@QM(F# zIp{6M*#(@?tsu1Rq-Mdq+eV}ibRSpv#976C_5xlI`$#1tN`sK1?)5M+sj=OXG6dNu zV1K{y>!i0&9w8O{a>`IA#mo(3a zf*+Q=&HW7&(nX8~C1tiHZj%>;asBEp$p_Q!@Y0T8R~OuPEy3Lq@^t$8=~(FhPVmJJ z#VF8`(fNzK-b%Iin7|cxWP0xr*M&zoz|fCx@=Y!-0j_~cuxsDHHpmSo)qOalZ$bRl z2F$j0k3llJ$>28HH3l_W(KjF^!@LwtLej_b9;i;{ku2x+&WA@jKTO0ad71@_Yta!{ z2oqhO4zaU433LK371>E{bZ?+3kLZ9WQ2+3PTZAP90%P13Yy3lr3mhmy|>eN6(SHs1C%Q39p)YsUr7(kuaoIJGJhXV-PyG zjnxhcAC;fqY@6;MWWBnRK6ocG`%T&0&*k95#yK7DFtZV?;cy;!RD_*YJjsb6Q`$;K zy)&X{P`*5xEgjTQ9r=oh0|>Z_yeFm?ev!p z7q;JA4mtu@qa39v%6i)Z4%qwdxcHuOMO;a1wFMP_290FqH1OsmCG{ zq^afYrz2BQyQ0*JGE}1h!W9fKgk$b!)|!%q(1x?5=}PpmZQ$e;2EB*k4%+&+u;(E* z2n@=9HsqMv;4>Nn^2v&@4T-YTkd`TdWU^U*;sA5|r7TjZGnLY*xC=_K-GmDfkWEGC z;oN&!c1xB-<4J7=9 zJ(BedZwZhG4|64<=wvCn4)}w%Zx_TEs6ehmjVG&p5pi46r zg=3-3Q~;v55KR&8CfG;`Lv6NsXB}RqPVyNeKAfj9=Ol>fQlEUl2cH7=mPV!68+;jgtKvo5F#8&9m? z``w+#S5UR=QHFGM~noocC zVFa#v2%oo{%;wi~_~R2ci}`=B|0@ zinDfNxV3%iHIS(7{h_WEXqu!v~`CMH+7^SkvLe_3i}=pyDRah zN#L)F-`JLj6BiG}sj*WBmrdZuVVEo86Z<6VB}s)T$ZcWvG?i0cqI}WhUq2Y#{f~x# zi1LjxSZCwiKX}*ETGVzZ157=jydo*xC^}mJ<+)!DDCd4sx?VM%Y;&CTpw5;M*ihZ| zJ!FBJj0&j&-oJs?9a_I$;jzd%7|pdsQ3m`bPBe$nLoV1!YV8?Pw~0D zmSD-5Ue60>L$Rw;yk{_2d~v@CnvZa%!7{{7lb$kxWx!pzyh;6G~RbN5+|mFTbxcxf!XyfbLI^zMQSb6P~xzESXmV{9 zCMp)baZSz%)j&JWkc|Gq;_*$K@zQ%tH^91X2|Byv>=SmWR$7-shf|_^>Ll;*9+c(e z{N%43;&e8}_QGW+zE0m0myb-@QU%=Qo>``5UzB(lH0sK=E``{ZBl2Ni^-QtDp0ME1 zK88E-db_XBZQaU}cuvkCgH7crju~9eE-Y`os~0P-J=s;aS#wil$HGdK;Ut?dSO71ssyrdm{QRpMAV2nXslvlIE#+Oh>l7y_~?;}F!;ENCR zO+IG#NWIRI`FLntsz^FldCkky2f!d-%Pij9iLKr>IfCK);=}}?(NL%#4PfE(4kPQN zSC%BpZJ*P+PO5mHw0Wd%!zJsn&4g<$n#_?(=)JnoR2DK(mCPHp6e6VdV>?E5KCUF@ zf7W9wm%G#Wfm*NxTWIcJX-qtR=~NFxz4PSmDVAU8(B2wIm#IdHae-F{3jKQFiX?8NlKEhXR2Z|JCUd@HMnNVwqF~V9YJtD+T zQlOroDX-mg2% zBKV^Q5m5ECK{nWjJ7FHOSUi*a-C_?S_yo~G5HuRZH6R``^dS3Bh6u!nD`kFbxYThD zw~2%zL4tHA26rcdln4^=A(C+f9hLlcuMCv{8`u;?uoEVbU=YVNkBP#s3KnM@Oi)fQ zt_F3VjY)zASub%Q{Y?XgzlD3M5#gUBUuhW;$>uBSJH9UBfBtug*S|-;h?|L#^Z&uE zB&)spqM89dWg9ZrXi#F{KtL@r9g^xeR8J+$EhL~2u@cf`dS{8GUC76JP0hHtCKRg0 zt*rVyl&jaJAez;!fb!yX^+So4-8XMNpP@d3H*eF%t_?I|zN^1Iu5aGBXSm+}eCqn3 z^+vzcM*J>wV-FJRrx@^5;l>h0{OYT)lg{dr8!{s7(i{5T|3bivDoTonV1yo1@nVPR zXxEgGg^x5KHgp?=$xBwm_cKHeDurCgO>$B$GSO`Cd<~J8@>ni>Z-Ef!3+ck(MHVy@ z@#<*kCOb5S$V+Fvc@{Qv$oLfnOAG&YO5z_E2j6E z7a+c(>-`H)>g+6DeY1Y*ag-B6>Cl@@VhkZY@Uihe!{LlRpuTsmIsN4;+UDsHd954n9WZV6qq*{qZ5j<W)`UorOmXtVnLo3T{t#h3q^fooqQ~A+EY<$TDG4RKP*cK0liX95STt= zToC<2M2*(H1tZ)0s|v~iSAa^F-9jMwCy4cK0HM*3$@1Q`Pz}FFYm`PGP0wuamWrt*ehz3(|Fn%;0;K4}!Q~cx{0U0L=cs6lcrY^Y%Vf_rXpQIw~DfxB-72tZU6gdK8C~ea6(2P@kGH}!2N?>r(Ca{ zsI!6B!alPl%j1CHq97PTVRng$!~?s2{+6ffC#;X2z(Xb#9GsSYYe@9zY~7Dc7Hfgh z5Tq!})o30pA3ywg<9W3NpvUs;E%Cehz=s?EfLzcV0H?b{=q?vJCih2y%dhls6w3j$ zk9LB0L&(15mtul3T^QSK7KIZVTod#Sc)?1gzY~M=?ay87V}6G?F>~AIv()-N zD3rHX`;r;L{9N|Z8REN}OZB&SZ|5a80B%dQd-CNESP7HnuNn43T~Agcl1YOF@#W03 z1b*t!>t5G@XwVygHYczDIC|RdMB+ z$s5_5_W-EXN-u_5Pb{((!+8xa+?@_#dwtYHeJ_49Dql%3Fv0yXeV?!cC&Iqx@s~P%$X6%1 zYzS9pqaUv&aBQqO zBQs7d63FZIL1B&<8^oni%CZOdf6&;^oNqQ-9j-NBuQ^|9baQuZ^Jtyt&?cHq$Q9JE z5D>QY1?MU7%VVbvjysl~-a&ImiE(uFwHo{!kp;Jd`OLE!^4k8ID{`e-&>2uB7XB~= z+nIQGZ8-Sbfa}OrVPL}!mdieCrs3Nq8Ic_lpTKMIJ{h>XS$C3`h~ z?p2AbK~%t$t(NcOq5ZB3V|`a0io8A))v_PMt)Hg3x+07RL>i zGUq@t&+VV`kj55_snp?)Y@0rKZr`riC`9Q(B1P^nxffV9AvBLPrE<8D>ZP{HCDY@JIvYcYNRz8 z0Rf+Q0riSU@KaVpK)0M{2}Wuh!o~t*6>)EZSCQD{=}N4Oxjo1KO-MNpPYuPABh}E|rM!=TSl^F%NV^dg+>WNGi@Q5C z%JGsP#em`4LxDdIzA@VF&`2bLDv%J)(7vedDiXDqx{y6$Y0o~j*nVY73pINPCY?9y z$Rd&^64MN)Pkxr-CuZ+WqAJx6vuIAwmjkN{aPkrJ0I4F5-Bl}$hRzhRhZ^xN&Oe5$ za4Wrh6PyFfDG+Nzd8NTp2})j>pGtyejb&;NkU3C5-_H;{?>xK1QQ9S`xaHoMgee=2 zEbEh+*I!ggW@{T{qENlruZT)ODp~ZXHBc_Ngqu{jyC#qjyYGAQsO8VT^lts$z0HP+ z2xs^QjUwWuiEh863(PqO4BAosmhaK`pEI{-geBD9UuIn8ugOt-|6S(xkBLeGhW~)< z8aWBs0)bzOnY4wC$yW{M@&(iTe{8zhDnKP<1yr9J8akUK)1svAuxC)}x-<>S!9(?F zcA?{_C?@ZV2Aei`n#l(9zu`WS-hJsAXWt(SGp4(xg7~3*c5@odW;kXXbGuLOFMj{d z{gx81mQREmRAUHhfp#zoWh>z}GuS|raw1R#en%9R3hSR`qGglQhaq>#K!M%tooG;? zzjo}>sL7a3M5jW*s8R;#Y8b(l;%*I$@YH9)YzWR!T6WLI{$8ScBvw+5&()>NhPzd! z{>P(yk8{(G&2ovV^|#1HbcVMvXU&;0pk&6CxBTvBAB>#tK~qALsH`Ad1P0tAKWHv+BR8Fv4!`+>Obu1UX^Ov zmOpuS@Ui|NK4k-)TbG?+9T$)rkvq+?=0RDa=xdmY#JHLastjqPXdDbShqW>7NrHZ7 z7(9(HjM1-Ef(^`%3TlhySDJ27vQ?H`xr9VOM%0ANsA|A3-jj|r`KAo%oTajX3>^E` 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 YM{}PByk10KD_nuQ4E7Du?}+~TKh4V)`~Uy| diff --git a/samples/standalone/.mvn/wrapper/maven-wrapper.properties b/samples/standalone/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index 015dfe6821..0000000000 --- a/samples/standalone/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,18 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.3/apache-maven-3.8.3-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar diff --git a/samples/standalone/README.adoc b/samples/standalone/README.adoc deleted file mode 100644 index 6e391725a3..0000000000 --- a/samples/standalone/README.adoc +++ /dev/null @@ -1,20 +0,0 @@ -= Spring Cloud Contract Verifier Samples - -Projects that contain different samples of Spring Cloud Contract Verifier. - -Below you can find a list of samples: - -include::contracts/README.adoc[] - -include::dsl/http-server/README.adoc[] - -include::dsl/http-client/README.adoc[] - -include::messaging/stream-sink/README.adoc[] - -include::messaging/stream-source/README.adoc[] - -include::restdocs/http-server/README.adoc[] - -include::restdocs/http-client/README.adoc[] - diff --git a/samples/standalone/contracts/.mvn/wrapper/maven-wrapper.jar b/samples/standalone/contracts/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index c6feb8bb6f76f2553e266ff8bf8867105154237e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49519 zcmb@tV|1n6wzeBvGe*U>ZQHh;%-Bg)Y}={WHY%yuwkkF%MnzxVwRUS~wY|@J_gP;% z^VfXZ{5793?z><89(^dufT2xlYVOQnYG>@?lA@vQF|UF0&X7tk8BUf?wq2J& zZe&>>paKUg4@;fwk0yeUPvM$yk)=f>TSFFB^a8f|_@mbE#MaBnd5qf6;hXq}c%IeK zn7gB0Kldbedq-vl@2wxJi{$%lufroKUjQLSFmt|<;M8~<5otM5ur#Dgc@ivmwRiYZW(Oco7kb8DWmo|a{coqYMU2raB9r6e9viK6MI3c&%jp05-Tf*O#6@8Ra=egYy01 z-V!G;_omANEvU-8!*>*)lWka9M<+IkNsrsenbXOfLc6qrYe`;lpst;vfs*70$z9UM zq%L>pFCOr$X*|9&3L2h;?VA9-IU*iR6FiGlJ=b~DzE5s^thxXUs4%~*zD#K&k>wZAU8 zpaa!M+Z-zjkfGK15N!&o<3=cgbZV7%ex@j^)Q9V`q^i;Fsbkbe6eHJ;dx{QbdCCs1 zdxq^WxoPsr`eiK3D0Ep}k$ank-0G&+lY!ZHDZBYEx%% z2FyE?Lb0cflLB)kDIj;G=m`^UO<4h(RWdF-DT>p{1J5J90!K!AgC0)?jxPbm$KUjg zJED+#7xQmAmr`(S%BQTV-c97As~r3zD$E;3S)@}p5udA@m6pLgRL5h-;m>LvCq?&Q zokC7Vnk-zBEaa;=Y;6(LJHS>mOJV&%0YfRdUOqbKZy~b z(905jIW0Pg;y`Yv2t+RnDvL4yGEUX*tK)JT6TWn4ik~L)fX#tAV!d8)+A)qWtSjcr z7s|f%f;*%XW!jiRvv9ayj@f&dc|1tKDc{O3BWcLGsn-OYyXRLXEOEwP4k?c`nIut0 z?4S;eO@EoynmkxHq>QpDL1q^wOQxrl))2qya?dk05^5hK? z{P6;WKHUaHw9B0dd&|xw&CYN2fVrn};Gq<=Z^QZk3e~HzzY~JrnPCs0XwMp#B<9Gm zw0?7h#4EY%O-ub6mi&O2vcpIkuM?st;RtEpKSz^Xr#3WHhpsZd!gh|_jGQ`KA30T- zKlz9vgB;pY^}Uh??nQKSzk>2&J+Qi*r3DeX4^$%2ag9^x_YckA-f9p_;8ulh(8j9~ zes{O#{v!m%n^el(VryTF-C%xfJJ$rZj)|Y|8o&))q9CEwg2;Wz&xzyHD=@T_B%b}C z=8G^*4*J4#jUJn{7-3^U(_uUp6E8+GDt#le)nya-Q4kL5ZGiFxT4bF+mX`whcif*? z>CL&Ryn3HHT^^QmWYr<}Q1_Jj7fOh}cS8r+^R#at-CnNl3!1_$96&7nR}gh}))7a0J&z-_eI))+{RCt)r8|7|sV9o01^9nv?aePxMqwPP!x|sNmnn&6{K$K*mVX9lxSAmcqAV1(hKA-=coeTb*otxTOGYXsh zW$31^q7L@<#y~SUYoNKP1JK?4|FQNQb$i8mCG@WhX9i_^;@M2f#!nq7_K*M!4lGz1 z5tfADkO7BZDLgVQ?k7C)f;$eqjHI&zgxhf}x$8^ZEwFfm-qY=+M+fbS)9r8fFE5H9 zv{WPU35cR8%z;(W%5<>y+E&v84J4^Y##N!$B++RI`CZ1i3IW9Nau=*pSxW&^Ov-F> zex=&9XYLVcm1Y?am>2VC`%gMev9$#~; zYwxYvMfeKFsd!OBB@eOb2QNHFcsfKm;&z{OVEUiYmQ}~L@>$Ms@|Ptf3jQO-=Q;1+ zFCw+p+Z3lK_FmIAYnk2V;o915cDM}%Ht5RH%w}P>Yg9{h1mZ}~R6tUII4X7i4-2i% z2Uiw3_uHR!d~5(s;p6btI@-xhAkRg9K|n#}PNT9Dw9P>z$3>30lP1(=mcQ|tpyv3@ ze1qU!69OAx4s7$8r7Y-#5I`m!BXq`f!6C(BtUlG-oq+liqMCS_D@0nSFc%y+N6_Zh zi%L3LhF3zZP{d1)L&SXxPD(fp@T@J;jZeNaf$zl>vAh7=tI z2;wS^QyRdZm~)Ur&!af;8eB8*7(F96K^=WbC$)#TWvB~Awo5AtPf8Il4snD}Xsqd< z>cH+gcg72nTg5tl>oFbwdT{BDyy1=f=4~h~L$)UX;FXa;NdSlyF{(YLrx&VDp`pQI zh3pQtC=d8i1V6yUmFon*LQsNYWen?eO-gSZ4cvYcdEd0klSxcBYw+|5AyCv6TT96h z{7Yh9`h}biU?3oBFn=d8>Hn`1Q*w6rgeX^QbC-WFwjY}Int0;qUny4WMjIee@#0%l z>YAWLVCNo1lp$>9L$Tx`t!dp?>5Pfbhc*!*wzfWkj_x`Q?`3Jc@9r8uq~dgb+lgeh zlA`eUal3e2ZnWQSSYB>qy#85^>j7!=uO-hG5*erp22NaC81#Ytioc>r?D9$b_JiC+ zSp)8KR$%}FjFNRkeE#c5vKbXNJDBoO< z)73Jt7Y|3v45efud1xkg2GO3OwYfsuBV`f6S_D>Aoh2%=`1Y$bHP>0kBvTSowX57H z&1nbbx=IT>X^ScKYL&&{LNq~^UNgR|at`D;SxTYpLvnj_F*bGgNV2tEl1k$ccA&NW zmX(LV*>Op)BOgoric(98mIU)$eUa&jM5bKlnOrHm$p^v@u;W0J)!@XWg+#X=9En(-tiw!l?65rD=zzl(+%<)bI{ZN;SRco{jO;>7 zlSY|TIxuN|d#YHx^^~>iYj2V>cC>wQwWzGVI!6#epjJ6tl_`7tDY17WMKMB@s*Jr& zXOs*@>EwQ6s>M13eZEBJ#q0|;8jao{wK4keesH9?$OSk~_3#*x`8fAzQa7fprQ6(Z zi$}B%m81y*S)RxaX;wW!5{{EDw8)IE3XDRO1Y^%TMr}c|Y>WBAKT=b*K&uMT(?JSl zO>gVtl_bKQ$??TeWr7wYO+Vbl?CTQj?JrW&td`|#@;R2Gca9jq^p`{@)KY97o3}Af zfTh{pUUWD;P7sq=I!lA6;*hq0Nq`F56T)x$K?BMOk}tptYw(%$?*otp2N6IF3#GgqM46Cda!qzvGZcMgcGV`bY5ZIfOB6^;US#WgRai zq#vS8ZqPY953|eFw<-p2Cakx|z#_{4pG}mk{EANI{PnK*CUslvS8whko=OTe13|It z>{O2p=mmanR2-n>LQHaMo}noWCmjFO@7^z~`Y{V>O`@rT{yBS=VXsb}*Pi_zDqM3? zjCZqWR}fEzAkms+Hiq8~qRAFvo}dVW{1gcZ?v&PdX?UG*yS}zT9g7nZ!F1WRH}sHA zJ4~B2Br~8?uhbaX!3g+7=3fVM)q^wEzv**rk5e34==NRCV z3G$G5B!DICFslm)c){oesa_0muLxGoq`xYVNURl*NhE#v2>y9vDz&vJwrB`Q>DhN# zY2GnY!Y^8E%PU0}haXL$8a5QN1-&7NWuC~{62j| z2ozmFyx8GpOzj?&KK1JF28;E8H_p4N^LMm9K0y}!lCxcK79eFGTtGm?7jy?t94Q@X zli|our1#|>f*68fyA0bSn=YisYSl8HB(dFN4Y$qb7p4DR0YQt=^eEMnJkgiM48$>QV6x5*^a|D|t zMPDk}u<^YEYrt|H&hy)DRk%rDIb{LTo;h7=fp^J9Lr&`{9`8_pS*tQ_$KXB$2#5{h z-&yPbN-zInq{7aYZuaItS8-2Mb4OQe2jD*&)0~898E|HlAq`o!M&It@vvnj z_y@))>~_oR%S8OfmFTGYIat^#8_YKMqWLac<^}RZFDcJqvSJa>&6HaLS7p-$)QyL= zHrO|t75`d41Bp37RZtKR%g^%o@9C5Ce=CjuvVQ-KI#Uw2WWa>cho;jztUt~Le*_pT zkfA2iif9QFp;vhd)|A?tdAQ?9o~?EqgL;=)eKFQ{E^u?OIP}fl^5A;$^ZVutCIqj5 z&*i+G?!Px|5~~6zTYf>~uw*kM`5p&Hju&#w!7^An3*mQwTK22wC7p^OsvMjWf`$MY zLX|ZFV#+>Uq2!QyRD9cgbI9nswteMAMWtK(_=d%r?TLrx?_rkjbjI(rbK#T9Gn}J| z5ajow3ZErpw+%}YfVL-q^{r~##xJ^_ux2yO1!LJZXg)>F70STV=&Ruwp&XP^_?$h0 zn>$a?!>N+Kt$UXzg`e+szB}*uw)Z$uL6?>*!0IrE)SgV~#a?Qgg7HuTsu3ncrcs|l z=sQSMtr}S!sQ4SriKg=M`1Y|bC`XJ+J(YT)op!Q);kj0_e)YNVNw8SI|1f%9%X?i5>$lLE(Wfc$wY?(O985d5e*)UPtF!7gG3(Kd z-^=-%-wWCEK`r4oFh^{|;Ci%W^P>K%9dBNDqi%c$Q{iY#(zbwN7~pQI=SHd%WuV7Z zO?0P;Zc6yeN;)IbJIP0=>W)EgE!76jM^?IyQ*D(T})1NGmP z~YAb6T^#R6;)Ls;cV~LWk z33lcLpbSjxStw9Z>Nv&+rPOXxCGB=?ttZs?{OF7;GYlV&w7-82POb$XrogqFpLA2`j&MLZXr=IG>PAFSb2np~x;E_kV{ zsDwbK$?iYRn7$;mHYZhQn6P2#_hXAHd?;q~!Zy}%;@%wT3u|Sa-!WxxOE_fwyFv*Db@>X;Rl+fK1oP?55*dN0#2%SuikZ)y7Kx>`8*9d?}5 zKvXF7J5&Ey6{A8qUFxrFOh<$xdSWV^dw7z|`7RVZJhAwO72V zRrM_3*wI`^ycl7~>6KaCYBr#WGR>}B)Q(V%&$MhVrU>u~ql zjGeZF&>=_ld$oY!V}5}Gb> z*iP38KOav9RHY)0uITwgz99w- zJX-0BGCdY*$c7pi@>@-`2>#>}c(DHaI62ntpKz z`c01Z#u7WuMZ71!jl7hv5|o61+uv5nG?*dffEL~328P5HlKh2&RQ;9X@f>c1x<>v= zZWNSz3Ii~oyAsKCmbd}|$2%ZN&3gc9>(NV=Z4Fnz2F@)PPbx1wwVMsUn=-G=cqE3# zjY{G4OI~2o$|*iuswTg1=hcZK$C=0^rOt-aOwXuxU=*uT?yF00)6sE}ZAZyy*$ZTH zk!P*xILX#5RygHy{k?2((&pRQv9_Ew+wZ>KPho_o1-{~I*s1h8 zBse@ONdkk-8EG?r5qof}lwTxdmmEN|%qw(STW|PFsw1LD!h_Vjo;C4?@h|da4Y;*; zvApQ=T&=jWU39Uz=_yN@Bn0{{)yn8RZ2&X!<*KBv-7tcWdkF1Ij8D0mU zwbcs}0vDaLGd@xx%S_QZ1H)GTt`~>+#z}HXJTl9S!sd9seVJc|_wUMSdD$>k`K_RG zlq(fsnR@KM^;C}}&vG2t+}_nGPuI5ovg$6TYeMPIREGxP@2r~RKd@>gV`mq0XENsh z%IRZ-ZNP+4#J`o-yRpP;w@;CrSr3wiix3e9Qc|s(WapRq950P->g|JYC$A)$YrGeH zz5dKlAHAPJ>%?llqqB&#+#VU3sp=9>Xms1J;tSYN>LMwNtU68yr!})K4X>%^IrIDp z>SHy&6fJHybwS^BW>okFeaQp6wxaVP`hy;ZX#e+=w3c?PGD&_LmeqL8oZ*YaM1+#S z5WNAKo4+99JW(+qcMjh;+c%R#R?t;(aQ`2`C=bo((ERzgAwKKazXy*0wHN;v;P|f> zBW&?`h#_I^?Bc5GX7XP@|MOiw%&-#?EQ|w+FdCl_&qPN&s$|Z17UCF9oXS#N z)px6>zm&}0osTnCGI;AXsj`q=LpIsW4x}q~70uey5N_NpdJ*Gv^@$g@f2{EB>LP7Y zE5P`jZh1vHNgk7LfMT({jLCjRZa4ubW;UA#%<@Zj?efrPdm{W3J5UEFgm`YkVqz;AMFetZuM5uQpvORb1GDX`WZGwTrF z46+&sAri5QXCfGYpdgonWR5`>ZEa;?jrKvfNvXF<&l)1uU-3q#4X16R2~?P0yg3H` zfw82QWZo^cac+%(g^_6`+2>~Fvy{pOCGnj86+=-!N`GPWAjus1ejhn6f4|mDkU6EE z&u~;xfdRMkj=h;4d~~+4(>L8weT3cz9e@E11EH!tX<IC!@kS+dsIQA`HQ2vdoS zzSD0U?mb1M0@qXu{yhZk2Y6}2B-AvvYg|tRr6z*_*2l*VLiR6G;M{O^Znq~LI%=I_ zCEU{htx&Bo+69G`p|A@R>KlY1*;;!{aWq?Pc0Cu!mT-0S`!>3<@s%Ri;utYNQ+CXDj+LC5<*$4*$-mogGg^S~3JRv{ry zPJzKJg!XKb>P}yJVc^1V@T&MV{z;@DLhvV{dG?RogCcPkROivliSr58>5Zw&&A2?n z9`JOLU;eQGaOr6GB(u{t3!+$NaLge$x#M&*sg!J;m~rRc)Ij5|?KX_4WiM-eE%t8e zqUM7eZ~ZonavR;K4g2t$4Fj=UVyEHM7LPb%8#0?Ks{~?!qhx9)2^>rg8{0npLtFKR zJB)19TFiD^T7IUXA8wt!@n5gj&@OK~EO}MR6^qd?^-?%-0~b2K9RWh+_mSEQQWsLCFOt#JlAQMgNxvv-m z;sF*r;WZ*Wi@I|6pMN+|_rLYKlWwvpKZY9rA;fo8l8hFQGI?4#kt1-r4UL;nPF@{~ z2T~a@2>yD|GuU55boxoIIe_BFo2Vq&rs&2itv|B>OC*bIeOqMBRw~y5KRMwiVHc)` zIBdliiY?Ai7*+k#NZf3MW5!hya~RZ6r7k)b?HF0e(n`ZX=iCpT7St`FDwL@SGgKlq zNnnU*3IcnYDzJg{7V$cb`xeb4(s(({&%f69XMTw-JQErS%?X_}?&y&tvHw@>1v{#R z4J@(=el^kRI+jGa;4)l#v%-jM^$~0ulxh6-{w*4Lsa>Tuc z>ElR3uM~GUChI)c{TW${73A3$vs<&iH;e?4HjW2MvSz9tp9@69+`_@x{Qte^eFo5IlAi&zw$=t6u8K%8JtjRI88PFNM7R>DaCO3rgngmk zI-RMOyt@kr-gVra=tl^@J#tI7M$dird(?aU!`&1xcm~2;dHN(RCxh4H((f|orQ!BS zu;(3Vn+^doXaqlhnjBJj-)w?5{;EEZTMx+?G>Rp4U^g<_yw_blAkdbj=5YrNhZB9@ zNmW=-!yFx5?5aF^+6*1XI|s3lIn_eyh`uv%?liNzSC#z&z^R(mqEYL@TdWzgkf>g1 zedzs*={eJavn{8vF%4nf@et<@wkOPR>NiVuYtESbFXQ;sDz_;|ITVeoW|me5>jN5P z5--{13JT{3ktkAf9M;Jty)yectg#{+9sK{C;2CvPU81tB3{8S5>hK{EXdVe?fR?sd8m`V zPM*$)g$HKp0~9Xf6#z!YJ&g!%VkCMxkt>ofE!62?#-&%|95^)JJ9 zk;GlJdoH0HwtDF(_aTv}mt$?EyRyE6@pm5DG~Gj-2%3HcZT13e)$)z99bdK_WCx|Q zQNza(R)Z>ZKTn8oIdcw%c^pFaMpFZ4HOds!BODgSBWJJYW3I_WJvoEm4xsfs%#LZ6 zdPCk{5XJ>2f7Hj-i*9lTW6BKCIuy)3L!b3(uPoSgW1WA+OEYYBRgSsJq7wjHh%c8ymMs3FU%~cprqL*084p*^T3{J%Gwq`jB30n(&y6- zII8-_r-s5&CVtsoNZ9%On?7yn;oZG03-$wx^uRk9>b*ufh15|HHk|%=MA^ioyb9CYU$7y$4R|M5HvpiCTxKSU`LUg$+ zB3IBl&{qO}agqF~BFM6&11wMeR-#Rkuh_(^j+P4{;X_w|siva$5P`dykyhfAUD%e8 z+{G0|7(Q`_U91sMKFO^rHoCWfXi0$^ev)-187G}klYv@+Rf%uZ&T4-Uhh=)pcU6O1 znXc^c5)!$X+39|4`yNHuCj0wkm+K1VN0G3_EL?-ZH$p5Y*v6ec4MV zS~1~}ZUhl&i^4`Fa|zyH4I%rXp;D6{&@*^TPEX2;4aI$}H@*ROEyFfe^RZI%;T>X> z>WVSUmx@2gGBxkV&nfyPK=JI$HxRKUv(-*xA_C;lDxT|PgX*&YYdkrd5-*3E1OSXBs>35DLsHHp%zm+n0N(Yu{lMo>_t&d1Xy zfCxl=(CNNx>ze+7w)60mp>(M``Qn$aUrVb$cJAb6=Do7VgW`Qn2;v5{9tB)jP$_mB zn{Hb_sMs4yxK|!`PI7+zO68}{Iv)dpu!+ZZl)xuoVU(oFsm<3gT{j2c*ORl|Lt+?dR^M?0 znW6rNA)cR*ci;z?BaG(f(XynY_y+kTjj~T$9{N{>ITQ4-DmZ6{cOkoea9*LpYL{Apo0hSpLqJu z9`tjP&ei;%pn9QY>-$9=<73M#X;qGb+%Bt0x>=u`eDtthI+LWB9CdAO=ulZo9&Ohs2X8GW>b7#&U|py28KTvPBl#Nqv^{AgkVXrOyS z@%3)}$I&mJOYWoG$BBb)Kb~0ptDmBxHNH^i6B8FA7NR2HfTnjP?eDnoY4NS_aYg4P zGGPw11sAf^^fTkY#j@T#6Ll*^GVaPo-1;aS6_a}{r{tWZilzse2m zc?LS=B|EWxCD|!O%|%t3C@Rd7=rKJRsteAWRoDu|*Kx-QwYZQeYpGrZ_1J%mFM;*S*u=0 z%1OC9>kmCGqBBu#-1jVPRVW*BTv%3uPI8fO?JOZD#P_W^V+K7&KVB>hzZ@PdY*%Ezo;}|5Mk`Mo2m*_K%no*jDJGp(s9j;&U`Z>z zO#SEe)k!p$VE-j2xDoX$!;Up5%8x$c`GH$l+gTA*YQaE0jwCOA<*__2NkV){z_u2=4NQ zSk$(oj$%ygio?3V8T3IyGMYvPs`t{im2IoHs7or+>>MYvG%Q?PwOLqe%73uGh6Wn; zo>e7qI$9?%cVVkvQLOLKcU5n*`~qn8pzkdu=Z4#2VnhUy>S*;kT=NqA!dQtnE?wVg zOKobxJ|QCjk`!(2*~5NQx{{=Lr=)ndyn{V|&PxUa=xQXVU?#M24F8H%C*uvs(#Va0 zSkp}0EFYq0#9xp&$O?gIInc#^^_6Ol88W%)S5A@HeE0(SR&!Yl>u=*5JEoUViDR@2 zJBjTsp=Y44W`Nb2+*CcZCkwP(QChX1s)b09DEIZCKt1$q2~;&DJ9!{bQ1Y6&T_9u1 zZM8^im8Wf#FUO6tZqc7#`z0cN_JA>#U_b7he%?cCnlV2&47y5Fc)Z7bp5xGe1zNq9 zl1VaV-tsm3fY=oIX^SPl!P;9$o?**0brq#ShM~3CXhh^SK0oOKB9O>;q3G@ z&4&h$mLSgohc^5IC|H>IGfZvVQFUT>T$|U7{znY`56<5d)07oiv*2R0+-BGPPkWJ! zIOzKF+<5o2YLWP|SGCx8w@<>u6K1o`++xJ+6kaJrt<&0Haq zyUccgxI$sR07Vo9-pF);heBva;?&NcAzC*gSSG9B3c?A;IH9J zl$j%F4*8;F0;H2Cjo*kWz4{kSh?nX}23&&KL+U(#nOAuR`wn@uwUNkWEgb*ZShKPy z`aXTJT4f*Um4`iv2KOfzf-~`#pOfH8>is*xnLBDTyx2Xuc8Y2Od6z((P2AZK@b_96 z#0V6jdw>sEDJ#uNGV|EshD1g&bYZCzCZTZ)286HLHc8Eyy_HPi;d#%;Wx}d6tUUxq z_VB$+898z_{9-A<*v6VI7?(dC04o!8$>DQ$OdbrA_@<6auiBNp{Dw$Hs@@gcybIQT zAU7Pc5YEX&&9IZ~iDo&V`&8K$-4o$)g?wF8xdv1I8-n}1bc7tviIBqt z#iIl1Hn;W?>2&#bU#VZ1wxq(7z=Q15#0yoz)#|r`KSPKI-{aN%l61^?B4RMDt?Vk` z)G#K6vUN?C!t{Q<@O4$0(qI>$U@@TI2FVF;AhSSb5}LtXx&=k&8%MWM3wv;Xq0p~W z#ZX;QFv5G9-i6=+d;R7Dwi)ciIZ1_V!aw;K^etau+g0fOA2HXpV#LQZGzf?h#@}(o z|3w!sZ|&mp$;tmDiO=zef5C|Alz+@@4u5#yZ7yNpP=&`432%a{K#{;nsS!jwk-$Qs zZRty}+N`Y~)c8|$&ra{bOQWM2K7qa}4Y{ndK%dKp&{ zFCvX{PAy_C{xzS_-`0>JlPP7&5!5 zBQ$NQz^z#2y-VeIxnfY|RzU`w+1t6vwQ|wM)LlpuaUzYehGII;>2DYyR|~wC@l97s zgX=f*1qtfDyco%BHmN+o<2qoi`D67R+RM$$NN5-moE4kx3MCFfuip*45nComOZKQf z3!(8tkSdhY5+A%@Y=eVEZkXU3S6B2V-R$ZuRIXWhsrJg3g)p4vXY@RV60bKuG zT6T!enE<;(A{*HPQhae*(@_!maV~AWD4EOwq10tkCXq+HPoe_Pu?d4Kg=2ypcs?&f zLa>mEmPF4ucJ%i~fEsNIa{QmQU27%Abh|w(`q)s~He5$5WYQ_wNJX6Qop<=7;I1jd zNZak`}0lVm+^O!i;|Lwo}ofXuJ)*UtH4xaPm*R7?YS*<&D__=@Kki>{f_Z-XqM;Tj195+~@d;rx zh5pj8oMuupWa#E(%85**I~1Zat-Sa^_R11-CiKdd`8m(DGuzOm9lX$Dd!DX!_Al}d zS!-|}dWG80S;`jSKDH%Uv;-OJNeBI0Bp$z->{_>1KU%h&Af7nns(L=xRN1 zLvOP=*UWIr)_5G2+fCsUV7mV|D>-~_VnvZ3_>=9 z_bL6`eK%W*9eJ34&Puz^@^ZIyoF@%DTun#OOEdUEn8>N9q(}?5*?`o?!_<(i%yc`k zf!xXD6SQscHgPgiHt>x6{n{+}%azrfV4VHi#umyi0;11c816`E??2`$;Rc`)qA2H( z5L|{o=ut7Te=^~@cR0_#cah0?w0Me$&>}ga8xxy=?DDl#}S~Y z4o2n`%IyGjQEP%8qS|v(kFK&RCJbF1gsRVJ>ceSjU`LuYJu%C>SRV#l`)ShD&KKzv ztD<9l0lcW0UQ8xjv|1NXRrCZhZh3JFX_BNT@V|u9$o~8M=cjOX|5iBS|9PAGPvQLc z6sA~BTM(~!c&V=5<}ZIx}O7A;|&bd7vR_y)t+ z?Vm7kb^gJ88g;!fRfMTSvKaPozQz4WcYD8l#0WxQ${P%0A$pwhjXzyA0ZzErH{1@M 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 diff --git a/samples/standalone/contracts/.mvn/wrapper/maven-wrapper.properties b/samples/standalone/contracts/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index 6637cedb28..0000000000 --- a/samples/standalone/contracts/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1 +0,0 @@ -distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip \ No newline at end of file diff --git a/samples/standalone/contracts/README.adoc b/samples/standalone/contracts/README.adoc deleted file mode 100644 index d5daaa6fef..0000000000 --- a/samples/standalone/contracts/README.adoc +++ /dev/null @@ -1,68 +0,0 @@ -= Common contracts repo - -This repo contains all contracts for apps in the system. - -== As a consumer - -You are working offline in order to play around with the API of the producer. -What you need to do is to have the producer's stubs installed locally. To do that -you have to (from the root of the repo) - -[source,bash] ----- -cd com/example/server/ -mvn clean install -DskipTests ----- - -Then if you do `ls ./target` you'll see `server-0.0.1-SNAPSHOT-stubs.jar`. This jar will - contain the stubs generated from your contracts. That way you -can reference the `com.example:server:+:stubs` dependency in your consumer tests. - -== As a producer - -Assuming that the consumers have filed a PR with the proposed contract the producers -can work offline to generate tests and stubs. To work offline, as a producer you just have -to go to the root folder of the contracts and: - -[source,bash] ----- -./mvnw clean install -DskipTests ----- - -Then if you do `ls ./target` you'll see `contracts-0.0.1-SNAPSHOT.jar`. This file contains -all DSL contracts, for all applications. - -Now the producer can include the `contracts-0.0.1-SNAPSHOT.jar` from your local maven repository. -You can achieve that by setting the proper flag in plugin properties. - -Example for Maven - -[source,xml] ----- - - org.springframework.cloud - spring-cloud-contract-maven-plugin - - LOCAL - - com.example.standalone - contracts - - - ----- - -and for Gradle: - -[source,groovy] ----- -contracts { - testFramework ='Spock' - testMode = 'JaxRsClient' - baseClassForTests = 'org.springframework.cloud.MvcSpec' - stubsMode = 'LOCAL' - contractDependency { - stringNotation = "com.example:contracts" - } -} ----- \ No newline at end of file diff --git a/samples/standalone/contracts/build.log b/samples/standalone/contracts/build.log new file mode 100644 index 0000000000..0b2a5d0dcd --- /dev/null +++ b/samples/standalone/contracts/build.log @@ -0,0 +1,45 @@ +[INFO] Scanning for projects... +[INFO] +[INFO] ------------------< com.example.standalone:contracts >------------------ +[INFO] Building Contracts 0.0.1 +[INFO] --------------------------------[ jar ]--------------------------------- +[INFO] +[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ contracts --- +[INFO] Deleting /home/marcin/repo/spring-cloud-contract/samples/standalone/contracts/target +[INFO] +[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ contracts --- +[INFO] Using 'UTF-8' encoding to copy filtered resources. +[INFO] skip non existing resourceDirectory /home/marcin/repo/spring-cloud-contract/samples/standalone/contracts/src/main/resources +[INFO] +[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ contracts --- +[INFO] No sources to compile +[INFO] +[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ contracts --- +[INFO] Using 'UTF-8' encoding to copy filtered resources. +[INFO] skip non existing resourceDirectory /home/marcin/repo/spring-cloud-contract/samples/standalone/contracts/src/test/resources +[INFO] +[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ contracts --- +[INFO] No sources to compile +[INFO] +[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ contracts --- +[INFO] No tests to run. +[INFO] +[INFO] --- maven-assembly-plugin:2.2-beta-5:single (contracts) @ contracts --- +[INFO] Building jar: /home/marcin/repo/spring-cloud-contract/samples/standalone/contracts/target/contracts-0.0.1.jar +[WARNING] Configuration options: 'appendAssemblyId' is set to false, and 'classifier' is missing. +Instead of attaching the assembly file: /home/marcin/repo/spring-cloud-contract/samples/standalone/contracts/target/contracts-0.0.1.jar, it will become the file for main project artifact. +NOTE: If multiple descriptors or descriptor-formats are provided for this project, the value of this file will be non-deterministic! +[INFO] +[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ contracts --- +[WARNING] JAR will be empty - no content was marked for inclusion! +[INFO] Building jar: /home/marcin/repo/spring-cloud-contract/samples/standalone/contracts/target/contracts-0.0.1.jar +[INFO] +[INFO] --- maven-install-plugin:2.4:install (default-install) @ contracts --- +[INFO] Installing /home/marcin/repo/spring-cloud-contract/samples/standalone/contracts/target/contracts-0.0.1.jar to /home/marcin/.m2/repository/com/example/standalone/contracts/0.0.1/contracts-0.0.1.jar +[INFO] Installing /home/marcin/repo/spring-cloud-contract/samples/standalone/contracts/interpolated-pom.xml to /home/marcin/.m2/repository/com/example/standalone/contracts/0.0.1/contracts-0.0.1.pom +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ +[INFO] Total time: 0.564 s +[INFO] Finished at: 2023-09-06T14:29:15+02:00 +[INFO] ------------------------------------------------------------------------ diff --git a/samples/standalone/contracts/com/example/server/client1/expectation.groovy b/samples/standalone/contracts/com/example/server/client1/expectation.groovy deleted file mode 100644 index ba3850f752..0000000000 --- a/samples/standalone/contracts/com/example/server/client1/expectation.groovy +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts - -org.springframework.cloud.contract.spec.Contract.make { - request { // (1) - method 'PUT' // (2) - url '/fraudcheck' // (3) - body([ // (4) - clientId : $(regex('[0-9]{10}')), - loanAmount: 99999 - ]) - headers { // (5) - contentType('application/vnd.fraud.v1+json') - } - } - response { // (6) - status OK() // (7) - body([ // (8) - fraudCheckStatus: "FRAUD", - rejectionReason : "Amount too high" - ]) - headers { // (9) - contentType('application/vnd.fraud.v1+json') - } - } -} - -/* -Since we don't want to force on the user to hardcode values of fields that are dynamic -(timestamps, database ids etc.), one can parametrize those entries. If you wrap your field's - value in a `$(...)` or `value(...)` and provide a dynamic value of a field then - the concrete value will be generated for you. If you want to be really explicit about - which side gets which value you can do that by using the `value(consumer(...), producer(...))` notation. - That way what's present in the `consumer` section will end up in the produced stub. What's - there in the `producer` will end up in the autogenerated test. If you provide only the - regular expression side without the concrete value then Spring Cloud Contract will generate one for you. - -From the Consumer perspective, when shooting a request in the integration test: - -(1) - If the consumer sends a request -(2) - With the "PUT" method -(3) - to the URL "/fraudcheck" -(4) - with the JSON body that - * has a field `clientId` that matches a regular expression `[0-9]{10}` - * has a field `loanAmount` that is equal to `99999` -(5) - with header `Content-Type` equal to `application/vnd.fraud.v1+json` -(6) - then the response will be sent with -(7) - status equal `200` -(8) - and JSON body equal to - { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" } -(9) - with header `Content-Type` equal to `application/vnd.fraud.v1+json` - -From the Producer perspective, in the autogenerated producer-side test: - -(1) - A request will be sent to the producer -(2) - With the "PUT" method -(3) - to the URL "/fraudcheck" -(4) - with the JSON body that - * has a field `clientId` that will have a generated value that matches a regular expression `[0-9]{10}` - * has a field `loanAmount` that is equal to `99999` -(5) - with header `Content-Type` equal to `application/vnd.fraud.v1+json` -(6) - then the test will assert if the response has been sent with -(7) - status equal `200` -(8) - and JSON body equal to - { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" } -(9) - with header `Content-Type` matching `application/vnd.fraud.v1+json.*` - */ diff --git a/samples/standalone/contracts/com/example/server/client2/expectation.groovy b/samples/standalone/contracts/com/example/server/client2/expectation.groovy deleted file mode 100644 index bd1ad7b711..0000000000 --- a/samples/standalone/contracts/com/example/server/client2/expectation.groovy +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts - -org.springframework.cloud.contract.spec.Contract.make { - request { // (1) - method 'PUT' // (2) - url '/fraudcheck2' // (3) - body([ // (4) - clientId : value(consumer(regex('[0-9]{10}'))), - loanAmount: 99999 - ]) - headers { // (5) - header('Content-Type', 'application/vnd.fraud.v1+json') - } - } - response { // (6) - status OK() // (7) - body([ // (8) - fraudCheckStatus: "FRAUD", - rejectionReason : "Amount too high" - ]) - headers { // (9) - header('Content-Type': value( - producer(regex('application/vnd.fraud.v1.json.*')), - consumer('application/vnd.fraud.v1+json')) - ) - } - } -} - -/* -Since we don't want to force on the user to hardcode values of fields that are dynamic -(timestamps, database ids etc.), one can provide parametrize those entries by using the -`value(consumer(...), producer(...))` method. That way what's present in the `consumer` -section will end up in the produced stub. What's there in the `producer` will end up in the -autogenerated test. If you provide only the regular expression side without the concrete -value then Spring Cloud Contract will generate one for you. - -From the Consumer perspective, when shooting a request in the integration test: - -(1) - If the consumer sends a request -(2) - With the "PUT" method -(3) - to the URL "/fraudcheck" -(4) - with the JSON body that - * has a field `clientId` that matches a regular expression `[0-9]{10}` - * has a field `loanAmount` that is equal to `99999` -(5) - with header `Content-Type` equal to `application/vnd.fraud.v1+json` -(6) - then the response will be sent with -(7) - status equal `200` -(8) - and JSON body equal to - { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" } -(9) - with header `Content-Type` equal to `application/vnd.fraud.v1+json` - -From the Producer perspective, in the autogenerated producer-side test: - -(1) - A request will be sent to the producer -(2) - With the "PUT" method -(3) - to the URL "/fraudcheck" -(4) - with the JSON body that - * has a field `clientId` that will have a generated value that matches a regular expression `[0-9]{10}` - * has a field `loanAmount` that is equal to `99999` -(5) - with header `Content-Type` equal to `application/vnd.fraud.v1+json` -(6) - then the test will assert if the response has been sent with -(7) - status equal `200` -(8) - and JSON body equal to - { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" } -(9) - with header `Content-Type` matching `application/vnd.fraud.v1+json.*` - */ diff --git a/samples/standalone/contracts/com/example/server/client3/expectation.groovy b/samples/standalone/contracts/com/example/server/client3/expectation.groovy deleted file mode 100644 index 1a850d19c2..0000000000 --- a/samples/standalone/contracts/com/example/server/client3/expectation.groovy +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts - -org.springframework.cloud.contract.spec.Contract.make { - request { // (1) - method 'PUT' // (2) - url '/fraudcheck3' // (3) - body([ // (4) - clientId : value(consumer(regex('[0-9]{10}'))), - loanAmount: 99999 - ]) - headers { // (5) - header('Content-Type', 'application/vnd.fraud.v1+json') - } - } - response { // (6) - status OK() // (7) - body([ // (8) - fraudCheckStatus: "FRAUD", - rejectionReason : "Amount too high" - ]) - headers { // (9) - header('Content-Type': value( - producer(regex('application/vnd.fraud.v1.json.*')), - consumer('application/vnd.fraud.v1+json')) - ) - } - } -} - -/* -Since we don't want to force on the user to hardcode values of fields that are dynamic -(timestamps, database ids etc.), one can provide parametrize those entries by using the -`value(consumer(...), producer(...))` method. That way what's present in the `consumer` -section will end up in the produced stub. What's there in the `producer` will end up in the -autogenerated test. If you provide only the regular expression side without the concrete -value then Spring Cloud Contract will generate one for you. - -From the Consumer perspective, when shooting a request in the integration test: - -(1) - If the consumer sends a request -(2) - With the "PUT" method -(3) - to the URL "/fraudcheck" -(4) - with the JSON body that - * has a field `clientId` that matches a regular expression `[0-9]{10}` - * has a field `loanAmount` that is equal to `99999` -(5) - with header `Content-Type` equal to `application/vnd.fraud.v1+json` -(6) - then the response will be sent with -(7) - status equal `200` -(8) - and JSON body equal to - { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" } -(9) - with header `Content-Type` equal to `application/vnd.fraud.v1+json` - -From the Producer perspective, in the autogenerated producer-side test: - -(1) - A request will be sent to the producer -(2) - With the "PUT" method -(3) - to the URL "/fraudcheck" -(4) - with the JSON body that - * has a field `clientId` that will have a generated value that matches a regular expression `[0-9]{10}` - * has a field `loanAmount` that is equal to `99999` -(5) - with header `Content-Type` equal to `application/vnd.fraud.v1+json` -(6) - then the test will assert if the response has been sent with -(7) - status equal `200` -(8) - and JSON body equal to - { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" } -(9) - with header `Content-Type` matching `application/vnd.fraud.v1+json.*` - */ diff --git a/samples/standalone/contracts/com/example/server/pom.xml b/samples/standalone/contracts/com/example/server/pom.xml deleted file mode 100644 index 8e065ee5d5..0000000000 --- a/samples/standalone/contracts/com/example/server/pom.xml +++ /dev/null @@ -1,109 +0,0 @@ - - - 4.0.0 - - com.example - server - 0.0.1 - - Server Stubs - POM used to install locally stubs for consumer side - - - org.springframework.boot - spring-boot-starter-parent - 3.2.0-SNAPSHOT - - - - - UTF-8 - 17 - 4.1.0-SNAPSHOT - 2023.0.0-SNAPSHOT - true - - - - - - org.springframework.cloud - spring-cloud-dependencies - ${spring-cloud-release.version} - pom - import - - - - - - - - org.springframework.cloud - spring-cloud-contract-maven-plugin - ${spring-cloud-contract.version} - true - - - ${project.basedir} - - - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - - diff --git a/samples/standalone/contracts/mvnw b/samples/standalone/contracts/mvnw deleted file mode 100755 index 63fcc8f0fc..0000000000 --- a/samples/standalone/contracts/mvnw +++ /dev/null @@ -1,234 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Maven2 Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # - # Look for the Apple JDKs first to preserve the existing behaviour, and then look - # for the new JDKs provided by Oracle. - # - if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then - # - # Apple JDKs - # - export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home - fi - - if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then - # - # Apple JDKs - # - export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home - fi - - if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then - # - # Oracle JDKs - # - export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home - fi - - if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then - # - # Apple JDKs - # - export JAVA_HOME=`/usr/libexec/java_home` - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi - -# For Migwn, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" - # TODO classpath? -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`which java`" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` -fi - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - local basedir=$(pwd) - local wdir=$(pwd) - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - wdir=$(cd "$wdir/.."; pwd) - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" - fi -} - -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" -export MAVEN_CMD_LINE_ARGS - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -exec "$JAVACMD" \ - $MAVEN_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CMD_LINE_ARGS - diff --git a/samples/standalone/contracts/mvnw.cmd b/samples/standalone/contracts/mvnw.cmd deleted file mode 100644 index 66e928bd13..0000000000 --- a/samples/standalone/contracts/mvnw.cmd +++ /dev/null @@ -1,145 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM https://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven2 Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -set MAVEN_CMD_LINE_ARGS=%MAVEN_CONFIG% %* - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" - -set WRAPPER_JAR=""%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% diff --git a/samples/standalone/contracts/pom.xml b/samples/standalone/contracts/pom.xml deleted file mode 100644 index b2cc286f73..0000000000 --- a/samples/standalone/contracts/pom.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - 4.0.0 - - com.example.standalone - contracts - 0.0.1 - - Contracts - Contains all the Spring Cloud Contracts, well, contracts. JAR used by the - producers to generate tests and stubs - - - - UTF-8 - - - - - - org.apache.maven.plugins - maven-assembly-plugin - - - contracts - prepare-package - - single - - - true - ${basedir}/src/assembly/contracts.xml - - false - - - - - - - - diff --git a/samples/standalone/contracts/src/assembly/contracts.xml b/samples/standalone/contracts/src/assembly/contracts.xml deleted file mode 100644 index 478cdc59d1..0000000000 --- a/samples/standalone/contracts/src/assembly/contracts.xml +++ /dev/null @@ -1,23 +0,0 @@ - - project - - jar - - false - - - ${project.basedir} - / - true - - **/${project.build.directory}/** - mvnw - mvnw.cmd - .mvn/** - src/** - - - - diff --git a/samples/standalone/dsl/build.log b/samples/standalone/dsl/build.log new file mode 100644 index 0000000000..eebb142ecc --- /dev/null +++ b/samples/standalone/dsl/build.log @@ -0,0 +1,5071 @@ +[INFO] Scanning for projects... +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-build/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/boot/spring-boot-starter-parent/3.2.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/boot/spring-boot-dependencies/3.2.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-commons-dependencies/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-dependencies-parent/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-contract-dependencies/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-netflix-dependencies/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-stream-dependencies/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-zookeeper-dependencies/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-consul-dependencies/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-build-dependencies/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-contract-maven-plugin/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-contract-tools/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-contract-parent/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-contract-verifier/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-contract-spec/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-contract-spec-java/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-contract-spec-groovy/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-contract-shade/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/boot/spring-boot-test-autoconfigure/3.2.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/boot/spring-boot/3.2.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/boot/spring-boot-test/3.2.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/3.2.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/slf4j/slf4j-api/maven-metadata.xml +[INFO] Downloading from spring-releases: https://repo.spring.io/release/org/slf4j/slf4j-api/maven-metadata.xml +[WARNING] Could not transfer metadata org.slf4j:slf4j-api/maven-metadata.xml from/to spring-releases (https://repo.spring.io/release): authentication failed for https://repo.spring.io/release/org/slf4j/slf4j-api/maven-metadata.xml, status: 401 Unauthorized +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/boot/spring-boot-starter-test/3.2.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/boot/spring-boot-starter/3.2.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/boot/spring-boot-starter-logging/3.2.0-SNAPSHOT/maven-metadata.xml +[WARNING] org.slf4j:slf4j-api/maven-metadata.xmlfailed to transfer from https://repo.spring.io/release during a previous attempt. This failure was cached in the local repository and resolution will not be reattempted until the update interval of spring-releases has elapsed or updates are forced. Original error: Could not transfer metadata org.slf4j:slf4j-api/maven-metadata.xml from/to spring-releases (https://repo.spring.io/release): authentication failed for https://repo.spring.io/release/org/slf4j/slf4j-api/maven-metadata.xml, status: 401 Unauthorized +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-contract-converters/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-contract-stub-runner/4.1.0-SNAPSHOT/maven-metadata.xml +[WARNING] org.slf4j:slf4j-api/maven-metadata.xmlfailed to transfer from https://repo.spring.io/release during a previous attempt. This failure was cached in the local repository and resolution will not be reattempted until the update interval of spring-releases has elapsed or updates are forced. Original error: Could not transfer metadata org.slf4j:slf4j-api/maven-metadata.xml from/to spring-releases (https://repo.spring.io/release): authentication failed for https://repo.spring.io/release/org/slf4j/slf4j-api/maven-metadata.xml, status: 401 Unauthorized +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-contract-wiremock/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-test-support/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-commons-parent/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/boot/spring-boot-starter-web/3.2.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/boot/spring-boot-starter-json/3.2.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/boot/spring-boot-starter-tomcat/3.2.0-SNAPSHOT/maven-metadata.xml +[WARNING] org.slf4j:slf4j-api/maven-metadata.xmlfailed to transfer from https://repo.spring.io/release during a previous attempt. This failure was cached in the local repository and resolution will not be reattempted until the update interval of spring-releases has elapsed or updates are forced. Original error: Could not transfer metadata org.slf4j:slf4j-api/maven-metadata.xml from/to spring-releases (https://repo.spring.io/release): authentication failed for https://repo.spring.io/release/org/slf4j/slf4j-api/maven-metadata.xml, status: 401 Unauthorized +[INFO] Downloading from maven-default-http-blocker: http://0.0.0.0/org/slf4j/slf4j-api/maven-metadata.xml +[WARNING] Could not transfer metadata org.slf4j:slf4j-api/maven-metadata.xml from/to maven-default-http-blocker (http://0.0.0.0/): transfer failed for http://0.0.0.0/org/slf4j/slf4j-api/maven-metadata.xml +[INFO] ------------------------------------------------------------------------ +[INFO] Reactor Build Order: +[INFO] +[INFO] Spring Cloud Contract Verifier Http Server Sample [jar] +[INFO] Spring Cloud Contract Verifier Http Client Sample [jar] +[INFO] Spring Cloud Contract Standalone Dsl Test Samples [pom] +[INFO] +[INFO] --------------------< com.example:http-server-dsl >--------------------- +[INFO] Building Spring Cloud Contract Verifier Http Server Sample 0.0.1 [1/3] +[INFO] --------------------------------[ jar ]--------------------------------- +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/boot/spring-boot-maven-plugin/3.2.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/boot/spring-boot-starter-actuator/3.2.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/boot/spring-boot-actuator-autoconfigure/3.2.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/boot/spring-boot-actuator/3.2.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-starter-stream-rabbit/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-stream-binder-rabbit-parent/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-stream-binders/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-stream-parent/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-stream-binder-rabbit/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-stream-binder-rabbit-core/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-stream/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-stream-core/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/boot/spring-boot-starter-validation/3.2.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-function-context/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-function-parent/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-function-dependencies/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-function-core/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/boot/spring-boot-starter-amqp/3.2.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/boot/spring-boot-starter-webflux/3.2.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/boot/spring-boot-starter-reactor-netty/3.2.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-stream-test-binder/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-starter-contract-verifier/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-contract-starters/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] +[INFO] --- maven-clean-plugin:3.0.0:clean (default-clean) @ http-server-dsl --- +[INFO] Deleting /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target +[INFO] Deleting /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/build (includes = [], excludes = []) +[INFO] +[INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ http-server-dsl --- +[INFO] Copying 1 resource from src/main/resources to target/classes +[INFO] Copying 0 resource from src/main/resources to target/classes +[INFO] +[INFO] --- maven-compiler-plugin:3.11.0:compile (default-compile) @ http-server-dsl --- +[INFO] Changes detected - recompiling the module! :source +[INFO] Compiling 11 source files with javac [debug release 17] to target/classes +[INFO] /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/MessagingConfiguration.java: /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/MessagingConfiguration.java uses or overrides a deprecated API. +[INFO] /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/MessagingConfiguration.java: Recompile with -Xlint:deprecation for details. +[INFO] +[INFO] --- spring-cloud-contract-maven-plugin:4.1.0-SNAPSHOT:generateTests (default-generateTests) @ http-server-dsl --- +[INFO] Generating server tests source code for Spring Cloud Contract Verifier contract verification +[INFO] Will use contracts provided in the folder [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/src/test/resources/contracts] +[INFO] Directory with contract is present at [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/src/test/resources/contracts] +[INFO] Test Source directory: /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/generated-test-sources/contracts added. +[INFO] Using [null] as base class for test classes, [null] as base package for tests, [com.example.fraud] as package with base classes, base class mappings [] +[INFO] Creating new class file [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/generated-test-sources/contracts/com/example/fraud/BinaryTest.java] +[INFO] Creating new class file [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/generated-test-sources/contracts/com/example/fraud/FraudTest.java] +[INFO] Creating new class file [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/generated-test-sources/contracts/com/example/fraud/FraudnameTest.java] +[INFO] Creating new class file [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/generated-test-sources/contracts/com/example/fraud/MessagingTest.java] +[INFO] Creating new class file [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/generated-test-sources/contracts/com/example/fraud/MultipartTest.java] +[INFO] Creating new class file [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/generated-test-sources/contracts/com/example/fraud/TestTest.java] +[INFO] Creating new class file [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/generated-test-sources/contracts/com/example/fraud/yml/FraudTest.java] +[INFO] Creating new class file [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/generated-test-sources/contracts/com/example/fraud/yml/FraudnameTest.java] +[INFO] Generated 8 test classes. +[INFO] +[INFO] --- spring-cloud-contract-maven-plugin:4.1.0-SNAPSHOT:convert (default-convert) @ http-server-dsl --- +[INFO] Will use contracts provided in the folder [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/src/test/resources/contracts] +[INFO] Copying Spring Cloud Contract Verifier contracts to [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/stubs/META-INF/com.example/http-server-dsl/0.0.1/contracts]. Only files matching [.*] pattern will end up in the final JAR with stubs. +[INFO] Using 'UTF-8' encoding to copy filtered resources. +[INFO] Copying 23 resources +[INFO] Converting from Spring Cloud Contract Verifier contracts to WireMock stubs mappings +[INFO] Spring Cloud Contract Verifier contracts directory: /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/src/test/resources/contracts +[INFO] Stub Server stubs mappings directory: /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/stubs/META-INF/com.example/http-server-dsl/0.0.1/mappings +[INFO] Creating new stub [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/stubs/META-INF/com.example/http-server-dsl/0.0.1/mappings/binary/shouldWorkWithBinaryPayload.json] +[INFO] Creating new stub [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/stubs/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraud/shouldMarkClientAsFraud.json] +[INFO] Creating new stub [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/stubs/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraud/shouldMarkClientAsNotFraud.json] +[INFO] Creating new stub [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/stubs/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraud/should count all frauds.json] +[INFO] Creating new stub [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/stubs/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraud/shouldReturnFraudStats_1.json] +[INFO] Creating new stub [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/stubs/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraudname/shouldReturnACookie.json] +[INFO] Creating new stub [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/stubs/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraudname/shouldReturnAFraudForTheName.json] +[INFO] Creating new stub [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/stubs/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraudname/shouldReturnNonFraudForTheName.json] +[INFO] Creating new stub [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/stubs/META-INF/com.example/http-server-dsl/0.0.1/mappings/messaging/shouldReturnOkWhenServiceIsHealthy.json] +[INFO] Creating new stub [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/stubs/META-INF/com.example/http-server-dsl/0.0.1/mappings/multipart/shouldWorkForMultipartAsBytesWithContentType.json] +[INFO] Creating new stub [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/stubs/META-INF/com.example/http-server-dsl/0.0.1/mappings/multipart/shouldWorkForMultipartWithContentType.json] +[INFO] Creating new stub [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/stubs/META-INF/com.example/http-server-dsl/0.0.1/mappings/test/MyHttpContract.json] +[INFO] Creating new stub [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/stubs/META-INF/com.example/http-server-dsl/0.0.1/mappings/yml/fraud/shouldMarkClientAsFraud.json] +[INFO] Creating new stub [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/stubs/META-INF/com.example/http-server-dsl/0.0.1/mappings/yml/fraud/shouldMarkClientAsNotFraud.json] +[INFO] Creating new stub [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/stubs/META-INF/com.example/http-server-dsl/0.0.1/mappings/yml/fraud/should count all frauds.json] +[INFO] Creating new stub [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/stubs/META-INF/com.example/http-server-dsl/0.0.1/mappings/yml/fraud/shouldReturnFraudStats_1.json] +[INFO] Creating new stub [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/stubs/META-INF/com.example/http-server-dsl/0.0.1/mappings/yml/fraudname/shouldReturnAFraudForTheName.json] +[INFO] Creating new stub [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/stubs/META-INF/com.example/http-server-dsl/0.0.1/mappings/yml/fraudname/shouldReturnNonFraudForTheName.json] +[INFO] +[INFO] --- maven-resources-plugin:3.3.1:testResources (default-testResources) @ http-server-dsl --- +[INFO] Copying 23 resources from src/test/resources to target/test-classes +[INFO] Copying 6 resources from target/generated-test-resources/contracts to target/test-classes +[INFO] +[INFO] --- maven-antrun-plugin:3.1.0:run (default) @ http-server-dsl --- +[INFO] Executing tasks +[INFO] Executed tasks +[INFO] +[INFO] --- maven-compiler-plugin:3.11.0:testCompile (default-testCompile) @ http-server-dsl --- +[INFO] Changes detected - recompiling the module! :dependency +[INFO] Compiling 16 source files with javac [debug release 17] to target/test-classes +[INFO] +[INFO] --- maven-surefire-plugin:3.1.2:test (default-test) @ http-server-dsl --- +[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider +[INFO] +[INFO] ------------------------------------------------------- +[INFO] T E S T S +[INFO] ------------------------------------------------------- +[INFO] Running com.example.fraud.MessagingTest + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v3.2.0-SNAPSHOT) + +2023-09-06T14:29:20.824+02:00 INFO 206409 --- [ main] com.example.fraud.MessagingTest : Starting MessagingTest using Java 17.0.1 with PID 206409 (started by marcin in /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server) +2023-09-06T14:29:20.826+02:00 INFO 206409 --- [ main] com.example.fraud.MessagingTest : No active profile set, falling back to 1 default profile: "default" +2023-09-06T14:29:21.501+02:00 INFO 206409 --- [ main] faultConfiguringBeanFactoryPostProcessor : No bean named 'errorChannel' has been explicitly defined. Therefore, a default PublishSubscribeChannel will be created. +2023-09-06T14:29:21.506+02:00 INFO 206409 --- [ main] faultConfiguringBeanFactoryPostProcessor : No bean named 'integrationHeaderChannelRegistry' has been explicitly defined. Therefore, a default DefaultHeaderChannelRegistry will be created. +2023-09-06T14:29:22.743+02:00 WARN 206409 --- [ main] onConfiguration$FunctionBindingRegistrar : You have defined function definition that does not exist: my_output +2023-09-06T14:29:23.049+02:00 INFO 206409 --- [ main] o.s.c.c.v.m.i.ContractVerifierMessaging : The message verifier sender implementation is of type [class org.springframework.cloud.contract.verifier.messaging.stream.ContractVerifierStreamAutoConfiguration$InputDestinationConfiguration$1] +2023-09-06T14:29:23.049+02:00 INFO 206409 --- [ main] o.s.c.c.v.m.i.ContractVerifierMessaging : The message verifier receiver implementation is of type [class org.springframework.cloud.contract.verifier.messaging.stream.ContractVerifierStreamAutoConfiguration$InputDestinationConfiguration$2] +2023-09-06T14:29:23.077+02:00 INFO 206409 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 1 endpoint(s) beneath base path '/actuator' +2023-09-06T14:29:23.151+02:00 INFO 206409 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel +2023-09-06T14:29:23.152+02:00 INFO 206409 --- [ main] o.s.i.channel.PublishSubscribeChannel : Channel 'application.errorChannel' has 1 subscriber(s). +2023-09-06T14:29:23.152+02:00 INFO 206409 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started bean '_org.springframework.integration.errorLogger' +2023-09-06T14:29:23.165+02:00 INFO 206409 --- [ main] o.s.i.endpoint.ReactiveStreamsConsumer : started bean 'my_output_integrationflow.org.springframework.integration.config.ConsumerEndpointFactoryBean#0' +2023-09-06T14:29:23.165+02:00 INFO 206409 --- [ main] o.s.i.endpoint.ReactiveStreamsConsumer : started bean 'sensor_data_integrationflow.org.springframework.integration.config.ConsumerEndpointFactoryBean#0' +2023-09-06T14:29:23.170+02:00 INFO 206409 --- [ main] o.s.i.channel.PublishSubscribeChannel : Channel 'bytes_output.destination' has 1 subscriber(s). +2023-09-06T14:29:23.171+02:00 INFO 206409 --- [ main] o.s.c.s.m.DirectWithAttributesChannel : Channel 'application.my_output-out-0' has 1 subscriber(s). +2023-09-06T14:29:23.173+02:00 INFO 206409 --- [ main] o.s.i.channel.PublishSubscribeChannel : Channel 'sensor_data.destination' has 1 subscriber(s). +2023-09-06T14:29:23.174+02:00 INFO 206409 --- [ main] o.s.c.s.m.DirectWithAttributesChannel : Channel 'application.sensor_data-out-0' has 1 subscriber(s). +2023-09-06T14:29:23.186+02:00 INFO 206409 --- [ main] com.example.fraud.MessagingTest : Started MessagingTest in 2.514 seconds (process running for 3.066) +OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended +2023-09-06T14:29:23.783+02:00 INFO 206409 --- [ main] o.s.b.t.m.w.SpringBootMockServletContext : Initializing Spring TestDispatcherServlet '' +2023-09-06T14:29:23.783+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet '' +2023-09-06T14:29:23.785+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 1 ms +2023-09-06T14:29:23.926+02:00 INFO 206409 --- [ main] com.example.fraud.MessageSender : Emitting the message +2023-09-06T14:29:24.045+02:00 INFO 206409 --- [ main] com.example.fraud.MessageSender : Emitting the message +[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.592 s -- in com.example.fraud.MessagingTest +[INFO] Running com.example.fraud.FraudnameTest +2023-09-06T14:29:24.091+02:00 INFO 206409 --- [ main] o.s.mock.web.MockServletContext : Initializing Spring TestDispatcherServlet '' +2023-09-06T14:29:24.091+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet '' +2023-09-06T14:29:24.091+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 0 ms +2023-09-06T14:29:24.134+02:00 INFO 206409 --- [ main] o.s.mock.web.MockServletContext : Initializing Spring TestDispatcherServlet '' +2023-09-06T14:29:24.134+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet '' +2023-09-06T14:29:24.134+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 0 ms +2023-09-06T14:29:24.173+02:00 INFO 206409 --- [ main] o.s.mock.web.MockServletContext : Initializing Spring TestDispatcherServlet '' +2023-09-06T14:29:24.173+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet '' +2023-09-06T14:29:24.173+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 0 ms +[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.106 s -- in com.example.fraud.FraudnameTest +[INFO] Running com.example.fraud.TestTest +2023-09-06T14:29:24.189+02:00 INFO 206409 --- [ main] o.s.mock.web.MockServletContext : Initializing Spring TestDispatcherServlet '' +2023-09-06T14:29:24.190+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet '' +2023-09-06T14:29:24.190+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 0 ms +[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.012 s -- in com.example.fraud.TestTest +[INFO] Running com.example.fraud.FraudTest +2023-09-06T14:29:24.206+02:00 INFO 206409 --- [ main] o.s.mock.web.MockServletContext : Initializing Spring TestDispatcherServlet '' +2023-09-06T14:29:24.206+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet '' +2023-09-06T14:29:24.206+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 0 ms +2023-09-06T14:29:24.228+02:00 INFO 206409 --- [ main] o.s.mock.web.MockServletContext : Initializing Spring TestDispatcherServlet '' +2023-09-06T14:29:24.228+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet '' +2023-09-06T14:29:24.228+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 0 ms +2023-09-06T14:29:24.242+02:00 INFO 206409 --- [ main] o.s.mock.web.MockServletContext : Initializing Spring TestDispatcherServlet '' +2023-09-06T14:29:24.242+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet '' +2023-09-06T14:29:24.243+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 0 ms +2023-09-06T14:29:24.254+02:00 INFO 206409 --- [ main] o.s.mock.web.MockServletContext : Initializing Spring TestDispatcherServlet '' +2023-09-06T14:29:24.254+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet '' +2023-09-06T14:29:24.254+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 0 ms +[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.065 s -- in com.example.fraud.FraudTest +[INFO] Running com.example.fraud.MultipartTest +2023-09-06T14:29:24.273+02:00 INFO 206409 --- [ main] o.s.mock.web.MockServletContext : Initializing Spring TestDispatcherServlet '' +2023-09-06T14:29:24.273+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet '' +2023-09-06T14:29:24.273+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 0 ms +2023-09-06T14:29:24.295+02:00 INFO 206409 --- [ main] o.s.mock.web.MockServletContext : Initializing Spring TestDispatcherServlet '' +2023-09-06T14:29:24.296+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet '' +2023-09-06T14:29:24.296+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 0 ms +[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.039 s -- in com.example.fraud.MultipartTest +[INFO] Running com.example.fraud.yml.FraudnameTest +2023-09-06T14:29:24.313+02:00 INFO 206409 --- [ main] o.s.mock.web.MockServletContext : Initializing Spring TestDispatcherServlet '' +2023-09-06T14:29:24.313+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet '' +2023-09-06T14:29:24.313+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 0 ms +2023-09-06T14:29:24.329+02:00 INFO 206409 --- [ main] o.s.mock.web.MockServletContext : Initializing Spring TestDispatcherServlet '' +2023-09-06T14:29:24.329+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet '' +2023-09-06T14:29:24.329+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 0 ms +[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.032 s -- in com.example.fraud.yml.FraudnameTest +[INFO] Running com.example.fraud.yml.FraudTest +2023-09-06T14:29:24.343+02:00 INFO 206409 --- [ main] o.s.mock.web.MockServletContext : Initializing Spring TestDispatcherServlet '' +2023-09-06T14:29:24.344+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet '' +2023-09-06T14:29:24.344+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 0 ms +2023-09-06T14:29:24.358+02:00 INFO 206409 --- [ main] o.s.mock.web.MockServletContext : Initializing Spring TestDispatcherServlet '' +2023-09-06T14:29:24.358+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet '' +2023-09-06T14:29:24.359+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 1 ms +2023-09-06T14:29:24.371+02:00 INFO 206409 --- [ main] o.s.mock.web.MockServletContext : Initializing Spring TestDispatcherServlet '' +2023-09-06T14:29:24.371+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet '' +2023-09-06T14:29:24.372+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 0 ms +2023-09-06T14:29:24.383+02:00 INFO 206409 --- [ main] o.s.mock.web.MockServletContext : Initializing Spring TestDispatcherServlet '' +2023-09-06T14:29:24.383+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet '' +2023-09-06T14:29:24.383+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 0 ms +[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.053 s -- in com.example.fraud.yml.FraudTest +[INFO] Running com.example.fraud.BinaryTest +2023-09-06T14:29:24.396+02:00 INFO 206409 --- [ main] o.s.mock.web.MockServletContext : Initializing Spring TestDispatcherServlet '' +2023-09-06T14:29:24.396+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet '' +2023-09-06T14:29:24.397+02:00 INFO 206409 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 0 ms +[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.013 s -- in com.example.fraud.BinaryTest +[INFO] +[INFO] Results: +[INFO] +[INFO] Tests run: 20, Failures: 0, Errors: 0, Skipped: 0 +[INFO] +[INFO] +[INFO] --- exec-maven-plugin:1.6.0:exec (gradle) @ http-server-dsl --- +To honour the JVM settings for this build a single-use Daemon process will be forked. For more on this, please refer to https://docs.gradle.org/8.3/userguide/gradle_daemon.html#sec:disabling_the_daemon in the Gradle documentation. +Daemon will be stopped at the end of the build +> Task :clean UP-TO-DATE + +> Task :compileJava +Note: /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/MessagingConfiguration.java uses or overrides a deprecated API. +Note: Recompile with -Xlint:deprecation for details. + +> Task :processResources +> Task :classes +> Task :resolveMainClassName +> Task :bootJar +> Task :jar +> Task :copyContracts +> Task :generateClientStubs +> Task :verifierStubsJar +> Task :assemble +> Task :check +> Task :build +> Task :generatePomFileForMavenPublication +> Task :publishMavenPublicationToMavenLocal +> Task :publishToMavenLocal + +Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0. + +You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins. + +For more on this, please refer to https://docs.gradle.org/8.3/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation. + +BUILD SUCCESSFUL in 10s +11 actionable tasks: 10 executed, 1 up-to-date +[INFO] +[INFO] --- spring-cloud-contract-maven-plugin:4.1.0-SNAPSHOT:generateStubs (default-generateStubs) @ http-server-dsl --- +[INFO] Files matching this pattern will be excluded from stubs generation [] +[INFO] Building jar: /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/http-server-dsl-0.0.1-stubs.jar +[INFO] +[INFO] --- maven-jar-plugin:3.3.0:jar (default-jar) @ http-server-dsl --- +[INFO] Building jar: /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/http-server-dsl-0.0.1.jar +[INFO] +[INFO] --- spring-boot-maven-plugin:3.2.0-SNAPSHOT:repackage (repackage) @ http-server-dsl --- +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/boot/spring-boot-buildpack-platform/3.2.0-SNAPSHOT/maven-metadata.xml +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/boot/spring-boot-loader-tools/3.2.0-SNAPSHOT/maven-metadata.xml +[INFO] Replacing main artifact /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/http-server-dsl-0.0.1.jar with repackaged archive, adding nested dependencies in BOOT-INF/. +[INFO] The original artifact has been renamed to /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/http-server-dsl-0.0.1.jar.original +[INFO] +[INFO] --- maven-install-plugin:3.1.1:install (default-install) @ http-server-dsl --- +[INFO] Installing /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/pom.xml to /home/marcin/.m2/repository/com/example/http-server-dsl/0.0.1/http-server-dsl-0.0.1.pom +[INFO] Installing /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/http-server-dsl-0.0.1.jar to /home/marcin/.m2/repository/com/example/http-server-dsl/0.0.1/http-server-dsl-0.0.1.jar +[INFO] Installing /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-server/target/http-server-dsl-0.0.1-stubs.jar to /home/marcin/.m2/repository/com/example/http-server-dsl/0.0.1/http-server-dsl-0.0.1-stubs.jar +[INFO] +[INFO] --------------------< com.example:http-client-dsl >--------------------- +[INFO] Building Spring Cloud Contract Verifier Http Client Sample 0.0.1 [2/3] +[INFO] --------------------------------[ jar ]--------------------------------- +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-starter-contract-stub-runner/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] +[INFO] --- maven-clean-plugin:3.0.0:clean (default-clean) @ http-client-dsl --- +[INFO] Deleting /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-client/target +[INFO] +[INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ http-client-dsl --- +[INFO] Copying 1 resource from src/main/resources to target/classes +[INFO] Copying 0 resource from src/main/resources to target/classes +[INFO] +[INFO] --- maven-compiler-plugin:3.11.0:compile (default-compile) @ http-client-dsl --- +[INFO] Changes detected - recompiling the module! :source +[INFO] Compiling 12 source files with javac [debug release 17] to target/classes +[INFO] +[INFO] --- maven-resources-plugin:3.3.1:testResources (default-testResources) @ http-client-dsl --- +[INFO] Copying 6 resources from src/test/resources to target/test-classes +[INFO] +[INFO] --- maven-compiler-plugin:3.11.0:testCompile (default-testCompile) @ http-client-dsl --- +[INFO] Changes detected - recompiling the module! :dependency +[INFO] Compiling 5 source files with javac [debug release 17] to target/test-classes +[INFO] /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-client/src/test/java/com/example/loan/TestControllerTests.java: Some input files use or override a deprecated API. +[INFO] /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-client/src/test/java/com/example/loan/TestControllerTests.java: Recompile with -Xlint:deprecation for details. +[INFO] +[INFO] --- maven-surefire-plugin:3.1.2:test (default-test) @ http-client-dsl --- +[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider +[INFO] +[INFO] ------------------------------------------------------- +[INFO] T E S T S +[INFO] ------------------------------------------------------- +[INFO] Running com.example.loan.LoanApplicationServiceContextPathTests +14:29:36.802 [main] INFO org.springframework.test.context.support.AnnotationConfigContextLoaderUtils -- Could not detect default configuration classes for test class [com.example.loan.LoanApplicationServiceContextPathTests]: LoanApplicationServiceContextPathTests does not declare any static, non-private, non-final, nested classes annotated with @Configuration. +14:29:36.865 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper -- Found @SpringBootConfiguration com.example.loan.Application for test class com.example.loan.LoanApplicationServiceContextPathTests + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v3.2.0-SNAPSHOT) + +2023-09-06T14:29:37.101+02:00 INFO 207411 --- [ main] l.LoanApplicationServiceContextPathTests : Starting LoanApplicationServiceContextPathTests using Java 17.0.1 with PID 207411 (started by marcin in /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-client) +2023-09-06T14:29:37.102+02:00 INFO 207411 --- [ main] l.LoanApplicationServiceContextPathTests : No active profile set, falling back to 1 default profile: "default" +2023-09-06T14:29:37.234+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockApplicationListener : Registered WireMock server port property to the default <8080> value +2023-09-06T14:29:37.243+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockApplicationListener : Registered property source for property [wiremock.server.https-port] with value [13405] +2023-09-06T14:29:37.243+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockApplicationListener : Registered property source for dynamic https port +2023-09-06T14:29:37.713+02:00 INFO 207411 --- [ main] faultConfiguringBeanFactoryPostProcessor : No bean named 'errorChannel' has been explicitly defined. Therefore, a default PublishSubscribeChannel will be created. +2023-09-06T14:29:37.721+02:00 INFO 207411 --- [ main] faultConfiguringBeanFactoryPostProcessor : No bean named 'integrationHeaderChannelRegistry' has been explicitly defined. Therefore, a default DefaultHeaderChannelRegistry will be created. +2023-09-06T14:29:37.855+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration' of type [org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). The currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor] is declared through a non-static factory method on that class; consider declaring it as static instead. +2023-09-06T14:29:37.859+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.stream.config.BindersHealthIndicatorAutoConfiguration' of type [org.springframework.cloud.stream.config.BindersHealthIndicatorAutoConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:37.861+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'bindersHealthContributor' of type [org.springframework.cloud.stream.config.BindersHealthIndicatorAutoConfiguration$BindersHealthContributor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:37.862+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'bindersHealthIndicatorListener' of type [org.springframework.cloud.stream.config.BindersHealthIndicatorAutoConfiguration$BindersHealthIndicatorListener] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:37.864+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.stream.binder.rabbit.config.ExtendedBindingHandlerMappingsProviderConfiguration' of type [org.springframework.cloud.stream.binder.rabbit.config.ExtendedBindingHandlerMappingsProviderConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:37.865+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'rabbitExtendedPropertiesDefaultMappingsProvider' of type [org.springframework.cloud.stream.binder.rabbit.config.ExtendedBindingHandlerMappingsProviderConfiguration$$Lambda$895/0x000000080105a6b0] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:37.865+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'BindingHandlerAdvise' of type [org.springframework.cloud.stream.config.BindingHandlerAdvise] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:37.872+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'spelConverter' of type [org.springframework.cloud.stream.config.SpelExpressionConverterConfiguration$SpelConverter] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:37.877+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'stubrunner-org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties' of type [org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:37.881+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.CompositeStubDownloader : Registered following stub downloaders [org.springframework.cloud.contract.stubrunner.ScmStubDownloaderBuilder, org.springframework.cloud.contract.stubrunner.ClasspathStubProvider, org.springframework.cloud.contract.stubrunner.FileStubDownloader, org.springframework.cloud.contract.stubrunner.AetherStubDownloaderBuilder] +2023-09-06T14:29:37.882+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.StubRunnerFactory : Will download stubs for dependencies [com.example:http-server-dsl:0.0.1:stubs] +2023-09-06T14:29:37.882+02:00 INFO 207411 --- [ main] o.s.c.c.s.AetherStubDownloaderBuilder : Will download stubs and contracts via Aether +2023-09-06T14:29:37.897+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Will be resolving versions for the following options: [StubRunnerOptions{minPortValue=10000, maxPortValue=15000, stubRepositoryRoot='null', stubsMode='LOCAL', stubsClassifier='stubs', dependencies=[com.example:http-server-dsl:0.0.1:stubs], stubIdsToPortMapping={com.example:http-server-dsl:0.0.1:stubs=6565}, username='', password='', stubRunnerProxyOptions='null', stubsPerConsumer='false', httpServerStubConfigurer='class org.springframework.cloud.contract.stubrunner.HttpServerStubConfigurer$NoOpHttpServerStubConfigurer', serverId='null'}] +2023-09-06T14:29:37.902+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.AetherFactories : No custom maven user settings provided, will use [/home/marcin/.m2/settings.xml] +2023-09-06T14:29:37.920+02:00 INFO 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Remote repos not passed but the switch to work offline was set. Stubs will be used from your local Maven repository. +2023-09-06T14:29:37.958+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.AetherFactories : No custom maven user settings provided, will use [/home/marcin/.m2/settings.xml] +2023-09-06T14:29:37.960+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.AetherFactories : Local Repository Directory set to [/home/marcin/.m2/repository]. Work offline: [true] +2023-09-06T14:29:37.962+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.CompositeStubDownloader : Found a matching stub downloader [org.springframework.cloud.contract.stubrunner.AetherStubDownloader] +2023-09-06T14:29:37.965+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Resolved version range is [{}] +2023-09-06T14:29:37.965+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Will download the stub for version [0.0.1] +2023-09-06T14:29:37.965+02:00 INFO 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Resolved version is [0.0.1] +2023-09-06T14:29:37.966+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Resolving artifact [com.example:http-server-dsl:jar:stubs:0.0.1] using remote repositories [] +2023-09-06T14:29:37.968+02:00 INFO 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Resolved artifact [com.example:http-server-dsl:jar:stubs:0.0.1] to /home/marcin/.m2/repository/com/example/http-server-dsl/0.0.1/http-server-dsl-0.0.1-stubs.jar +2023-09-06T14:29:37.970+02:00 INFO 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Unpacking stub from JAR [URI: file:/home/marcin/.m2/repository/com/example/http-server-dsl/0.0.1/http-server-dsl-0.0.1-stubs.jar] +2023-09-06T14:29:37.979+02:00 INFO 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Unpacked file to [/tmp/contracts-1694003377969-0] +2023-09-06T14:29:37.980+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.CompositeStubDownloader : Found a matching entry [com.example:http-server-dsl:0.0.1:stubs=/tmp/contracts-1694003377969-0] by stub downloader [org.springframework.cloud.contract.stubrunner.AetherStubDownloader] +2023-09-06T14:29:37.980+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.StubRunnerFactory : For stub configuration [com.example:http-server-dsl:0.0.1:stubs] the downloaded entry is [com.example:http-server-dsl:0.0.1:stubs=/tmp/contracts-1694003377969-0] +2023-09-06T14:29:40.143+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : For com.example:http-server-dsl:0.0.1:stubs Started WireMock at [http] port [6565] +2023-09-06T14:29:40.206+02:00 INFO 207411 --- [tp1268380397-41] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [225] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "d0ddffca-2181-453b-9236-1eccb331de5a", + "request" : { + "url" : "/ping", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "OK" + }, + "uuid" : "d0ddffca-2181-453b-9236-1eccb331de5a" +} + +2023-09-06T14:29:40.216+02:00 INFO 207411 --- [tp1268380397-34] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [227] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "c52a1b9e-55cd-4b3b-a765-74e3f270c557", + "request" : { + "url" : "/health", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "OK" + }, + "uuid" : "c52a1b9e-55cd-4b3b-a765-74e3f270c557" +} + +2023-09-06T14:29:40.219+02:00 INFO 207411 --- [tp1268380397-40] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [280] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "6cf2a97d-5eac-4d1a-bdb4-262a2626ed62", + "request" : { + "url" : "/example", + "method" : "GET" + }, + "response" : { + "status" : 200, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "6cf2a97d-5eac-4d1a-bdb4-262a2626ed62" +} + +2023-09-06T14:29:40.220+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003377969-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/test/MyHttpContract.json] +2023-09-06T14:29:40.221+02:00 INFO 207411 --- [tp1268380397-41] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [415] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "fa16a598-8141-456c-a737-ea03dc554383", + "request" : { + "url" : "/drunks", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "{\"count\":100}", + "headers" : { + "Content-Type" : "application/json" + }, + "fixedDelayMilliseconds" : 2000, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "fa16a598-8141-456c-a737-ea03dc554383" +} + +2023-09-06T14:29:40.222+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003377969-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraud/shouldReturnFraudStats_1.json] +2023-09-06T14:29:40.226+02:00 INFO 207411 --- [tp1268380397-40] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [707] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "660fc6f9-2508-45a0-a1a3-4d3035c2955b", + "request" : { + "url" : "/fraudcheck", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "matches" : "application/json.*" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.['client.id'] =~ /[0-9]{10}/)]" + }, { + "matchesJsonPath" : "$[?(@.['loanAmount'] == 99999)]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"FRAUD\",\"rejection.reason\":\"Amount too high\"}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "660fc6f9-2508-45a0-a1a3-4d3035c2955b" +} + +2023-09-06T14:29:40.227+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003377969-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraud/shouldMarkClientAsFraud.json] +2023-09-06T14:29:40.229+02:00 INFO 207411 --- [tp1268380397-41] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [691] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "cf47e5df-1c9c-42f9-a3fb-fd3d1c869f65", + "request" : { + "url" : "/fraudcheck", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "matches" : "application/json.*" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.['client.id'] =~ /[0-9]{10}/)]" + }, { + "matchesJsonPath" : "$[?(@.['loanAmount'] == 123.123)]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"OK\",\"rejection.reason\":null}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "cf47e5df-1c9c-42f9-a3fb-fd3d1c869f65" +} + +2023-09-06T14:29:40.230+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003377969-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraud/shouldMarkClientAsNotFraud.json] +2023-09-06T14:29:40.231+02:00 INFO 207411 --- [tp1268380397-40] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [378] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "f5243e52-a4d7-453b-95a3-340595e07430", + "request" : { + "url" : "/frauds", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "{\"count\":780}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "f5243e52-a4d7-453b-95a3-340595e07430" +} + +2023-09-06T14:29:40.232+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003377969-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraud/should count all frauds.json] +2023-09-06T14:29:40.234+02:00 INFO 207411 --- [tp1268380397-41] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [1212] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "2de50d1e-4e66-4772-b884-f1f91a290d33", + "request" : { + "url" : "/tests", + "method" : "POST", + "headers" : { + "Content-Type" : { + "matches" : "multipart/form-data.*" + } + }, + "bodyPatterns" : [ { + "matches" : ".*--(.*)\r?\nContent-Disposition: form-data; name=\"file1\"; filename=\"[\\S\\s]+\"\r?\n(Content-Type: .*\r?\n)?(Content-Transfer-Encoding: .*\r?\n)?(Content-Length: \\d+\r?\n)?\r?\n[\\S\\s]+\r?\n--.*" + }, { + "matches" : ".*--(.*)\r?\nContent-Disposition: form-data; name=\"file2\"; filename=\"[\\S\\s]+\"\r?\n(Content-Type: .*\r?\n)?(Content-Transfer-Encoding: .*\r?\n)?(Content-Length: \\d+\r?\n)?\r?\n[\\S\\s]+\r?\n--.*" + }, { + "matches" : ".*--(.*)\r?\nContent-Disposition: form-data; name=\"test\"; filename=\"[\\S\\s]+\"\r?\n(Content-Type: application/json\r?\n)?(Content-Transfer-Encoding: .*\r?\n)?(Content-Length: \\d+\r?\n)?\r?\n[\\S\\s]+\r?\n--.*" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"status\":\"ok\"}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "2de50d1e-4e66-4772-b884-f1f91a290d33" +} + +2023-09-06T14:29:40.239+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003377969-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/multipart/shouldWorkForMultipartWithContentType.json] +2023-09-06T14:29:40.241+02:00 INFO 207411 --- [tp1268380397-40] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [1212] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "e10ced51-f2a6-47d9-adcb-da55409ebd9c", + "request" : { + "url" : "/tests", + "method" : "POST", + "headers" : { + "Content-Type" : { + "matches" : "multipart/form-data.*" + } + }, + "bodyPatterns" : [ { + "matches" : ".*--(.*)\r?\nContent-Disposition: form-data; name=\"file1\"; filename=\"[\\S\\s]+\"\r?\n(Content-Type: .*\r?\n)?(Content-Transfer-Encoding: .*\r?\n)?(Content-Length: \\d+\r?\n)?\r?\n[\\S\\s]+\r?\n--.*" + }, { + "matches" : ".*--(.*)\r?\nContent-Disposition: form-data; name=\"file2\"; filename=\"[\\S\\s]+\"\r?\n(Content-Type: .*\r?\n)?(Content-Transfer-Encoding: .*\r?\n)?(Content-Length: \\d+\r?\n)?\r?\n[\\S\\s]+\r?\n--.*" + }, { + "matches" : ".*--(.*)\r?\nContent-Disposition: form-data; name=\"test\"; filename=\"[\\S\\s]+\"\r?\n(Content-Type: application/json\r?\n)?(Content-Transfer-Encoding: .*\r?\n)?(Content-Length: \\d+\r?\n)?\r?\n[\\S\\s]+\r?\n--.*" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"status\":\"ok\"}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "e10ced51-f2a6-47d9-adcb-da55409ebd9c" +} + +2023-09-06T14:29:40.242+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003377969-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/multipart/shouldWorkForMultipartAsBytesWithContentType.json] +2023-09-06T14:29:40.243+02:00 INFO 207411 --- [tp1268380397-41] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [280] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "e2b18718-34cd-4a7b-83ca-8278cb54c70e", + "request" : { + "urlPath" : "/foo", + "method" : "GET" + }, + "response" : { + "status" : 200, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "e2b18718-34cd-4a7b-83ca-8278cb54c70e" +} + +2023-09-06T14:29:40.244+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003377969-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/messaging/shouldReturnOkWhenServiceIsHealthy.json] +2023-09-06T14:29:40.252+02:00 INFO 207411 --- [tp1268380397-40] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [41072] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "a1a3e8ea-3a5a-491d-90e2-b8d3a48c8a54", + "request" : { + "url" : "/1", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "matches" : "application/octet-stream.*" + } + }, + "bodyPatterns" : [ { + "binaryEqualTo" : "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YXRlRGVjb2RlIC9MZW5ndGggMjQ3ID4+CnN0cmVhbQp4nF2QTWvDMAyG7/4VOnaHYtddoYdg6DIKOeyDZfsBjq1khsU2jnPIv58/SgcT2PAgvZJe0bZ77qyJQN+DUz1GGI3VARe3BoUw4GQsOXDQRsUblV/N0hOaxP22RJw7OzrSNAD0I2WXGDbYXbQb8IHQt6AxGDvB7qvtE/er9z84o43AiBCgcUydXqR/lTMCLbJ9p1PexG2fNH8Vn5tH4IUPdRvlNC5eKgzSTkgalkJAc00hCFr9L3+qqmFU3zKU6mOqZowzkYmfCz2eKj1VOle6VmoLHXmlOuXWL8/Ld7mbUWsIyUc5XjGQVzcW7/f1zmdVfr87IHo2ZW5kc3RyZWFtCmVuZG9iagoxMCAwIG9iago8PCAvVHlwZSAvT2JqU3RtIC9MZW5ndGggNDU5IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlIC9OIDYgL0ZpcnN0IDM3ID4+CnN0cmVhbQp4nHVRy27bMBC89yv2aB/MlyhRBAIDdlw3RuEkiJ3kUOTASKxKVBIFiQbqv+9Sjlr3UBAEAe7szOws58CAC0g48ARUClyC1sBTEByfDKRWn25ugD72vjwVtofZ4acz9HGzhUaJOSyXY/nWn9oAHOhXVw7wDTKkfYI3oMdzZ7HbVHaYsOs90HvfN6YGWhhsmv7NYLceaeiqd6beH4Fu7FDYtjRtiIVIjM4+mD+3hS9dWwHdlbYNLpwXd0APp/cwSkZhho9/bh0CLeix8cPQqPN/3dvd5nAegm127XcPEfTQl7aParNJbQ70yVZuCP0ZZqvSv9t5lO+62jaIQLXlcmQ6+i+7zd50f43iYK9YH13EEXvXBd/HuEeLf2bA5giJlsU/zukrRsHwqpRBPEIpkieCJZiMjIUsy4jWcYmxrIQgPFNawQWephnhqUjkpXrV/DalsorJB9AsJUIlUqIb091ZV/0IoHhKcsTzaUMBFoJzorlkGVqsTTWAvHhdr/0v9LPIMknSlKkcFomQRDGFeoKJnIzKnCWKcKaTPO42Nm5djVPnl0jix71p7NWOdsHUrli1VW1jlgfc1gtINKZziSxXcV1FjMP9BoAQz0xlbmRzdHJlYW0KZW5kb2JqCjEgMCBvYmoKPDwgL1R5cGUgL1hSZWYgL0xlbmd0aCAxNiAvRmlsdGVyIC9GbGF0ZURlY29kZSAvRGVjb2RlUGFybXMgPDwgL0NvbHVtbnMgNCAvUHJlZGljdG9yIDEyID4+IC9XIFsgMSAyIDEgXSAvU2l6ZSAyIC9JRCBbPGEyOGUxYTMyZjIzMjg4ZjI1YzRkZGRhODQ3NmQ2YjUxPjxhMjhlMWEzMmYyMzI4OGYyNWM0ZGRkYTg0NzZkNmI1MT5dID4+CnN0cmVhbQp4nGNiAAImRgsRBgAA/ABSCmVuZHN0cmVhbQplbmRvYmoKICAgICAgICAgICAgICAgCnN0YXJ0eHJlZgoyMTYKJSVFT0YK" + } ] + }, + "response" : { + "status" : 200, + "base64Body" : "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", + "headers" : { + "Content-Type" : "application/octet-stream" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "a1a3e8ea-3a5a-491d-90e2-b8d3a48c8a54" +} + +2023-09-06T14:29:40.263+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003377969-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/binary/shouldWorkWithBinaryPayload.json] +2023-09-06T14:29:40.264+02:00 INFO 207411 --- [tp1268380397-41] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [386] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "72de0479-f640-4b3d-aab9-a9f6ad0e33f9", + "request" : { + "urlPath" : "/yamldrunks", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "{\"count\":100}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "72de0479-f640-4b3d-aab9-a9f6ad0e33f9" +} + +2023-09-06T14:29:40.265+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003377969-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/yml/fraud/shouldReturnFraudStats_1.json] +2023-09-06T14:29:40.267+02:00 INFO 207411 --- [tp1268380397-40] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [715] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "44c88877-5d4b-491e-8ac5-7ab599794d69", + "request" : { + "urlPath" : "/yamlfraudcheck", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "equalTo" : "application/json" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.['loanAmount'] == 99999)]" + }, { + "matchesJsonPath" : "$[?(@.['client.id'] =~ /([0-9]{10})/)]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"FRAUD\",\"rejection.reason\":\"Amount too high\"}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "44c88877-5d4b-491e-8ac5-7ab599794d69" +} + +2023-09-06T14:29:40.268+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003377969-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/yml/fraud/shouldMarkClientAsFraud.json] +2023-09-06T14:29:40.269+02:00 INFO 207411 --- [tp1268380397-41] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [699] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "1ccb766e-ce35-47e6-b14b-eccd836e237e", + "request" : { + "urlPath" : "/yamlfraudcheck", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "equalTo" : "application/json" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.['loanAmount'] == 123.123)]" + }, { + "matchesJsonPath" : "$[?(@.['client.id'] =~ /([0-9]{10})/)]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"OK\",\"rejection.reason\":null}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "1ccb766e-ce35-47e6-b14b-eccd836e237e" +} + +2023-09-06T14:29:40.270+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003377969-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/yml/fraud/shouldMarkClientAsNotFraud.json] +2023-09-06T14:29:40.272+02:00 INFO 207411 --- [tp1268380397-40] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [423] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "18870094-18db-484a-ade9-e161dae03756", + "request" : { + "urlPath" : "/yamlfrauds", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "{\"count\":200}", + "headers" : { + "Content-Type" : "application/json" + }, + "fixedDelayMilliseconds" : 2000, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "18870094-18db-484a-ade9-e161dae03756" +} + +2023-09-06T14:29:40.272+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003377969-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/yml/fraud/should count all frauds.json] +2023-09-06T14:29:40.273+02:00 INFO 207411 --- [tp1268380397-41] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [665] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "3ba3f8d4-ff5d-4355-84dd-e92248677ef2", + "request" : { + "urlPath" : "/yamlfrauds/name", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "equalTo" : "application/json" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.name =~ /([\\p{L}]*)/)]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"result\":\"Don't worry {{{ jsonpath this '$.name' }}} you're not a fraud\"}", + "headers" : { + "Content-Type" : "{{{ request.headers.Content-Type.0 }}}" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "3ba3f8d4-ff5d-4355-84dd-e92248677ef2" +} + +2023-09-06T14:29:40.274+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003377969-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/yml/fraudname/shouldReturnNonFraudForTheName.json] +2023-09-06T14:29:40.276+02:00 INFO 207411 --- [tp1268380397-40] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [675] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "a8c7f458-fd9a-4c9f-af66-f0085c38faa4", + "request" : { + "urlPath" : "/yamlfrauds/name", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "equalTo" : "application/json" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.['name'] == 'fraud')]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"result\":\"Sorry {{{ jsonpath this '$.name' }}} but you're a fraud\"}", + "headers" : { + "Content-Type" : "{{{ request.headers.Content-Type.0 }}}" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "a8c7f458-fd9a-4c9f-af66-f0085c38faa4", + "priority" : 1 +} + +2023-09-06T14:29:40.276+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003377969-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/yml/fraudname/shouldReturnAFraudForTheName.json] +2023-09-06T14:29:40.278+02:00 INFO 207411 --- [tp1268380397-41] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [667] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "c50f9381-4230-4937-ab58-d9e8e21f303a", + "request" : { + "url" : "/frauds/name", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "matches" : "application/json.*" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.['name'] =~ /[\\p{L}]*/)]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"result\":\"Don't worry {{{jsonPath request.body '$.name'}}} you're not a fraud\"}", + "headers" : { + "Content-Type" : "{{{request.headers.Content-Type.[0]}}}" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "c50f9381-4230-4937-ab58-d9e8e21f303a" +} + +2023-09-06T14:29:40.278+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003377969-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraudname/shouldReturnNonFraudForTheName.json] +2023-09-06T14:29:40.280+02:00 INFO 207411 --- [tp1268380397-40] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [437] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "7c109624-495a-4d92-bcba-09c4d470d98f", + "request" : { + "url" : "/frauds/name", + "method" : "GET", + "cookies" : { + "name2" : { + "equalTo" : "bar" + }, + "name" : { + "equalTo" : "foo" + } + } + }, + "response" : { + "status" : 200, + "body" : "foo bar", + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "7c109624-495a-4d92-bcba-09c4d470d98f" +} + +2023-09-06T14:29:40.281+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003377969-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraudname/shouldReturnACookie.json] +2023-09-06T14:29:40.282+02:00 INFO 207411 --- [tp1268380397-41] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [675] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "70027628-be19-49fc-b12b-f0bba0c88265", + "request" : { + "url" : "/frauds/name", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "matches" : "application/json.*" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.['name'] == 'fraud')]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"result\":\"Sorry {{{jsonPath request.body '$.name'}}} but you're a fraud\"}", + "headers" : { + "Content-Type" : "{{{request.headers.Content-Type.[0]}}}" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "70027628-be19-49fc-b12b-f0bba0c88265", + "priority" : 1 +} + +2023-09-06T14:29:40.283+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003377969-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraudname/shouldReturnAFraudForTheName.json] +2023-09-06T14:29:40.284+02:00 INFO 207411 --- [ main] o.s.c.contract.stubrunner.StubServer : Started stub server for project [com.example:http-server-dsl:0.0.1:stubs] on port 6565 with [18] mappings +2023-09-06T14:29:40.285+02:00 DEBUG 207411 --- [ main] o.s.c.contract.stubrunner.StubServer : Ports for this server are https [-1] and http [6565] +2023-09-06T14:29:40.285+02:00 INFO 207411 --- [ main] o.s.c.c.stubrunner.StubRunnerExecutor : All stubs are now running RunningStubs [namesAndPorts={com.example:http-server-dsl:0.0.1:stubs=6565}] +2023-09-06T14:29:40.286+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'batchStubRunner' of type [org.springframework.cloud.contract.stubrunner.BatchStubRunner] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:40.768+02:00 INFO 207411 --- [ main] o.s.c.s.m.DirectWithAttributesChannel : Channel 'application.listener-in-0' has 1 subscriber(s). +2023-09-06T14:29:40.901+02:00 INFO 207411 --- [ main] o.s.c.c.v.m.i.ContractVerifierMessaging : The message verifier sender implementation is of type [class org.springframework.cloud.contract.verifier.messaging.stream.ContractVerifierStreamAutoConfiguration$InputDestinationConfiguration$1] +2023-09-06T14:29:40.901+02:00 INFO 207411 --- [ main] o.s.c.c.v.m.i.ContractVerifierMessaging : The message verifier receiver implementation is of type [class org.springframework.cloud.contract.verifier.messaging.stream.ContractVerifierStreamAutoConfiguration$InputDestinationConfiguration$2] +2023-09-06T14:29:40.968+02:00 INFO 207411 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel +2023-09-06T14:29:40.968+02:00 INFO 207411 --- [ main] o.s.i.channel.PublishSubscribeChannel : Channel 'application.errorChannel' has 1 subscriber(s). +2023-09-06T14:29:40.969+02:00 INFO 207411 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started bean '_org.springframework.integration.errorLogger' +2023-09-06T14:29:40.970+02:00 INFO 207411 --- [ main] o.s.c.s.binder.DefaultBinderFactory : Creating binder: integration +2023-09-06T14:29:40.970+02:00 INFO 207411 --- [ main] o.s.c.s.binder.DefaultBinderFactory : Constructing binder child context for integration +2023-09-06T14:29:41.023+02:00 INFO 207411 --- [ main] o.s.c.s.binder.DefaultBinderFactory : Caching the binder: integration +2023-09-06T14:29:41.035+02:00 INFO 207411 --- [ main] o.s.c.stream.binder.BinderErrorChannel : Channel '367553828.listener-in-0.errors' has 1 subscriber(s). +2023-09-06T14:29:41.036+02:00 INFO 207411 --- [ main] o.s.c.stream.binder.BinderErrorChannel : Channel '367553828.listener-in-0.errors' has 2 subscriber(s). +2023-09-06T14:29:41.036+02:00 INFO 207411 --- [ main] o.s.i.channel.PublishSubscribeChannel : Channel 'sensor_data.destination' has 1 subscriber(s). +2023-09-06T14:29:41.037+02:00 INFO 207411 --- [ main] r$IntegrationBinderInboundChannelAdapter : started org.springframework.cloud.stream.binder.test.TestChannelBinder$IntegrationBinderInboundChannelAdapter@182ce25e +2023-09-06T14:29:41.050+02:00 INFO 207411 --- [ main] l.LoanApplicationServiceContextPathTests : Started LoanApplicationServiceContextPathTests in 4.119 seconds (process running for 4.712) +2023-09-06T14:29:41.053+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended +2023-09-06T14:29:41.655+02:00 INFO 207411 --- [tp1268380397-40] WireMock : Request received: +127.0.0.1 - PUT /fraudcheck + +Accept: [application/json, application/*+json] +Content-Type: [application/json] +Accept-Encoding: [gzip, x-gzip, deflate] +Transfer-Encoding: [chunked] +Host: [localhost:6565] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.2.1 (Java/17.0.1)] +{"loanAmount":123.123,"client.id":"1234567890"} + + +Matched response definition: +{ + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"OK\",\"rejection.reason\":null}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] +} + +Response: +HTTP/1.1 200 +Content-Type: [application/json] +Matched-Stub-Id: [cf47e5df-1c9c-42f9-a3fb-fd3d1c869f65] + +2023-09-06T14:29:41.696+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +2023-09-06T14:29:41.707+02:00 INFO 207411 --- [tp1268380397-39] WireMock : Request received: +127.0.0.1 - PUT /fraudcheck + +Accept: [application/json, application/*+json] +Content-Type: [application/json] +Accept-Encoding: [gzip, x-gzip, deflate] +Transfer-Encoding: [chunked] +Host: [localhost:6565] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.2.1 (Java/17.0.1)] +{"loanAmount":99999.0,"client.id":"1234567890"} + + +Matched response definition: +{ + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"FRAUD\",\"rejection.reason\":\"Amount too high\"}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] +} + +Response: +HTTP/1.1 200 +Content-Type: [application/json] +Matched-Stub-Id: [660fc6f9-2508-45a0-a1a3-4d3035c2955b] + +2023-09-06T14:29:41.708+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +2023-09-06T14:29:41.710+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +2023-09-06T14:29:41.710+02:00 WARN 207411 --- [ main] .StubRunnerWireMockTestExecutionListener : You've used fixed ports for WireMock setup - will mark context as dirty. Please use random ports, as much as possible. Your tests will be faster and more reliable and this warning will go away +2023-09-06T14:29:41.713+02:00 INFO 207411 --- [ main] r$IntegrationBinderInboundChannelAdapter : stopped org.springframework.cloud.stream.binder.test.TestChannelBinder$IntegrationBinderInboundChannelAdapter@182ce25e +2023-09-06T14:29:41.716+02:00 INFO 207411 --- [ main] o.s.c.stream.binder.BinderErrorChannel : Channel 'application.367553828.listener-in-0.errors' has 1 subscriber(s). +2023-09-06T14:29:41.718+02:00 INFO 207411 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Removing {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel +2023-09-06T14:29:41.719+02:00 INFO 207411 --- [ main] o.s.i.channel.PublishSubscribeChannel : Channel 'application.errorChannel' has 0 subscriber(s). +2023-09-06T14:29:41.719+02:00 INFO 207411 --- [ main] o.s.i.endpoint.EventDrivenConsumer : stopped bean '_org.springframework.integration.errorLogger' +2023-09-06T14:29:41.729+02:00 DEBUG 207411 --- [ main] o.s.c.contract.stubrunner.StubServer : Ports for this server are https [-1] and http [6565] +2023-09-06T14:29:41.729+02:00 DEBUG 207411 --- [ main] o.s.c.contract.stubrunner.StubServer : Stopping the server at port [6565] +[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 5.023 s -- in com.example.loan.LoanApplicationServiceContextPathTests +[INFO] Running com.example.loan.GoodbyeWorldTests +2023-09-06T14:29:41.742+02:00 INFO 207411 --- [ main] t.c.s.AnnotationConfigContextLoaderUtils : Could not detect default configuration classes for test class [com.example.loan.GoodbyeWorldTests]: GoodbyeWorldTests does not declare any static, non-private, non-final, nested classes annotated with @Configuration. +2023-09-06T14:29:41.745+02:00 INFO 207411 --- [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.example.loan.Application for test class com.example.loan.GoodbyeWorldTests + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v3.2.0-SNAPSHOT) + +2023-09-06T14:29:41.772+02:00 INFO 207411 --- [ main] com.example.loan.GoodbyeWorldTests : Starting GoodbyeWorldTests using Java 17.0.1 with PID 207411 (started by marcin in /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-client) +2023-09-06T14:29:41.772+02:00 INFO 207411 --- [ main] com.example.loan.GoodbyeWorldTests : No active profile set, falling back to 1 default profile: "default" +2023-09-06T14:29:41.773+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockApplicationListener : Registered WireMock server port property to the default <8080> value +2023-09-06T14:29:41.774+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockApplicationListener : Registered property source for property [wiremock.server.https-port] with value [12531] +2023-09-06T14:29:41.774+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockApplicationListener : Registered property source for dynamic https port +2023-09-06T14:29:41.936+02:00 INFO 207411 --- [ main] faultConfiguringBeanFactoryPostProcessor : No bean named 'errorChannel' has been explicitly defined. Therefore, a default PublishSubscribeChannel will be created. +2023-09-06T14:29:41.936+02:00 INFO 207411 --- [ main] faultConfiguringBeanFactoryPostProcessor : No bean named 'integrationHeaderChannelRegistry' has been explicitly defined. Therefore, a default DefaultHeaderChannelRegistry will be created. +2023-09-06T14:29:41.956+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration' of type [org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). The currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor] is declared through a non-static factory method on that class; consider declaring it as static instead. +2023-09-06T14:29:41.959+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.stream.config.BindersHealthIndicatorAutoConfiguration' of type [org.springframework.cloud.stream.config.BindersHealthIndicatorAutoConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:41.959+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'bindersHealthContributor' of type [org.springframework.cloud.stream.config.BindersHealthIndicatorAutoConfiguration$BindersHealthContributor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:41.960+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'bindersHealthIndicatorListener' of type [org.springframework.cloud.stream.config.BindersHealthIndicatorAutoConfiguration$BindersHealthIndicatorListener] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:41.961+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.stream.binder.rabbit.config.ExtendedBindingHandlerMappingsProviderConfiguration' of type [org.springframework.cloud.stream.binder.rabbit.config.ExtendedBindingHandlerMappingsProviderConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:41.961+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'rabbitExtendedPropertiesDefaultMappingsProvider' of type [org.springframework.cloud.stream.binder.rabbit.config.ExtendedBindingHandlerMappingsProviderConfiguration$$Lambda$895/0x000000080105a6b0] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:41.961+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'BindingHandlerAdvise' of type [org.springframework.cloud.stream.config.BindingHandlerAdvise] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:41.962+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'spelConverter' of type [org.springframework.cloud.stream.config.SpelExpressionConverterConfiguration$SpelConverter] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:41.966+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'stubrunner-org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties' of type [org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:41.967+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.CompositeStubDownloader : Registered following stub downloaders [org.springframework.cloud.contract.stubrunner.ScmStubDownloaderBuilder, org.springframework.cloud.contract.stubrunner.ClasspathStubProvider, org.springframework.cloud.contract.stubrunner.FileStubDownloader, org.springframework.cloud.contract.stubrunner.AetherStubDownloaderBuilder] +2023-09-06T14:29:41.967+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.StubRunnerFactory : Will download stubs for dependencies [com.example:http-server-dsl:+:stubs] +2023-09-06T14:29:41.968+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.CompositeStubDownloader : Found a matching stub downloader [org.springframework.cloud.contract.stubrunner.StubsStubDownloader] +2023-09-06T14:29:41.969+02:00 INFO 207411 --- [ main] o.s.c.c.stubrunner.StubsStubDownloader : Stubs are present under [classpath:contractsAtRuntime/]. Will copy them to a temporary directory. +2023-09-06T14:29:41.974+02:00 DEBUG 207411 --- [ main] .s.c.c.s.ResourceResolvingStubDownloader : For paths [classpath:contractsAtRuntime/**/*.*] found following resources [file [/home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-client/target/test-classes/contractsAtRuntime/goodbyeWorld.groovy]] +2023-09-06T14:29:41.975+02:00 DEBUG 207411 --- [ main] .s.c.c.s.ResourceResolvingStubDownloader : Relative path for resource is [goodbyeWorld.groovy] +2023-09-06T14:29:41.975+02:00 DEBUG 207411 --- [ main] .s.c.c.s.ResourceResolvingStubDownloader : Relative path without file name is [goodbyeWorld.groovy] +2023-09-06T14:29:41.976+02:00 DEBUG 207411 --- [ main] .s.c.c.s.ResourceResolvingStubDownloader : Stored file [/tmp/classpath-stubs-1694003381974-0/goodbyeWorld.groovy/goodbyeWorld.groovy] +2023-09-06T14:29:41.977+02:00 INFO 207411 --- [ main] .s.c.c.s.ResourceResolvingStubDownloader : Unpacked files for [com.example:http-server-dsl:+] to folder [/tmp/classpath-stubs-1694003381974-0] +2023-09-06T14:29:41.977+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.CompositeStubDownloader : Found a matching entry [com.example:http-server-dsl:+:stubs=/tmp/classpath-stubs-1694003381974-0] by stub downloader [org.springframework.cloud.contract.stubrunner.StubsStubDownloader] +2023-09-06T14:29:41.978+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.StubRunnerFactory : For stub configuration [com.example:http-server-dsl:+:stubs] the downloaded entry is [com.example:http-server-dsl:+:stubs=/tmp/classpath-stubs-1694003381974-0] +2023-09-06T14:29:41.978+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.StubRunnerFactory : Flag to generate stubs at runtime was switched on. Will remove the current mappings and will generate new ones. +2023-09-06T14:29:42.073+02:00 DEBUG 207411 --- [ main] o.s.c.c.v.file.ContractFileScanner : Creating a contract entry for path [/tmp/classpath-stubs-1694003381974-0/goodbyeWorld.groovy/goodbyeWorld.groovy] and metadata [ContractMetadata{path=/tmp/classpath-stubs-1694003381974-0/goodbyeWorld.groovy/goodbyeWorld.groovy, ignored=false, groupSize=1, order=null}] +2023-09-06T14:29:42.073+02:00 DEBUG 207411 --- [ main] o.s.c.c.v.file.ContractFileScanner : File [/tmp/classpath-stubs-1694003381974-0/goodbyeWorld.groovy/goodbyeWorld.groovy] is ignored. Is a contract file? [true]. Should be included by pattern? [true] +2023-09-06T14:29:42.073+02:00 DEBUG 207411 --- [ main] o.s.c.c.v.file.ContractFileScanner : File [/tmp/classpath-stubs-1694003381974-0/goodbyeWorld.groovy] wasn't ignored but no converter was applicable. The file is a directory [true] +2023-09-06T14:29:42.073+02:00 DEBUG 207411 --- [ main] o.s.c.c.v.c.RecursiveFilesConverter : Found the following contracts {/tmp/classpath-stubs-1694003381974-0/goodbyeWorld.groovy=[ContractMetadata{path=/tmp/classpath-stubs-1694003381974-0/goodbyeWorld.groovy/goodbyeWorld.groovy, ignored=false, groupSize=1, order=null}]} +2023-09-06T14:29:42.074+02:00 DEBUG 207411 --- [ main] o.s.c.c.v.c.RecursiveFilesConverter : Will create a stub for contract [ContractMetadata{path=/tmp/classpath-stubs-1694003381974-0/goodbyeWorld.groovy/goodbyeWorld.groovy, ignored=false, groupSize=1, order=null}] +2023-09-06T14:29:42.074+02:00 DEBUG 207411 --- [ main] o.s.c.c.v.c.RecursiveFilesConverter : Stub Generators [[org.springframework.cloud.contract.verifier.wiremock.DslToWireMockClientConverter@247e1f35]] will convert contents of [/tmp/classpath-stubs-1694003381974-0/goodbyeWorld.groovy] +2023-09-06T14:29:42.087+02:00 INFO 207411 --- [ main] o.s.c.c.v.c.RecursiveFilesConverter : Creating new stub [/tmp/classpath-stubs-1694003381974-0/goodbyeWorld.groovy/goodbyeWorld.json] +2023-09-06T14:29:42.102+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.AvailablePortScanner : Trying to execute closure with port [13490] +2023-09-06T14:29:42.107+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : For com.example:http-server-dsl:+:stubs Started WireMock at [http] port [13490] +2023-09-06T14:29:42.110+02:00 INFO 207411 --- [tp1394853598-56] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [225] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "3afaf209-b545-460f-ba3e-646be6d26938", + "request" : { + "url" : "/ping", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "OK" + }, + "uuid" : "3afaf209-b545-460f-ba3e-646be6d26938" +} + +2023-09-06T14:29:42.113+02:00 INFO 207411 --- [tp1394853598-50] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [227] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "7b541da6-13b3-4ad6-b873-5add0f58c52c", + "request" : { + "url" : "/health", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "OK" + }, + "uuid" : "7b541da6-13b3-4ad6-b873-5add0f58c52c" +} + +2023-09-06T14:29:42.116+02:00 INFO 207411 --- [tp1394853598-55] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [311] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "d943fc67-1809-4f93-9389-ea2d877923e6", + "request" : { + "url" : "/goodbye", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "Goodbye World!", + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "d943fc67-1809-4f93-9389-ea2d877923e6" +} + +2023-09-06T14:29:42.117+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/classpath-stubs-1694003381974-0/goodbyeWorld.groovy/goodbyeWorld.json] +2023-09-06T14:29:42.117+02:00 INFO 207411 --- [ main] o.s.c.contract.stubrunner.StubServer : Started stub server for project [com.example:http-server-dsl:+:stubs] on port 13490 with [1] mappings +2023-09-06T14:29:42.117+02:00 DEBUG 207411 --- [ main] o.s.c.contract.stubrunner.StubServer : Ports for this server are https [-1] and http [13490] +2023-09-06T14:29:42.117+02:00 INFO 207411 --- [ main] o.s.c.c.stubrunner.StubRunnerExecutor : All stubs are now running RunningStubs [namesAndPorts={com.example:http-server-dsl:+:stubs=13490}] +2023-09-06T14:29:42.117+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'batchStubRunner' of type [org.springframework.cloud.contract.stubrunner.BatchStubRunner] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:42.284+02:00 INFO 207411 --- [ main] o.s.c.s.m.DirectWithAttributesChannel : Channel 'application.listener-in-0' has 1 subscriber(s). +2023-09-06T14:29:42.323+02:00 INFO 207411 --- [ main] o.s.c.c.v.m.i.ContractVerifierMessaging : The message verifier sender implementation is of type [class org.springframework.cloud.contract.verifier.messaging.stream.ContractVerifierStreamAutoConfiguration$InputDestinationConfiguration$1] +2023-09-06T14:29:42.323+02:00 INFO 207411 --- [ main] o.s.c.c.v.m.i.ContractVerifierMessaging : The message verifier receiver implementation is of type [class org.springframework.cloud.contract.verifier.messaging.stream.ContractVerifierStreamAutoConfiguration$InputDestinationConfiguration$2] +2023-09-06T14:29:42.359+02:00 INFO 207411 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel +2023-09-06T14:29:42.359+02:00 INFO 207411 --- [ main] o.s.i.channel.PublishSubscribeChannel : Channel 'application.errorChannel' has 1 subscriber(s). +2023-09-06T14:29:42.359+02:00 INFO 207411 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started bean '_org.springframework.integration.errorLogger' +2023-09-06T14:29:42.360+02:00 INFO 207411 --- [ main] o.s.c.s.binder.DefaultBinderFactory : Creating binder: integration +2023-09-06T14:29:42.360+02:00 INFO 207411 --- [ main] o.s.c.s.binder.DefaultBinderFactory : Constructing binder child context for integration +2023-09-06T14:29:42.392+02:00 INFO 207411 --- [ main] o.s.c.s.binder.DefaultBinderFactory : Caching the binder: integration +2023-09-06T14:29:42.393+02:00 INFO 207411 --- [ main] o.s.c.stream.binder.BinderErrorChannel : Channel '1098385231.listener-in-0.errors' has 1 subscriber(s). +2023-09-06T14:29:42.393+02:00 INFO 207411 --- [ main] o.s.c.stream.binder.BinderErrorChannel : Channel '1098385231.listener-in-0.errors' has 2 subscriber(s). +2023-09-06T14:29:42.393+02:00 INFO 207411 --- [ main] o.s.i.channel.PublishSubscribeChannel : Channel 'sensor_data.destination' has 1 subscriber(s). +2023-09-06T14:29:42.394+02:00 INFO 207411 --- [ main] r$IntegrationBinderInboundChannelAdapter : started org.springframework.cloud.stream.binder.test.TestChannelBinder$IntegrationBinderInboundChannelAdapter@22955ef2 +2023-09-06T14:29:42.403+02:00 INFO 207411 --- [ main] com.example.loan.GoodbyeWorldTests : Started GoodbyeWorldTests in 0.656 seconds (process running for 6.066) +2023-09-06T14:29:42.405+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +2023-09-06T14:29:42.424+02:00 INFO 207411 --- [tp1394853598-56] WireMock : Request received: +127.0.0.1 - GET /goodbye + +Accept: [text/plain, application/json, application/*+json, */*] +User-Agent: [Java/17.0.1] +Host: [localhost:13490] +Connection: [keep-alive] + + + +Matched response definition: +{ + "status" : 200, + "body" : "Goodbye World!", + "transformers" : [ "response-template", "spring-cloud-contract" ] +} + +Response: +HTTP/1.1 200 +Matched-Stub-Id: [d943fc67-1809-4f93-9389-ea2d877923e6] + +2023-09-06T14:29:42.428+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +2023-09-06T14:29:42.431+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.691 s -- in com.example.loan.GoodbyeWorldTests +[INFO] Running com.example.loan.MessageConsumedTests + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v3.2.0-SNAPSHOT) + +2023-09-06T14:29:42.469+02:00 INFO 207411 --- [ main] com.example.loan.MessageConsumedTests : Starting MessageConsumedTests using Java 17.0.1 with PID 207411 (started by marcin in /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-client) +2023-09-06T14:29:42.469+02:00 INFO 207411 --- [ main] com.example.loan.MessageConsumedTests : No active profile set, falling back to 1 default profile: "default" +2023-09-06T14:29:42.471+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockApplicationListener : Registered WireMock server port property to the default <8080> value +2023-09-06T14:29:42.472+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockApplicationListener : Registered property source for property [wiremock.server.https-port] with value [13341] +2023-09-06T14:29:42.472+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockApplicationListener : Registered property source for dynamic https port +2023-09-06T14:29:42.635+02:00 INFO 207411 --- [ main] faultConfiguringBeanFactoryPostProcessor : No bean named 'errorChannel' has been explicitly defined. Therefore, a default PublishSubscribeChannel will be created. +2023-09-06T14:29:42.636+02:00 INFO 207411 --- [ main] faultConfiguringBeanFactoryPostProcessor : No bean named 'integrationHeaderChannelRegistry' has been explicitly defined. Therefore, a default DefaultHeaderChannelRegistry will be created. +2023-09-06T14:29:42.653+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration' of type [org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). The currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor] is declared through a non-static factory method on that class; consider declaring it as static instead. +2023-09-06T14:29:42.654+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.stream.config.BindersHealthIndicatorAutoConfiguration' of type [org.springframework.cloud.stream.config.BindersHealthIndicatorAutoConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:42.655+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'bindersHealthContributor' of type [org.springframework.cloud.stream.config.BindersHealthIndicatorAutoConfiguration$BindersHealthContributor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:42.655+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'bindersHealthIndicatorListener' of type [org.springframework.cloud.stream.config.BindersHealthIndicatorAutoConfiguration$BindersHealthIndicatorListener] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:42.656+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.stream.binder.rabbit.config.ExtendedBindingHandlerMappingsProviderConfiguration' of type [org.springframework.cloud.stream.binder.rabbit.config.ExtendedBindingHandlerMappingsProviderConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:42.656+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'rabbitExtendedPropertiesDefaultMappingsProvider' of type [org.springframework.cloud.stream.binder.rabbit.config.ExtendedBindingHandlerMappingsProviderConfiguration$$Lambda$895/0x000000080105a6b0] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:42.656+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'BindingHandlerAdvise' of type [org.springframework.cloud.stream.config.BindingHandlerAdvise] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:42.657+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'spelConverter' of type [org.springframework.cloud.stream.config.SpelExpressionConverterConfiguration$SpelConverter] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:42.660+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'stubrunner-org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties' of type [org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:42.660+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.CompositeStubDownloader : Registered following stub downloaders [org.springframework.cloud.contract.stubrunner.ScmStubDownloaderBuilder, org.springframework.cloud.contract.stubrunner.ClasspathStubProvider, org.springframework.cloud.contract.stubrunner.FileStubDownloader, org.springframework.cloud.contract.stubrunner.AetherStubDownloaderBuilder] +2023-09-06T14:29:42.660+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.StubRunnerFactory : Will download stubs for dependencies [com.example:http-server-dsl:0.0.1:stubs] +2023-09-06T14:29:42.660+02:00 INFO 207411 --- [ main] o.s.c.c.s.AetherStubDownloaderBuilder : Will download stubs and contracts via Aether +2023-09-06T14:29:42.660+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Will be resolving versions for the following options: [StubRunnerOptions{minPortValue=10000, maxPortValue=15000, stubRepositoryRoot='null', stubsMode='LOCAL', stubsClassifier='stubs', dependencies=[com.example:http-server-dsl:0.0.1:stubs], stubIdsToPortMapping={}, username='', password='', stubRunnerProxyOptions='null', stubsPerConsumer='false', httpServerStubConfigurer='class org.springframework.cloud.contract.stubrunner.HttpServerStubConfigurer$NoOpHttpServerStubConfigurer', serverId='null'}] +2023-09-06T14:29:42.660+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.AetherFactories : No custom maven user settings provided, will use [/home/marcin/.m2/settings.xml] +2023-09-06T14:29:42.662+02:00 INFO 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Remote repos not passed but the switch to work offline was set. Stubs will be used from your local Maven repository. +2023-09-06T14:29:42.663+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.AetherFactories : No custom maven user settings provided, will use [/home/marcin/.m2/settings.xml] +2023-09-06T14:29:42.665+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.AetherFactories : Local Repository Directory set to [/home/marcin/.m2/repository]. Work offline: [true] +2023-09-06T14:29:42.665+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.CompositeStubDownloader : Found a matching stub downloader [org.springframework.cloud.contract.stubrunner.AetherStubDownloader] +2023-09-06T14:29:42.665+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Resolved version range is [{}] +2023-09-06T14:29:42.665+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Will download the stub for version [0.0.1] +2023-09-06T14:29:42.665+02:00 INFO 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Resolved version is [0.0.1] +2023-09-06T14:29:42.665+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Resolving artifact [com.example:http-server-dsl:jar:stubs:0.0.1] using remote repositories [] +2023-09-06T14:29:42.666+02:00 INFO 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Resolved artifact [com.example:http-server-dsl:jar:stubs:0.0.1] to /home/marcin/.m2/repository/com/example/http-server-dsl/0.0.1/http-server-dsl-0.0.1-stubs.jar +2023-09-06T14:29:42.666+02:00 INFO 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Unpacking stub from JAR [URI: file:/home/marcin/.m2/repository/com/example/http-server-dsl/0.0.1/http-server-dsl-0.0.1-stubs.jar] +2023-09-06T14:29:42.670+02:00 INFO 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Unpacked file to [/tmp/contracts-1694003382666-0] +2023-09-06T14:29:42.670+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.CompositeStubDownloader : Found a matching entry [com.example:http-server-dsl:0.0.1:stubs=/tmp/contracts-1694003382666-0] by stub downloader [org.springframework.cloud.contract.stubrunner.AetherStubDownloader] +2023-09-06T14:29:42.670+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.StubRunnerFactory : For stub configuration [com.example:http-server-dsl:0.0.1:stubs] the downloaded entry is [com.example:http-server-dsl:0.0.1:stubs=/tmp/contracts-1694003382666-0] +2023-09-06T14:29:43.167+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.AvailablePortScanner : Trying to execute closure with port [11301] +2023-09-06T14:29:43.172+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : For com.example:http-server-dsl:0.0.1:stubs Started WireMock at [http] port [11301] +2023-09-06T14:29:43.174+02:00 INFO 207411 --- [qtp748453706-70] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [225] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "e7ba5f2f-ee6b-4a4c-9d14-441f91f8e682", + "request" : { + "url" : "/ping", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "OK" + }, + "uuid" : "e7ba5f2f-ee6b-4a4c-9d14-441f91f8e682" +} + +2023-09-06T14:29:43.177+02:00 INFO 207411 --- [qtp748453706-63] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [227] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "26d3b182-50db-4297-a01c-3e7c8cc460fb", + "request" : { + "url" : "/health", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "OK" + }, + "uuid" : "26d3b182-50db-4297-a01c-3e7c8cc460fb" +} + +2023-09-06T14:29:43.179+02:00 INFO 207411 --- [qtp748453706-69] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [280] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "6cf2a97d-5eac-4d1a-bdb4-262a2626ed62", + "request" : { + "url" : "/example", + "method" : "GET" + }, + "response" : { + "status" : 200, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "6cf2a97d-5eac-4d1a-bdb4-262a2626ed62" +} + +2023-09-06T14:29:43.180+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003382666-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/test/MyHttpContract.json] +2023-09-06T14:29:43.181+02:00 INFO 207411 --- [qtp748453706-64] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [415] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "fa16a598-8141-456c-a737-ea03dc554383", + "request" : { + "url" : "/drunks", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "{\"count\":100}", + "headers" : { + "Content-Type" : "application/json" + }, + "fixedDelayMilliseconds" : 2000, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "fa16a598-8141-456c-a737-ea03dc554383" +} + +2023-09-06T14:29:43.182+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003382666-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraud/shouldReturnFraudStats_1.json] +2023-09-06T14:29:43.184+02:00 INFO 207411 --- [qtp748453706-69] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [707] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "660fc6f9-2508-45a0-a1a3-4d3035c2955b", + "request" : { + "url" : "/fraudcheck", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "matches" : "application/json.*" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.['client.id'] =~ /[0-9]{10}/)]" + }, { + "matchesJsonPath" : "$[?(@.['loanAmount'] == 99999)]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"FRAUD\",\"rejection.reason\":\"Amount too high\"}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "660fc6f9-2508-45a0-a1a3-4d3035c2955b" +} + +2023-09-06T14:29:43.185+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003382666-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraud/shouldMarkClientAsFraud.json] +2023-09-06T14:29:43.187+02:00 INFO 207411 --- [qtp748453706-64] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [691] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "cf47e5df-1c9c-42f9-a3fb-fd3d1c869f65", + "request" : { + "url" : "/fraudcheck", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "matches" : "application/json.*" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.['client.id'] =~ /[0-9]{10}/)]" + }, { + "matchesJsonPath" : "$[?(@.['loanAmount'] == 123.123)]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"OK\",\"rejection.reason\":null}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "cf47e5df-1c9c-42f9-a3fb-fd3d1c869f65" +} + +2023-09-06T14:29:43.188+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003382666-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraud/shouldMarkClientAsNotFraud.json] +2023-09-06T14:29:43.189+02:00 INFO 207411 --- [qtp748453706-69] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [378] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "f5243e52-a4d7-453b-95a3-340595e07430", + "request" : { + "url" : "/frauds", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "{\"count\":780}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "f5243e52-a4d7-453b-95a3-340595e07430" +} + +2023-09-06T14:29:43.190+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003382666-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraud/should count all frauds.json] +2023-09-06T14:29:43.191+02:00 INFO 207411 --- [qtp748453706-68] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [1212] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "2de50d1e-4e66-4772-b884-f1f91a290d33", + "request" : { + "url" : "/tests", + "method" : "POST", + "headers" : { + "Content-Type" : { + "matches" : "multipart/form-data.*" + } + }, + "bodyPatterns" : [ { + "matches" : ".*--(.*)\r?\nContent-Disposition: form-data; name=\"file1\"; filename=\"[\\S\\s]+\"\r?\n(Content-Type: .*\r?\n)?(Content-Transfer-Encoding: .*\r?\n)?(Content-Length: \\d+\r?\n)?\r?\n[\\S\\s]+\r?\n--.*" + }, { + "matches" : ".*--(.*)\r?\nContent-Disposition: form-data; name=\"file2\"; filename=\"[\\S\\s]+\"\r?\n(Content-Type: .*\r?\n)?(Content-Transfer-Encoding: .*\r?\n)?(Content-Length: \\d+\r?\n)?\r?\n[\\S\\s]+\r?\n--.*" + }, { + "matches" : ".*--(.*)\r?\nContent-Disposition: form-data; name=\"test\"; filename=\"[\\S\\s]+\"\r?\n(Content-Type: application/json\r?\n)?(Content-Transfer-Encoding: .*\r?\n)?(Content-Length: \\d+\r?\n)?\r?\n[\\S\\s]+\r?\n--.*" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"status\":\"ok\"}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "2de50d1e-4e66-4772-b884-f1f91a290d33" +} + +2023-09-06T14:29:43.192+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003382666-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/multipart/shouldWorkForMultipartWithContentType.json] +2023-09-06T14:29:43.194+02:00 INFO 207411 --- [qtp748453706-64] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [1212] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "e10ced51-f2a6-47d9-adcb-da55409ebd9c", + "request" : { + "url" : "/tests", + "method" : "POST", + "headers" : { + "Content-Type" : { + "matches" : "multipart/form-data.*" + } + }, + "bodyPatterns" : [ { + "matches" : ".*--(.*)\r?\nContent-Disposition: form-data; name=\"file1\"; filename=\"[\\S\\s]+\"\r?\n(Content-Type: .*\r?\n)?(Content-Transfer-Encoding: .*\r?\n)?(Content-Length: \\d+\r?\n)?\r?\n[\\S\\s]+\r?\n--.*" + }, { + "matches" : ".*--(.*)\r?\nContent-Disposition: form-data; name=\"file2\"; filename=\"[\\S\\s]+\"\r?\n(Content-Type: .*\r?\n)?(Content-Transfer-Encoding: .*\r?\n)?(Content-Length: \\d+\r?\n)?\r?\n[\\S\\s]+\r?\n--.*" + }, { + "matches" : ".*--(.*)\r?\nContent-Disposition: form-data; name=\"test\"; filename=\"[\\S\\s]+\"\r?\n(Content-Type: application/json\r?\n)?(Content-Transfer-Encoding: .*\r?\n)?(Content-Length: \\d+\r?\n)?\r?\n[\\S\\s]+\r?\n--.*" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"status\":\"ok\"}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "e10ced51-f2a6-47d9-adcb-da55409ebd9c" +} + +2023-09-06T14:29:43.196+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003382666-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/multipart/shouldWorkForMultipartAsBytesWithContentType.json] +2023-09-06T14:29:43.197+02:00 INFO 207411 --- [qtp748453706-68] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [280] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "e2b18718-34cd-4a7b-83ca-8278cb54c70e", + "request" : { + "urlPath" : "/foo", + "method" : "GET" + }, + "response" : { + "status" : 200, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "e2b18718-34cd-4a7b-83ca-8278cb54c70e" +} + +2023-09-06T14:29:43.197+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003382666-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/messaging/shouldReturnOkWhenServiceIsHealthy.json] +2023-09-06T14:29:43.204+02:00 INFO 207411 --- [qtp748453706-64] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [41072] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "a1a3e8ea-3a5a-491d-90e2-b8d3a48c8a54", + "request" : { + "url" : "/1", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "matches" : "application/octet-stream.*" + } + }, + "bodyPatterns" : [ { + "binaryEqualTo" : "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YXRlRGVjb2RlIC9MZW5ndGggMjQ3ID4+CnN0cmVhbQp4nF2QTWvDMAyG7/4VOnaHYtddoYdg6DIKOeyDZfsBjq1khsU2jnPIv58/SgcT2PAgvZJe0bZ77qyJQN+DUz1GGI3VARe3BoUw4GQsOXDQRsUblV/N0hOaxP22RJw7OzrSNAD0I2WXGDbYXbQb8IHQt6AxGDvB7qvtE/er9z84o43AiBCgcUydXqR/lTMCLbJ9p1PexG2fNH8Vn5tH4IUPdRvlNC5eKgzSTkgalkJAc00hCFr9L3+qqmFU3zKU6mOqZowzkYmfCz2eKj1VOle6VmoLHXmlOuXWL8/Ld7mbUWsIyUc5XjGQVzcW7/f1zmdVfr87IHo2ZW5kc3RyZWFtCmVuZG9iagoxMCAwIG9iago8PCAvVHlwZSAvT2JqU3RtIC9MZW5ndGggNDU5IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlIC9OIDYgL0ZpcnN0IDM3ID4+CnN0cmVhbQp4nHVRy27bMBC89yv2aB/MlyhRBAIDdlw3RuEkiJ3kUOTASKxKVBIFiQbqv+9Sjlr3UBAEAe7szOws58CAC0g48ARUClyC1sBTEByfDKRWn25ugD72vjwVtofZ4acz9HGzhUaJOSyXY/nWn9oAHOhXVw7wDTKkfYI3oMdzZ7HbVHaYsOs90HvfN6YGWhhsmv7NYLceaeiqd6beH4Fu7FDYtjRtiIVIjM4+mD+3hS9dWwHdlbYNLpwXd0APp/cwSkZhho9/bh0CLeix8cPQqPN/3dvd5nAegm127XcPEfTQl7aParNJbQ70yVZuCP0ZZqvSv9t5lO+62jaIQLXlcmQ6+i+7zd50f43iYK9YH13EEXvXBd/HuEeLf2bA5giJlsU/zukrRsHwqpRBPEIpkieCJZiMjIUsy4jWcYmxrIQgPFNawQWephnhqUjkpXrV/DalsorJB9AsJUIlUqIb091ZV/0IoHhKcsTzaUMBFoJzorlkGVqsTTWAvHhdr/0v9LPIMknSlKkcFomQRDGFeoKJnIzKnCWKcKaTPO42Nm5djVPnl0jix71p7NWOdsHUrli1VW1jlgfc1gtINKZziSxXcV1FjMP9BoAQz0xlbmRzdHJlYW0KZW5kb2JqCjEgMCBvYmoKPDwgL1R5cGUgL1hSZWYgL0xlbmd0aCAxNiAvRmlsdGVyIC9GbGF0ZURlY29kZSAvRGVjb2RlUGFybXMgPDwgL0NvbHVtbnMgNCAvUHJlZGljdG9yIDEyID4+IC9XIFsgMSAyIDEgXSAvU2l6ZSAyIC9JRCBbPGEyOGUxYTMyZjIzMjg4ZjI1YzRkZGRhODQ3NmQ2YjUxPjxhMjhlMWEzMmYyMzI4OGYyNWM0ZGRkYTg0NzZkNmI1MT5dID4+CnN0cmVhbQp4nGNiAAImRgsRBgAA/ABSCmVuZHN0cmVhbQplbmRvYmoKICAgICAgICAgICAgICAgCnN0YXJ0eHJlZgoyMTYKJSVFT0YK" + } ] + }, + "response" : { + "status" : 200, + "base64Body" : "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", + "headers" : { + "Content-Type" : "application/octet-stream" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "a1a3e8ea-3a5a-491d-90e2-b8d3a48c8a54" +} + +2023-09-06T14:29:43.210+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003382666-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/binary/shouldWorkWithBinaryPayload.json] +2023-09-06T14:29:43.211+02:00 INFO 207411 --- [qtp748453706-68] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [386] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "72de0479-f640-4b3d-aab9-a9f6ad0e33f9", + "request" : { + "urlPath" : "/yamldrunks", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "{\"count\":100}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "72de0479-f640-4b3d-aab9-a9f6ad0e33f9" +} + +2023-09-06T14:29:43.212+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003382666-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/yml/fraud/shouldReturnFraudStats_1.json] +2023-09-06T14:29:43.214+02:00 INFO 207411 --- [qtp748453706-64] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [715] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "44c88877-5d4b-491e-8ac5-7ab599794d69", + "request" : { + "urlPath" : "/yamlfraudcheck", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "equalTo" : "application/json" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.['loanAmount'] == 99999)]" + }, { + "matchesJsonPath" : "$[?(@.['client.id'] =~ /([0-9]{10})/)]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"FRAUD\",\"rejection.reason\":\"Amount too high\"}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "44c88877-5d4b-491e-8ac5-7ab599794d69" +} + +2023-09-06T14:29:43.214+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003382666-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/yml/fraud/shouldMarkClientAsFraud.json] +2023-09-06T14:29:43.216+02:00 INFO 207411 --- [qtp748453706-68] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [699] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "1ccb766e-ce35-47e6-b14b-eccd836e237e", + "request" : { + "urlPath" : "/yamlfraudcheck", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "equalTo" : "application/json" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.['loanAmount'] == 123.123)]" + }, { + "matchesJsonPath" : "$[?(@.['client.id'] =~ /([0-9]{10})/)]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"OK\",\"rejection.reason\":null}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "1ccb766e-ce35-47e6-b14b-eccd836e237e" +} + +2023-09-06T14:29:43.217+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003382666-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/yml/fraud/shouldMarkClientAsNotFraud.json] +2023-09-06T14:29:43.218+02:00 INFO 207411 --- [qtp748453706-64] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [423] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "18870094-18db-484a-ade9-e161dae03756", + "request" : { + "urlPath" : "/yamlfrauds", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "{\"count\":200}", + "headers" : { + "Content-Type" : "application/json" + }, + "fixedDelayMilliseconds" : 2000, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "18870094-18db-484a-ade9-e161dae03756" +} + +2023-09-06T14:29:43.218+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003382666-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/yml/fraud/should count all frauds.json] +2023-09-06T14:29:43.220+02:00 INFO 207411 --- [qtp748453706-68] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [665] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "3ba3f8d4-ff5d-4355-84dd-e92248677ef2", + "request" : { + "urlPath" : "/yamlfrauds/name", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "equalTo" : "application/json" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.name =~ /([\\p{L}]*)/)]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"result\":\"Don't worry {{{ jsonpath this '$.name' }}} you're not a fraud\"}", + "headers" : { + "Content-Type" : "{{{ request.headers.Content-Type.0 }}}" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "3ba3f8d4-ff5d-4355-84dd-e92248677ef2" +} + +2023-09-06T14:29:43.220+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003382666-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/yml/fraudname/shouldReturnNonFraudForTheName.json] +2023-09-06T14:29:43.221+02:00 INFO 207411 --- [qtp748453706-64] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [675] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "a8c7f458-fd9a-4c9f-af66-f0085c38faa4", + "request" : { + "urlPath" : "/yamlfrauds/name", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "equalTo" : "application/json" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.['name'] == 'fraud')]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"result\":\"Sorry {{{ jsonpath this '$.name' }}} but you're a fraud\"}", + "headers" : { + "Content-Type" : "{{{ request.headers.Content-Type.0 }}}" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "a8c7f458-fd9a-4c9f-af66-f0085c38faa4", + "priority" : 1 +} + +2023-09-06T14:29:43.222+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003382666-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/yml/fraudname/shouldReturnAFraudForTheName.json] +2023-09-06T14:29:43.223+02:00 INFO 207411 --- [qtp748453706-69] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [667] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "c50f9381-4230-4937-ab58-d9e8e21f303a", + "request" : { + "url" : "/frauds/name", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "matches" : "application/json.*" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.['name'] =~ /[\\p{L}]*/)]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"result\":\"Don't worry {{{jsonPath request.body '$.name'}}} you're not a fraud\"}", + "headers" : { + "Content-Type" : "{{{request.headers.Content-Type.[0]}}}" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "c50f9381-4230-4937-ab58-d9e8e21f303a" +} + +2023-09-06T14:29:43.224+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003382666-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraudname/shouldReturnNonFraudForTheName.json] +2023-09-06T14:29:43.225+02:00 INFO 207411 --- [qtp748453706-68] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [437] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "7c109624-495a-4d92-bcba-09c4d470d98f", + "request" : { + "url" : "/frauds/name", + "method" : "GET", + "cookies" : { + "name2" : { + "equalTo" : "bar" + }, + "name" : { + "equalTo" : "foo" + } + } + }, + "response" : { + "status" : 200, + "body" : "foo bar", + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "7c109624-495a-4d92-bcba-09c4d470d98f" +} + +2023-09-06T14:29:43.226+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003382666-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraudname/shouldReturnACookie.json] +2023-09-06T14:29:43.227+02:00 INFO 207411 --- [qtp748453706-69] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [675] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "70027628-be19-49fc-b12b-f0bba0c88265", + "request" : { + "url" : "/frauds/name", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "matches" : "application/json.*" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.['name'] == 'fraud')]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"result\":\"Sorry {{{jsonPath request.body '$.name'}}} but you're a fraud\"}", + "headers" : { + "Content-Type" : "{{{request.headers.Content-Type.[0]}}}" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "70027628-be19-49fc-b12b-f0bba0c88265", + "priority" : 1 +} + +2023-09-06T14:29:43.228+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003382666-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraudname/shouldReturnAFraudForTheName.json] +2023-09-06T14:29:43.228+02:00 INFO 207411 --- [ main] o.s.c.contract.stubrunner.StubServer : Started stub server for project [com.example:http-server-dsl:0.0.1:stubs] on port 11301 with [18] mappings +2023-09-06T14:29:43.228+02:00 DEBUG 207411 --- [ main] o.s.c.contract.stubrunner.StubServer : Ports for this server are https [-1] and http [11301] +2023-09-06T14:29:43.228+02:00 INFO 207411 --- [ main] o.s.c.c.stubrunner.StubRunnerExecutor : All stubs are now running RunningStubs [namesAndPorts={com.example:http-server-dsl:0.0.1:stubs=11301}] +2023-09-06T14:29:43.228+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'batchStubRunner' of type [org.springframework.cloud.contract.stubrunner.BatchStubRunner] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:43.320+02:00 INFO 207411 --- [ main] o.s.c.s.m.DirectWithAttributesChannel : Channel 'application.listener-in-0' has 1 subscriber(s). +2023-09-06T14:29:43.339+02:00 INFO 207411 --- [ main] o.s.c.c.v.m.i.ContractVerifierMessaging : The message verifier sender implementation is of type [class org.springframework.cloud.contract.verifier.messaging.stream.ContractVerifierStreamAutoConfiguration$InputDestinationConfiguration$1] +2023-09-06T14:29:43.339+02:00 INFO 207411 --- [ main] o.s.c.c.v.m.i.ContractVerifierMessaging : The message verifier receiver implementation is of type [class org.springframework.cloud.contract.verifier.messaging.stream.ContractVerifierStreamAutoConfiguration$InputDestinationConfiguration$2] +2023-09-06T14:29:43.356+02:00 INFO 207411 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel +2023-09-06T14:29:43.356+02:00 INFO 207411 --- [ main] o.s.i.channel.PublishSubscribeChannel : Channel 'application.errorChannel' has 1 subscriber(s). +2023-09-06T14:29:43.356+02:00 INFO 207411 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started bean '_org.springframework.integration.errorLogger' +2023-09-06T14:29:43.357+02:00 INFO 207411 --- [ main] o.s.c.stream.binder.BinderErrorChannel : Channel '815457062.listener-in-0.errors' has 1 subscriber(s). +2023-09-06T14:29:43.357+02:00 INFO 207411 --- [ main] o.s.c.stream.binder.BinderErrorChannel : Channel '815457062.listener-in-0.errors' has 2 subscriber(s). +2023-09-06T14:29:43.357+02:00 INFO 207411 --- [ main] o.s.i.channel.PublishSubscribeChannel : Channel 'sensor_data.destination' has 1 subscriber(s). +2023-09-06T14:29:43.357+02:00 INFO 207411 --- [ main] r$IntegrationBinderInboundChannelAdapter : started org.springframework.cloud.stream.binder.test.TestChannelBinder$IntegrationBinderInboundChannelAdapter@5db94eaf +2023-09-06T14:29:43.362+02:00 INFO 207411 --- [ main] com.example.loan.MessageConsumedTests : Started MessageConsumedTests in 0.918 seconds (process running for 7.024) +2023-09-06T14:29:43.363+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +com.example.loan.SensorData@17d99e0f +2023-09-06T14:29:43.504+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +2023-09-06T14:29:43.506+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.073 s -- in com.example.loan.MessageConsumedTests +[INFO] Running com.example.loan.LoanApplicationServiceTests +2023-09-06T14:29:43.509+02:00 INFO 207411 --- [ main] t.c.s.AnnotationConfigContextLoaderUtils : Could not detect default configuration classes for test class [com.example.loan.LoanApplicationServiceTests]: LoanApplicationServiceTests does not declare any static, non-private, non-final, nested classes annotated with @Configuration. +2023-09-06T14:29:43.511+02:00 INFO 207411 --- [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.example.loan.Application for test class com.example.loan.LoanApplicationServiceTests + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v3.2.0-SNAPSHOT) + +2023-09-06T14:29:43.536+02:00 INFO 207411 --- [ main] c.e.loan.LoanApplicationServiceTests : Starting LoanApplicationServiceTests using Java 17.0.1 with PID 207411 (started by marcin in /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-client) +2023-09-06T14:29:43.537+02:00 INFO 207411 --- [ main] c.e.loan.LoanApplicationServiceTests : No active profile set, falling back to 1 default profile: "default" +2023-09-06T14:29:43.538+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockApplicationListener : Registered WireMock server port property to the default <8080> value +2023-09-06T14:29:43.538+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockApplicationListener : Registered property source for property [wiremock.server.https-port] with value [14234] +2023-09-06T14:29:43.538+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockApplicationListener : Registered property source for dynamic https port +2023-09-06T14:29:43.692+02:00 INFO 207411 --- [ main] faultConfiguringBeanFactoryPostProcessor : No bean named 'errorChannel' has been explicitly defined. Therefore, a default PublishSubscribeChannel will be created. +2023-09-06T14:29:43.692+02:00 INFO 207411 --- [ main] faultConfiguringBeanFactoryPostProcessor : No bean named 'integrationHeaderChannelRegistry' has been explicitly defined. Therefore, a default DefaultHeaderChannelRegistry will be created. +2023-09-06T14:29:43.708+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration' of type [org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). The currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor] is declared through a non-static factory method on that class; consider declaring it as static instead. +2023-09-06T14:29:43.710+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.stream.config.BindersHealthIndicatorAutoConfiguration' of type [org.springframework.cloud.stream.config.BindersHealthIndicatorAutoConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:43.711+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'bindersHealthContributor' of type [org.springframework.cloud.stream.config.BindersHealthIndicatorAutoConfiguration$BindersHealthContributor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:43.711+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'bindersHealthIndicatorListener' of type [org.springframework.cloud.stream.config.BindersHealthIndicatorAutoConfiguration$BindersHealthIndicatorListener] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:43.711+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.stream.binder.rabbit.config.ExtendedBindingHandlerMappingsProviderConfiguration' of type [org.springframework.cloud.stream.binder.rabbit.config.ExtendedBindingHandlerMappingsProviderConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:43.712+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'rabbitExtendedPropertiesDefaultMappingsProvider' of type [org.springframework.cloud.stream.binder.rabbit.config.ExtendedBindingHandlerMappingsProviderConfiguration$$Lambda$895/0x000000080105a6b0] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:43.712+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'BindingHandlerAdvise' of type [org.springframework.cloud.stream.config.BindingHandlerAdvise] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:43.713+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'spelConverter' of type [org.springframework.cloud.stream.config.SpelExpressionConverterConfiguration$SpelConverter] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:43.716+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'stubrunner-org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties' of type [org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:43.716+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.CompositeStubDownloader : Registered following stub downloaders [org.springframework.cloud.contract.stubrunner.ScmStubDownloaderBuilder, org.springframework.cloud.contract.stubrunner.ClasspathStubProvider, org.springframework.cloud.contract.stubrunner.FileStubDownloader, org.springframework.cloud.contract.stubrunner.AetherStubDownloaderBuilder] +2023-09-06T14:29:43.716+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.StubRunnerFactory : Will download stubs for dependencies [com.example:http-server-dsl:0.0.1:stubs] +2023-09-06T14:29:43.716+02:00 INFO 207411 --- [ main] o.s.c.c.s.AetherStubDownloaderBuilder : Will download stubs and contracts via Aether +2023-09-06T14:29:43.716+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Will be resolving versions for the following options: [StubRunnerOptions{minPortValue=10000, maxPortValue=15000, stubRepositoryRoot='null', stubsMode='LOCAL', stubsClassifier='stubs', dependencies=[com.example:http-server-dsl:0.0.1:stubs], stubIdsToPortMapping={}, username='', password='', stubRunnerProxyOptions='null', stubsPerConsumer='false', httpServerStubConfigurer='class org.springframework.cloud.contract.stubrunner.HttpServerStubConfigurer$NoOpHttpServerStubConfigurer', serverId='null'}] +2023-09-06T14:29:43.717+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.AetherFactories : No custom maven user settings provided, will use [/home/marcin/.m2/settings.xml] +2023-09-06T14:29:43.718+02:00 INFO 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Remote repos not passed but the switch to work offline was set. Stubs will be used from your local Maven repository. +2023-09-06T14:29:43.719+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.AetherFactories : No custom maven user settings provided, will use [/home/marcin/.m2/settings.xml] +2023-09-06T14:29:43.720+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.AetherFactories : Local Repository Directory set to [/home/marcin/.m2/repository]. Work offline: [true] +2023-09-06T14:29:43.720+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.CompositeStubDownloader : Found a matching stub downloader [org.springframework.cloud.contract.stubrunner.AetherStubDownloader] +2023-09-06T14:29:43.721+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Resolved version range is [{}] +2023-09-06T14:29:43.721+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Will download the stub for version [0.0.1] +2023-09-06T14:29:43.721+02:00 INFO 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Resolved version is [0.0.1] +2023-09-06T14:29:43.721+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Resolving artifact [com.example:http-server-dsl:jar:stubs:0.0.1] using remote repositories [] +2023-09-06T14:29:43.721+02:00 INFO 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Resolved artifact [com.example:http-server-dsl:jar:stubs:0.0.1] to /home/marcin/.m2/repository/com/example/http-server-dsl/0.0.1/http-server-dsl-0.0.1-stubs.jar +2023-09-06T14:29:43.721+02:00 INFO 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Unpacking stub from JAR [URI: file:/home/marcin/.m2/repository/com/example/http-server-dsl/0.0.1/http-server-dsl-0.0.1-stubs.jar] +2023-09-06T14:29:43.726+02:00 INFO 207411 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Unpacked file to [/tmp/contracts-1694003383721-0] +2023-09-06T14:29:43.726+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.CompositeStubDownloader : Found a matching entry [com.example:http-server-dsl:0.0.1:stubs=/tmp/contracts-1694003383721-0] by stub downloader [org.springframework.cloud.contract.stubrunner.AetherStubDownloader] +2023-09-06T14:29:43.726+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.StubRunnerFactory : For stub configuration [com.example:http-server-dsl:0.0.1:stubs] the downloaded entry is [com.example:http-server-dsl:0.0.1:stubs=/tmp/contracts-1694003383721-0] +2023-09-06T14:29:44.161+02:00 DEBUG 207411 --- [ main] o.s.c.c.stubrunner.AvailablePortScanner : Trying to execute closure with port [11276] +2023-09-06T14:29:44.167+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : For com.example:http-server-dsl:0.0.1:stubs Started WireMock at [http] port [11276] +2023-09-06T14:29:44.171+02:00 INFO 207411 --- [qtp906926883-83] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [225] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "eebc0ca1-47fe-47fb-aa7a-5c0137aeef80", + "request" : { + "url" : "/ping", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "OK" + }, + "uuid" : "eebc0ca1-47fe-47fb-aa7a-5c0137aeef80" +} + +2023-09-06T14:29:44.173+02:00 INFO 207411 --- [qtp906926883-76] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [227] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "2d6592f9-12e7-4a6e-aa98-e61bf1d68263", + "request" : { + "url" : "/health", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "OK" + }, + "uuid" : "2d6592f9-12e7-4a6e-aa98-e61bf1d68263" +} + +2023-09-06T14:29:44.176+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [280] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "6cf2a97d-5eac-4d1a-bdb4-262a2626ed62", + "request" : { + "url" : "/example", + "method" : "GET" + }, + "response" : { + "status" : 200, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "6cf2a97d-5eac-4d1a-bdb4-262a2626ed62" +} + +2023-09-06T14:29:44.176+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003383721-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/test/MyHttpContract.json] +2023-09-06T14:29:44.178+02:00 INFO 207411 --- [qtp906926883-77] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [415] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "fa16a598-8141-456c-a737-ea03dc554383", + "request" : { + "url" : "/drunks", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "{\"count\":100}", + "headers" : { + "Content-Type" : "application/json" + }, + "fixedDelayMilliseconds" : 2000, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "fa16a598-8141-456c-a737-ea03dc554383" +} + +2023-09-06T14:29:44.179+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003383721-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraud/shouldReturnFraudStats_1.json] +2023-09-06T14:29:44.181+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [707] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "660fc6f9-2508-45a0-a1a3-4d3035c2955b", + "request" : { + "url" : "/fraudcheck", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "matches" : "application/json.*" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.['client.id'] =~ /[0-9]{10}/)]" + }, { + "matchesJsonPath" : "$[?(@.['loanAmount'] == 99999)]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"FRAUD\",\"rejection.reason\":\"Amount too high\"}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "660fc6f9-2508-45a0-a1a3-4d3035c2955b" +} + +2023-09-06T14:29:44.182+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003383721-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraud/shouldMarkClientAsFraud.json] +2023-09-06T14:29:44.184+02:00 INFO 207411 --- [qtp906926883-77] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [691] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "cf47e5df-1c9c-42f9-a3fb-fd3d1c869f65", + "request" : { + "url" : "/fraudcheck", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "matches" : "application/json.*" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.['client.id'] =~ /[0-9]{10}/)]" + }, { + "matchesJsonPath" : "$[?(@.['loanAmount'] == 123.123)]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"OK\",\"rejection.reason\":null}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "cf47e5df-1c9c-42f9-a3fb-fd3d1c869f65" +} + +2023-09-06T14:29:44.185+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003383721-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraud/shouldMarkClientAsNotFraud.json] +2023-09-06T14:29:44.187+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [378] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "f5243e52-a4d7-453b-95a3-340595e07430", + "request" : { + "url" : "/frauds", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "{\"count\":780}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "f5243e52-a4d7-453b-95a3-340595e07430" +} + +2023-09-06T14:29:44.187+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003383721-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraud/should count all frauds.json] +2023-09-06T14:29:44.189+02:00 INFO 207411 --- [qtp906926883-77] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [1212] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "2de50d1e-4e66-4772-b884-f1f91a290d33", + "request" : { + "url" : "/tests", + "method" : "POST", + "headers" : { + "Content-Type" : { + "matches" : "multipart/form-data.*" + } + }, + "bodyPatterns" : [ { + "matches" : ".*--(.*)\r?\nContent-Disposition: form-data; name=\"file1\"; filename=\"[\\S\\s]+\"\r?\n(Content-Type: .*\r?\n)?(Content-Transfer-Encoding: .*\r?\n)?(Content-Length: \\d+\r?\n)?\r?\n[\\S\\s]+\r?\n--.*" + }, { + "matches" : ".*--(.*)\r?\nContent-Disposition: form-data; name=\"file2\"; filename=\"[\\S\\s]+\"\r?\n(Content-Type: .*\r?\n)?(Content-Transfer-Encoding: .*\r?\n)?(Content-Length: \\d+\r?\n)?\r?\n[\\S\\s]+\r?\n--.*" + }, { + "matches" : ".*--(.*)\r?\nContent-Disposition: form-data; name=\"test\"; filename=\"[\\S\\s]+\"\r?\n(Content-Type: application/json\r?\n)?(Content-Transfer-Encoding: .*\r?\n)?(Content-Length: \\d+\r?\n)?\r?\n[\\S\\s]+\r?\n--.*" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"status\":\"ok\"}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "2de50d1e-4e66-4772-b884-f1f91a290d33" +} + +2023-09-06T14:29:44.190+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003383721-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/multipart/shouldWorkForMultipartWithContentType.json] +2023-09-06T14:29:44.192+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [1212] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "e10ced51-f2a6-47d9-adcb-da55409ebd9c", + "request" : { + "url" : "/tests", + "method" : "POST", + "headers" : { + "Content-Type" : { + "matches" : "multipart/form-data.*" + } + }, + "bodyPatterns" : [ { + "matches" : ".*--(.*)\r?\nContent-Disposition: form-data; name=\"file1\"; filename=\"[\\S\\s]+\"\r?\n(Content-Type: .*\r?\n)?(Content-Transfer-Encoding: .*\r?\n)?(Content-Length: \\d+\r?\n)?\r?\n[\\S\\s]+\r?\n--.*" + }, { + "matches" : ".*--(.*)\r?\nContent-Disposition: form-data; name=\"file2\"; filename=\"[\\S\\s]+\"\r?\n(Content-Type: .*\r?\n)?(Content-Transfer-Encoding: .*\r?\n)?(Content-Length: \\d+\r?\n)?\r?\n[\\S\\s]+\r?\n--.*" + }, { + "matches" : ".*--(.*)\r?\nContent-Disposition: form-data; name=\"test\"; filename=\"[\\S\\s]+\"\r?\n(Content-Type: application/json\r?\n)?(Content-Transfer-Encoding: .*\r?\n)?(Content-Length: \\d+\r?\n)?\r?\n[\\S\\s]+\r?\n--.*" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"status\":\"ok\"}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "e10ced51-f2a6-47d9-adcb-da55409ebd9c" +} + +2023-09-06T14:29:44.194+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003383721-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/multipart/shouldWorkForMultipartAsBytesWithContentType.json] +2023-09-06T14:29:44.196+02:00 INFO 207411 --- [qtp906926883-77] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [280] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "e2b18718-34cd-4a7b-83ca-8278cb54c70e", + "request" : { + "urlPath" : "/foo", + "method" : "GET" + }, + "response" : { + "status" : 200, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "e2b18718-34cd-4a7b-83ca-8278cb54c70e" +} + +2023-09-06T14:29:44.197+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003383721-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/messaging/shouldReturnOkWhenServiceIsHealthy.json] +2023-09-06T14:29:44.203+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [41072] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "a1a3e8ea-3a5a-491d-90e2-b8d3a48c8a54", + "request" : { + "url" : "/1", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "matches" : "application/octet-stream.*" + } + }, + "bodyPatterns" : [ { + "binaryEqualTo" : "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YXRlRGVjb2RlIC9MZW5ndGggMjQ3ID4+CnN0cmVhbQp4nF2QTWvDMAyG7/4VOnaHYtddoYdg6DIKOeyDZfsBjq1khsU2jnPIv58/SgcT2PAgvZJe0bZ77qyJQN+DUz1GGI3VARe3BoUw4GQsOXDQRsUblV/N0hOaxP22RJw7OzrSNAD0I2WXGDbYXbQb8IHQt6AxGDvB7qvtE/er9z84o43AiBCgcUydXqR/lTMCLbJ9p1PexG2fNH8Vn5tH4IUPdRvlNC5eKgzSTkgalkJAc00hCFr9L3+qqmFU3zKU6mOqZowzkYmfCz2eKj1VOle6VmoLHXmlOuXWL8/Ld7mbUWsIyUc5XjGQVzcW7/f1zmdVfr87IHo2ZW5kc3RyZWFtCmVuZG9iagoxMCAwIG9iago8PCAvVHlwZSAvT2JqU3RtIC9MZW5ndGggNDU5IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlIC9OIDYgL0ZpcnN0IDM3ID4+CnN0cmVhbQp4nHVRy27bMBC89yv2aB/MlyhRBAIDdlw3RuEkiJ3kUOTASKxKVBIFiQbqv+9Sjlr3UBAEAe7szOws58CAC0g48ARUClyC1sBTEByfDKRWn25ugD72vjwVtofZ4acz9HGzhUaJOSyXY/nWn9oAHOhXVw7wDTKkfYI3oMdzZ7HbVHaYsOs90HvfN6YGWhhsmv7NYLceaeiqd6beH4Fu7FDYtjRtiIVIjM4+mD+3hS9dWwHdlbYNLpwXd0APp/cwSkZhho9/bh0CLeix8cPQqPN/3dvd5nAegm127XcPEfTQl7aParNJbQ70yVZuCP0ZZqvSv9t5lO+62jaIQLXlcmQ6+i+7zd50f43iYK9YH13EEXvXBd/HuEeLf2bA5giJlsU/zukrRsHwqpRBPEIpkieCJZiMjIUsy4jWcYmxrIQgPFNawQWephnhqUjkpXrV/DalsorJB9AsJUIlUqIb091ZV/0IoHhKcsTzaUMBFoJzorlkGVqsTTWAvHhdr/0v9LPIMknSlKkcFomQRDGFeoKJnIzKnCWKcKaTPO42Nm5djVPnl0jix71p7NWOdsHUrli1VW1jlgfc1gtINKZziSxXcV1FjMP9BoAQz0xlbmRzdHJlYW0KZW5kb2JqCjEgMCBvYmoKPDwgL1R5cGUgL1hSZWYgL0xlbmd0aCAxNiAvRmlsdGVyIC9GbGF0ZURlY29kZSAvRGVjb2RlUGFybXMgPDwgL0NvbHVtbnMgNCAvUHJlZGljdG9yIDEyID4+IC9XIFsgMSAyIDEgXSAvU2l6ZSAyIC9JRCBbPGEyOGUxYTMyZjIzMjg4ZjI1YzRkZGRhODQ3NmQ2YjUxPjxhMjhlMWEzMmYyMzI4OGYyNWM0ZGRkYTg0NzZkNmI1MT5dID4+CnN0cmVhbQp4nGNiAAImRgsRBgAA/ABSCmVuZHN0cmVhbQplbmRvYmoKICAgICAgICAgICAgICAgCnN0YXJ0eHJlZgoyMTYKJSVFT0YK" + } ] + }, + "response" : { + "status" : 200, + "base64Body" : "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", + "headers" : { + "Content-Type" : "application/octet-stream" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "a1a3e8ea-3a5a-491d-90e2-b8d3a48c8a54" +} + +2023-09-06T14:29:44.208+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003383721-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/binary/shouldWorkWithBinaryPayload.json] +2023-09-06T14:29:44.210+02:00 INFO 207411 --- [qtp906926883-77] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [386] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "72de0479-f640-4b3d-aab9-a9f6ad0e33f9", + "request" : { + "urlPath" : "/yamldrunks", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "{\"count\":100}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "72de0479-f640-4b3d-aab9-a9f6ad0e33f9" +} + +2023-09-06T14:29:44.211+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003383721-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/yml/fraud/shouldReturnFraudStats_1.json] +2023-09-06T14:29:44.213+02:00 INFO 207411 --- [qtp906926883-81] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [715] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "44c88877-5d4b-491e-8ac5-7ab599794d69", + "request" : { + "urlPath" : "/yamlfraudcheck", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "equalTo" : "application/json" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.['loanAmount'] == 99999)]" + }, { + "matchesJsonPath" : "$[?(@.['client.id'] =~ /([0-9]{10})/)]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"FRAUD\",\"rejection.reason\":\"Amount too high\"}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "44c88877-5d4b-491e-8ac5-7ab599794d69" +} + +2023-09-06T14:29:44.214+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003383721-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/yml/fraud/shouldMarkClientAsFraud.json] +2023-09-06T14:29:44.216+02:00 INFO 207411 --- [qtp906926883-77] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [699] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "1ccb766e-ce35-47e6-b14b-eccd836e237e", + "request" : { + "urlPath" : "/yamlfraudcheck", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "equalTo" : "application/json" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.['loanAmount'] == 123.123)]" + }, { + "matchesJsonPath" : "$[?(@.['client.id'] =~ /([0-9]{10})/)]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"OK\",\"rejection.reason\":null}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "1ccb766e-ce35-47e6-b14b-eccd836e237e" +} + +2023-09-06T14:29:44.217+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003383721-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/yml/fraud/shouldMarkClientAsNotFraud.json] +2023-09-06T14:29:44.218+02:00 INFO 207411 --- [qtp906926883-81] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [423] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "18870094-18db-484a-ade9-e161dae03756", + "request" : { + "urlPath" : "/yamlfrauds", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "{\"count\":200}", + "headers" : { + "Content-Type" : "application/json" + }, + "fixedDelayMilliseconds" : 2000, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "18870094-18db-484a-ade9-e161dae03756" +} + +2023-09-06T14:29:44.219+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003383721-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/yml/fraud/should count all frauds.json] +2023-09-06T14:29:44.220+02:00 INFO 207411 --- [qtp906926883-77] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [665] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "3ba3f8d4-ff5d-4355-84dd-e92248677ef2", + "request" : { + "urlPath" : "/yamlfrauds/name", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "equalTo" : "application/json" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.name =~ /([\\p{L}]*)/)]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"result\":\"Don't worry {{{ jsonpath this '$.name' }}} you're not a fraud\"}", + "headers" : { + "Content-Type" : "{{{ request.headers.Content-Type.0 }}}" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "3ba3f8d4-ff5d-4355-84dd-e92248677ef2" +} + +2023-09-06T14:29:44.221+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003383721-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/yml/fraudname/shouldReturnNonFraudForTheName.json] +2023-09-06T14:29:44.223+02:00 INFO 207411 --- [qtp906926883-81] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [675] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "a8c7f458-fd9a-4c9f-af66-f0085c38faa4", + "request" : { + "urlPath" : "/yamlfrauds/name", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "equalTo" : "application/json" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.['name'] == 'fraud')]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"result\":\"Sorry {{{ jsonpath this '$.name' }}} but you're a fraud\"}", + "headers" : { + "Content-Type" : "{{{ request.headers.Content-Type.0 }}}" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "a8c7f458-fd9a-4c9f-af66-f0085c38faa4", + "priority" : 1 +} + +2023-09-06T14:29:44.225+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003383721-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/yml/fraudname/shouldReturnAFraudForTheName.json] +2023-09-06T14:29:44.227+02:00 INFO 207411 --- [qtp906926883-77] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [667] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "c50f9381-4230-4937-ab58-d9e8e21f303a", + "request" : { + "url" : "/frauds/name", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "matches" : "application/json.*" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.['name'] =~ /[\\p{L}]*/)]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"result\":\"Don't worry {{{jsonPath request.body '$.name'}}} you're not a fraud\"}", + "headers" : { + "Content-Type" : "{{{request.headers.Content-Type.[0]}}}" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "c50f9381-4230-4937-ab58-d9e8e21f303a" +} + +2023-09-06T14:29:44.228+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003383721-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraudname/shouldReturnNonFraudForTheName.json] +2023-09-06T14:29:44.229+02:00 INFO 207411 --- [qtp906926883-81] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [437] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "7c109624-495a-4d92-bcba-09c4d470d98f", + "request" : { + "url" : "/frauds/name", + "method" : "GET", + "cookies" : { + "name2" : { + "equalTo" : "bar" + }, + "name" : { + "equalTo" : "foo" + } + } + }, + "response" : { + "status" : 200, + "body" : "foo bar", + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "7c109624-495a-4d92-bcba-09c4d470d98f" +} + +2023-09-06T14:29:44.230+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003383721-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraudname/shouldReturnACookie.json] +2023-09-06T14:29:44.232+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [675] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "70027628-be19-49fc-b12b-f0bba0c88265", + "request" : { + "url" : "/frauds/name", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "matches" : "application/json.*" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.['name'] == 'fraud')]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"result\":\"Sorry {{{jsonPath request.body '$.name'}}} but you're a fraud\"}", + "headers" : { + "Content-Type" : "{{{request.headers.Content-Type.[0]}}}" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "70027628-be19-49fc-b12b-f0bba0c88265", + "priority" : 1 +} + +2023-09-06T14:29:44.233+02:00 DEBUG 207411 --- [ main] o.s.c.c.s.p.w.WireMockHttpServerStub : Registered stub mappings from [/tmp/contracts-1694003383721-0/META-INF/com.example/http-server-dsl/0.0.1/mappings/fraudname/shouldReturnAFraudForTheName.json] +2023-09-06T14:29:44.233+02:00 INFO 207411 --- [ main] o.s.c.contract.stubrunner.StubServer : Started stub server for project [com.example:http-server-dsl:0.0.1:stubs] on port 11276 with [18] mappings +2023-09-06T14:29:44.233+02:00 DEBUG 207411 --- [ main] o.s.c.contract.stubrunner.StubServer : Ports for this server are https [-1] and http [11276] +2023-09-06T14:29:44.233+02:00 INFO 207411 --- [ main] o.s.c.c.stubrunner.StubRunnerExecutor : All stubs are now running RunningStubs [namesAndPorts={com.example:http-server-dsl:0.0.1:stubs=11276}] +2023-09-06T14:29:44.234+02:00 WARN 207411 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'batchStubRunner' of type [org.springframework.cloud.contract.stubrunner.BatchStubRunner] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:29:44.324+02:00 INFO 207411 --- [ main] o.s.c.s.m.DirectWithAttributesChannel : Channel 'application.listener-in-0' has 1 subscriber(s). +2023-09-06T14:29:44.353+02:00 INFO 207411 --- [ main] o.s.c.c.v.m.i.ContractVerifierMessaging : The message verifier sender implementation is of type [class org.springframework.cloud.contract.verifier.messaging.stream.ContractVerifierStreamAutoConfiguration$InputDestinationConfiguration$1] +2023-09-06T14:29:44.353+02:00 INFO 207411 --- [ main] o.s.c.c.v.m.i.ContractVerifierMessaging : The message verifier receiver implementation is of type [class org.springframework.cloud.contract.verifier.messaging.stream.ContractVerifierStreamAutoConfiguration$InputDestinationConfiguration$2] +2023-09-06T14:29:44.379+02:00 INFO 207411 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel +2023-09-06T14:29:44.380+02:00 INFO 207411 --- [ main] o.s.i.channel.PublishSubscribeChannel : Channel 'application.errorChannel' has 1 subscriber(s). +2023-09-06T14:29:44.380+02:00 INFO 207411 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started bean '_org.springframework.integration.errorLogger' +2023-09-06T14:29:44.380+02:00 INFO 207411 --- [ main] o.s.c.s.binder.DefaultBinderFactory : Creating binder: integration +2023-09-06T14:29:44.380+02:00 INFO 207411 --- [ main] o.s.c.s.binder.DefaultBinderFactory : Constructing binder child context for integration +2023-09-06T14:29:44.395+02:00 INFO 207411 --- [ main] o.s.c.s.binder.DefaultBinderFactory : Caching the binder: integration +2023-09-06T14:29:44.395+02:00 INFO 207411 --- [ main] o.s.c.stream.binder.BinderErrorChannel : Channel '2081959096.listener-in-0.errors' has 1 subscriber(s). +2023-09-06T14:29:44.395+02:00 INFO 207411 --- [ main] o.s.c.stream.binder.BinderErrorChannel : Channel '2081959096.listener-in-0.errors' has 2 subscriber(s). +2023-09-06T14:29:44.395+02:00 INFO 207411 --- [ main] o.s.i.channel.PublishSubscribeChannel : Channel 'sensor_data.destination' has 1 subscriber(s). +2023-09-06T14:29:44.395+02:00 INFO 207411 --- [ main] r$IntegrationBinderInboundChannelAdapter : started org.springframework.cloud.stream.binder.test.TestChannelBinder$IntegrationBinderInboundChannelAdapter@24f878f7 +2023-09-06T14:29:44.400+02:00 INFO 207411 --- [ main] c.e.loan.LoanApplicationServiceTests : Started LoanApplicationServiceTests in 0.887 seconds (process running for 8.062) +2023-09-06T14:29:44.401+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +2023-09-06T14:29:44.417+02:00 INFO 207411 --- [qtp906926883-77] WireMock : Warning: JSON path expression '$[?(@.['name'] == 'fraud')]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:44.417+02:00 INFO 207411 --- [qtp906926883-77] WireMock : Warning: JSON path expression '$[?(@.['name'] == 'fraud')]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:44.417+02:00 INFO 207411 --- [qtp906926883-77] WireMock : Warning: JSON path expression '$[?(@.['name'] =~ /[\p{L}]*/)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:44.417+02:00 INFO 207411 --- [qtp906926883-77] WireMock : Warning: JSON path expression '$[?(@.name =~ /([\p{L}]*)/)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:44.418+02:00 INFO 207411 --- [qtp906926883-77] WireMock : Warning: JSON path expression '$[?(@.['loanAmount'] == 123.123)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:44.418+02:00 INFO 207411 --- [qtp906926883-77] WireMock : Warning: JSON path expression '$[?(@.['client.id'] =~ /([0-9]{10})/)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:44.418+02:00 INFO 207411 --- [qtp906926883-77] WireMock : Warning: JSON path expression '$[?(@.['loanAmount'] == 99999)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:44.418+02:00 INFO 207411 --- [qtp906926883-77] WireMock : Warning: JSON path expression '$[?(@.['client.id'] =~ /([0-9]{10})/)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:44.418+02:00 INFO 207411 --- [qtp906926883-77] WireMock : Warning: JSON path expression '$[?(@.['client.id'] =~ /[0-9]{10}/)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:44.418+02:00 INFO 207411 --- [qtp906926883-77] WireMock : Warning: JSON path expression '$[?(@.['loanAmount'] == 123.123)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:44.418+02:00 INFO 207411 --- [qtp906926883-77] WireMock : Warning: JSON path expression '$[?(@.['client.id'] =~ /[0-9]{10}/)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:44.418+02:00 INFO 207411 --- [qtp906926883-77] WireMock : Warning: JSON path expression '$[?(@.['loanAmount'] == 99999)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:44.420+02:00 INFO 207411 --- [qtp906926883-77] WireMock : Request received: +127.0.0.1 - GET /drunks + +Accept: [application/json, application/*+json] +Content-Type: [application/json] +Accept-Encoding: [gzip, x-gzip, deflate] +Host: [localhost:11276] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.2.1 (Java/17.0.1)] + + + +Matched response definition: +{ + "status" : 200, + "body" : "{\"count\":100}", + "headers" : { + "Content-Type" : "application/json" + }, + "fixedDelayMilliseconds" : 2000, + "transformers" : [ "response-template", "spring-cloud-contract" ] +} + +Response: +HTTP/1.1 200 +Content-Type: [application/json] +Matched-Stub-Id: [fa16a598-8141-456c-a737-ea03dc554383] + +2023-09-06T14:29:45.418+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +2023-09-06T14:29:45.425+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Request received: +127.0.0.1 - PUT /yamlfraudcheck + +Accept: [application/json, application/*+json] +Content-Type: [application/json] +Accept-Encoding: [gzip, x-gzip, deflate] +Transfer-Encoding: [chunked] +Host: [localhost:11276] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.2.1 (Java/17.0.1)] +{"loanAmount":123.123,"client.id":"1234567890"} + + +Matched response definition: +{ + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"OK\",\"rejection.reason\":null}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] +} + +Response: +HTTP/1.1 200 +Content-Type: [application/json] +Matched-Stub-Id: [1ccb766e-ce35-47e6-b14b-eccd836e237e] + +2023-09-06T14:29:45.426+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +2023-09-06T14:29:45.430+02:00 INFO 207411 --- [qtp906926883-83] WireMock : Warning: JSON path expression '$[?(@.['name'] == 'fraud')]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:45.431+02:00 INFO 207411 --- [qtp906926883-83] WireMock : Warning: JSON path expression '$[?(@.['name'] == 'fraud')]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:45.431+02:00 INFO 207411 --- [qtp906926883-83] WireMock : Warning: JSON path expression '$[?(@.['name'] =~ /[\p{L}]*/)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:45.431+02:00 INFO 207411 --- [qtp906926883-83] WireMock : Warning: JSON path expression '$[?(@.name =~ /([\p{L}]*)/)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:45.431+02:00 INFO 207411 --- [qtp906926883-83] WireMock : Warning: JSON path expression '$[?(@.['loanAmount'] == 123.123)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:45.431+02:00 INFO 207411 --- [qtp906926883-83] WireMock : Warning: JSON path expression '$[?(@.['client.id'] =~ /([0-9]{10})/)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:45.431+02:00 INFO 207411 --- [qtp906926883-83] WireMock : Warning: JSON path expression '$[?(@.['loanAmount'] == 99999)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:45.431+02:00 INFO 207411 --- [qtp906926883-83] WireMock : Warning: JSON path expression '$[?(@.['client.id'] =~ /([0-9]{10})/)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:45.431+02:00 INFO 207411 --- [qtp906926883-83] WireMock : Warning: JSON path expression '$[?(@.['client.id'] =~ /[0-9]{10}/)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:45.431+02:00 INFO 207411 --- [qtp906926883-83] WireMock : Warning: JSON path expression '$[?(@.['loanAmount'] == 123.123)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:45.431+02:00 INFO 207411 --- [qtp906926883-83] WireMock : Warning: JSON path expression '$[?(@.['client.id'] =~ /[0-9]{10}/)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:45.431+02:00 INFO 207411 --- [qtp906926883-83] WireMock : Warning: JSON path expression '$[?(@.['loanAmount'] == 99999)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:45.432+02:00 INFO 207411 --- [qtp906926883-83] WireMock : Request received: +127.0.0.1 - GET /drunks + +Accept: [application/json, application/*+json] +Content-Type: [application/json] +Accept-Encoding: [gzip, x-gzip, deflate] +Host: [localhost:11276] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.2.1 (Java/17.0.1)] + + + +Matched response definition: +{ + "status" : 200, + "body" : "{\"count\":100}", + "headers" : { + "Content-Type" : "application/json" + }, + "fixedDelayMilliseconds" : 2000, + "transformers" : [ "response-template", "spring-cloud-contract" ] +} + +Response: +HTTP/1.1 200 +Content-Type: [application/json] +Matched-Stub-Id: [fa16a598-8141-456c-a737-ea03dc554383] + +2023-09-06T14:29:47.434+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +2023-09-06T14:29:47.438+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.['name'] == 'fraud')]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:47.438+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.['name'] == 'fraud')]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:47.438+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.['name'] =~ /[\p{L}]*/)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:47.438+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.name =~ /([\p{L}]*)/)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:47.438+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.['loanAmount'] == 123.123)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:47.438+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.['client.id'] =~ /([0-9]{10})/)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:47.438+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.['loanAmount'] == 99999)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:47.438+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.['client.id'] =~ /([0-9]{10})/)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:47.439+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Request received: +127.0.0.1 - GET /frauds + +Accept: [application/json, application/*+json] +Content-Type: [application/json] +Accept-Encoding: [gzip, x-gzip, deflate] +Host: [localhost:11276] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.2.1 (Java/17.0.1)] + + + +Matched response definition: +{ + "status" : 200, + "body" : "{\"count\":780}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] +} + +Response: +HTTP/1.1 200 +Content-Type: [application/json] +Matched-Stub-Id: [f5243e52-a4d7-453b-95a3-340595e07430] + +2023-09-06T14:29:47.441+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +2023-09-06T14:29:47.447+02:00 INFO 207411 --- [qtp906926883-77] WireMock : Request received: +127.0.0.1 - PUT /fraudcheck + +Accept: [application/json, application/*+json] +Content-Type: [application/json] +Accept-Encoding: [gzip, x-gzip, deflate] +Transfer-Encoding: [chunked] +Host: [localhost:11276] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.2.1 (Java/17.0.1)] +{"loanAmount":123.123,"client.id":"1234567890"} + + +Matched response definition: +{ + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"OK\",\"rejection.reason\":null}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] +} + +Response: +HTTP/1.1 200 +Content-Type: [application/json] +Matched-Stub-Id: [cf47e5df-1c9c-42f9-a3fb-fd3d1c869f65] + +2023-09-06T14:29:47.448+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +2023-09-06T14:29:47.453+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.['name'] == 'fraud')]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:47.453+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.['name'] == 'fraud')]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:47.457+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Request received: +127.0.0.1 - GET /frauds/name + +Accept: [text/plain, application/json, application/*+json, */*] +Cookie: [name=foo; name2=bar] +Accept-Encoding: [gzip, x-gzip, deflate] +Host: [localhost:11276] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.2.1 (Java/17.0.1)] + + + +Matched response definition: +{ + "status" : 200, + "body" : "foo bar", + "transformers" : [ "response-template", "spring-cloud-contract" ] +} + +Response: +HTTP/1.1 200 +Matched-Stub-Id: [7c109624-495a-4d92-bcba-09c4d470d98f] + +2023-09-06T14:29:47.458+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +2023-09-06T14:29:47.463+02:00 INFO 207411 --- [qtp906926883-77] WireMock : Request received: +127.0.0.1 - PUT /fraudcheck + +Accept: [application/json, application/*+json] +Content-Type: [application/json] +Accept-Encoding: [gzip, x-gzip, deflate] +Transfer-Encoding: [chunked] +Host: [localhost:11276] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.2.1 (Java/17.0.1)] +{"loanAmount":99999.0,"client.id":"1234567890"} + + +Matched response definition: +{ + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"FRAUD\",\"rejection.reason\":\"Amount too high\"}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] +} + +Response: +HTTP/1.1 200 +Content-Type: [application/json] +Matched-Stub-Id: [660fc6f9-2508-45a0-a1a3-4d3035c2955b] + +2023-09-06T14:29:47.464+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +2023-09-06T14:29:47.467+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.['name'] == 'fraud')]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:47.467+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.['name'] == 'fraud')]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:47.467+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.['name'] =~ /[\p{L}]*/)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:47.467+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.name =~ /([\p{L}]*)/)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:47.468+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Request received: +127.0.0.1 - GET /yamlfrauds + +Accept: [application/json, application/*+json] +Content-Type: [application/json] +Accept-Encoding: [gzip, x-gzip, deflate] +Host: [localhost:11276] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.2.1 (Java/17.0.1)] + + + +Matched response definition: +{ + "status" : 200, + "body" : "{\"count\":200}", + "headers" : { + "Content-Type" : "application/json" + }, + "fixedDelayMilliseconds" : 2000, + "transformers" : [ "response-template", "spring-cloud-contract" ] +} + +Response: +HTTP/1.1 200 +Content-Type: [application/json] +Matched-Stub-Id: [18870094-18db-484a-ade9-e161dae03756] + +2023-09-06T14:29:49.470+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +2023-09-06T14:29:49.483+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.['name'] == 'fraud')]' failed to match document '%PDF-1.5 +%���� +2 0 obj +<< /Linearized 1 /L 14631 /H [ 687 126 ] /O 6 /E 14356 /N 1 /T 14355 >> +endobj + +3 0 obj +<< /Type /XRef /Length 49 /Filter /FlateDecode /DecodeParms << /Columns 4 /Predictor 12 >> /W [ 1 2 1 ] /Index [ 2 15 ] /Info 11 0 R /Root 4 0 R /Size 17 /Prev 14356 /ID [] >> +stream +x�cbd�g`b`8 $���XF@���Zb�d +v�Xv L���@ ����0 +endstream +endobj + +4 0 obj +<< /Pages 12 0 R /Type /Catalog >> +endobj +5 0 obj +<< /Filter /FlateDecode /S 36 /Length 49 >> +stream +x�c```e``Z�&���fb�(H-30�g�c``�>������( +endstream +endobj +6 0 obj +<< /Contents 7 0 R /MediaBox [ 0 0 596 843 ] /Parent 12 0 R /Resources << /ExtGState << /G0 13 0 R >> /Font << /F0 14 0 R >> >> /StructParents 0 /Type /Page >> +endobj +7 0 obj +<< /Filter /FlateDecode /Length 200 >> +stream +x���� +�0 ��}���uI�4-����Y)��AA}0���I���~��KZÔ¨H��؞�� +������n{���E�����R�y�b�!�=���h��x/��<�f�;���`EB'�%z���l��;�6p�! M/E�g�>��;�#�v�d-�E��Eb!ÉŠp@�&�-��H�W�2�6!yoч(�>)6O����Z�endstream +endobj +8 0 obj +<< /Filter /FlateDecode /Length1 29380 /Length 12131 >> +stream +x��} |TE�喙��Y!B �MB"H ì‹@"�L$M�I���q���e7@T�f.�(����,.�����8��~��{;������~�i����:U�ԩS��v�Q0U�F�%���]�o#��������}m�� ��DY{�-/,����_��Y��ŋ�.�퇶��׋�����ގ��"���V�?]�J<���� b��:l(.s�)����+P�\b��<�P�]hǘ���K�/��aDW�"�-�p���ω��t��������/��n;엀��?�������\���sO�/ p���gJO��� 4*��=��7l�Y��c�&k,��A��0J��D"z5�V� �/���n��ںP�e:�4�o�$�.�!�� +�nE9t�� �i� `0�lÖ��TY���c��quӌ�8*�L������7h.� �M� �bL%(oF�}�h��A��֭t/��G�u�梼�L��m�5�IR����g�9�˴�h�p�Na.y�J�f�:���#�� +Z���mB;(��+d=�e�+0�r��@��(��3찂��n� �;��i���Ƽ�7�HιqN�ߴ�B6�k�|H�}_�6��5nj��Z_��D��A*W���Y�"M�)�t�\���j�E�e�������g���k1���p���?��5�� ��0�R�A�����Ê�Tо�+C7����O�7(/źN��z�c�*0�R +K{�?M�\�;��0�_Bf��#0w���ì±ï¿½ï¿½8��Did���'A!m�CÅ™ ���q:V� � +|l�C�g�n�MЫ�xE���T�ذ��6��T�iì™ï¿½XRO�� �o"^�)���Yز�?��S2f�T��|��G9OS�{O|Gc� +j"��T�;�,��Z>�V��G�$cV���/2Ö”O�'L:��\{�=�%��~���}�H�h3�̷�AN�@W]��As��ҺS��7�0�z�w4%`?��ZNDy]+z����gÙyn�?����q�'�#�b����B�-�6�X���`��6I%���W��;�Z�!gn���r���|�{��� +�~��@5�# ��0��ڦQ�gP&2h�%���X��y��O���}��E�}ª����md�k�Ӡ�H7I��A˛�Q��kK~���T�|3��@���L|i�,� ��af�(�:�����x��k�Ϸ��U��l��[�gH�lM�ق��ߧ����e~�9N�H��d��˷�����c��� s_'��6~n�}�a���>�u��1�.�-Ü·Åš�c��{ ��L��5��iw�Yj�S�����3�mV��'�[��ӕ}�֧i������`�A�v����zZ�yt�V`?��)}�ւ(J� �L�îŸï¿½Y��nҎ� ���v�AW���T�TIe��j�d����4���T �J�C�#�>��B"�'�P�8d"(r�2�1��|܋� ��l�� ���mT}2(���f� �w_��AS�}�;z�2����h����i�s�c<�~Ó¤-��Y����5�_+��V"çŠï¿½�:m�s�:�U�G�(�R +�Ws�F�]!�����e�X�A���{�F�P�u>�A� �$��B�2���ػ����� �oA��;B�e�A�[��V�{)�=��oi�v%�Dg�?,�^8/b/�c@��Xm@Õ…��kat���K��Z0�V��{�Rr�键��N���a��F�imi�8@��ZZ-Ë¢=uӼ��.�-e�a�$���(�K3�0�_I�b6��툽(H��Z���V�IW�� �`_� m:�����=!唎]��%��K�ke��l���+���W�-셭�v�m��}j�r\��2�>�;���dІ�| +m6�Oi�6��-H0��h�p��'� +E��q��g7��?= ,��E�i���[: +,��/���|$ +�u�o�ۚC�X}sX��e���`?��K����@�q9� o��.���X��P�1[��']@T� � +�1��"�6���N��m� +0Ç›j��{��"���F����<�?7�� �%�{!�w�[���~~6� ��Q��b ���=��@8������ �C�����?�S�;�v���@oh��S�z�m���_�?�;3hE +?���s�����}~��O�� +�!����N"���.+����hR�����K��O��Y�_��Y�_A7���Z�=��{���ԑ��6NA \P.���;X�5( +��l ����62/;�|<�����iLÓ´@-Q[��h����!"&��b��K�E< ;�s��e����-?[C���8���|k�u�u��f����ǭO[ß±���<�7����� z�������C�a�p=K/ӗ����'�-���;�'�'ǧ���_O���`Mh����9!.�{BJ� �g"O K�O�$����!)*)&�kRϤ~I�����%�LZ�tW�Ƥ'�v$�Mz>�դ��'}����a��#���s��c�&�!g��>u�N�P7�nx]f]V���V��S竟s~����}�>����6(�m`O���<�:<��F��[�ݪ=,�h#&�k��b�X/6��D��X|c�Z���k9cz.ÞšaͿ����V�n�C��z���s=�t}��y��������M�ížk�uJ�5=��P�<���Mj���I��6z�<�1<7��s��y�0�9vF�1x�G� x.�nT���u�����ZW_����\���� �=��AK���`G�ED�ɪ�|VQ�e��ن�� +��������TLEt +����X���oן������_Wo���~I���?׻��}1���cƷ�'�����䲓���r� +�g�Փ5'o��X±�c���?���7G�:���u������xZ��v���O�>:�h�ѮG������^�M�Eۣ�l������k{���m��!�_�Z�[�v�9��eZ�����@���������h�i.�r+� nD��:�y���k����Ib�Y��{v��,�5�]W2�߶\բ��ô��k��Z��L��*z��͸"���7�]t�~�5�ZI/�1:M�V�'�D?�&z�ޤ��I�C�� +�9� +z������i.�G��]z� +���>��鯈�o�;��摋�S ���6P-�r� 7U�1]E��u��E�'�q�,m�%���i)���A{�Z�ƙ��PÕ³{�:���Gç©Y������`����6�@Ä‚Y�����+��a�����8�ʶ�'ؓ�)�,/��v���/:�j�*��=�v�gY- em����ea� ��t��g�s�y�:����"�������,�E���e�Xg� +{�E�օŲ�������� �t���M�;��f� gb��+Kb��0{����ge��p�ƺ��%}ŎЇt�>�O�(���3v��a?�������β_ٿ�o�Kau���g +�'�1�s�q�-��m<�� Ö‹����<����=��Ry���XoÉ£x'Þ™G�ޅ��8���<�'�>,�'���+O���2Þw�=x +_�o��Y����R�&m��B�E[�ݦݥݣ���������M{R{ZÛ®=���^�^�^���b����>�>�Ni_i�j�k�����'�O�3��������9^�� -X ���0����xLl���b�xB<�S�i����̻�3b�x���������'�������xM�.�o����xG��a�xO�/�*>Gć�#�R��O�QqL|&���8%>_�/�W�o�k��V�]|'�!�?����Q�$�)~��/ؗ��U�K�&Ή:�N;x +�G��nzoG;i�J��hr�Dm�6I��MÓ¦kWk��T-�~a_��b1=O��{��G�N6�nc�l!���]��j� +�{��X *�R����5�Lm�X&*E�X.���"�B����J�׉��q�� +'��L�OÜ;̓���+Ö‰�Cb�؈��a��6@��&��D�_3�o�vШ ��Ú¦mX���":FFu��%6N�OHìš”|Y��=Rz�JM��'�o����w�������lힽ�=�‹�����+����o�u��w:�.���_?8��G���c�?q��x��x��x��x��x��x��x��x�����3233F �|��!� +�߯oz��i��z�����䤮� �z\l���Î�";Fth�.�m�Ð����"4Ψgv��|ݛ��ɉW\�K��7�����Rƫ�+1��d$綒�0$3%Y�>����g'�ރY�z-�19����<�����+�v���G=;�(K��|=�;zaQMv~��4*q�3�WO� 6�72�|;���#��l� +���������^-)�^��497;+:>>�WO/�H��đ޶)J�F)5^�(�M��]r6�J��s���0���R�X`�����yRG����F^�eTS����]Ѽ5Z�Ɏr�XS�B�n��ۼ5^>��0����5��z5�8n�m|y^��-�J]�D�ʘ�31[���ӽ��#�j��ci:�xiʢ��;g����zMNnb�wDtb�=+f{���hg� �SË–^=���3��M[� m�8���%7nJ�g��(q,«;tX���9 +�� �q �~�zy �".o����!�^��Z�pG���=?������5֤�_H�2NC +�~ޛ����C��m�6W���z.�剉�a:�G��[{Þ4�?>^.�� ����zr�Q�iN��HK���|ٲ��1M�T�[��'"�w���o@r�m�:��.�e��i����8n�\=�&���%�}Pc��yÛ�բ���hM�"(g6 +�Bn�W$�?� +�Z[�R�0}�7,� +��v�����i�f���Ҳ<�E��y!5 �|\Ό���m5C�X� �)'7^�iØ™I��ַ�D^�7.%F�Yl!m�y���٫�h$���щ���{��zN��X����_�)���N�o�h���y�U�+3��j�t���Lf�V%'kÊ€%�>��j��"w��7�d�";�����(��;��3����k� +1���3�SG��� +OJ��4(4}fG\��8�����Ԗ1�� +Zy�YÍš -|g����i�p���q����.=3���i +�8���h���l�.���+���4�������h ?����C�>�0p������8?��( +���� �0~L�'�����cx���Q<��O�}�?�i�1pp�Ť��L\��DF�Lx��Z���ߺ���/v�)q2{�� p(��@:0 ��+��}H����� X��C��}�Ro ��ww@M-?�#yd\fG~��A�p�A������}����[�����;b�(3�>a�a�ih��vv +��e�����8<Ó€�D`6p`��x��p � H�o}�6PƼ���Q�1]>��\���yF��u(�G�w����e���G��K��Gr�Bp�\0�|$Ϙ +N>�'�ã�?�l���N���̶� +^�����*�J~�7!m�oG�������=�����Y�V��U;Y�bV��Uc�ײ�VêcYu�~� +�+�YÆ®��Q���~�U�Yu2�Nb�]Y��f���c�*����L��@/��6�ã��xl�}x|��!=��+i��#�r����+�+�� +��:,�+�W0�+�-�#���~�4���N�ᷩg[<Ó€�l` p�*sN��L�V���FO�%� +> �����.a1a)aWh���lb�/����-?�]@;����5�_��R`f ���F]������u��e��H~..3���b�� +�d�:�ܪܟb$�G1|h������vGrϸ����;î·˜/ã¾ï¿½ï¿½`��y.�#�V�qGP�mw�1�Ľ�V���k�^]����%� +�w�-�dwÜ1c��Ǩ��p����qS�g�]��b��e�1��1�� +3���>��zÄ��c��(���j�ikYQFO�Z[�m�m�-���o��u�E�:���   +��@j}'3R���a��?3�H(>�˧��X�5��J����qSG�q��7G����XË‚p�ZG2o�8�3�;(e\��7�;0e��6���ݚ�Z/_Y�p��2��Z-��{��v��DK�m���<��pDԈ����κ�#�|�4�D��x׎�����%Ï›._��q޻�]vޟ�dg���4H^�m8�){��׆g�å«eÓ•��G�!b~Tr��K9�b +���\�C��$� �$%����r��]���w�d"ur+w��\�@d���L�j:�dt��2��J$&"�1J�u�%�:+��M"i��-�"�(Mk��1dBO�eBOB&�?�q�LIa;��9f�����l'��]��(�[=G×·;�����9�"I�No^�3��H�ҷ�y�晲yhb�v�����}f�3k�Ќ�ى����c&��B�-���M��`��`���1/�)w{��õSÑ<8��7�cX�p�C�G�����7�P@6���)���dS��g6E-��m1��P�.q$�x*Ý•���2�s�U�J�p���w?h��{[��C4��c�8��s��l�͗S���g�iT��r��ԴFAY7L�����IG�]P͟��2b���y�7v\G*�1o�{q]�ǃ;t������&�'9_?<�&g��cR�����h�A�*�^�t����:�vQm�9��B�jZL{�#��}KKh��W�ZN��@�4��h +��WI3鄸��UTJ�ڗ��w�o3=B{�7}�)�:����,��Q/����� vg�3�-Õ|�*h�6K0_��,��*� h<d�y +Fw��,�ݠ��(���W!C�����^֟��ñ–™¾ï¿½ï¿½:�è�h�Ƨ�^�OY��o�� u��4��E��~���҆���Rw��2z�ޠwY"{��YB,� ������i��1����/�g����Im��;���5:�:�46�M��yP��h�O���{1�qD�n�k�m��ڥ᤯ +V$���%�������>d_�Q|6����-�����TBkh���� 6�]� +l���cٻ���s�|~Z+�h/���Lnq��f�*�7 +� +�6���/�w3MF<,���Ѓ��:L��s�>g���#�������b��mR�Aï‚–w���[�@��:���[y����D^� ���~~�w�?�oZ����h��aZ�V�Vh���vJt��~N�����g���?|���� +԰�am�]�S�5�a�W�a�ގ�<��ZD���W�uf=�pv<3��c �u��2��=�l�=/}�N��P�lN���H>�k��/���N����i6-Xk�Eh=�1�,Í©y�E�Zͫ��}�}������ 'D�Hc�lQ)_��-3-o[��YK�7[k�?�3�6�6�6�v�m�타|�-*=C�6�U;�-ղ�g�V�Wt��!��l*��sD*��V��.��r�u(�&�����_��|�6��cSi�������Aȿ�=L�Bߋ�1�C�:k[�O[ChSo����)����v���F:*�X$��?�MB� �[r)^�������MT�q<�mE^�a��_��� ����t������+�/�@ҭԗ�@_ӣ��-����w�ޞ�".���ue��-c���������"��kO����)m�8c��n��i�o)-���Y!il:%���n7h�"t ��L����{�2��B�\���� ��{�'"È…=~5��!�e��ThiÃu��� +Sh��QZ�+�Rß� �`��������h [��'*Ǜ�'��WYF�ÖѾ^��§�-��NbQ�w|���4��Ո�h*���AtwC�]Gsp?������S߆ |�o�V����ɾ�|q,��|�4���Gl��RL����l��V8���} �p �p �p �p �p �p �p �p �p �/�3� ��S�6���/��Z�.�=YÄ—�ė�:X-_r�yÞ‡�:�JQ)ag��6!��a���������;�]|�$< �׵�����b��]�&"!OL�dDX-�6i"�3L�Z������~��J=H�A�CE��t��2����%�N;;k��_�(��ӆ�I�����7�It�PK�?�-��}�a� +�OJK6c� ʒ�= +�����'���� +A�� ����f�Ϊe�<�0BYX��2=tRh~hy���2kA�ٔY���JK`Ùˆa�g�)�����`�������_>o��=�(�qn4�y~<_ ��U��8�P�.���e��q�t�u�L�J��f��3_�2߲��?�$N�ז�,P��%��۲a:DGFG &:GG��#w�y����.�&����9×’xuØ´v��ψ�5���ѫ"��N����ۘ�suÖ¥m�4�S�c��6㿟���Ј�G|���Z@�f�Z�>���ExD.��a�7����ɉ �`+ـ���m�v�;ܰw˛��GGY��o�8��?�J�/7��tt�|����C��L� +�v<(�� �����u�W�pd�⭲>2Z�6U��?P����Fo���kd𢙌�Fo���kd����Fo���kd����Fo��䃚�7X�e��C�շQs�Z�ar.���o><�R���G�qL�c��N�� +�G+]Ƙ]���5�*�{�C�+���K>����t�4���%�Q99i.�����@)~<�Q)�1�t�Rx���ޥ$t��*�,Uo��)��2����X��/CÆï¿½ï¿½ï¿½ï¿½ï¿½>4������Um&z�NA�B��Q��`<7PA �,P6���I%��T@�)��Éw�C:z��r�Rꩴ����0Dz���Y�F�3(��%jDZ���r�:u�Hr +*�~0�Q�fc�G\7��Rq^a��5���5���|c] +�L�4�[S�2F���@�I��N�J�x<'B�\�~���t+o�������� +�Œ$?���h<�R�٨����c��l|ƫ� +� ���Ĵ�XoXl�\���M{�B�g^|P���HI������x��ZA��Q��1���T}�r���2C5�k#O����6sG��٘{�o�Lm2�,4s���S������c��1 :Í�l�;*Oy̼1׌���˿ۥǜ�Fi��+0�K���� +��+Sj�|��Lͪ����aT\�ٟCe����Z�Mo��\��t���/m��]�N�6�|���]YT�<+�-��o�����r�_����Ӯf�UE�W�F�fq�tG�}OI�J����*k1^�Z��j5�gn�,���g*����E��1�j�%f�6�o�r3>�2|���5��X5� W�Ç“g�Ӽ �1�����֠����F��+S���̫ �������x���{�i�5Z����.\G�[M7c���}�_1{+_��/Y��� 5��W���iÞ–=8!�#�S&��H���� +�y����^x���&��9�ƙ��՟8î‡ï¿½����5����DB�^��$�З�O�������w����� �e��Y��)�2���i����:��g��7x�?���B��� +Lų�ÜQ%߬�=�fw����zG��!�Z���g���>��(�?��J� Y���[Z�xl;gQ�s�����s������2��Qe�ev���T//v��Yv�����`�Բ�JY��ǖ�_���{��#=U�,.֧� +�q�~��Q��f�c�dg�Ϟ��S���{Z.��ì=j���++���-Rzd�K?�Y�/*��=2Ba]ei��>�J�5bÂ…h������ћ��[��S6Gn=���0Fz�J���픫S�txs��&�䲗:�� +��~XND��J���e؅�&t��o�����e�� �ŕ�9�J�QÕ¼w�>�T��"�,0'sq�%캻��p�u9.��/���}�.�ƈ� +��z�� +�[�ZU�*q� A���*���6[�,�B�T�)v����e��� +��T�t#�M�T��1vn��d�[P�t+5È•gE�9� +�n%�.*�,.@�.t9��w���V҉�QД��T2vx��XN�nZ=���*�;���z�!R`��L���mP�����}��ݯw���i�PÙ»O�~���w�>p@����y<�C�Ҫ��RK� �(+i�'�zV��J�[Fa�)es�C' g�!�������p���v�7�8�����ӊ<%�i%�;L+q϶�<�*+��U�b�:���,��~TÒ¸ ���`�����k�"��|�ߪ���}��,�+���h��� �>`��W{��Xvu1�O���-t9[������'ƈ�� i�zE,0�#E��6j��x�K� +u=�c�/0���endstream +endobj +9 0 obj +<< /Filter /FlateDecode /Length 247 >> +stream +x�]�Mk�0 ���:v�b�]��`�2 +9�e���d��6�sȿ�?J�� ��^Ѷ{@߃S=F����0�d,9p�F��_������D�;;:�4�#e�6�]���з�1;������?8�����qL�^��3-�}�S��m�4��G��u�4.^* �NH�B@sM!Z�/��aT�2��c�f�3��� =�*=U:W�Vj y�:��/��w��Qk�G9^1�W7����gU~�; z6endstream +endobj +10 0 obj +<< /Type /ObjStm /Length 459 /Filter /FlateDecode /N 6 /First 37 >> +stream +x�uQ�n�0��+�hÌ—(Qv\7F�$���P��H�JT���R�Z�P����,��� H8�T +\���S� �V�nn�>��<����3�q��F�9,�c�֟��WW� +2�}�7��sg��Tv���=�{�7�Zl���`�i�w���n�Pض4m��H��>�?��/][ݕ� +.�w@��0JFa��n-��������p�mv�w���j�Im��Vn�f�ҿ�y���6�@��rd:�/���t��`�X]�{��ǸG�f�����?��+F��A> /W [ 1 2 1 ] /Size 2 /ID [] >> +stream +x�cb&F �R +endstream +endobj + +startxref +216 +%%EOF +' because of error 'Filter: [?] can not be applied to primitives. Current context is: %PDF-1.5 +%���� +2 0 obj +<< /Linearized 1 /L 14631 /H [ 687 126 ] /O 6 /E 14356 /N 1 /T 14355 >> +endobj + +3 0 obj +<< /Type /XRef /Length 49 /Filter /FlateDecode /DecodeParms << /Columns 4 /Predictor 12 >> /W [ 1 2 1 ] /Index [ 2 15 ] /Info 11 0 R /Root 4 0 R /Size 17 /Prev 14356 /ID [] >> +stream +x�cbd�g`b`8 $���XF@���Zb�d +v�Xv L���@ ����0 +endstream +endobj + +4 0 obj +<< /Pages 12 0 R /Type /Catalog >> +endobj +5 0 obj +<< /Filter /FlateDecode /S 36 /Length 49 >> +stream +x�c```e``Z�&���fb�(H-30�g�c``�>������( +endstream +endobj +6 0 obj +<< /Contents 7 0 R /MediaBox [ 0 0 596 843 ] /Parent 12 0 R /Resources << /ExtGState << /G0 13 0 R >> /Font << /F0 14 0 R >> >> /StructParents 0 /Type /Page >> +endobj +7 0 obj +<< /Filter /FlateDecode /Length 200 >> +stream +x���� +�0 ��}���uI�4-����Y)��AA}0���I���~��KZÔ¨H��؞�� +������n{���E�����R�y�b�!�=���h��x/��<�f�;���`EB'�%z���l��;�6p�! M/E�g�>��;�#�v�d-�E��Eb!ÉŠp@�&�-��H�' +2023-09-06T14:29:49.489+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.['name'] == 'fraud')]' failed to match document '%PDF-1.5 +%���� +2 0 obj +<< /Linearized 1 /L 14631 /H [ 687 126 ] /O 6 /E 14356 /N 1 /T 14355 >> +endobj + +3 0 obj +<< /Type /XRef /Length 49 /Filter /FlateDecode /DecodeParms << /Columns 4 /Predictor 12 >> /W [ 1 2 1 ] /Index [ 2 15 ] /Info 11 0 R /Root 4 0 R /Size 17 /Prev 14356 /ID [] >> +stream +x�cbd�g`b`8 $���XF@���Zb�d +v�Xv L���@ ����0 +endstream +endobj + +4 0 obj +<< /Pages 12 0 R /Type /Catalog >> +endobj +5 0 obj +<< /Filter /FlateDecode /S 36 /Length 49 >> +stream +x�c```e``Z�&���fb�(H-30�g�c``�>������( +endstream +endobj +6 0 obj +<< /Contents 7 0 R /MediaBox [ 0 0 596 843 ] /Parent 12 0 R /Resources << /ExtGState << /G0 13 0 R >> /Font << /F0 14 0 R >> >> /StructParents 0 /Type /Page >> +endobj +7 0 obj +<< /Filter /FlateDecode /Length 200 >> +stream +x���� +�0 ��}���uI�4-����Y)��AA}0���I���~��KZÔ¨H��؞�� +������n{���E�����R�y�b�!�=���h��x/��<�f�;���`EB'�%z���l��;�6p�! M/E�g�>��;�#�v�d-�E��Eb!ÉŠp@�&�-��H�W�2�6!yoч(�>)6O����Z�endstream +endobj +8 0 obj +<< /Filter /FlateDecode /Length1 29380 /Length 12131 >> +stream +x��} |TE�喙��Y!B �MB"H ì‹@"�L$M�I���q���e7@T�f.�(����,.�����8��~��{;������~�i����:U�ԩS��v�Q0U�F�%���]�o#��������}m�� ��DY{�-/,����_��Y��ŋ�.�퇶��׋�����ގ��"���V�?]�J<���� b��:l(.s�)����+P�\b��<�P�]hǘ���K�/��aDW�"�-�p���ω��t��������/��n;엀��?�������\���sO�/ p���gJO��� 4*��=��7l�Y��c�&k,��A��0J��D"z5�V� �/���n��ںP�e:�4�o�$�.�!�� +�nE9t�� �i� `0�lÖ��TY���c��quӌ�8*�L������7h.� �M� �bL%(oF�}�h��A��֭t/��G�u�梼�L��m�5�IR����g�9�˴�h�p�Na.y�J�f�:���#�� +Z���mB;(��+d=�e�+0�r��@��(��3찂��n� �;��i���Ƽ�7�HιqN�ߴ�B6�k�|H�}_�6��5nj��Z_��D��A*W���Y�"M�)�t�\���j�E�e�������g���k1���p���?��5�� ��0�R�A�����Ê�Tо�+C7����O�7(/źN��z�c�*0�R +K{�?M�\�;��0�_Bf��#0w���ì±ï¿½ï¿½8��Did���'A!m�CÅ™ ���q:V� � +|l�C�g�n�MЫ�xE���T�ذ��6��T�iì™ï¿½XRO�� �o"^�)���Yز�?��S2f�T��|��G9OS�{O|Gc� +j"��T�;�,��Z>�V��G�$cV���/2Ö”O�'L:��\{�=�%��~���}�H�h3�̷�AN�@W]��As��ҺS��7�0�z�w4%`?��ZNDy]+z����gÙyn�?����q�'�#�b����B�-�6�X���`��6I%���W��;�Z�!gn���r���|�{��� +�~��@5�# ��0��ڦQ�gP&2h�%���X��y��O���}��E�}ª����md�k�Ӡ�H7I��A˛�Q��kK~���T�|3��@���L|i�,� ��af�(�:�����x��k�Ϸ��U��l��[�gH�lM�ق��ߧ����e~�9N�H��d��˷�����c��� s_'��6~n�}�a���>�u��1�.�-Ü·Åš�c��{ ��L��5��iw�Yj�S�����3�mV��'�[��ӕ}�֧i������`�A�v����zZ�yt�V`?��)}�ւ(J� �L�îŸï¿½Y��nҎ� ���v�AW���T�TIe��j�d����4���T �J�C�#�>��B"�'�P�8d"(r�2�1��|܋� ��l�� ���mT}2(���f� �w_��AS�}�;z�2����h����i�s�c<�~Ó¤-��Y����5�_+��V"çŠï¿½�:m�s�:�U�G�(�R +�Ws�F�]!�����e�X�A���{�F�P�u>�A� �$��B�2���ػ����� �oA��;B�e�A�[��V�{)�=��oi�v%�Dg�?,�^8/b/�c@��Xm@Õ…��kat���K��Z0�V��{�Rr�键��N���a��F�imi�8@��ZZ-Ë¢=uӼ��.�-e�a�$���(�K3�0�_I�b6��툽(H��Z���V�IW�� �`_� m:�����=!唎]��%��K�ke��l���+���W�-셭�v�m��}j�r\��2�>�;���dІ�| +m6�Oi�6��-H0��h�p��'� +E��q��g7��?= ,��E�i���[: +,��/���|$ +�u�o�ۚC�X}sX��e���`?��K����@�q9� o��.���X��P�1[��']@T� � +�1��"�6���N��m� +0Ç›j��{��"���F����<�?7�� �%�{!�w�[���~~6� ��Q��b ���=��@8������ �C�����?�S�;�v���@oh��S�z�m���_�?�;3hE +?���s�����}~��O�� +�!����N"���.+����hR�����K��O��Y�_��Y�_A7���Z�=��{���ԑ��6NA \P.���;X�5( +��l ����62/;�|<�����iLÓ´@-Q[��h����!"&��b��K�E< ;�s��e����-?[C���8���|k�u�u��f����ǭO[ß±���<�7����� z�������C�a�p=K/ӗ����'�-���;�'�'ǧ���_O���`Mh����9!.�{BJ� �g"O K�O�$����!)*)&�kRϤ~I�����%�LZ�tW�Ƥ'�v$�Mz>�դ��'}����a��#���s��c�&�!g��>u�N�P7�nx]f]V���V��S竟s~����}�>����6(�m`O���<�:<��F��[�ݪ=,�h#&�k��b�X/6��D��X|c�Z���k9cz.ÞšaͿ����V�n�C��z���s=�t}��y��������M�ížk�uJ�5=��P�<���Mj���I��6z�<�1<7��s��y�0�9vF�1x�G� x.�nT���u�����ZW_����\���� �=��AK���`G�ED�ɪ�|VQ�e��ن�� +��������TLEt +����X���oן������_Wo���~I���?׻��}1���cƷ�'�����䲓���r� +�g�Փ5'o��X±�c���?���7G�:���u������xZ��v���O�>:�h�ѮG������^�M�Eۣ�l������k{���m��!�_�Z�[�v�9��eZ�����@���������h�i.�r+� nD��:�y���k����Ib�Y��{v��,�5�]W2�߶\բ��ô��k��Z��L��*z��͸"���7�]t�~�5�ZI/�1:M�V�'�D?�&z�ޤ��I�C�� +�9� +z������i.�G��]z� +���>��鯈�o�;��摋�S ���6P-�r� 7U�1]E��u��E�'�q�,m�%���i)���A{�Z�ƙ��PÕ³{�:���Gç©Y������`����6�@Ä‚Y�����+��a�����8�ʶ�'ؓ�)�,/��v���/:�j�*��=�v�gY- em����ea� ��t��g�s�y�:����"�������,�E���e�Xg� +{�E�օŲ�������� �t���M�;��f� gb��+Kb��0{����ge��p�ƺ��%}ŎЇt�>�O�(���3v��a?�������β_ٿ�o�Kau���g +�'�1�s�q�-��m<�� Ö‹����<����=��Ry���XoÉ£x'Þ™G�ޅ��8���<�'�>,�'���+O���2Þw�=x +_�o��Y����R�&m��B�E[�ݦݥݣ���������M{R{ZÛ®=���^�^�^���b����>�>�Ni_i�j�k�����'�O�3��������9^�� -X ���0����xLl���b�xB<�S�i����̻�3b�x���������'�������xM�.�o����xG��a�xO�/�*>Gć�#�R��O�QqL|&���8%>_�/�W�o�k��V�]|'�!�?����Q�$�)~��/ؗ��U�K�&Ή:�N;x +�G��nzoG;i�J��hr�Dm�6I��MÓ¦kWk��T-�~a_��b1=O��{��G�N6�nc�l!���]��j� +�{��X *�R����5�Lm�X&*E�X.���"�B����J�׉��q�� +'��L�OÜ;̓���+Ö‰�Cb�؈��a��6@��&��D�_3�o�vШ ��Ú¦mX���":FFu��%6N�OHìš”|Y��=Rz�JM��'�o����w�������lힽ�=�‹�����+����o�u��w:�.���_?8��G���c�?q��x��x��x��x��x��x��x��x�����3233F �|��!� +�߯oz��i��z�����䤮� �z\l���Î�";Fth�.�m�Ð����"4Ψgv��|ݛ��ɉW\�K��7�����Rƫ�+1��d$綒�0$3%Y�>����g'�ރY�z-�19����<�����+�v���G=;�(K��|=�;zaQMv~��4*q�3�WO� 6�72�|;���#��l� +���������^-)�^��497;+:>>�WO/�H��đ޶)J�F)5^�(�M��]r6�J��s���0���R�X`�����yRG����F^�eTS����]Ѽ5Z�Ɏr�XS�B�n��ۼ5^>��0����5��z5�8n�m|y^��-�J]�D�ʘ�31[���ӽ��#�j��ci:�xiʢ��;g����zMNnb�wDtb�=+f{���hg� �SË–^=���3��M[� m�8���%7nJ�g��(q,«;tX���9 +�� �q �~�zy �".o����!�^��Z�pG���=?������5֤�_H�2NC +�~ޛ����C��m�6W���z.�剉�a:�G��[{Þ4�?>^.�� ����zr�Q�iN��HK���|ٲ��1M�T�[��'"�w���o@r�m�:��.�e��i����8n�\=�&���%�}Pc��yÛ�բ���hM�"(g6 +�Bn�W$�?� +�Z[�R�0}�7,� +��v�����i�f���Ҳ<�E��y!5 �|\Ό���m5C�X� �)'7^�iØ™I��ַ�D^�7.%F�Yl!m�y���٫�h$���щ���{��zN��X����_�)���N�o�h���y�U�+3��j�t���Lf�V%'kÊ€%�>��j��"w��7�d�";�����(��;��3����k� +1���3�SG��� +OJ��4(4}fG\��8�����Ԗ1�� +Zy�YÍš -|g����i�p���q����.=3���i +�8���h���l�.���+���4�������h ?����C�>�0p������8?��( +���� �0~L�'�����cx���Q<��O�}�?�i�1pp�Ť��L\��DF�Lx��Z���ߺ���/v�)q2{�� p(��@:0 ��+��}H����� X��C��}�Ro ��ww@M-?�#yd\fG~��A�p�A������}����[�����;b�(3�>a�a�ih��vv +��e�����8<Ó€�D`6p`��x��p � H�o}�6PƼ���Q�1]>��\���yF��u(�G�w����e���G��K��Gr�Bp�\0�|$Ϙ +N>�'�ã�?�l���N���̶� +^�����*�J~�7!m�oG�������=�����Y�V��U;Y�bV��Uc�ײ�VêcYu�~� +�+�YÆ®��Q���~�U�Yu2�Nb�]Y��f���c�*����L��@/��6�ã��xl�}x|��!=��+i��#�r����+�+�� +��:,�+�W0�+�-�#���~�4���N�ᷩg[<Ó€�l` p�*sN��L�V���FO�%� +> �����.a1a)aWh���lb�/����-?�]@;����5�_��R`f ���F]������u��e��H~..3���b�� +�d�:�ܪܟb$�G1|h������vGrϸ����;î·˜/ã¾ï¿½ï¿½`��y.�#�V�qGP�mw�1�Ľ�V���k�^]����%� +�w�-�dwÜ1c��Ǩ��p����qS�g�]��b��e�1��1�� +3���>��zÄ��c��(���j�ikYQFO�Z[�m�m�-���o��u�E�:���   +��@j}'3R���a��?3�H(>�˧��X�5��J����qSG�q��7G����XË‚p�ZG2o�8�3�;(e\��7�;0e��6���ݚ�Z/_Y�p��2��Z-��{��v��DK�m���<��pDԈ����κ�#�|�4�D��x׎�����%Ï›._��q޻�]vޟ�dg���4H^�m8�){��׆g�å«eÓ•��G�!b~Tr��K9�b +���\�C��$� �$%����r��]���w�d"ur+w��\�@d���L�j:�dt��2��J$&"�1J�u�%�:+��M"i��-�"�(Mk��1dBO�eBOB&�?�q�LIa;��9f�����l'��]��(�[=G×·;�����9�"I�No^�3��H�ҷ�y�晲yhb�v�����}f�3k�Ќ�ى����c&��B�-���M��`��`���1/�)w{��õSÑ<8��7�cX�p�C�G�����7�P@6���)���dS��g6E-��m1��P�.q$�x*Ý•���2�s�U�J�p���w?h��{[��C4��c�8��s��l�͗S���g�iT��r��ԴFAY7L�����IG�]P͟��2b���y�7v\G*�1o�{q]�ǃ;t������&�'9_?<�&g��cR�����h�A�*�^�t����:�vQm�9��B�jZL{�#��}KKh��W�ZN��@�4��h +��WI3鄸��UTJ�ڗ��w�o3=B{�7}�)�:����,��Q/����� vg�3�-Õ|�*h�6K0_��,��*� h<d�y +Fw��,�ݠ��(���W!C�����^֟��ñ–™¾ï¿½ï¿½:�è�h�Ƨ�^�OY��o�� u��4��E��~���҆���Rw��2z�ޠwY"{��YB,� ������i��1����/�g����Im��;���5:�:�46�M��yP��h�O���{1�qD�n�k�m��ڥ᤯ +V$���%�������>d_�Q|6����-�����TBkh���� 6�]� +l���cٻ���s�|~Z+�h/���Lnq��f�*�7 +� +�6���/�w3MF<,���Ѓ��:L��s�>g���#�������b��mR�Aï‚–w���[�@��:���[y����D^� ���~~�w�?�oZ����h��aZ�V�Vh���vJt��~N�����g���?|���� +԰�am�]�S�5�a�W�a�ގ�<��ZD���W�uf=�pv<3��c �u��2��=�l�=/}�N��P�lN���H>�k��/���N����i6-Xk�Eh=�1�,Í©y�E�Zͫ��}�}������ 'D�Hc�lQ)_��-3-o[��YK�7[k�?�3�6�6�6�v�m�타|�-*=C�6�U;�-ղ�g�V�Wt��!��l*��sD*��V��.��r�u(�&�����_��|�6��cSi�������Aȿ�=L�Bߋ�1�C�:k[�O[ChSo����)����v���F:*�X$��?�MB� �[r)^�������MT�q<�mE^�a��_��� ����t������+�/�@ҭԗ�@_ӣ��-����w�ޞ�".���ue��-c���������"��kO����)m�8c��n��i�o)-���Y!il:%���n7h�"t ��L����{�2��B�\���� ��{�'"È…=~5��!�e��ThiÃu��� +Sh��QZ�+�Rß� �`��������h [��'*Ǜ�'��WYF�ÖѾ^��§�-��NbQ�w|���4��Ո�h*���AtwC�]Gsp?������S߆ |�o�V����ɾ�|q,��|�4���Gl��RL����l��V8���} �p �p �p �p �p �p �p �p �p �/�3� ��S�6���/��Z�.�=YÄ—�ė�:X-_r�yÞ‡�:�JQ)ag��6!��a���������;�]|�$< �׵�����b��]�&"!OL�dDX-�6i"�3L�Z������~��J=H�A�CE��t��2����%�N;;k��_�(��ӆ�I�����7�It�PK�?�-��}�a� +�OJK6c� ʒ�= +�����'���� +A�� ����f�Ϊe�<�0BYX��2=tRh~hy���2kA�ٔY���JK`Ùˆa�g�)�����`�������_>o��=�(�qn4�y~<_ ��U��8�P�.���e��q�t�u�L�J��f��3_�2߲��?�$N�ז�,P��%��۲a:DGFG &:GG��#w�y����.�&����9×’xuØ´v��ψ�5���ѫ"��N����ۘ�suÖ¥m�4�S�c��6㿟���Ј�G|���Z@�f�Z�>���ExD.��a�7����ɉ �`+ـ���m�v�;ܰw˛��GGY��o�8��?�J�/7��tt�|����C��L� +�v<(�� �����u�W�pd�⭲>2Z�6U��?P����Fo���kd𢙌�Fo���kd����Fo���kd����Fo��䃚�7X�e��C�շQs�Z�ar.���o><�R���G�qL�c��N�� +�G+]Ƙ]���5�*�{�C�+���K>����t�4���%�Q99i.�����@)~<�Q)�1�t�Rx���ޥ$t��*�,Uo��)��2����X��/CÆï¿½ï¿½ï¿½ï¿½ï¿½>4������Um&z�NA�B��Q��`<7PA �,P6���I%��T@�)��Éw�C:z��r�Rꩴ����0Dz���Y�F�3(��%jDZ���r�:u�Hr +*�~0�Q�fc�G\7��Rq^a��5���5���|c] +�L�4�[S�2F���@�I��N�J�x<'B�\�~���t+o�������� +�Œ$?���h<�R�٨����c��l|ƫ� +� ���Ĵ�XoXl�\���M{�B�g^|P���HI������x��ZA��Q��1���T}�r���2C5�k#O����6sG��٘{�o�Lm2�,4s���S������c��1 :Í�l�;*Oy̼1׌���˿ۥǜ�Fi��+0�K���� +��+Sj�|��Lͪ����aT\�ٟCe����Z�Mo��\��t���/m��]�N�6�|���]YT�<+�-��o�����r�_����Ӯf�UE�W�F�fq�tG�}OI�J����*k1^�Z��j5�gn�,���g*����E��1�j�%f�6�o�r3>�2|���5��X5� W�Ç“g�Ӽ �1�����֠����F��+S���̫ �������x���{�i�5Z����.\G�[M7c���}�_1{+_��/Y��� 5��W���iÞ–=8!�#�S&��H���� +�y����^x���&��9�ƙ��՟8î‡ï¿½����5����DB�^��$�З�O�������w����� �e��Y��)�2���i����:��g��7x�?���B��� +Lų�ÜQ%߬�=�fw����zG��!�Z���g���>��(�?��J� Y���[Z�xl;gQ�s�����s������2��Qe�ev���T//v��Yv�����`�Բ�JY��ǖ�_���{��#=U�,.֧� +�q�~��Q��f�c�dg�Ϟ��S���{Z.��ì=j���++���-Rzd�K?�Y�/*��=2Ba]ei��>�J�5bÂ…h������ћ��[��S6Gn=���0Fz�J���픫S�txs��&�䲗:�� +��~XND��J���e؅�&t��o�����e�� �ŕ�9�J�QÕ¼w�>�T��"�,0'sq�%캻��p�u9.��/���}�.�ƈ� +��z�� +�[�ZU�*q� A���*���6[�,�B�T�)v����e��� +��T�t#�M�T��1vn��d�[P�t+5È•gE�9� +�n%�.*�,.@�.t9��w���V҉�QД��T2vx��XN�nZ=���*�;���z�!R`��L���mP�����}��ݯw���i�PÙ»O�~���w�>p@����y<�C�Ҫ��RK� �(+i�'�zV��J�[Fa�)es�C' g�!�������p���v�7�8�����ӊ<%�i%�;L+q϶�<�*+��U�b�:���,��~TÒ¸ ���`�����k�"��|�ߪ���}��,�+���h��� �>`��W{��Xvu1�O���-t9[������'ƈ�� i�zE,0�#E��6j��x�K� +u=�c�/0���endstream +endobj +9 0 obj +<< /Filter /FlateDecode /Length 247 >> +stream +x�]�Mk�0 ���:v�b�]��`�2 +9�e���d��6�sȿ�?J�� ��^Ѷ{@߃S=F����0�d,9p�F��_������D�;;:�4�#e�6�]���з�1;������?8�����qL�^��3-�}�S��m�4��G��u�4.^* �NH�B@sM!Z�/��aT�2��c�f�3��� =�*=U:W�Vj y�:��/��w��Qk�G9^1�W7����gU~�; z6endstream +endobj +10 0 obj +<< /Type /ObjStm /Length 459 /Filter /FlateDecode /N 6 /First 37 >> +stream +x�uQ�n�0��+�hÌ—(Qv\7F�$���P��H�JT���R�Z�P����,��� H8�T +\���S� �V�nn�>��<����3�q��F�9,�c�֟��WW� +2�}�7��sg��Tv���=�{�7�Zl���`�i�w���n�Pض4m��H��>�?��/][ݕ� +.�w@��0JFa��n-��������p�mv�w���j�Im��Vn�f�ҿ�y���6�@��rd:�/���t��`�X]�{��ǸG�f�����?��+F��A> /W [ 1 2 1 ] /Size 2 /ID [] >> +stream +x�cb&F �R +endstream +endobj + +startxref +216 +%%EOF +' because of error 'Filter: [?] can not be applied to primitives. Current context is: %PDF-1.5 +%���� +2 0 obj +<< /Linearized 1 /L 14631 /H [ 687 126 ] /O 6 /E 14356 /N 1 /T 14355 >> +endobj + +3 0 obj +<< /Type /XRef /Length 49 /Filter /FlateDecode /DecodeParms << /Columns 4 /Predictor 12 >> /W [ 1 2 1 ] /Index [ 2 15 ] /Info 11 0 R /Root 4 0 R /Size 17 /Prev 14356 /ID [] >> +stream +x�cbd�g`b`8 $���XF@���Zb�d +v�Xv L���@ ����0 +endstream +endobj + +4 0 obj +<< /Pages 12 0 R /Type /Catalog >> +endobj +5 0 obj +<< /Filter /FlateDecode /S 36 /Length 49 >> +stream +x�c```e``Z�&���fb�(H-30�g�c``�>������( +endstream +endobj +6 0 obj +<< /Contents 7 0 R /MediaBox [ 0 0 596 843 ] /Parent 12 0 R /Resources << /ExtGState << /G0 13 0 R >> /Font << /F0 14 0 R >> >> /StructParents 0 /Type /Page >> +endobj +7 0 obj +<< /Filter /FlateDecode /Length 200 >> +stream +x���� +�0 ��}���uI�4-����Y)��AA}0���I���~��KZÔ¨H��؞�� +������n{���E�����R�y�b�!�=���h��x/��<�f�;���`EB'�%z���l��;�6p�! M/E�g�>��;�#�v�d-�E��Eb!ÉŠp@�&�-��H�' +2023-09-06T14:29:49.492+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.['name'] =~ /[\p{L}]*/)]' failed to match document '%PDF-1.5 +%���� +2 0 obj +<< /Linearized 1 /L 14631 /H [ 687 126 ] /O 6 /E 14356 /N 1 /T 14355 >> +endobj + +3 0 obj +<< /Type /XRef /Length 49 /Filter /FlateDecode /DecodeParms << /Columns 4 /Predictor 12 >> /W [ 1 2 1 ] /Index [ 2 15 ] /Info 11 0 R /Root 4 0 R /Size 17 /Prev 14356 /ID [] >> +stream +x�cbd�g`b`8 $���XF@���Zb�d +v�Xv L���@ ����0 +endstream +endobj + +4 0 obj +<< /Pages 12 0 R /Type /Catalog >> +endobj +5 0 obj +<< /Filter /FlateDecode /S 36 /Length 49 >> +stream +x�c```e``Z�&���fb�(H-30�g�c``�>������( +endstream +endobj +6 0 obj +<< /Contents 7 0 R /MediaBox [ 0 0 596 843 ] /Parent 12 0 R /Resources << /ExtGState << /G0 13 0 R >> /Font << /F0 14 0 R >> >> /StructParents 0 /Type /Page >> +endobj +7 0 obj +<< /Filter /FlateDecode /Length 200 >> +stream +x���� +�0 ��}���uI�4-����Y)��AA}0���I���~��KZÔ¨H��؞�� +������n{���E�����R�y�b�!�=���h��x/��<�f�;���`EB'�%z���l��;�6p�! M/E�g�>��;�#�v�d-�E��Eb!ÉŠp@�&�-��H�W�2�6!yoч(�>)6O����Z�endstream +endobj +8 0 obj +<< /Filter /FlateDecode /Length1 29380 /Length 12131 >> +stream +x��} |TE�喙��Y!B �MB"H ì‹@"�L$M�I���q���e7@T�f.�(����,.�����8��~��{;������~�i����:U�ԩS��v�Q0U�F�%���]�o#��������}m�� ��DY{�-/,����_��Y��ŋ�.�퇶��׋�����ގ��"���V�?]�J<���� b��:l(.s�)����+P�\b��<�P�]hǘ���K�/��aDW�"�-�p���ω��t��������/��n;엀��?�������\���sO�/ p���gJO��� 4*��=��7l�Y��c�&k,��A��0J��D"z5�V� �/���n��ںP�e:�4�o�$�.�!�� +�nE9t�� �i� `0�lÖ��TY���c��quӌ�8*�L������7h.� �M� �bL%(oF�}�h��A��֭t/��G�u�梼�L��m�5�IR����g�9�˴�h�p�Na.y�J�f�:���#�� +Z���mB;(��+d=�e�+0�r��@��(��3찂��n� �;��i���Ƽ�7�HιqN�ߴ�B6�k�|H�}_�6��5nj��Z_��D��A*W���Y�"M�)�t�\���j�E�e�������g���k1���p���?��5�� ��0�R�A�����Ê�Tо�+C7����O�7(/źN��z�c�*0�R +K{�?M�\�;��0�_Bf��#0w���ì±ï¿½ï¿½8��Did���'A!m�CÅ™ ���q:V� � +|l�C�g�n�MЫ�xE���T�ذ��6��T�iì™ï¿½XRO�� �o"^�)���Yز�?��S2f�T��|��G9OS�{O|Gc� +j"��T�;�,��Z>�V��G�$cV���/2Ö”O�'L:��\{�=�%��~���}�H�h3�̷�AN�@W]��As��ҺS��7�0�z�w4%`?��ZNDy]+z����gÙyn�?����q�'�#�b����B�-�6�X���`��6I%���W��;�Z�!gn���r���|�{��� +�~��@5�# ��0��ڦQ�gP&2h�%���X��y��O���}��E�}ª����md�k�Ӡ�H7I��A˛�Q��kK~���T�|3��@���L|i�,� ��af�(�:�����x��k�Ϸ��U��l��[�gH�lM�ق��ߧ����e~�9N�H��d��˷�����c��� s_'��6~n�}�a���>�u��1�.�-Ü·Åš�c��{ ��L��5��iw�Yj�S�����3�mV��'�[��ӕ}�֧i������`�A�v����zZ�yt�V`?��)}�ւ(J� �L�îŸï¿½Y��nҎ� ���v�AW���T�TIe��j�d����4���T �J�C�#�>��B"�'�P�8d"(r�2�1��|܋� ��l�� ���mT}2(���f� �w_��AS�}�;z�2����h����i�s�c<�~Ó¤-��Y����5�_+��V"çŠï¿½�:m�s�:�U�G�(�R +�Ws�F�]!�����e�X�A���{�F�P�u>�A� �$��B�2���ػ����� �oA��;B�e�A�[��V�{)�=��oi�v%�Dg�?,�^8/b/�c@��Xm@Õ…��kat���K��Z0�V��{�Rr�键��N���a��F�imi�8@��ZZ-Ë¢=uӼ��.�-e�a�$���(�K3�0�_I�b6��툽(H��Z���V�IW�� �`_� m:�����=!唎]��%��K�ke��l���+���W�-셭�v�m��}j�r\��2�>�;���dІ�| +m6�Oi�6��-H0��h�p��'� +E��q��g7��?= ,��E�i���[: +,��/���|$ +�u�o�ۚC�X}sX��e���`?��K����@�q9� o��.���X��P�1[��']@T� � +�1��"�6���N��m� +0Ç›j��{��"���F����<�?7�� �%�{!�w�[���~~6� ��Q��b ���=��@8������ �C�����?�S�;�v���@oh��S�z�m���_�?�;3hE +?���s�����}~��O�� +�!����N"���.+����hR�����K��O��Y�_��Y�_A7���Z�=��{���ԑ��6NA \P.���;X�5( +��l ����62/;�|<�����iLÓ´@-Q[��h����!"&��b��K�E< ;�s��e����-?[C���8���|k�u�u��f����ǭO[ß±���<�7����� z�������C�a�p=K/ӗ����'�-���;�'�'ǧ���_O���`Mh����9!.�{BJ� �g"O K�O�$����!)*)&�kRϤ~I�����%�LZ�tW�Ƥ'�v$�Mz>�դ��'}����a��#���s��c�&�!g��>u�N�P7�nx]f]V���V��S竟s~����}�>����6(�m`O���<�:<��F��[�ݪ=,�h#&�k��b�X/6��D��X|c�Z���k9cz.ÞšaͿ����V�n�C��z���s=�t}��y��������M�ížk�uJ�5=��P�<���Mj���I��6z�<�1<7��s��y�0�9vF�1x�G� x.�nT���u�����ZW_����\���� �=��AK���`G�ED�ɪ�|VQ�e��ن�� +��������TLEt +����X���oן������_Wo���~I���?׻��}1���cƷ�'�����䲓���r� +�g�Փ5'o��X±�c���?���7G�:���u������xZ��v���O�>:�h�ѮG������^�M�Eۣ�l������k{���m��!�_�Z�[�v�9��eZ�����@���������h�i.�r+� nD��:�y���k����Ib�Y��{v��,�5�]W2�߶\բ��ô��k��Z��L��*z��͸"���7�]t�~�5�ZI/�1:M�V�'�D?�&z�ޤ��I�C�� +�9� +z������i.�G��]z� +���>��鯈�o�;��摋�S ���6P-�r� 7U�1]E��u��E�'�q�,m�%���i)���A{�Z�ƙ��PÕ³{�:���Gç©Y������`����6�@Ä‚Y�����+��a�����8�ʶ�'ؓ�)�,/��v���/:�j�*��=�v�gY- em����ea� ��t��g�s�y�:����"�������,�E���e�Xg� +{�E�օŲ�������� �t���M�;��f� gb��+Kb��0{����ge��p�ƺ��%}ŎЇt�>�O�(���3v��a?�������β_ٿ�o�Kau���g +�'�1�s�q�-��m<�� Ö‹����<����=��Ry���XoÉ£x'Þ™G�ޅ��8���<�'�>,�'���+O���2Þw�=x +_�o��Y����R�&m��B�E[�ݦݥݣ���������M{R{ZÛ®=���^�^�^���b����>�>�Ni_i�j�k�����'�O�3��������9^�� -X ���0����xLl���b�xB<�S�i����̻�3b�x���������'�������xM�.�o����xG��a�xO�/�*>Gć�#�R��O�QqL|&���8%>_�/�W�o�k��V�]|'�!�?����Q�$�)~��/ؗ��U�K�&Ή:�N;x +�G��nzoG;i�J��hr�Dm�6I��MÓ¦kWk��T-�~a_��b1=O��{��G�N6�nc�l!���]��j� +�{��X *�R����5�Lm�X&*E�X.���"�B����J�׉��q�� +'��L�OÜ;̓���+Ö‰�Cb�؈��a��6@��&��D�_3�o�vШ ��Ú¦mX���":FFu��%6N�OHìš”|Y��=Rz�JM��'�o����w�������lힽ�=�‹�����+����o�u��w:�.���_?8��G���c�?q��x��x��x��x��x��x��x��x�����3233F �|��!� +�߯oz��i��z�����䤮� �z\l���Î�";Fth�.�m�Ð����"4Ψgv��|ݛ��ɉW\�K��7�����Rƫ�+1��d$綒�0$3%Y�>����g'�ރY�z-�19����<�����+�v���G=;�(K��|=�;zaQMv~��4*q�3�WO� 6�72�|;���#��l� +���������^-)�^��497;+:>>�WO/�H��đ޶)J�F)5^�(�M��]r6�J��s���0���R�X`�����yRG����F^�eTS����]Ѽ5Z�Ɏr�XS�B�n��ۼ5^>��0����5��z5�8n�m|y^��-�J]�D�ʘ�31[���ӽ��#�j��ci:�xiʢ��;g����zMNnb�wDtb�=+f{���hg� �SË–^=���3��M[� m�8���%7nJ�g��(q,«;tX���9 +�� �q �~�zy �".o����!�^��Z�pG���=?������5֤�_H�2NC +�~ޛ����C��m�6W���z.�剉�a:�G��[{Þ4�?>^.�� ����zr�Q�iN��HK���|ٲ��1M�T�[��'"�w���o@r�m�:��.�e��i����8n�\=�&���%�}Pc��yÛ�բ���hM�"(g6 +�Bn�W$�?� +�Z[�R�0}�7,� +��v�����i�f���Ҳ<�E��y!5 �|\Ό���m5C�X� �)'7^�iØ™I��ַ�D^�7.%F�Yl!m�y���٫�h$���щ���{��zN��X����_�)���N�o�h���y�U�+3��j�t���Lf�V%'kÊ€%�>��j��"w��7�d�";�����(��;��3����k� +1���3�SG��� +OJ��4(4}fG\��8�����Ԗ1�� +Zy�YÍš -|g����i�p���q����.=3���i +�8���h���l�.���+���4�������h ?����C�>�0p������8?��( +���� �0~L�'�����cx���Q<��O�}�?�i�1pp�Ť��L\��DF�Lx��Z���ߺ���/v�)q2{�� p(��@:0 ��+��}H����� X��C��}�Ro ��ww@M-?�#yd\fG~��A�p�A������}����[�����;b�(3�>a�a�ih��vv +��e�����8<Ó€�D`6p`��x��p � H�o}�6PƼ���Q�1]>��\���yF��u(�G�w����e���G��K��Gr�Bp�\0�|$Ϙ +N>�'�ã�?�l���N���̶� +^�����*�J~�7!m�oG�������=�����Y�V��U;Y�bV��Uc�ײ�VêcYu�~� +�+�YÆ®��Q���~�U�Yu2�Nb�]Y��f���c�*����L��@/��6�ã��xl�}x|��!=��+i��#�r����+�+�� +��:,�+�W0�+�-�#���~�4���N�ᷩg[<Ó€�l` p�*sN��L�V���FO�%� +> �����.a1a)aWh���lb�/����-?�]@;����5�_��R`f ���F]������u��e��H~..3���b�� +�d�:�ܪܟb$�G1|h������vGrϸ����;î·˜/ã¾ï¿½ï¿½`��y.�#�V�qGP�mw�1�Ľ�V���k�^]����%� +�w�-�dwÜ1c��Ǩ��p����qS�g�]��b��e�1��1�� +3���>��zÄ��c��(���j�ikYQFO�Z[�m�m�-���o��u�E�:���   +��@j}'3R���a��?3�H(>�˧��X�5��J����qSG�q��7G����XË‚p�ZG2o�8�3�;(e\��7�;0e��6���ݚ�Z/_Y�p��2��Z-��{��v��DK�m���<��pDԈ����κ�#�|�4�D��x׎�����%Ï›._��q޻�]vޟ�dg���4H^�m8�){��׆g�å«eÓ•��G�!b~Tr��K9�b +���\�C��$� �$%����r��]���w�d"ur+w��\�@d���L�j:�dt��2��J$&"�1J�u�%�:+��M"i��-�"�(Mk��1dBO�eBOB&�?�q�LIa;��9f�����l'��]��(�[=G×·;�����9�"I�No^�3��H�ҷ�y�晲yhb�v�����}f�3k�Ќ�ى����c&��B�-���M��`��`���1/�)w{��õSÑ<8��7�cX�p�C�G�����7�P@6���)���dS��g6E-��m1��P�.q$�x*Ý•���2�s�U�J�p���w?h��{[��C4��c�8��s��l�͗S���g�iT��r��ԴFAY7L�����IG�]P͟��2b���y�7v\G*�1o�{q]�ǃ;t������&�'9_?<�&g��cR�����h�A�*�^�t����:�vQm�9��B�jZL{�#��}KKh��W�ZN��@�4��h +��WI3鄸��UTJ�ڗ��w�o3=B{�7}�)�:����,��Q/����� vg�3�-Õ|�*h�6K0_��,��*� h<d�y +Fw��,�ݠ��(���W!C�����^֟��ñ–™¾ï¿½ï¿½:�è�h�Ƨ�^�OY��o�� u��4��E��~���҆���Rw��2z�ޠwY"{��YB,� ������i��1����/�g����Im��;���5:�:�46�M��yP��h�O���{1�qD�n�k�m��ڥ᤯ +V$���%�������>d_�Q|6����-�����TBkh���� 6�]� +l���cٻ���s�|~Z+�h/���Lnq��f�*�7 +� +�6���/�w3MF<,���Ѓ��:L��s�>g���#�������b��mR�Aï‚–w���[�@��:���[y����D^� ���~~�w�?�oZ����h��aZ�V�Vh���vJt��~N�����g���?|���� +԰�am�]�S�5�a�W�a�ގ�<��ZD���W�uf=�pv<3��c �u��2��=�l�=/}�N��P�lN���H>�k��/���N����i6-Xk�Eh=�1�,Í©y�E�Zͫ��}�}������ 'D�Hc�lQ)_��-3-o[��YK�7[k�?�3�6�6�6�v�m�타|�-*=C�6�U;�-ղ�g�V�Wt��!��l*��sD*��V��.��r�u(�&�����_��|�6��cSi�������Aȿ�=L�Bߋ�1�C�:k[�O[ChSo����)����v���F:*�X$��?�MB� �[r)^�������MT�q<�mE^�a��_��� ����t������+�/�@ҭԗ�@_ӣ��-����w�ޞ�".���ue��-c���������"��kO����)m�8c��n��i�o)-���Y!il:%���n7h�"t ��L����{�2��B�\���� ��{�'"È…=~5��!�e��ThiÃu��� +Sh��QZ�+�Rß� �`��������h [��'*Ǜ�'��WYF�ÖѾ^��§�-��NbQ�w|���4��Ո�h*���AtwC�]Gsp?������S߆ |�o�V����ɾ�|q,��|�4���Gl��RL����l��V8���} �p �p �p �p �p �p �p �p �p �/�3� ��S�6���/��Z�.�=YÄ—�ė�:X-_r�yÞ‡�:�JQ)ag��6!��a���������;�]|�$< �׵�����b��]�&"!OL�dDX-�6i"�3L�Z������~��J=H�A�CE��t��2����%�N;;k��_�(��ӆ�I�����7�It�PK�?�-��}�a� +�OJK6c� ʒ�= +�����'���� +A�� ����f�Ϊe�<�0BYX��2=tRh~hy���2kA�ٔY���JK`Ùˆa�g�)�����`�������_>o��=�(�qn4�y~<_ ��U��8�P�.���e��q�t�u�L�J��f��3_�2߲��?�$N�ז�,P��%��۲a:DGFG &:GG��#w�y����.�&����9×’xuØ´v��ψ�5���ѫ"��N����ۘ�suÖ¥m�4�S�c��6㿟���Ј�G|���Z@�f�Z�>���ExD.��a�7����ɉ �`+ـ���m�v�;ܰw˛��GGY��o�8��?�J�/7��tt�|����C��L� +�v<(�� �����u�W�pd�⭲>2Z�6U��?P����Fo���kd𢙌�Fo���kd����Fo���kd����Fo��䃚�7X�e��C�շQs�Z�ar.���o><�R���G�qL�c��N�� +�G+]Ƙ]���5�*�{�C�+���K>����t�4���%�Q99i.�����@)~<�Q)�1�t�Rx���ޥ$t��*�,Uo��)��2����X��/CÆï¿½ï¿½ï¿½ï¿½ï¿½>4������Um&z�NA�B��Q��`<7PA �,P6���I%��T@�)��Éw�C:z��r�Rꩴ����0Dz���Y�F�3(��%jDZ���r�:u�Hr +*�~0�Q�fc�G\7��Rq^a��5���5���|c] +�L�4�[S�2F���@�I��N�J�x<'B�\�~���t+o�������� +�Œ$?���h<�R�٨����c��l|ƫ� +� ���Ĵ�XoXl�\���M{�B�g^|P���HI������x��ZA��Q��1���T}�r���2C5�k#O����6sG��٘{�o�Lm2�,4s���S������c��1 :Í�l�;*Oy̼1׌���˿ۥǜ�Fi��+0�K���� +��+Sj�|��Lͪ����aT\�ٟCe����Z�Mo��\��t���/m��]�N�6�|���]YT�<+�-��o�����r�_����Ӯf�UE�W�F�fq�tG�}OI�J����*k1^�Z��j5�gn�,���g*����E��1�j�%f�6�o�r3>�2|���5��X5� W�Ç“g�Ӽ �1�����֠����F��+S���̫ �������x���{�i�5Z����.\G�[M7c���}�_1{+_��/Y��� 5��W���iÞ–=8!�#�S&��H���� +�y����^x���&��9�ƙ��՟8î‡ï¿½����5����DB�^��$�З�O�������w����� �e��Y��)�2���i����:��g��7x�?���B��� +Lų�ÜQ%߬�=�fw����zG��!�Z���g���>��(�?��J� Y���[Z�xl;gQ�s�����s������2��Qe�ev���T//v��Yv�����`�Բ�JY��ǖ�_���{��#=U�,.֧� +�q�~��Q��f�c�dg�Ϟ��S���{Z.��ì=j���++���-Rzd�K?�Y�/*��=2Ba]ei��>�J�5bÂ…h������ћ��[��S6Gn=���0Fz�J���픫S�txs��&�䲗:�� +��~XND��J���e؅�&t��o�����e�� �ŕ�9�J�QÕ¼w�>�T��"�,0'sq�%캻��p�u9.��/���}�.�ƈ� +��z�� +�[�ZU�*q� A���*���6[�,�B�T�)v����e��� +��T�t#�M�T��1vn��d�[P�t+5È•gE�9� +�n%�.*�,.@�.t9��w���V҉�QД��T2vx��XN�nZ=���*�;���z�!R`��L���mP�����}��ݯw���i�PÙ»O�~���w�>p@����y<�C�Ҫ��RK� �(+i�'�zV��J�[Fa�)es�C' g�!�������p���v�7�8�����ӊ<%�i%�;L+q϶�<�*+��U�b�:���,��~TÒ¸ ���`�����k�"��|�ߪ���}��,�+���h��� �>`��W{��Xvu1�O���-t9[������'ƈ�� i�zE,0�#E��6j��x�K� +u=�c�/0���endstream +endobj +9 0 obj +<< /Filter /FlateDecode /Length 247 >> +stream +x�]�Mk�0 ���:v�b�]��`�2 +9�e���d��6�sȿ�?J�� ��^Ѷ{@߃S=F����0�d,9p�F��_������D�;;:�4�#e�6�]���з�1;������?8�����qL�^��3-�}�S��m�4��G��u�4.^* �NH�B@sM!Z�/��aT�2��c�f�3��� =�*=U:W�Vj y�:��/��w��Qk�G9^1�W7����gU~�; z6endstream +endobj +10 0 obj +<< /Type /ObjStm /Length 459 /Filter /FlateDecode /N 6 /First 37 >> +stream +x�uQ�n�0��+�hÌ—(Qv\7F�$���P��H�JT���R�Z�P����,��� H8�T +\���S� �V�nn�>��<����3�q��F�9,�c�֟��WW� +2�}�7��sg��Tv���=�{�7�Zl���`�i�w���n�Pض4m��H��>�?��/][ݕ� +.�w@��0JFa��n-��������p�mv�w���j�Im��Vn�f�ҿ�y���6�@��rd:�/���t��`�X]�{��ǸG�f�����?��+F��A> /W [ 1 2 1 ] /Size 2 /ID [] >> +stream +x�cb&F �R +endstream +endobj + +startxref +216 +%%EOF +' because of error 'Filter: [?] can not be applied to primitives. Current context is: %PDF-1.5 +%���� +2 0 obj +<< /Linearized 1 /L 14631 /H [ 687 126 ] /O 6 /E 14356 /N 1 /T 14355 >> +endobj + +3 0 obj +<< /Type /XRef /Length 49 /Filter /FlateDecode /DecodeParms << /Columns 4 /Predictor 12 >> /W [ 1 2 1 ] /Index [ 2 15 ] /Info 11 0 R /Root 4 0 R /Size 17 /Prev 14356 /ID [] >> +stream +x�cbd�g`b`8 $���XF@���Zb�d +v�Xv L���@ ����0 +endstream +endobj + +4 0 obj +<< /Pages 12 0 R /Type /Catalog >> +endobj +5 0 obj +<< /Filter /FlateDecode /S 36 /Length 49 >> +stream +x�c```e``Z�&���fb�(H-30�g�c``�>������( +endstream +endobj +6 0 obj +<< /Contents 7 0 R /MediaBox [ 0 0 596 843 ] /Parent 12 0 R /Resources << /ExtGState << /G0 13 0 R >> /Font << /F0 14 0 R >> >> /StructParents 0 /Type /Page >> +endobj +7 0 obj +<< /Filter /FlateDecode /Length 200 >> +stream +x���� +�0 ��}���uI�4-����Y)��AA}0���I���~��KZÔ¨H��؞�� +������n{���E�����R�y�b�!�=���h��x/��<�f�;���`EB'�%z���l��;�6p�! M/E�g�>��;�#�v�d-�E��Eb!ÉŠp@�&�-��H�' +2023-09-06T14:29:49.494+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.name =~ /([\p{L}]*)/)]' failed to match document '%PDF-1.5 +%���� +2 0 obj +<< /Linearized 1 /L 14631 /H [ 687 126 ] /O 6 /E 14356 /N 1 /T 14355 >> +endobj + +3 0 obj +<< /Type /XRef /Length 49 /Filter /FlateDecode /DecodeParms << /Columns 4 /Predictor 12 >> /W [ 1 2 1 ] /Index [ 2 15 ] /Info 11 0 R /Root 4 0 R /Size 17 /Prev 14356 /ID [] >> +stream +x�cbd�g`b`8 $���XF@���Zb�d +v�Xv L���@ ����0 +endstream +endobj + +4 0 obj +<< /Pages 12 0 R /Type /Catalog >> +endobj +5 0 obj +<< /Filter /FlateDecode /S 36 /Length 49 >> +stream +x�c```e``Z�&���fb�(H-30�g�c``�>������( +endstream +endobj +6 0 obj +<< /Contents 7 0 R /MediaBox [ 0 0 596 843 ] /Parent 12 0 R /Resources << /ExtGState << /G0 13 0 R >> /Font << /F0 14 0 R >> >> /StructParents 0 /Type /Page >> +endobj +7 0 obj +<< /Filter /FlateDecode /Length 200 >> +stream +x���� +�0 ��}���uI�4-����Y)��AA}0���I���~��KZÔ¨H��؞�� +������n{���E�����R�y�b�!�=���h��x/��<�f�;���`EB'�%z���l��;�6p�! M/E�g�>��;�#�v�d-�E��Eb!ÉŠp@�&�-��H�W�2�6!yoч(�>)6O����Z�endstream +endobj +8 0 obj +<< /Filter /FlateDecode /Length1 29380 /Length 12131 >> +stream +x��} |TE�喙��Y!B �MB"H ì‹@"�L$M�I���q���e7@T�f.�(����,.�����8��~��{;������~�i����:U�ԩS��v�Q0U�F�%���]�o#��������}m�� ��DY{�-/,����_��Y��ŋ�.�퇶��׋�����ގ��"���V�?]�J<���� b��:l(.s�)����+P�\b��<�P�]hǘ���K�/��aDW�"�-�p���ω��t��������/��n;엀��?�������\���sO�/ p���gJO��� 4*��=��7l�Y��c�&k,��A��0J��D"z5�V� �/���n��ںP�e:�4�o�$�.�!�� +�nE9t�� �i� `0�lÖ��TY���c��quӌ�8*�L������7h.� �M� �bL%(oF�}�h��A��֭t/��G�u�梼�L��m�5�IR����g�9�˴�h�p�Na.y�J�f�:���#�� +Z���mB;(��+d=�e�+0�r��@��(��3찂��n� �;��i���Ƽ�7�HιqN�ߴ�B6�k�|H�}_�6��5nj��Z_��D��A*W���Y�"M�)�t�\���j�E�e�������g���k1���p���?��5�� ��0�R�A�����Ê�Tо�+C7����O�7(/źN��z�c�*0�R +K{�?M�\�;��0�_Bf��#0w���ì±ï¿½ï¿½8��Did���'A!m�CÅ™ ���q:V� � +|l�C�g�n�MЫ�xE���T�ذ��6��T�iì™ï¿½XRO�� �o"^�)���Yز�?��S2f�T��|��G9OS�{O|Gc� +j"��T�;�,��Z>�V��G�$cV���/2Ö”O�'L:��\{�=�%��~���}�H�h3�̷�AN�@W]��As��ҺS��7�0�z�w4%`?��ZNDy]+z����gÙyn�?����q�'�#�b����B�-�6�X���`��6I%���W��;�Z�!gn���r���|�{��� +�~��@5�# ��0��ڦQ�gP&2h�%���X��y��O���}��E�}ª����md�k�Ӡ�H7I��A˛�Q��kK~���T�|3��@���L|i�,� ��af�(�:�����x��k�Ϸ��U��l��[�gH�lM�ق��ߧ����e~�9N�H��d��˷�����c��� s_'��6~n�}�a���>�u��1�.�-Ü·Åš�c��{ ��L��5��iw�Yj�S�����3�mV��'�[��ӕ}�֧i������`�A�v����zZ�yt�V`?��)}�ւ(J� �L�îŸï¿½Y��nҎ� ���v�AW���T�TIe��j�d����4���T �J�C�#�>��B"�'�P�8d"(r�2�1��|܋� ��l�� ���mT}2(���f� �w_��AS�}�;z�2����h����i�s�c<�~Ó¤-��Y����5�_+��V"çŠï¿½�:m�s�:�U�G�(�R +�Ws�F�]!�����e�X�A���{�F�P�u>�A� �$��B�2���ػ����� �oA��;B�e�A�[��V�{)�=��oi�v%�Dg�?,�^8/b/�c@��Xm@Õ…��kat���K��Z0�V��{�Rr�键��N���a��F�imi�8@��ZZ-Ë¢=uӼ��.�-e�a�$���(�K3�0�_I�b6��툽(H��Z���V�IW�� �`_� m:�����=!唎]��%��K�ke��l���+���W�-셭�v�m��}j�r\��2�>�;���dІ�| +m6�Oi�6��-H0��h�p��'� +E��q��g7��?= ,��E�i���[: +,��/���|$ +�u�o�ۚC�X}sX��e���`?��K����@�q9� o��.���X��P�1[��']@T� � +�1��"�6���N��m� +0Ç›j��{��"���F����<�?7�� �%�{!�w�[���~~6� ��Q��b ���=��@8������ �C�����?�S�;�v���@oh��S�z�m���_�?�;3hE +?���s�����}~��O�� +�!����N"���.+����hR�����K��O��Y�_��Y�_A7���Z�=��{���ԑ��6NA \P.���;X�5( +��l ����62/;�|<�����iLÓ´@-Q[��h����!"&��b��K�E< ;�s��e����-?[C���8���|k�u�u��f����ǭO[ß±���<�7����� z�������C�a�p=K/ӗ����'�-���;�'�'ǧ���_O���`Mh����9!.�{BJ� �g"O K�O�$����!)*)&�kRϤ~I�����%�LZ�tW�Ƥ'�v$�Mz>�դ��'}����a��#���s��c�&�!g��>u�N�P7�nx]f]V���V��S竟s~����}�>����6(�m`O���<�:<��F��[�ݪ=,�h#&�k��b�X/6��D��X|c�Z���k9cz.ÞšaͿ����V�n�C��z���s=�t}��y��������M�ížk�uJ�5=��P�<���Mj���I��6z�<�1<7��s��y�0�9vF�1x�G� x.�nT���u�����ZW_����\���� �=��AK���`G�ED�ɪ�|VQ�e��ن�� +��������TLEt +����X���oן������_Wo���~I���?׻��}1���cƷ�'�����䲓���r� +�g�Փ5'o��X±�c���?���7G�:���u������xZ��v���O�>:�h�ѮG������^�M�Eۣ�l������k{���m��!�_�Z�[�v�9��eZ�����@���������h�i.�r+� nD��:�y���k����Ib�Y��{v��,�5�]W2�߶\բ��ô��k��Z��L��*z��͸"���7�]t�~�5�ZI/�1:M�V�'�D?�&z�ޤ��I�C�� +�9� +z������i.�G��]z� +���>��鯈�o�;��摋�S ���6P-�r� 7U�1]E��u��E�'�q�,m�%���i)���A{�Z�ƙ��PÕ³{�:���Gç©Y������`����6�@Ä‚Y�����+��a�����8�ʶ�'ؓ�)�,/��v���/:�j�*��=�v�gY- em����ea� ��t��g�s�y�:����"�������,�E���e�Xg� +{�E�օŲ�������� �t���M�;��f� gb��+Kb��0{����ge��p�ƺ��%}ŎЇt�>�O�(���3v��a?�������β_ٿ�o�Kau���g +�'�1�s�q�-��m<�� Ö‹����<����=��Ry���XoÉ£x'Þ™G�ޅ��8���<�'�>,�'���+O���2Þw�=x +_�o��Y����R�&m��B�E[�ݦݥݣ���������M{R{ZÛ®=���^�^�^���b����>�>�Ni_i�j�k�����'�O�3��������9^�� -X ���0����xLl���b�xB<�S�i����̻�3b�x���������'�������xM�.�o����xG��a�xO�/�*>Gć�#�R��O�QqL|&���8%>_�/�W�o�k��V�]|'�!�?����Q�$�)~��/ؗ��U�K�&Ή:�N;x +�G��nzoG;i�J��hr�Dm�6I��MÓ¦kWk��T-�~a_��b1=O��{��G�N6�nc�l!���]��j� +�{��X *�R����5�Lm�X&*E�X.���"�B����J�׉��q�� +'��L�OÜ;̓���+Ö‰�Cb�؈��a��6@��&��D�_3�o�vШ ��Ú¦mX���":FFu��%6N�OHìš”|Y��=Rz�JM��'�o����w�������lힽ�=�‹�����+����o�u��w:�.���_?8��G���c�?q��x��x��x��x��x��x��x��x�����3233F �|��!� +�߯oz��i��z�����䤮� �z\l���Î�";Fth�.�m�Ð����"4Ψgv��|ݛ��ɉW\�K��7�����Rƫ�+1��d$綒�0$3%Y�>����g'�ރY�z-�19����<�����+�v���G=;�(K��|=�;zaQMv~��4*q�3�WO� 6�72�|;���#��l� +���������^-)�^��497;+:>>�WO/�H��đ޶)J�F)5^�(�M��]r6�J��s���0���R�X`�����yRG����F^�eTS����]Ѽ5Z�Ɏr�XS�B�n��ۼ5^>��0����5��z5�8n�m|y^��-�J]�D�ʘ�31[���ӽ��#�j��ci:�xiʢ��;g����zMNnb�wDtb�=+f{���hg� �SË–^=���3��M[� m�8���%7nJ�g��(q,«;tX���9 +�� �q �~�zy �".o����!�^��Z�pG���=?������5֤�_H�2NC +�~ޛ����C��m�6W���z.�剉�a:�G��[{Þ4�?>^.�� ����zr�Q�iN��HK���|ٲ��1M�T�[��'"�w���o@r�m�:��.�e��i����8n�\=�&���%�}Pc��yÛ�բ���hM�"(g6 +�Bn�W$�?� +�Z[�R�0}�7,� +��v�����i�f���Ҳ<�E��y!5 �|\Ό���m5C�X� �)'7^�iØ™I��ַ�D^�7.%F�Yl!m�y���٫�h$���щ���{��zN��X����_�)���N�o�h���y�U�+3��j�t���Lf�V%'kÊ€%�>��j��"w��7�d�";�����(��;��3����k� +1���3�SG��� +OJ��4(4}fG\��8�����Ԗ1�� +Zy�YÍš -|g����i�p���q����.=3���i +�8���h���l�.���+���4�������h ?����C�>�0p������8?��( +���� �0~L�'�����cx���Q<��O�}�?�i�1pp�Ť��L\��DF�Lx��Z���ߺ���/v�)q2{�� p(��@:0 ��+��}H����� X��C��}�Ro ��ww@M-?�#yd\fG~��A�p�A������}����[�����;b�(3�>a�a�ih��vv +��e�����8<Ó€�D`6p`��x��p � H�o}�6PƼ���Q�1]>��\���yF��u(�G�w����e���G��K��Gr�Bp�\0�|$Ϙ +N>�'�ã�?�l���N���̶� +^�����*�J~�7!m�oG�������=�����Y�V��U;Y�bV��Uc�ײ�VêcYu�~� +�+�YÆ®��Q���~�U�Yu2�Nb�]Y��f���c�*����L��@/��6�ã��xl�}x|��!=��+i��#�r����+�+�� +��:,�+�W0�+�-�#���~�4���N�ᷩg[<Ó€�l` p�*sN��L�V���FO�%� +> �����.a1a)aWh���lb�/����-?�]@;����5�_��R`f ���F]������u��e��H~..3���b�� +�d�:�ܪܟb$�G1|h������vGrϸ����;î·˜/ã¾ï¿½ï¿½`��y.�#�V�qGP�mw�1�Ľ�V���k�^]����%� +�w�-�dwÜ1c��Ǩ��p����qS�g�]��b��e�1��1�� +3���>��zÄ��c��(���j�ikYQFO�Z[�m�m�-���o��u�E�:���   +��@j}'3R���a��?3�H(>�˧��X�5��J����qSG�q��7G����XË‚p�ZG2o�8�3�;(e\��7�;0e��6���ݚ�Z/_Y�p��2��Z-��{��v��DK�m���<��pDԈ����κ�#�|�4�D��x׎�����%Ï›._��q޻�]vޟ�dg���4H^�m8�){��׆g�å«eÓ•��G�!b~Tr��K9�b +���\�C��$� �$%����r��]���w�d"ur+w��\�@d���L�j:�dt��2��J$&"�1J�u�%�:+��M"i��-�"�(Mk��1dBO�eBOB&�?�q�LIa;��9f�����l'��]��(�[=G×·;�����9�"I�No^�3��H�ҷ�y�晲yhb�v�����}f�3k�Ќ�ى����c&��B�-���M��`��`���1/�)w{��õSÑ<8��7�cX�p�C�G�����7�P@6���)���dS��g6E-��m1��P�.q$�x*Ý•���2�s�U�J�p���w?h��{[��C4��c�8��s��l�͗S���g�iT��r��ԴFAY7L�����IG�]P͟��2b���y�7v\G*�1o�{q]�ǃ;t������&�'9_?<�&g��cR�����h�A�*�^�t����:�vQm�9��B�jZL{�#��}KKh��W�ZN��@�4��h +��WI3鄸��UTJ�ڗ��w�o3=B{�7}�)�:����,��Q/����� vg�3�-Õ|�*h�6K0_��,��*� h<d�y +Fw��,�ݠ��(���W!C�����^֟��ñ–™¾ï¿½ï¿½:�è�h�Ƨ�^�OY��o�� u��4��E��~���҆���Rw��2z�ޠwY"{��YB,� ������i��1����/�g����Im��;���5:�:�46�M��yP��h�O���{1�qD�n�k�m��ڥ᤯ +V$���%�������>d_�Q|6����-�����TBkh���� 6�]� +l���cٻ���s�|~Z+�h/���Lnq��f�*�7 +� +�6���/�w3MF<,���Ѓ��:L��s�>g���#�������b��mR�Aï‚–w���[�@��:���[y����D^� ���~~�w�?�oZ����h��aZ�V�Vh���vJt��~N�����g���?|���� +԰�am�]�S�5�a�W�a�ގ�<��ZD���W�uf=�pv<3��c �u��2��=�l�=/}�N��P�lN���H>�k��/���N����i6-Xk�Eh=�1�,Í©y�E�Zͫ��}�}������ 'D�Hc�lQ)_��-3-o[��YK�7[k�?�3�6�6�6�v�m�타|�-*=C�6�U;�-ղ�g�V�Wt��!��l*��sD*��V��.��r�u(�&�����_��|�6��cSi�������Aȿ�=L�Bߋ�1�C�:k[�O[ChSo����)����v���F:*�X$��?�MB� �[r)^�������MT�q<�mE^�a��_��� ����t������+�/�@ҭԗ�@_ӣ��-����w�ޞ�".���ue��-c���������"��kO����)m�8c��n��i�o)-���Y!il:%���n7h�"t ��L����{�2��B�\���� ��{�'"È…=~5��!�e��ThiÃu��� +Sh��QZ�+�Rß� �`��������h [��'*Ǜ�'��WYF�ÖѾ^��§�-��NbQ�w|���4��Ո�h*���AtwC�]Gsp?������S߆ |�o�V����ɾ�|q,��|�4���Gl��RL����l��V8���} �p �p �p �p �p �p �p �p �p �/�3� ��S�6���/��Z�.�=YÄ—�ė�:X-_r�yÞ‡�:�JQ)ag��6!��a���������;�]|�$< �׵�����b��]�&"!OL�dDX-�6i"�3L�Z������~��J=H�A�CE��t��2����%�N;;k��_�(��ӆ�I�����7�It�PK�?�-��}�a� +�OJK6c� ʒ�= +�����'���� +A�� ����f�Ϊe�<�0BYX��2=tRh~hy���2kA�ٔY���JK`Ùˆa�g�)�����`�������_>o��=�(�qn4�y~<_ ��U��8�P�.���e��q�t�u�L�J��f��3_�2߲��?�$N�ז�,P��%��۲a:DGFG &:GG��#w�y����.�&����9×’xuØ´v��ψ�5���ѫ"��N����ۘ�suÖ¥m�4�S�c��6㿟���Ј�G|���Z@�f�Z�>���ExD.��a�7����ɉ �`+ـ���m�v�;ܰw˛��GGY��o�8��?�J�/7��tt�|����C��L� +�v<(�� �����u�W�pd�⭲>2Z�6U��?P����Fo���kd𢙌�Fo���kd����Fo���kd����Fo��䃚�7X�e��C�շQs�Z�ar.���o><�R���G�qL�c��N�� +�G+]Ƙ]���5�*�{�C�+���K>����t�4���%�Q99i.�����@)~<�Q)�1�t�Rx���ޥ$t��*�,Uo��)��2����X��/CÆï¿½ï¿½ï¿½ï¿½ï¿½>4������Um&z�NA�B��Q��`<7PA �,P6���I%��T@�)��Éw�C:z��r�Rꩴ����0Dz���Y�F�3(��%jDZ���r�:u�Hr +*�~0�Q�fc�G\7��Rq^a��5���5���|c] +�L�4�[S�2F���@�I��N�J�x<'B�\�~���t+o�������� +�Œ$?���h<�R�٨����c��l|ƫ� +� ���Ĵ�XoXl�\���M{�B�g^|P���HI������x��ZA��Q��1���T}�r���2C5�k#O����6sG��٘{�o�Lm2�,4s���S������c��1 :Í�l�;*Oy̼1׌���˿ۥǜ�Fi��+0�K���� +��+Sj�|��Lͪ����aT\�ٟCe����Z�Mo��\��t���/m��]�N�6�|���]YT�<+�-��o�����r�_����Ӯf�UE�W�F�fq�tG�}OI�J����*k1^�Z��j5�gn�,���g*����E��1�j�%f�6�o�r3>�2|���5��X5� W�Ç“g�Ӽ �1�����֠����F��+S���̫ �������x���{�i�5Z����.\G�[M7c���}�_1{+_��/Y��� 5��W���iÞ–=8!�#�S&��H���� +�y����^x���&��9�ƙ��՟8î‡ï¿½����5����DB�^��$�З�O�������w����� �e��Y��)�2���i����:��g��7x�?���B��� +Lų�ÜQ%߬�=�fw����zG��!�Z���g���>��(�?��J� Y���[Z�xl;gQ�s�����s������2��Qe�ev���T//v��Yv�����`�Բ�JY��ǖ�_���{��#=U�,.֧� +�q�~��Q��f�c�dg�Ϟ��S���{Z.��ì=j���++���-Rzd�K?�Y�/*��=2Ba]ei��>�J�5bÂ…h������ћ��[��S6Gn=���0Fz�J���픫S�txs��&�䲗:�� +��~XND��J���e؅�&t��o�����e�� �ŕ�9�J�QÕ¼w�>�T��"�,0'sq�%캻��p�u9.��/���}�.�ƈ� +��z�� +�[�ZU�*q� A���*���6[�,�B�T�)v����e��� +��T�t#�M�T��1vn��d�[P�t+5È•gE�9� +�n%�.*�,.@�.t9��w���V҉�QД��T2vx��XN�nZ=���*�;���z�!R`��L���mP�����}��ݯw���i�PÙ»O�~���w�>p@����y<�C�Ҫ��RK� �(+i�'�zV��J�[Fa�)es�C' g�!�������p���v�7�8�����ӊ<%�i%�;L+q϶�<�*+��U�b�:���,��~TÒ¸ ���`�����k�"��|�ߪ���}��,�+���h��� �>`��W{��Xvu1�O���-t9[������'ƈ�� i�zE,0�#E��6j��x�K� +u=�c�/0���endstream +endobj +9 0 obj +<< /Filter /FlateDecode /Length 247 >> +stream +x�]�Mk�0 ���:v�b�]��`�2 +9�e���d��6�sȿ�?J�� ��^Ѷ{@߃S=F����0�d,9p�F��_������D�;;:�4�#e�6�]���з�1;������?8�����qL�^��3-�}�S��m�4��G��u�4.^* �NH�B@sM!Z�/��aT�2��c�f�3��� =�*=U:W�Vj y�:��/��w��Qk�G9^1�W7����gU~�; z6endstream +endobj +10 0 obj +<< /Type /ObjStm /Length 459 /Filter /FlateDecode /N 6 /First 37 >> +stream +x�uQ�n�0��+�hÌ—(Qv\7F�$���P��H�JT���R�Z�P����,��� H8�T +\���S� �V�nn�>��<����3�q��F�9,�c�֟��WW� +2�}�7��sg��Tv���=�{�7�Zl���`�i�w���n�Pض4m��H��>�?��/][ݕ� +.�w@��0JFa��n-��������p�mv�w���j�Im��Vn�f�ҿ�y���6�@��rd:�/���t��`�X]�{��ǸG�f�����?��+F��A> /W [ 1 2 1 ] /Size 2 /ID [] >> +stream +x�cb&F �R +endstream +endobj + +startxref +216 +%%EOF +' because of error 'Filter: [?] can not be applied to primitives. Current context is: %PDF-1.5 +%���� +2 0 obj +<< /Linearized 1 /L 14631 /H [ 687 126 ] /O 6 /E 14356 /N 1 /T 14355 >> +endobj + +3 0 obj +<< /Type /XRef /Length 49 /Filter /FlateDecode /DecodeParms << /Columns 4 /Predictor 12 >> /W [ 1 2 1 ] /Index [ 2 15 ] /Info 11 0 R /Root 4 0 R /Size 17 /Prev 14356 /ID [] >> +stream +x�cbd�g`b`8 $���XF@���Zb�d +v�Xv L���@ ����0 +endstream +endobj + +4 0 obj +<< /Pages 12 0 R /Type /Catalog >> +endobj +5 0 obj +<< /Filter /FlateDecode /S 36 /Length 49 >> +stream +x�c```e``Z�&���fb�(H-30�g�c``�>������( +endstream +endobj +6 0 obj +<< /Contents 7 0 R /MediaBox [ 0 0 596 843 ] /Parent 12 0 R /Resources << /ExtGState << /G0 13 0 R >> /Font << /F0 14 0 R >> >> /StructParents 0 /Type /Page >> +endobj +7 0 obj +<< /Filter /FlateDecode /Length 200 >> +stream +x���� +�0 ��}���uI�4-����Y)��AA}0���I���~��KZÔ¨H��؞�� +������n{���E�����R�y�b�!�=���h��x/��<�f�;���`EB'�%z���l��;�6p�! M/E�g�>��;�#�v�d-�E��Eb!ÉŠp@�&�-��H�' +2023-09-06T14:29:49.496+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.['loanAmount'] == 123.123)]' failed to match document '%PDF-1.5 +%���� +2 0 obj +<< /Linearized 1 /L 14631 /H [ 687 126 ] /O 6 /E 14356 /N 1 /T 14355 >> +endobj + +3 0 obj +<< /Type /XRef /Length 49 /Filter /FlateDecode /DecodeParms << /Columns 4 /Predictor 12 >> /W [ 1 2 1 ] /Index [ 2 15 ] /Info 11 0 R /Root 4 0 R /Size 17 /Prev 14356 /ID [] >> +stream +x�cbd�g`b`8 $���XF@���Zb�d +v�Xv L���@ ����0 +endstream +endobj + +4 0 obj +<< /Pages 12 0 R /Type /Catalog >> +endobj +5 0 obj +<< /Filter /FlateDecode /S 36 /Length 49 >> +stream +x�c```e``Z�&���fb�(H-30�g�c``�>������( +endstream +endobj +6 0 obj +<< /Contents 7 0 R /MediaBox [ 0 0 596 843 ] /Parent 12 0 R /Resources << /ExtGState << /G0 13 0 R >> /Font << /F0 14 0 R >> >> /StructParents 0 /Type /Page >> +endobj +7 0 obj +<< /Filter /FlateDecode /Length 200 >> +stream +x���� +�0 ��}���uI�4-����Y)��AA}0���I���~��KZÔ¨H��؞�� +������n{���E�����R�y�b�!�=���h��x/��<�f�;���`EB'�%z���l��;�6p�! M/E�g�>��;�#�v�d-�E��Eb!ÉŠp@�&�-��H�W�2�6!yoч(�>)6O����Z�endstream +endobj +8 0 obj +<< /Filter /FlateDecode /Length1 29380 /Length 12131 >> +stream +x��} |TE�喙��Y!B �MB"H ì‹@"�L$M�I���q���e7@T�f.�(����,.�����8��~��{;������~�i����:U�ԩS��v�Q0U�F�%���]�o#��������}m�� ��DY{�-/,����_��Y��ŋ�.�퇶��׋�����ގ��"���V�?]�J<���� b��:l(.s�)����+P�\b��<�P�]hǘ���K�/��aDW�"�-�p���ω��t��������/��n;엀��?�������\���sO�/ p���gJO��� 4*��=��7l�Y��c�&k,��A��0J��D"z5�V� �/���n��ںP�e:�4�o�$�.�!�� +�nE9t�� �i� `0�lÖ��TY���c��quӌ�8*�L������7h.� �M� �bL%(oF�}�h��A��֭t/��G�u�梼�L��m�5�IR����g�9�˴�h�p�Na.y�J�f�:���#�� +Z���mB;(��+d=�e�+0�r��@��(��3찂��n� �;��i���Ƽ�7�HιqN�ߴ�B6�k�|H�}_�6��5nj��Z_��D��A*W���Y�"M�)�t�\���j�E�e�������g���k1���p���?��5�� ��0�R�A�����Ê�Tо�+C7����O�7(/źN��z�c�*0�R +K{�?M�\�;��0�_Bf��#0w���ì±ï¿½ï¿½8��Did���'A!m�CÅ™ ���q:V� � +|l�C�g�n�MЫ�xE���T�ذ��6��T�iì™ï¿½XRO�� �o"^�)���Yز�?��S2f�T��|��G9OS�{O|Gc� +j"��T�;�,��Z>�V��G�$cV���/2Ö”O�'L:��\{�=�%��~���}�H�h3�̷�AN�@W]��As��ҺS��7�0�z�w4%`?��ZNDy]+z����gÙyn�?����q�'�#�b����B�-�6�X���`��6I%���W��;�Z�!gn���r���|�{��� +�~��@5�# ��0��ڦQ�gP&2h�%���X��y��O���}��E�}ª����md�k�Ӡ�H7I��A˛�Q��kK~���T�|3��@���L|i�,� ��af�(�:�����x��k�Ϸ��U��l��[�gH�lM�ق��ߧ����e~�9N�H��d��˷�����c��� s_'��6~n�}�a���>�u��1�.�-Ü·Åš�c��{ ��L��5��iw�Yj�S�����3�mV��'�[��ӕ}�֧i������`�A�v����zZ�yt�V`?��)}�ւ(J� �L�îŸï¿½Y��nҎ� ���v�AW���T�TIe��j�d����4���T �J�C�#�>��B"�'�P�8d"(r�2�1��|܋� ��l�� ���mT}2(���f� �w_��AS�}�;z�2����h����i�s�c<�~Ó¤-��Y����5�_+��V"çŠï¿½�:m�s�:�U�G�(�R +�Ws�F�]!�����e�X�A���{�F�P�u>�A� �$��B�2���ػ����� �oA��;B�e�A�[��V�{)�=��oi�v%�Dg�?,�^8/b/�c@��Xm@Õ…��kat���K��Z0�V��{�Rr�键��N���a��F�imi�8@��ZZ-Ë¢=uӼ��.�-e�a�$���(�K3�0�_I�b6��툽(H��Z���V�IW�� �`_� m:�����=!唎]��%��K�ke��l���+���W�-셭�v�m��}j�r\��2�>�;���dІ�| +m6�Oi�6��-H0��h�p��'� +E��q��g7��?= ,��E�i���[: +,��/���|$ +�u�o�ۚC�X}sX��e���`?��K����@�q9� o��.���X��P�1[��']@T� � +�1��"�6���N��m� +0Ç›j��{��"���F����<�?7�� �%�{!�w�[���~~6� ��Q��b ���=��@8������ �C�����?�S�;�v���@oh��S�z�m���_�?�;3hE +?���s�����}~��O�� +�!����N"���.+����hR�����K��O��Y�_��Y�_A7���Z�=��{���ԑ��6NA \P.���;X�5( +��l ����62/;�|<�����iLÓ´@-Q[��h����!"&��b��K�E< ;�s��e����-?[C���8���|k�u�u��f����ǭO[ß±���<�7����� z�������C�a�p=K/ӗ����'�-���;�'�'ǧ���_O���`Mh����9!.�{BJ� �g"O K�O�$����!)*)&�kRϤ~I�����%�LZ�tW�Ƥ'�v$�Mz>�դ��'}����a��#���s��c�&�!g��>u�N�P7�nx]f]V���V��S竟s~����}�>����6(�m`O���<�:<��F��[�ݪ=,�h#&�k��b�X/6��D��X|c�Z���k9cz.ÞšaͿ����V�n�C��z���s=�t}��y��������M�ížk�uJ�5=��P�<���Mj���I��6z�<�1<7��s��y�0�9vF�1x�G� x.�nT���u�����ZW_����\���� �=��AK���`G�ED�ɪ�|VQ�e��ن�� +��������TLEt +����X���oן������_Wo���~I���?׻��}1���cƷ�'�����䲓���r� +�g�Փ5'o��X±�c���?���7G�:���u������xZ��v���O�>:�h�ѮG������^�M�Eۣ�l������k{���m��!�_�Z�[�v�9��eZ�����@���������h�i.�r+� nD��:�y���k����Ib�Y��{v��,�5�]W2�߶\բ��ô��k��Z��L��*z��͸"���7�]t�~�5�ZI/�1:M�V�'�D?�&z�ޤ��I�C�� +�9� +z������i.�G��]z� +���>��鯈�o�;��摋�S ���6P-�r� 7U�1]E��u��E�'�q�,m�%���i)���A{�Z�ƙ��PÕ³{�:���Gç©Y������`����6�@Ä‚Y�����+��a�����8�ʶ�'ؓ�)�,/��v���/:�j�*��=�v�gY- em����ea� ��t��g�s�y�:����"�������,�E���e�Xg� +{�E�օŲ�������� �t���M�;��f� gb��+Kb��0{����ge��p�ƺ��%}ŎЇt�>�O�(���3v��a?�������β_ٿ�o�Kau���g +�'�1�s�q�-��m<�� Ö‹����<����=��Ry���XoÉ£x'Þ™G�ޅ��8���<�'�>,�'���+O���2Þw�=x +_�o��Y����R�&m��B�E[�ݦݥݣ���������M{R{ZÛ®=���^�^�^���b����>�>�Ni_i�j�k�����'�O�3��������9^�� -X ���0����xLl���b�xB<�S�i����̻�3b�x���������'�������xM�.�o����xG��a�xO�/�*>Gć�#�R��O�QqL|&���8%>_�/�W�o�k��V�]|'�!�?����Q�$�)~��/ؗ��U�K�&Ή:�N;x +�G��nzoG;i�J��hr�Dm�6I��MÓ¦kWk��T-�~a_��b1=O��{��G�N6�nc�l!���]��j� +�{��X *�R����5�Lm�X&*E�X.���"�B����J�׉��q�� +'��L�OÜ;̓���+Ö‰�Cb�؈��a��6@��&��D�_3�o�vШ ��Ú¦mX���":FFu��%6N�OHìš”|Y��=Rz�JM��'�o����w�������lힽ�=�‹�����+����o�u��w:�.���_?8��G���c�?q��x��x��x��x��x��x��x��x�����3233F �|��!� +�߯oz��i��z�����䤮� �z\l���Î�";Fth�.�m�Ð����"4Ψgv��|ݛ��ɉW\�K��7�����Rƫ�+1��d$綒�0$3%Y�>����g'�ރY�z-�19����<�����+�v���G=;�(K��|=�;zaQMv~��4*q�3�WO� 6�72�|;���#��l� +���������^-)�^��497;+:>>�WO/�H��đ޶)J�F)5^�(�M��]r6�J��s���0���R�X`�����yRG����F^�eTS����]Ѽ5Z�Ɏr�XS�B�n��ۼ5^>��0����5��z5�8n�m|y^��-�J]�D�ʘ�31[���ӽ��#�j��ci:�xiʢ��;g����zMNnb�wDtb�=+f{���hg� �SË–^=���3��M[� m�8���%7nJ�g��(q,«;tX���9 +�� �q �~�zy �".o����!�^��Z�pG���=?������5֤�_H�2NC +�~ޛ����C��m�6W���z.�剉�a:�G��[{Þ4�?>^.�� ����zr�Q�iN��HK���|ٲ��1M�T�[��'"�w���o@r�m�:��.�e��i����8n�\=�&���%�}Pc��yÛ�բ���hM�"(g6 +�Bn�W$�?� +�Z[�R�0}�7,� +��v�����i�f���Ҳ<�E��y!5 �|\Ό���m5C�X� �)'7^�iØ™I��ַ�D^�7.%F�Yl!m�y���٫�h$���щ���{��zN��X����_�)���N�o�h���y�U�+3��j�t���Lf�V%'kÊ€%�>��j��"w��7�d�";�����(��;��3����k� +1���3�SG��� +OJ��4(4}fG\��8�����Ԗ1�� +Zy�YÍš -|g����i�p���q����.=3���i +�8���h���l�.���+���4�������h ?����C�>�0p������8?��( +���� �0~L�'�����cx���Q<��O�}�?�i�1pp�Ť��L\��DF�Lx��Z���ߺ���/v�)q2{�� p(��@:0 ��+��}H����� X��C��}�Ro ��ww@M-?�#yd\fG~��A�p�A������}����[�����;b�(3�>a�a�ih��vv +��e�����8<Ó€�D`6p`��x��p � H�o}�6PƼ���Q�1]>��\���yF��u(�G�w����e���G��K��Gr�Bp�\0�|$Ϙ +N>�'�ã�?�l���N���̶� +^�����*�J~�7!m�oG�������=�����Y�V��U;Y�bV��Uc�ײ�VêcYu�~� +�+�YÆ®��Q���~�U�Yu2�Nb�]Y��f���c�*����L��@/��6�ã��xl�}x|��!=��+i��#�r����+�+�� +��:,�+�W0�+�-�#���~�4���N�ᷩg[<Ó€�l` p�*sN��L�V���FO�%� +> �����.a1a)aWh���lb�/����-?�]@;����5�_��R`f ���F]������u��e��H~..3���b�� +�d�:�ܪܟb$�G1|h������vGrϸ����;î·˜/ã¾ï¿½ï¿½`��y.�#�V�qGP�mw�1�Ľ�V���k�^]����%� +�w�-�dwÜ1c��Ǩ��p����qS�g�]��b��e�1��1�� +3���>��zÄ��c��(���j�ikYQFO�Z[�m�m�-���o��u�E�:���   +��@j}'3R���a��?3�H(>�˧��X�5��J����qSG�q��7G����XË‚p�ZG2o�8�3�;(e\��7�;0e��6���ݚ�Z/_Y�p��2��Z-��{��v��DK�m���<��pDԈ����κ�#�|�4�D��x׎�����%Ï›._��q޻�]vޟ�dg���4H^�m8�){��׆g�å«eÓ•��G�!b~Tr��K9�b +���\�C��$� �$%����r��]���w�d"ur+w��\�@d���L�j:�dt��2��J$&"�1J�u�%�:+��M"i��-�"�(Mk��1dBO�eBOB&�?�q�LIa;��9f�����l'��]��(�[=G×·;�����9�"I�No^�3��H�ҷ�y�晲yhb�v�����}f�3k�Ќ�ى����c&��B�-���M��`��`���1/�)w{��õSÑ<8��7�cX�p�C�G�����7�P@6���)���dS��g6E-��m1��P�.q$�x*Ý•���2�s�U�J�p���w?h��{[��C4��c�8��s��l�͗S���g�iT��r��ԴFAY7L�����IG�]P͟��2b���y�7v\G*�1o�{q]�ǃ;t������&�'9_?<�&g��cR�����h�A�*�^�t����:�vQm�9��B�jZL{�#��}KKh��W�ZN��@�4��h +��WI3鄸��UTJ�ڗ��w�o3=B{�7}�)�:����,��Q/����� vg�3�-Õ|�*h�6K0_��,��*� h<d�y +Fw��,�ݠ��(���W!C�����^֟��ñ–™¾ï¿½ï¿½:�è�h�Ƨ�^�OY��o�� u��4��E��~���҆���Rw��2z�ޠwY"{��YB,� ������i��1����/�g����Im��;���5:�:�46�M��yP��h�O���{1�qD�n�k�m��ڥ᤯ +V$���%�������>d_�Q|6����-�����TBkh���� 6�]� +l���cٻ���s�|~Z+�h/���Lnq��f�*�7 +� +�6���/�w3MF<,���Ѓ��:L��s�>g���#�������b��mR�Aï‚–w���[�@��:���[y����D^� ���~~�w�?�oZ����h��aZ�V�Vh���vJt��~N�����g���?|���� +԰�am�]�S�5�a�W�a�ގ�<��ZD���W�uf=�pv<3��c �u��2��=�l�=/}�N��P�lN���H>�k��/���N����i6-Xk�Eh=�1�,Í©y�E�Zͫ��}�}������ 'D�Hc�lQ)_��-3-o[��YK�7[k�?�3�6�6�6�v�m�타|�-*=C�6�U;�-ղ�g�V�Wt��!��l*��sD*��V��.��r�u(�&�����_��|�6��cSi�������Aȿ�=L�Bߋ�1�C�:k[�O[ChSo����)����v���F:*�X$��?�MB� �[r)^�������MT�q<�mE^�a��_��� ����t������+�/�@ҭԗ�@_ӣ��-����w�ޞ�".���ue��-c���������"��kO����)m�8c��n��i�o)-���Y!il:%���n7h�"t ��L����{�2��B�\���� ��{�'"È…=~5��!�e��ThiÃu��� +Sh��QZ�+�Rß� �`��������h [��'*Ǜ�'��WYF�ÖѾ^��§�-��NbQ�w|���4��Ո�h*���AtwC�]Gsp?������S߆ |�o�V����ɾ�|q,��|�4���Gl��RL����l��V8���} �p �p �p �p �p �p �p �p �p �/�3� ��S�6���/��Z�.�=YÄ—�ė�:X-_r�yÞ‡�:�JQ)ag��6!��a���������;�]|�$< �׵�����b��]�&"!OL�dDX-�6i"�3L�Z������~��J=H�A�CE��t��2����%�N;;k��_�(��ӆ�I�����7�It�PK�?�-��}�a� +�OJK6c� ʒ�= +�����'���� +A�� ����f�Ϊe�<�0BYX��2=tRh~hy���2kA�ٔY���JK`Ùˆa�g�)�����`�������_>o��=�(�qn4�y~<_ ��U��8�P�.���e��q�t�u�L�J��f��3_�2߲��?�$N�ז�,P��%��۲a:DGFG &:GG��#w�y����.�&����9×’xuØ´v��ψ�5���ѫ"��N����ۘ�suÖ¥m�4�S�c��6㿟���Ј�G|���Z@�f�Z�>���ExD.��a�7����ɉ �`+ـ���m�v�;ܰw˛��GGY��o�8��?�J�/7��tt�|����C��L� +�v<(�� �����u�W�pd�⭲>2Z�6U��?P����Fo���kd𢙌�Fo���kd����Fo���kd����Fo��䃚�7X�e��C�շQs�Z�ar.���o><�R���G�qL�c��N�� +�G+]Ƙ]���5�*�{�C�+���K>����t�4���%�Q99i.�����@)~<�Q)�1�t�Rx���ޥ$t��*�,Uo��)��2����X��/CÆï¿½ï¿½ï¿½ï¿½ï¿½>4������Um&z�NA�B��Q��`<7PA �,P6���I%��T@�)��Éw�C:z��r�Rꩴ����0Dz���Y�F�3(��%jDZ���r�:u�Hr +*�~0�Q�fc�G\7��Rq^a��5���5���|c] +�L�4�[S�2F���@�I��N�J�x<'B�\�~���t+o�������� +�Œ$?���h<�R�٨����c��l|ƫ� +� ���Ĵ�XoXl�\���M{�B�g^|P���HI������x��ZA��Q��1���T}�r���2C5�k#O����6sG��٘{�o�Lm2�,4s���S������c��1 :Í�l�;*Oy̼1׌���˿ۥǜ�Fi��+0�K���� +��+Sj�|��Lͪ����aT\�ٟCe����Z�Mo��\��t���/m��]�N�6�|���]YT�<+�-��o�����r�_����Ӯf�UE�W�F�fq�tG�}OI�J����*k1^�Z��j5�gn�,���g*����E��1�j�%f�6�o�r3>�2|���5��X5� W�Ç“g�Ӽ �1�����֠����F��+S���̫ �������x���{�i�5Z����.\G�[M7c���}�_1{+_��/Y��� 5��W���iÞ–=8!�#�S&��H���� +�y����^x���&��9�ƙ��՟8î‡ï¿½����5����DB�^��$�З�O�������w����� �e��Y��)�2���i����:��g��7x�?���B��� +Lų�ÜQ%߬�=�fw����zG��!�Z���g���>��(�?��J� Y���[Z�xl;gQ�s�����s������2��Qe�ev���T//v��Yv�����`�Բ�JY��ǖ�_���{��#=U�,.֧� +�q�~��Q��f�c�dg�Ϟ��S���{Z.��ì=j���++���-Rzd�K?�Y�/*��=2Ba]ei��>�J�5bÂ…h������ћ��[��S6Gn=���0Fz�J���픫S�txs��&�䲗:�� +��~XND��J���e؅�&t��o�����e�� �ŕ�9�J�QÕ¼w�>�T��"�,0'sq�%캻��p�u9.��/���}�.�ƈ� +��z�� +�[�ZU�*q� A���*���6[�,�B�T�)v����e��� +��T�t#�M�T��1vn��d�[P�t+5È•gE�9� +�n%�.*�,.@�.t9��w���V҉�QД��T2vx��XN�nZ=���*�;���z�!R`��L���mP�����}��ݯw���i�PÙ»O�~���w�>p@����y<�C�Ҫ��RK� �(+i�'�zV��J�[Fa�)es�C' g�!�������p���v�7�8�����ӊ<%�i%�;L+q϶�<�*+��U�b�:���,��~TÒ¸ ���`�����k�"��|�ߪ���}��,�+���h��� �>`��W{��Xvu1�O���-t9[������'ƈ�� i�zE,0�#E��6j��x�K� +u=�c�/0���endstream +endobj +9 0 obj +<< /Filter /FlateDecode /Length 247 >> +stream +x�]�Mk�0 ���:v�b�]��`�2 +9�e���d��6�sȿ�?J�� ��^Ѷ{@߃S=F����0�d,9p�F��_������D�;;:�4�#e�6�]���з�1;������?8�����qL�^��3-�}�S��m�4��G��u�4.^* �NH�B@sM!Z�/��aT�2��c�f�3��� =�*=U:W�Vj y�:��/��w��Qk�G9^1�W7����gU~�; z6endstream +endobj +10 0 obj +<< /Type /ObjStm /Length 459 /Filter /FlateDecode /N 6 /First 37 >> +stream +x�uQ�n�0��+�hÌ—(Qv\7F�$���P��H�JT���R�Z�P����,��� H8�T +\���S� �V�nn�>��<����3�q��F�9,�c�֟��WW� +2�}�7��sg��Tv���=�{�7�Zl���`�i�w���n�Pض4m��H��>�?��/][ݕ� +.�w@��0JFa��n-��������p�mv�w���j�Im��Vn�f�ҿ�y���6�@��rd:�/���t��`�X]�{��ǸG�f�����?��+F��A> /W [ 1 2 1 ] /Size 2 /ID [] >> +stream +x�cb&F �R +endstream +endobj + +startxref +216 +%%EOF +' because of error 'Filter: [?] can not be applied to primitives. Current context is: %PDF-1.5 +%���� +2 0 obj +<< /Linearized 1 /L 14631 /H [ 687 126 ] /O 6 /E 14356 /N 1 /T 14355 >> +endobj + +3 0 obj +<< /Type /XRef /Length 49 /Filter /FlateDecode /DecodeParms << /Columns 4 /Predictor 12 >> /W [ 1 2 1 ] /Index [ 2 15 ] /Info 11 0 R /Root 4 0 R /Size 17 /Prev 14356 /ID [] >> +stream +x�cbd�g`b`8 $���XF@���Zb�d +v�Xv L���@ ����0 +endstream +endobj + +4 0 obj +<< /Pages 12 0 R /Type /Catalog >> +endobj +5 0 obj +<< /Filter /FlateDecode /S 36 /Length 49 >> +stream +x�c```e``Z�&���fb�(H-30�g�c``�>������( +endstream +endobj +6 0 obj +<< /Contents 7 0 R /MediaBox [ 0 0 596 843 ] /Parent 12 0 R /Resources << /ExtGState << /G0 13 0 R >> /Font << /F0 14 0 R >> >> /StructParents 0 /Type /Page >> +endobj +7 0 obj +<< /Filter /FlateDecode /Length 200 >> +stream +x���� +�0 ��}���uI�4-����Y)��AA}0���I���~��KZÔ¨H��؞�� +������n{���E�����R�y�b�!�=���h��x/��<�f�;���`EB'�%z���l��;�6p�! M/E�g�>��;�#�v�d-�E��Eb!ÉŠp@�&�-��H�' +2023-09-06T14:29:49.499+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.['client.id'] =~ /([0-9]{10})/)]' failed to match document '%PDF-1.5 +%���� +2 0 obj +<< /Linearized 1 /L 14631 /H [ 687 126 ] /O 6 /E 14356 /N 1 /T 14355 >> +endobj + +3 0 obj +<< /Type /XRef /Length 49 /Filter /FlateDecode /DecodeParms << /Columns 4 /Predictor 12 >> /W [ 1 2 1 ] /Index [ 2 15 ] /Info 11 0 R /Root 4 0 R /Size 17 /Prev 14356 /ID [] >> +stream +x�cbd�g`b`8 $���XF@���Zb�d +v�Xv L���@ ����0 +endstream +endobj + +4 0 obj +<< /Pages 12 0 R /Type /Catalog >> +endobj +5 0 obj +<< /Filter /FlateDecode /S 36 /Length 49 >> +stream +x�c```e``Z�&���fb�(H-30�g�c``�>������( +endstream +endobj +6 0 obj +<< /Contents 7 0 R /MediaBox [ 0 0 596 843 ] /Parent 12 0 R /Resources << /ExtGState << /G0 13 0 R >> /Font << /F0 14 0 R >> >> /StructParents 0 /Type /Page >> +endobj +7 0 obj +<< /Filter /FlateDecode /Length 200 >> +stream +x���� +�0 ��}���uI�4-����Y)��AA}0���I���~��KZÔ¨H��؞�� +������n{���E�����R�y�b�!�=���h��x/��<�f�;���`EB'�%z���l��;�6p�! M/E�g�>��;�#�v�d-�E��Eb!ÉŠp@�&�-��H�W�2�6!yoч(�>)6O����Z�endstream +endobj +8 0 obj +<< /Filter /FlateDecode /Length1 29380 /Length 12131 >> +stream +x��} |TE�喙��Y!B �MB"H ì‹@"�L$M�I���q���e7@T�f.�(����,.�����8��~��{;������~�i����:U�ԩS��v�Q0U�F�%���]�o#��������}m�� ��DY{�-/,����_��Y��ŋ�.�퇶��׋�����ގ��"���V�?]�J<���� b��:l(.s�)����+P�\b��<�P�]hǘ���K�/��aDW�"�-�p���ω��t��������/��n;엀��?�������\���sO�/ p���gJO��� 4*��=��7l�Y��c�&k,��A��0J��D"z5�V� �/���n��ںP�e:�4�o�$�.�!�� +�nE9t�� �i� `0�lÖ��TY���c��quӌ�8*�L������7h.� �M� �bL%(oF�}�h��A��֭t/��G�u�梼�L��m�5�IR����g�9�˴�h�p�Na.y�J�f�:���#�� +Z���mB;(��+d=�e�+0�r��@��(��3찂��n� �;��i���Ƽ�7�HιqN�ߴ�B6�k�|H�}_�6��5nj��Z_��D��A*W���Y�"M�)�t�\���j�E�e�������g���k1���p���?��5�� ��0�R�A�����Ê�Tо�+C7����O�7(/źN��z�c�*0�R +K{�?M�\�;��0�_Bf��#0w���ì±ï¿½ï¿½8��Did���'A!m�CÅ™ ���q:V� � +|l�C�g�n�MЫ�xE���T�ذ��6��T�iì™ï¿½XRO�� �o"^�)���Yز�?��S2f�T��|��G9OS�{O|Gc� +j"��T�;�,��Z>�V��G�$cV���/2Ö”O�'L:��\{�=�%��~���}�H�h3�̷�AN�@W]��As��ҺS��7�0�z�w4%`?��ZNDy]+z����gÙyn�?����q�'�#�b����B�-�6�X���`��6I%���W��;�Z�!gn���r���|�{��� +�~��@5�# ��0��ڦQ�gP&2h�%���X��y��O���}��E�}ª����md�k�Ӡ�H7I��A˛�Q��kK~���T�|3��@���L|i�,� ��af�(�:�����x��k�Ϸ��U��l��[�gH�lM�ق��ߧ����e~�9N�H��d��˷�����c��� s_'��6~n�}�a���>�u��1�.�-Ü·Åš�c��{ ��L��5��iw�Yj�S�����3�mV��'�[��ӕ}�֧i������`�A�v����zZ�yt�V`?��)}�ւ(J� �L�îŸï¿½Y��nҎ� ���v�AW���T�TIe��j�d����4���T �J�C�#�>��B"�'�P�8d"(r�2�1��|܋� ��l�� ���mT}2(���f� �w_��AS�}�;z�2����h����i�s�c<�~Ó¤-��Y����5�_+��V"çŠï¿½�:m�s�:�U�G�(�R +�Ws�F�]!�����e�X�A���{�F�P�u>�A� �$��B�2���ػ����� �oA��;B�e�A�[��V�{)�=��oi�v%�Dg�?,�^8/b/�c@��Xm@Õ…��kat���K��Z0�V��{�Rr�键��N���a��F�imi�8@��ZZ-Ë¢=uӼ��.�-e�a�$���(�K3�0�_I�b6��툽(H��Z���V�IW�� �`_� m:�����=!唎]��%��K�ke��l���+���W�-셭�v�m��}j�r\��2�>�;���dІ�| +m6�Oi�6��-H0��h�p��'� +E��q��g7��?= ,��E�i���[: +,��/���|$ +�u�o�ۚC�X}sX��e���`?��K����@�q9� o��.���X��P�1[��']@T� � +�1��"�6���N��m� +0Ç›j��{��"���F����<�?7�� �%�{!�w�[���~~6� ��Q��b ���=��@8������ �C�����?�S�;�v���@oh��S�z�m���_�?�;3hE +?���s�����}~��O�� +�!����N"���.+����hR�����K��O��Y�_��Y�_A7���Z�=��{���ԑ��6NA \P.���;X�5( +��l ����62/;�|<�����iLÓ´@-Q[��h����!"&��b��K�E< ;�s��e����-?[C���8���|k�u�u��f����ǭO[ß±���<�7����� z�������C�a�p=K/ӗ����'�-���;�'�'ǧ���_O���`Mh����9!.�{BJ� �g"O K�O�$����!)*)&�kRϤ~I�����%�LZ�tW�Ƥ'�v$�Mz>�դ��'}����a��#���s��c�&�!g��>u�N�P7�nx]f]V���V��S竟s~����}�>����6(�m`O���<�:<��F��[�ݪ=,�h#&�k��b�X/6��D��X|c�Z���k9cz.ÞšaͿ����V�n�C��z���s=�t}��y��������M�ížk�uJ�5=��P�<���Mj���I��6z�<�1<7��s��y�0�9vF�1x�G� x.�nT���u�����ZW_����\���� �=��AK���`G�ED�ɪ�|VQ�e��ن�� +��������TLEt +����X���oן������_Wo���~I���?׻��}1���cƷ�'�����䲓���r� +�g�Փ5'o��X±�c���?���7G�:���u������xZ��v���O�>:�h�ѮG������^�M�Eۣ�l������k{���m��!�_�Z�[�v�9��eZ�����@���������h�i.�r+� nD��:�y���k����Ib�Y��{v��,�5�]W2�߶\բ��ô��k��Z��L��*z��͸"���7�]t�~�5�ZI/�1:M�V�'�D?�&z�ޤ��I�C�� +�9� +z������i.�G��]z� +���>��鯈�o�;��摋�S ���6P-�r� 7U�1]E��u��E�'�q�,m�%���i)���A{�Z�ƙ��PÕ³{�:���Gç©Y������`����6�@Ä‚Y�����+��a�����8�ʶ�'ؓ�)�,/��v���/:�j�*��=�v�gY- em����ea� ��t��g�s�y�:����"�������,�E���e�Xg� +{�E�օŲ�������� �t���M�;��f� gb��+Kb��0{����ge��p�ƺ��%}ŎЇt�>�O�(���3v��a?�������β_ٿ�o�Kau���g +�'�1�s�q�-��m<�� Ö‹����<����=��Ry���XoÉ£x'Þ™G�ޅ��8���<�'�>,�'���+O���2Þw�=x +_�o��Y����R�&m��B�E[�ݦݥݣ���������M{R{ZÛ®=���^�^�^���b����>�>�Ni_i�j�k�����'�O�3��������9^�� -X ���0����xLl���b�xB<�S�i����̻�3b�x���������'�������xM�.�o����xG��a�xO�/�*>Gć�#�R��O�QqL|&���8%>_�/�W�o�k��V�]|'�!�?����Q�$�)~��/ؗ��U�K�&Ή:�N;x +�G��nzoG;i�J��hr�Dm�6I��MÓ¦kWk��T-�~a_��b1=O��{��G�N6�nc�l!���]��j� +�{��X *�R����5�Lm�X&*E�X.���"�B����J�׉��q�� +'��L�OÜ;̓���+Ö‰�Cb�؈��a��6@��&��D�_3�o�vШ ��Ú¦mX���":FFu��%6N�OHìš”|Y��=Rz�JM��'�o����w�������lힽ�=�‹�����+����o�u��w:�.���_?8��G���c�?q��x��x��x��x��x��x��x��x�����3233F �|��!� +�߯oz��i��z�����䤮� �z\l���Î�";Fth�.�m�Ð����"4Ψgv��|ݛ��ɉW\�K��7�����Rƫ�+1��d$綒�0$3%Y�>����g'�ރY�z-�19����<�����+�v���G=;�(K��|=�;zaQMv~��4*q�3�WO� 6�72�|;���#��l� +���������^-)�^��497;+:>>�WO/�H��đ޶)J�F)5^�(�M��]r6�J��s���0���R�X`�����yRG����F^�eTS����]Ѽ5Z�Ɏr�XS�B�n��ۼ5^>��0����5��z5�8n�m|y^��-�J]�D�ʘ�31[���ӽ��#�j��ci:�xiʢ��;g����zMNnb�wDtb�=+f{���hg� �SË–^=���3��M[� m�8���%7nJ�g��(q,«;tX���9 +�� �q �~�zy �".o����!�^��Z�pG���=?������5֤�_H�2NC +�~ޛ����C��m�6W���z.�剉�a:�G��[{Þ4�?>^.�� ����zr�Q�iN��HK���|ٲ��1M�T�[��'"�w���o@r�m�:��.�e��i����8n�\=�&���%�}Pc��yÛ�բ���hM�"(g6 +�Bn�W$�?� +�Z[�R�0}�7,� +��v�����i�f���Ҳ<�E��y!5 �|\Ό���m5C�X� �)'7^�iØ™I��ַ�D^�7.%F�Yl!m�y���٫�h$���щ���{��zN��X����_�)���N�o�h���y�U�+3��j�t���Lf�V%'kÊ€%�>��j��"w��7�d�";�����(��;��3����k� +1���3�SG��� +OJ��4(4}fG\��8�����Ԗ1�� +Zy�YÍš -|g����i�p���q����.=3���i +�8���h���l�.���+���4�������h ?����C�>�0p������8?��( +���� �0~L�'�����cx���Q<��O�}�?�i�1pp�Ť��L\��DF�Lx��Z���ߺ���/v�)q2{�� p(��@:0 ��+��}H����� X��C��}�Ro ��ww@M-?�#yd\fG~��A�p�A������}����[�����;b�(3�>a�a�ih��vv +��e�����8<Ó€�D`6p`��x��p � H�o}�6PƼ���Q�1]>��\���yF��u(�G�w����e���G��K��Gr�Bp�\0�|$Ϙ +N>�'�ã�?�l���N���̶� +^�����*�J~�7!m�oG�������=�����Y�V��U;Y�bV��Uc�ײ�VêcYu�~� +�+�YÆ®��Q���~�U�Yu2�Nb�]Y��f���c�*����L��@/��6�ã��xl�}x|��!=��+i��#�r����+�+�� +��:,�+�W0�+�-�#���~�4���N�ᷩg[<Ó€�l` p�*sN��L�V���FO�%� +> �����.a1a)aWh���lb�/����-?�]@;����5�_��R`f ���F]������u��e��H~..3���b�� +�d�:�ܪܟb$�G1|h������vGrϸ����;î·˜/ã¾ï¿½ï¿½`��y.�#�V�qGP�mw�1�Ľ�V���k�^]����%� +�w�-�dwÜ1c��Ǩ��p����qS�g�]��b��e�1��1�� +3���>��zÄ��c��(���j�ikYQFO�Z[�m�m�-���o��u�E�:���   +��@j}'3R���a��?3�H(>�˧��X�5��J����qSG�q��7G����XË‚p�ZG2o�8�3�;(e\��7�;0e��6���ݚ�Z/_Y�p��2��Z-��{��v��DK�m���<��pDԈ����κ�#�|�4�D��x׎�����%Ï›._��q޻�]vޟ�dg���4H^�m8�){��׆g�å«eÓ•��G�!b~Tr��K9�b +���\�C��$� �$%����r��]���w�d"ur+w��\�@d���L�j:�dt��2��J$&"�1J�u�%�:+��M"i��-�"�(Mk��1dBO�eBOB&�?�q�LIa;��9f�����l'��]��(�[=G×·;�����9�"I�No^�3��H�ҷ�y�晲yhb�v�����}f�3k�Ќ�ى����c&��B�-���M��`��`���1/�)w{��õSÑ<8��7�cX�p�C�G�����7�P@6���)���dS��g6E-��m1��P�.q$�x*Ý•���2�s�U�J�p���w?h��{[��C4��c�8��s��l�͗S���g�iT��r��ԴFAY7L�����IG�]P͟��2b���y�7v\G*�1o�{q]�ǃ;t������&�'9_?<�&g��cR�����h�A�*�^�t����:�vQm�9��B�jZL{�#��}KKh��W�ZN��@�4��h +��WI3鄸��UTJ�ڗ��w�o3=B{�7}�)�:����,��Q/����� vg�3�-Õ|�*h�6K0_��,��*� h<d�y +Fw��,�ݠ��(���W!C�����^֟��ñ–™¾ï¿½ï¿½:�è�h�Ƨ�^�OY��o�� u��4��E��~���҆���Rw��2z�ޠwY"{��YB,� ������i��1����/�g����Im��;���5:�:�46�M��yP��h�O���{1�qD�n�k�m��ڥ᤯ +V$���%�������>d_�Q|6����-�����TBkh���� 6�]� +l���cٻ���s�|~Z+�h/���Lnq��f�*�7 +� +�6���/�w3MF<,���Ѓ��:L��s�>g���#�������b��mR�Aï‚–w���[�@��:���[y����D^� ���~~�w�?�oZ����h��aZ�V�Vh���vJt��~N�����g���?|���� +԰�am�]�S�5�a�W�a�ގ�<��ZD���W�uf=�pv<3��c �u��2��=�l�=/}�N��P�lN���H>�k��/���N����i6-Xk�Eh=�1�,Í©y�E�Zͫ��}�}������ 'D�Hc�lQ)_��-3-o[��YK�7[k�?�3�6�6�6�v�m�타|�-*=C�6�U;�-ղ�g�V�Wt��!��l*��sD*��V��.��r�u(�&�����_��|�6��cSi�������Aȿ�=L�Bߋ�1�C�:k[�O[ChSo����)����v���F:*�X$��?�MB� �[r)^�������MT�q<�mE^�a��_��� ����t������+�/�@ҭԗ�@_ӣ��-����w�ޞ�".���ue��-c���������"��kO����)m�8c��n��i�o)-���Y!il:%���n7h�"t ��L����{�2��B�\���� ��{�'"È…=~5��!�e��ThiÃu��� +Sh��QZ�+�Rß� �`��������h [��'*Ǜ�'��WYF�ÖѾ^��§�-��NbQ�w|���4��Ո�h*���AtwC�]Gsp?������S߆ |�o�V����ɾ�|q,��|�4���Gl��RL����l��V8���} �p �p �p �p �p �p �p �p �p �/�3� ��S�6���/��Z�.�=YÄ—�ė�:X-_r�yÞ‡�:�JQ)ag��6!��a���������;�]|�$< �׵�����b��]�&"!OL�dDX-�6i"�3L�Z������~��J=H�A�CE��t��2����%�N;;k��_�(��ӆ�I�����7�It�PK�?�-��}�a� +�OJK6c� ʒ�= +�����'���� +A�� ����f�Ϊe�<�0BYX��2=tRh~hy���2kA�ٔY���JK`Ùˆa�g�)�����`�������_>o��=�(�qn4�y~<_ ��U��8�P�.���e��q�t�u�L�J��f��3_�2߲��?�$N�ז�,P��%��۲a:DGFG &:GG��#w�y����.�&����9×’xuØ´v��ψ�5���ѫ"��N����ۘ�suÖ¥m�4�S�c��6㿟���Ј�G|���Z@�f�Z�>���ExD.��a�7����ɉ �`+ـ���m�v�;ܰw˛��GGY��o�8��?�J�/7��tt�|����C��L� +�v<(�� �����u�W�pd�⭲>2Z�6U��?P����Fo���kd𢙌�Fo���kd����Fo���kd����Fo��䃚�7X�e��C�շQs�Z�ar.���o><�R���G�qL�c��N�� +�G+]Ƙ]���5�*�{�C�+���K>����t�4���%�Q99i.�����@)~<�Q)�1�t�Rx���ޥ$t��*�,Uo��)��2����X��/CÆï¿½ï¿½ï¿½ï¿½ï¿½>4������Um&z�NA�B��Q��`<7PA �,P6���I%��T@�)��Éw�C:z��r�Rꩴ����0Dz���Y�F�3(��%jDZ���r�:u�Hr +*�~0�Q�fc�G\7��Rq^a��5���5���|c] +�L�4�[S�2F���@�I��N�J�x<'B�\�~���t+o�������� +�Œ$?���h<�R�٨����c��l|ƫ� +� ���Ĵ�XoXl�\���M{�B�g^|P���HI������x��ZA��Q��1���T}�r���2C5�k#O����6sG��٘{�o�Lm2�,4s���S������c��1 :Í�l�;*Oy̼1׌���˿ۥǜ�Fi��+0�K���� +��+Sj�|��Lͪ����aT\�ٟCe����Z�Mo��\��t���/m��]�N�6�|���]YT�<+�-��o�����r�_����Ӯf�UE�W�F�fq�tG�}OI�J����*k1^�Z��j5�gn�,���g*����E��1�j�%f�6�o�r3>�2|���5��X5� W�Ç“g�Ӽ �1�����֠����F��+S���̫ �������x���{�i�5Z����.\G�[M7c���}�_1{+_��/Y��� 5��W���iÞ–=8!�#�S&��H���� +�y����^x���&��9�ƙ��՟8î‡ï¿½����5����DB�^��$�З�O�������w����� �e��Y��)�2���i����:��g��7x�?���B��� +Lų�ÜQ%߬�=�fw����zG��!�Z���g���>��(�?��J� Y���[Z�xl;gQ�s�����s������2��Qe�ev���T//v��Yv�����`�Բ�JY��ǖ�_���{��#=U�,.֧� +�q�~��Q��f�c�dg�Ϟ��S���{Z.��ì=j���++���-Rzd�K?�Y�/*��=2Ba]ei��>�J�5bÂ…h������ћ��[��S6Gn=���0Fz�J���픫S�txs��&�䲗:�� +��~XND��J���e؅�&t��o�����e�� �ŕ�9�J�QÕ¼w�>�T��"�,0'sq�%캻��p�u9.��/���}�.�ƈ� +��z�� +�[�ZU�*q� A���*���6[�,�B�T�)v����e��� +��T�t#�M�T��1vn��d�[P�t+5È•gE�9� +�n%�.*�,.@�.t9��w���V҉�QД��T2vx��XN�nZ=���*�;���z�!R`��L���mP�����}��ݯw���i�PÙ»O�~���w�>p@����y<�C�Ҫ��RK� �(+i�'�zV��J�[Fa�)es�C' g�!�������p���v�7�8�����ӊ<%�i%�;L+q϶�<�*+��U�b�:���,��~TÒ¸ ���`�����k�"��|�ߪ���}��,�+���h��� �>`��W{��Xvu1�O���-t9[������'ƈ�� i�zE,0�#E��6j��x�K� +u=�c�/0���endstream +endobj +9 0 obj +<< /Filter /FlateDecode /Length 247 >> +stream +x�]�Mk�0 ���:v�b�]��`�2 +9�e���d��6�sȿ�?J�� ��^Ѷ{@߃S=F����0�d,9p�F��_������D�;;:�4�#e�6�]���з�1;������?8�����qL�^��3-�}�S��m�4��G��u�4.^* �NH�B@sM!Z�/��aT�2��c�f�3��� =�*=U:W�Vj y�:��/��w��Qk�G9^1�W7����gU~�; z6endstream +endobj +10 0 obj +<< /Type /ObjStm /Length 459 /Filter /FlateDecode /N 6 /First 37 >> +stream +x�uQ�n�0��+�hÌ—(Qv\7F�$���P��H�JT���R�Z�P����,��� H8�T +\���S� �V�nn�>��<����3�q��F�9,�c�֟��WW� +2�}�7��sg��Tv���=�{�7�Zl���`�i�w���n�Pض4m��H��>�?��/][ݕ� +.�w@��0JFa��n-��������p�mv�w���j�Im��Vn�f�ҿ�y���6�@��rd:�/���t��`�X]�{��ǸG�f�����?��+F��A> /W [ 1 2 1 ] /Size 2 /ID [] >> +stream +x�cb&F �R +endstream +endobj + +startxref +216 +%%EOF +' because of error 'Filter: [?] can not be applied to primitives. Current context is: %PDF-1.5 +%���� +2 0 obj +<< /Linearized 1 /L 14631 /H [ 687 126 ] /O 6 /E 14356 /N 1 /T 14355 >> +endobj + +3 0 obj +<< /Type /XRef /Length 49 /Filter /FlateDecode /DecodeParms << /Columns 4 /Predictor 12 >> /W [ 1 2 1 ] /Index [ 2 15 ] /Info 11 0 R /Root 4 0 R /Size 17 /Prev 14356 /ID [] >> +stream +x�cbd�g`b`8 $���XF@���Zb�d +v�Xv L���@ ����0 +endstream +endobj + +4 0 obj +<< /Pages 12 0 R /Type /Catalog >> +endobj +5 0 obj +<< /Filter /FlateDecode /S 36 /Length 49 >> +stream +x�c```e``Z�&���fb�(H-30�g�c``�>������( +endstream +endobj +6 0 obj +<< /Contents 7 0 R /MediaBox [ 0 0 596 843 ] /Parent 12 0 R /Resources << /ExtGState << /G0 13 0 R >> /Font << /F0 14 0 R >> >> /StructParents 0 /Type /Page >> +endobj +7 0 obj +<< /Filter /FlateDecode /Length 200 >> +stream +x���� +�0 ��}���uI�4-����Y)��AA}0���I���~��KZÔ¨H��؞�� +������n{���E�����R�y�b�!�=���h��x/��<�f�;���`EB'�%z���l��;�6p�! M/E�g�>��;�#�v�d-�E��Eb!ÉŠp@�&�-��H�' +2023-09-06T14:29:49.501+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.['loanAmount'] == 99999)]' failed to match document '%PDF-1.5 +%���� +2 0 obj +<< /Linearized 1 /L 14631 /H [ 687 126 ] /O 6 /E 14356 /N 1 /T 14355 >> +endobj + +3 0 obj +<< /Type /XRef /Length 49 /Filter /FlateDecode /DecodeParms << /Columns 4 /Predictor 12 >> /W [ 1 2 1 ] /Index [ 2 15 ] /Info 11 0 R /Root 4 0 R /Size 17 /Prev 14356 /ID [] >> +stream +x�cbd�g`b`8 $���XF@���Zb�d +v�Xv L���@ ����0 +endstream +endobj + +4 0 obj +<< /Pages 12 0 R /Type /Catalog >> +endobj +5 0 obj +<< /Filter /FlateDecode /S 36 /Length 49 >> +stream +x�c```e``Z�&���fb�(H-30�g�c``�>������( +endstream +endobj +6 0 obj +<< /Contents 7 0 R /MediaBox [ 0 0 596 843 ] /Parent 12 0 R /Resources << /ExtGState << /G0 13 0 R >> /Font << /F0 14 0 R >> >> /StructParents 0 /Type /Page >> +endobj +7 0 obj +<< /Filter /FlateDecode /Length 200 >> +stream +x���� +�0 ��}���uI�4-����Y)��AA}0���I���~��KZÔ¨H��؞�� +������n{���E�����R�y�b�!�=���h��x/��<�f�;���`EB'�%z���l��;�6p�! M/E�g�>��;�#�v�d-�E��Eb!ÉŠp@�&�-��H�W�2�6!yoч(�>)6O����Z�endstream +endobj +8 0 obj +<< /Filter /FlateDecode /Length1 29380 /Length 12131 >> +stream +x��} |TE�喙��Y!B �MB"H ì‹@"�L$M�I���q���e7@T�f.�(����,.�����8��~��{;������~�i����:U�ԩS��v�Q0U�F�%���]�o#��������}m�� ��DY{�-/,����_��Y��ŋ�.�퇶��׋�����ގ��"���V�?]�J<���� b��:l(.s�)����+P�\b��<�P�]hǘ���K�/��aDW�"�-�p���ω��t��������/��n;엀��?�������\���sO�/ p���gJO��� 4*��=��7l�Y��c�&k,��A��0J��D"z5�V� �/���n��ںP�e:�4�o�$�.�!�� +�nE9t�� �i� `0�lÖ��TY���c��quӌ�8*�L������7h.� �M� �bL%(oF�}�h��A��֭t/��G�u�梼�L��m�5�IR����g�9�˴�h�p�Na.y�J�f�:���#�� +Z���mB;(��+d=�e�+0�r��@��(��3찂��n� �;��i���Ƽ�7�HιqN�ߴ�B6�k�|H�}_�6��5nj��Z_��D��A*W���Y�"M�)�t�\���j�E�e�������g���k1���p���?��5�� ��0�R�A�����Ê�Tо�+C7����O�7(/źN��z�c�*0�R +K{�?M�\�;��0�_Bf��#0w���ì±ï¿½ï¿½8��Did���'A!m�CÅ™ ���q:V� � +|l�C�g�n�MЫ�xE���T�ذ��6��T�iì™ï¿½XRO�� �o"^�)���Yز�?��S2f�T��|��G9OS�{O|Gc� +j"��T�;�,��Z>�V��G�$cV���/2Ö”O�'L:��\{�=�%��~���}�H�h3�̷�AN�@W]��As��ҺS��7�0�z�w4%`?��ZNDy]+z����gÙyn�?����q�'�#�b����B�-�6�X���`��6I%���W��;�Z�!gn���r���|�{��� +�~��@5�# ��0��ڦQ�gP&2h�%���X��y��O���}��E�}ª����md�k�Ӡ�H7I��A˛�Q��kK~���T�|3��@���L|i�,� ��af�(�:�����x��k�Ϸ��U��l��[�gH�lM�ق��ߧ����e~�9N�H��d��˷�����c��� s_'��6~n�}�a���>�u��1�.�-Ü·Åš�c��{ ��L��5��iw�Yj�S�����3�mV��'�[��ӕ}�֧i������`�A�v����zZ�yt�V`?��)}�ւ(J� �L�îŸï¿½Y��nҎ� ���v�AW���T�TIe��j�d����4���T �J�C�#�>��B"�'�P�8d"(r�2�1��|܋� ��l�� ���mT}2(���f� �w_��AS�}�;z�2����h����i�s�c<�~Ó¤-��Y����5�_+��V"çŠï¿½�:m�s�:�U�G�(�R +�Ws�F�]!�����e�X�A���{�F�P�u>�A� �$��B�2���ػ����� �oA��;B�e�A�[��V�{)�=��oi�v%�Dg�?,�^8/b/�c@��Xm@Õ…��kat���K��Z0�V��{�Rr�键��N���a��F�imi�8@��ZZ-Ë¢=uӼ��.�-e�a�$���(�K3�0�_I�b6��툽(H��Z���V�IW�� �`_� m:�����=!唎]��%��K�ke��l���+���W�-셭�v�m��}j�r\��2�>�;���dІ�| +m6�Oi�6��-H0��h�p��'� +E��q��g7��?= ,��E�i���[: +,��/���|$ +�u�o�ۚC�X}sX��e���`?��K����@�q9� o��.���X��P�1[��']@T� � +�1��"�6���N��m� +0Ç›j��{��"���F����<�?7�� �%�{!�w�[���~~6� ��Q��b ���=��@8������ �C�����?�S�;�v���@oh��S�z�m���_�?�;3hE +?���s�����}~��O�� +�!����N"���.+����hR�����K��O��Y�_��Y�_A7���Z�=��{���ԑ��6NA \P.���;X�5( +��l ����62/;�|<�����iLÓ´@-Q[��h����!"&��b��K�E< ;�s��e����-?[C���8���|k�u�u��f����ǭO[ß±���<�7����� z�������C�a�p=K/ӗ����'�-���;�'�'ǧ���_O���`Mh����9!.�{BJ� �g"O K�O�$����!)*)&�kRϤ~I�����%�LZ�tW�Ƥ'�v$�Mz>�դ��'}����a��#���s��c�&�!g��>u�N�P7�nx]f]V���V��S竟s~����}�>����6(�m`O���<�:<��F��[�ݪ=,�h#&�k��b�X/6��D��X|c�Z���k9cz.ÞšaͿ����V�n�C��z���s=�t}��y��������M�ížk�uJ�5=��P�<���Mj���I��6z�<�1<7��s��y�0�9vF�1x�G� x.�nT���u�����ZW_����\���� �=��AK���`G�ED�ɪ�|VQ�e��ن�� +��������TLEt +����X���oן������_Wo���~I���?׻��}1���cƷ�'�����䲓���r� +�g�Փ5'o��X±�c���?���7G�:���u������xZ��v���O�>:�h�ѮG������^�M�Eۣ�l������k{���m��!�_�Z�[�v�9��eZ�����@���������h�i.�r+� nD��:�y���k����Ib�Y��{v��,�5�]W2�߶\բ��ô��k��Z��L��*z��͸"���7�]t�~�5�ZI/�1:M�V�'�D?�&z�ޤ��I�C�� +�9� +z������i.�G��]z� +���>��鯈�o�;��摋�S ���6P-�r� 7U�1]E��u��E�'�q�,m�%���i)���A{�Z�ƙ��PÕ³{�:���Gç©Y������`����6�@Ä‚Y�����+��a�����8�ʶ�'ؓ�)�,/��v���/:�j�*��=�v�gY- em����ea� ��t��g�s�y�:����"�������,�E���e�Xg� +{�E�օŲ�������� �t���M�;��f� gb��+Kb��0{����ge��p�ƺ��%}ŎЇt�>�O�(���3v��a?�������β_ٿ�o�Kau���g +�'�1�s�q�-��m<�� Ö‹����<����=��Ry���XoÉ£x'Þ™G�ޅ��8���<�'�>,�'���+O���2Þw�=x +_�o��Y����R�&m��B�E[�ݦݥݣ���������M{R{ZÛ®=���^�^�^���b����>�>�Ni_i�j�k�����'�O�3��������9^�� -X ���0����xLl���b�xB<�S�i����̻�3b�x���������'�������xM�.�o����xG��a�xO�/�*>Gć�#�R��O�QqL|&���8%>_�/�W�o�k��V�]|'�!�?����Q�$�)~��/ؗ��U�K�&Ή:�N;x +�G��nzoG;i�J��hr�Dm�6I��MÓ¦kWk��T-�~a_��b1=O��{��G�N6�nc�l!���]��j� +�{��X *�R����5�Lm�X&*E�X.���"�B����J�׉��q�� +'��L�OÜ;̓���+Ö‰�Cb�؈��a��6@��&��D�_3�o�vШ ��Ú¦mX���":FFu��%6N�OHìš”|Y��=Rz�JM��'�o����w�������lힽ�=�‹�����+����o�u��w:�.���_?8��G���c�?q��x��x��x��x��x��x��x��x�����3233F �|��!� +�߯oz��i��z�����䤮� �z\l���Î�";Fth�.�m�Ð����"4Ψgv��|ݛ��ɉW\�K��7�����Rƫ�+1��d$綒�0$3%Y�>����g'�ރY�z-�19����<�����+�v���G=;�(K��|=�;zaQMv~��4*q�3�WO� 6�72�|;���#��l� +���������^-)�^��497;+:>>�WO/�H��đ޶)J�F)5^�(�M��]r6�J��s���0���R�X`�����yRG����F^�eTS����]Ѽ5Z�Ɏr�XS�B�n��ۼ5^>��0����5��z5�8n�m|y^��-�J]�D�ʘ�31[���ӽ��#�j��ci:�xiʢ��;g����zMNnb�wDtb�=+f{���hg� �SË–^=���3��M[� m�8���%7nJ�g��(q,«;tX���9 +�� �q �~�zy �".o����!�^��Z�pG���=?������5֤�_H�2NC +�~ޛ����C��m�6W���z.�剉�a:�G��[{Þ4�?>^.�� ����zr�Q�iN��HK���|ٲ��1M�T�[��'"�w���o@r�m�:��.�e��i����8n�\=�&���%�}Pc��yÛ�բ���hM�"(g6 +�Bn�W$�?� +�Z[�R�0}�7,� +��v�����i�f���Ҳ<�E��y!5 �|\Ό���m5C�X� �)'7^�iØ™I��ַ�D^�7.%F�Yl!m�y���٫�h$���щ���{��zN��X����_�)���N�o�h���y�U�+3��j�t���Lf�V%'kÊ€%�>��j��"w��7�d�";�����(��;��3����k� +1���3�SG��� +OJ��4(4}fG\��8�����Ԗ1�� +Zy�YÍš -|g����i�p���q����.=3���i +�8���h���l�.���+���4�������h ?����C�>�0p������8?��( +���� �0~L�'�����cx���Q<��O�}�?�i�1pp�Ť��L\��DF�Lx��Z���ߺ���/v�)q2{�� p(��@:0 ��+��}H����� X��C��}�Ro ��ww@M-?�#yd\fG~��A�p�A������}����[�����;b�(3�>a�a�ih��vv +��e�����8<Ó€�D`6p`��x��p � H�o}�6PƼ���Q�1]>��\���yF��u(�G�w����e���G��K��Gr�Bp�\0�|$Ϙ +N>�'�ã�?�l���N���̶� +^�����*�J~�7!m�oG�������=�����Y�V��U;Y�bV��Uc�ײ�VêcYu�~� +�+�YÆ®��Q���~�U�Yu2�Nb�]Y��f���c�*����L��@/��6�ã��xl�}x|��!=��+i��#�r����+�+�� +��:,�+�W0�+�-�#���~�4���N�ᷩg[<Ó€�l` p�*sN��L�V���FO�%� +> �����.a1a)aWh���lb�/����-?�]@;����5�_��R`f ���F]������u��e��H~..3���b�� +�d�:�ܪܟb$�G1|h������vGrϸ����;î·˜/ã¾ï¿½ï¿½`��y.�#�V�qGP�mw�1�Ľ�V���k�^]����%� +�w�-�dwÜ1c��Ǩ��p����qS�g�]��b��e�1��1�� +3���>��zÄ��c��(���j�ikYQFO�Z[�m�m�-���o��u�E�:���   +��@j}'3R���a��?3�H(>�˧��X�5��J����qSG�q��7G����XË‚p�ZG2o�8�3�;(e\��7�;0e��6���ݚ�Z/_Y�p��2��Z-��{��v��DK�m���<��pDԈ����κ�#�|�4�D��x׎�����%Ï›._��q޻�]vޟ�dg���4H^�m8�){��׆g�å«eÓ•��G�!b~Tr��K9�b +���\�C��$� �$%����r��]���w�d"ur+w��\�@d���L�j:�dt��2��J$&"�1J�u�%�:+��M"i��-�"�(Mk��1dBO�eBOB&�?�q�LIa;��9f�����l'��]��(�[=G×·;�����9�"I�No^�3��H�ҷ�y�晲yhb�v�����}f�3k�Ќ�ى����c&��B�-���M��`��`���1/�)w{��õSÑ<8��7�cX�p�C�G�����7�P@6���)���dS��g6E-��m1��P�.q$�x*Ý•���2�s�U�J�p���w?h��{[��C4��c�8��s��l�͗S���g�iT��r��ԴFAY7L�����IG�]P͟��2b���y�7v\G*�1o�{q]�ǃ;t������&�'9_?<�&g��cR�����h�A�*�^�t����:�vQm�9��B�jZL{�#��}KKh��W�ZN��@�4��h +��WI3鄸��UTJ�ڗ��w�o3=B{�7}�)�:����,��Q/����� vg�3�-Õ|�*h�6K0_��,��*� h<d�y +Fw��,�ݠ��(���W!C�����^֟��ñ–™¾ï¿½ï¿½:�è�h�Ƨ�^�OY��o�� u��4��E��~���҆���Rw��2z�ޠwY"{��YB,� ������i��1����/�g����Im��;���5:�:�46�M��yP��h�O���{1�qD�n�k�m��ڥ᤯ +V$���%�������>d_�Q|6����-�����TBkh���� 6�]� +l���cٻ���s�|~Z+�h/���Lnq��f�*�7 +� +�6���/�w3MF<,���Ѓ��:L��s�>g���#�������b��mR�Aï‚–w���[�@��:���[y����D^� ���~~�w�?�oZ����h��aZ�V�Vh���vJt��~N�����g���?|���� +԰�am�]�S�5�a�W�a�ގ�<��ZD���W�uf=�pv<3��c �u��2��=�l�=/}�N��P�lN���H>�k��/���N����i6-Xk�Eh=�1�,Í©y�E�Zͫ��}�}������ 'D�Hc�lQ)_��-3-o[��YK�7[k�?�3�6�6�6�v�m�타|�-*=C�6�U;�-ղ�g�V�Wt��!��l*��sD*��V��.��r�u(�&�����_��|�6��cSi�������Aȿ�=L�Bߋ�1�C�:k[�O[ChSo����)����v���F:*�X$��?�MB� �[r)^�������MT�q<�mE^�a��_��� ����t������+�/�@ҭԗ�@_ӣ��-����w�ޞ�".���ue��-c���������"��kO����)m�8c��n��i�o)-���Y!il:%���n7h�"t ��L����{�2��B�\���� ��{�'"È…=~5��!�e��ThiÃu��� +Sh��QZ�+�Rß� �`��������h [��'*Ǜ�'��WYF�ÖѾ^��§�-��NbQ�w|���4��Ո�h*���AtwC�]Gsp?������S߆ |�o�V����ɾ�|q,��|�4���Gl��RL����l��V8���} �p �p �p �p �p �p �p �p �p �/�3� ��S�6���/��Z�.�=YÄ—�ė�:X-_r�yÞ‡�:�JQ)ag��6!��a���������;�]|�$< �׵�����b��]�&"!OL�dDX-�6i"�3L�Z������~��J=H�A�CE��t��2����%�N;;k��_�(��ӆ�I�����7�It�PK�?�-��}�a� +�OJK6c� ʒ�= +�����'���� +A�� ����f�Ϊe�<�0BYX��2=tRh~hy���2kA�ٔY���JK`Ùˆa�g�)�����`�������_>o��=�(�qn4�y~<_ ��U��8�P�.���e��q�t�u�L�J��f��3_�2߲��?�$N�ז�,P��%��۲a:DGFG &:GG��#w�y����.�&����9×’xuØ´v��ψ�5���ѫ"��N����ۘ�suÖ¥m�4�S�c��6㿟���Ј�G|���Z@�f�Z�>���ExD.��a�7����ɉ �`+ـ���m�v�;ܰw˛��GGY��o�8��?�J�/7��tt�|����C��L� +�v<(�� �����u�W�pd�⭲>2Z�6U��?P����Fo���kd𢙌�Fo���kd����Fo���kd����Fo��䃚�7X�e��C�շQs�Z�ar.���o><�R���G�qL�c��N�� +�G+]Ƙ]���5�*�{�C�+���K>����t�4���%�Q99i.�����@)~<�Q)�1�t�Rx���ޥ$t��*�,Uo��)��2����X��/CÆï¿½ï¿½ï¿½ï¿½ï¿½>4������Um&z�NA�B��Q��`<7PA �,P6���I%��T@�)��Éw�C:z��r�Rꩴ����0Dz���Y�F�3(��%jDZ���r�:u�Hr +*�~0�Q�fc�G\7��Rq^a��5���5���|c] +�L�4�[S�2F���@�I��N�J�x<'B�\�~���t+o�������� +�Œ$?���h<�R�٨����c��l|ƫ� +� ���Ĵ�XoXl�\���M{�B�g^|P���HI������x��ZA��Q��1���T}�r���2C5�k#O����6sG��٘{�o�Lm2�,4s���S������c��1 :Í�l�;*Oy̼1׌���˿ۥǜ�Fi��+0�K���� +��+Sj�|��Lͪ����aT\�ٟCe����Z�Mo��\��t���/m��]�N�6�|���]YT�<+�-��o�����r�_����Ӯf�UE�W�F�fq�tG�}OI�J����*k1^�Z��j5�gn�,���g*����E��1�j�%f�6�o�r3>�2|���5��X5� W�Ç“g�Ӽ �1�����֠����F��+S���̫ �������x���{�i�5Z����.\G�[M7c���}�_1{+_��/Y��� 5��W���iÞ–=8!�#�S&��H���� +�y����^x���&��9�ƙ��՟8î‡ï¿½����5����DB�^��$�З�O�������w����� �e��Y��)�2���i����:��g��7x�?���B��� +Lų�ÜQ%߬�=�fw����zG��!�Z���g���>��(�?��J� Y���[Z�xl;gQ�s�����s������2��Qe�ev���T//v��Yv�����`�Բ�JY��ǖ�_���{��#=U�,.֧� +�q�~��Q��f�c�dg�Ϟ��S���{Z.��ì=j���++���-Rzd�K?�Y�/*��=2Ba]ei��>�J�5bÂ…h������ћ��[��S6Gn=���0Fz�J���픫S�txs��&�䲗:�� +��~XND��J���e؅�&t��o�����e�� �ŕ�9�J�QÕ¼w�>�T��"�,0'sq�%캻��p�u9.��/���}�.�ƈ� +��z�� +�[�ZU�*q� A���*���6[�,�B�T�)v����e��� +��T�t#�M�T��1vn��d�[P�t+5È•gE�9� +�n%�.*�,.@�.t9��w���V҉�QД��T2vx��XN�nZ=���*�;���z�!R`��L���mP�����}��ݯw���i�PÙ»O�~���w�>p@����y<�C�Ҫ��RK� �(+i�'�zV��J�[Fa�)es�C' g�!�������p���v�7�8�����ӊ<%�i%�;L+q϶�<�*+��U�b�:���,��~TÒ¸ ���`�����k�"��|�ߪ���}��,�+���h��� �>`��W{��Xvu1�O���-t9[������'ƈ�� i�zE,0�#E��6j��x�K� +u=�c�/0���endstream +endobj +9 0 obj +<< /Filter /FlateDecode /Length 247 >> +stream +x�]�Mk�0 ���:v�b�]��`�2 +9�e���d��6�sȿ�?J�� ��^Ѷ{@߃S=F����0�d,9p�F��_������D�;;:�4�#e�6�]���з�1;������?8�����qL�^��3-�}�S��m�4��G��u�4.^* �NH�B@sM!Z�/��aT�2��c�f�3��� =�*=U:W�Vj y�:��/��w��Qk�G9^1�W7����gU~�; z6endstream +endobj +10 0 obj +<< /Type /ObjStm /Length 459 /Filter /FlateDecode /N 6 /First 37 >> +stream +x�uQ�n�0��+�hÌ—(Qv\7F�$���P��H�JT���R�Z�P����,��� H8�T +\���S� �V�nn�>��<����3�q��F�9,�c�֟��WW� +2�}�7��sg��Tv���=�{�7�Zl���`�i�w���n�Pض4m��H��>�?��/][ݕ� +.�w@��0JFa��n-��������p�mv�w���j�Im��Vn�f�ҿ�y���6�@��rd:�/���t��`�X]�{��ǸG�f�����?��+F��A> /W [ 1 2 1 ] /Size 2 /ID [] >> +stream +x�cb&F �R +endstream +endobj + +startxref +216 +%%EOF +' because of error 'Filter: [?] can not be applied to primitives. Current context is: %PDF-1.5 +%���� +2 0 obj +<< /Linearized 1 /L 14631 /H [ 687 126 ] /O 6 /E 14356 /N 1 /T 14355 >> +endobj + +3 0 obj +<< /Type /XRef /Length 49 /Filter /FlateDecode /DecodeParms << /Columns 4 /Predictor 12 >> /W [ 1 2 1 ] /Index [ 2 15 ] /Info 11 0 R /Root 4 0 R /Size 17 /Prev 14356 /ID [] >> +stream +x�cbd�g`b`8 $���XF@���Zb�d +v�Xv L���@ ����0 +endstream +endobj + +4 0 obj +<< /Pages 12 0 R /Type /Catalog >> +endobj +5 0 obj +<< /Filter /FlateDecode /S 36 /Length 49 >> +stream +x�c```e``Z�&���fb�(H-30�g�c``�>������( +endstream +endobj +6 0 obj +<< /Contents 7 0 R /MediaBox [ 0 0 596 843 ] /Parent 12 0 R /Resources << /ExtGState << /G0 13 0 R >> /Font << /F0 14 0 R >> >> /StructParents 0 /Type /Page >> +endobj +7 0 obj +<< /Filter /FlateDecode /Length 200 >> +stream +x���� +�0 ��}���uI�4-����Y)��AA}0���I���~��KZÔ¨H��؞�� +������n{���E�����R�y�b�!�=���h��x/��<�f�;���`EB'�%z���l��;�6p�! M/E�g�>��;�#�v�d-�E��Eb!ÉŠp@�&�-��H�' +2023-09-06T14:29:49.502+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.['client.id'] =~ /([0-9]{10})/)]' failed to match document '%PDF-1.5 +%���� +2 0 obj +<< /Linearized 1 /L 14631 /H [ 687 126 ] /O 6 /E 14356 /N 1 /T 14355 >> +endobj + +3 0 obj +<< /Type /XRef /Length 49 /Filter /FlateDecode /DecodeParms << /Columns 4 /Predictor 12 >> /W [ 1 2 1 ] /Index [ 2 15 ] /Info 11 0 R /Root 4 0 R /Size 17 /Prev 14356 /ID [] >> +stream +x�cbd�g`b`8 $���XF@���Zb�d +v�Xv L���@ ����0 +endstream +endobj + +4 0 obj +<< /Pages 12 0 R /Type /Catalog >> +endobj +5 0 obj +<< /Filter /FlateDecode /S 36 /Length 49 >> +stream +x�c```e``Z�&���fb�(H-30�g�c``�>������( +endstream +endobj +6 0 obj +<< /Contents 7 0 R /MediaBox [ 0 0 596 843 ] /Parent 12 0 R /Resources << /ExtGState << /G0 13 0 R >> /Font << /F0 14 0 R >> >> /StructParents 0 /Type /Page >> +endobj +7 0 obj +<< /Filter /FlateDecode /Length 200 >> +stream +x���� +�0 ��}���uI�4-����Y)��AA}0���I���~��KZÔ¨H��؞�� +������n{���E�����R�y�b�!�=���h��x/��<�f�;���`EB'�%z���l��;�6p�! M/E�g�>��;�#�v�d-�E��Eb!ÉŠp@�&�-��H�W�2�6!yoч(�>)6O����Z�endstream +endobj +8 0 obj +<< /Filter /FlateDecode /Length1 29380 /Length 12131 >> +stream +x��} |TE�喙��Y!B �MB"H ì‹@"�L$M�I���q���e7@T�f.�(����,.�����8��~��{;������~�i����:U�ԩS��v�Q0U�F�%���]�o#��������}m�� ��DY{�-/,����_��Y��ŋ�.�퇶��׋�����ގ��"���V�?]�J<���� b��:l(.s�)����+P�\b��<�P�]hǘ���K�/��aDW�"�-�p���ω��t��������/��n;엀��?�������\���sO�/ p���gJO��� 4*��=��7l�Y��c�&k,��A��0J��D"z5�V� �/���n��ںP�e:�4�o�$�.�!�� +�nE9t�� �i� `0�lÖ��TY���c��quӌ�8*�L������7h.� �M� �bL%(oF�}�h��A��֭t/��G�u�梼�L��m�5�IR����g�9�˴�h�p�Na.y�J�f�:���#�� +Z���mB;(��+d=�e�+0�r��@��(��3찂��n� �;��i���Ƽ�7�HιqN�ߴ�B6�k�|H�}_�6��5nj��Z_��D��A*W���Y�"M�)�t�\���j�E�e�������g���k1���p���?��5�� ��0�R�A�����Ê�Tо�+C7����O�7(/źN��z�c�*0�R +K{�?M�\�;��0�_Bf��#0w���ì±ï¿½ï¿½8��Did���'A!m�CÅ™ ���q:V� � +|l�C�g�n�MЫ�xE���T�ذ��6��T�iì™ï¿½XRO�� �o"^�)���Yز�?��S2f�T��|��G9OS�{O|Gc� +j"��T�;�,��Z>�V��G�$cV���/2Ö”O�'L:��\{�=�%��~���}�H�h3�̷�AN�@W]��As��ҺS��7�0�z�w4%`?��ZNDy]+z����gÙyn�?����q�'�#�b����B�-�6�X���`��6I%���W��;�Z�!gn���r���|�{��� +�~��@5�# ��0��ڦQ�gP&2h�%���X��y��O���}��E�}ª����md�k�Ӡ�H7I��A˛�Q��kK~���T�|3��@���L|i�,� ��af�(�:�����x��k�Ϸ��U��l��[�gH�lM�ق��ߧ����e~�9N�H��d��˷�����c��� s_'��6~n�}�a���>�u��1�.�-Ü·Åš�c��{ ��L��5��iw�Yj�S�����3�mV��'�[��ӕ}�֧i������`�A�v����zZ�yt�V`?��)}�ւ(J� �L�îŸï¿½Y��nҎ� ���v�AW���T�TIe��j�d����4���T �J�C�#�>��B"�'�P�8d"(r�2�1��|܋� ��l�� ���mT}2(���f� �w_��AS�}�;z�2����h����i�s�c<�~Ó¤-��Y����5�_+��V"çŠï¿½�:m�s�:�U�G�(�R +�Ws�F�]!�����e�X�A���{�F�P�u>�A� �$��B�2���ػ����� �oA��;B�e�A�[��V�{)�=��oi�v%�Dg�?,�^8/b/�c@��Xm@Õ…��kat���K��Z0�V��{�Rr�键��N���a��F�imi�8@��ZZ-Ë¢=uӼ��.�-e�a�$���(�K3�0�_I�b6��툽(H��Z���V�IW�� �`_� m:�����=!唎]��%��K�ke��l���+���W�-셭�v�m��}j�r\��2�>�;���dІ�| +m6�Oi�6��-H0��h�p��'� +E��q��g7��?= ,��E�i���[: +,��/���|$ +�u�o�ۚC�X}sX��e���`?��K����@�q9� o��.���X��P�1[��']@T� � +�1��"�6���N��m� +0Ç›j��{��"���F����<�?7�� �%�{!�w�[���~~6� ��Q��b ���=��@8������ �C�����?�S�;�v���@oh��S�z�m���_�?�;3hE +?���s�����}~��O�� +�!����N"���.+����hR�����K��O��Y�_��Y�_A7���Z�=��{���ԑ��6NA \P.���;X�5( +��l ����62/;�|<�����iLÓ´@-Q[��h����!"&��b��K�E< ;�s��e����-?[C���8���|k�u�u��f����ǭO[ß±���<�7����� z�������C�a�p=K/ӗ����'�-���;�'�'ǧ���_O���`Mh����9!.�{BJ� �g"O K�O�$����!)*)&�kRϤ~I�����%�LZ�tW�Ƥ'�v$�Mz>�դ��'}����a��#���s��c�&�!g��>u�N�P7�nx]f]V���V��S竟s~����}�>����6(�m`O���<�:<��F��[�ݪ=,�h#&�k��b�X/6��D��X|c�Z���k9cz.ÞšaͿ����V�n�C��z���s=�t}��y��������M�ížk�uJ�5=��P�<���Mj���I��6z�<�1<7��s��y�0�9vF�1x�G� x.�nT���u�����ZW_����\���� �=��AK���`G�ED�ɪ�|VQ�e��ن�� +��������TLEt +����X���oן������_Wo���~I���?׻��}1���cƷ�'�����䲓���r� +�g�Փ5'o��X±�c���?���7G�:���u������xZ��v���O�>:�h�ѮG������^�M�Eۣ�l������k{���m��!�_�Z�[�v�9��eZ�����@���������h�i.�r+� nD��:�y���k����Ib�Y��{v��,�5�]W2�߶\բ��ô��k��Z��L��*z��͸"���7�]t�~�5�ZI/�1:M�V�'�D?�&z�ޤ��I�C�� +�9� +z������i.�G��]z� +���>��鯈�o�;��摋�S ���6P-�r� 7U�1]E��u��E�'�q�,m�%���i)���A{�Z�ƙ��PÕ³{�:���Gç©Y������`����6�@Ä‚Y�����+��a�����8�ʶ�'ؓ�)�,/��v���/:�j�*��=�v�gY- em����ea� ��t��g�s�y�:����"�������,�E���e�Xg� +{�E�օŲ�������� �t���M�;��f� gb��+Kb��0{����ge��p�ƺ��%}ŎЇt�>�O�(���3v��a?�������β_ٿ�o�Kau���g +�'�1�s�q�-��m<�� Ö‹����<����=��Ry���XoÉ£x'Þ™G�ޅ��8���<�'�>,�'���+O���2Þw�=x +_�o��Y����R�&m��B�E[�ݦݥݣ���������M{R{ZÛ®=���^�^�^���b����>�>�Ni_i�j�k�����'�O�3��������9^�� -X ���0����xLl���b�xB<�S�i����̻�3b�x���������'�������xM�.�o����xG��a�xO�/�*>Gć�#�R��O�QqL|&���8%>_�/�W�o�k��V�]|'�!�?����Q�$�)~��/ؗ��U�K�&Ή:�N;x +�G��nzoG;i�J��hr�Dm�6I��MÓ¦kWk��T-�~a_��b1=O��{��G�N6�nc�l!���]��j� +�{��X *�R����5�Lm�X&*E�X.���"�B����J�׉��q�� +'��L�OÜ;̓���+Ö‰�Cb�؈��a��6@��&��D�_3�o�vШ ��Ú¦mX���":FFu��%6N�OHìš”|Y��=Rz�JM��'�o����w�������lힽ�=�‹�����+����o�u��w:�.���_?8��G���c�?q��x��x��x��x��x��x��x��x�����3233F �|��!� +�߯oz��i��z�����䤮� �z\l���Î�";Fth�.�m�Ð����"4Ψgv��|ݛ��ɉW\�K��7�����Rƫ�+1��d$綒�0$3%Y�>����g'�ރY�z-�19����<�����+�v���G=;�(K��|=�;zaQMv~��4*q�3�WO� 6�72�|;���#��l� +���������^-)�^��497;+:>>�WO/�H��đ޶)J�F)5^�(�M��]r6�J��s���0���R�X`�����yRG����F^�eTS����]Ѽ5Z�Ɏr�XS�B�n��ۼ5^>��0����5��z5�8n�m|y^��-�J]�D�ʘ�31[���ӽ��#�j��ci:�xiʢ��;g����zMNnb�wDtb�=+f{���hg� �SË–^=���3��M[� m�8���%7nJ�g��(q,«;tX���9 +�� �q �~�zy �".o����!�^��Z�pG���=?������5֤�_H�2NC +�~ޛ����C��m�6W���z.�剉�a:�G��[{Þ4�?>^.�� ����zr�Q�iN��HK���|ٲ��1M�T�[��'"�w���o@r�m�:��.�e��i����8n�\=�&���%�}Pc��yÛ�բ���hM�"(g6 +�Bn�W$�?� +�Z[�R�0}�7,� +��v�����i�f���Ҳ<�E��y!5 �|\Ό���m5C�X� �)'7^�iØ™I��ַ�D^�7.%F�Yl!m�y���٫�h$���щ���{��zN��X����_�)���N�o�h���y�U�+3��j�t���Lf�V%'kÊ€%�>��j��"w��7�d�";�����(��;��3����k� +1���3�SG��� +OJ��4(4}fG\��8�����Ԗ1�� +Zy�YÍš -|g����i�p���q����.=3���i +�8���h���l�.���+���4�������h ?����C�>�0p������8?��( +���� �0~L�'�����cx���Q<��O�}�?�i�1pp�Ť��L\��DF�Lx��Z���ߺ���/v�)q2{�� p(��@:0 ��+��}H����� X��C��}�Ro ��ww@M-?�#yd\fG~��A�p�A������}����[�����;b�(3�>a�a�ih��vv +��e�����8<Ó€�D`6p`��x��p � H�o}�6PƼ���Q�1]>��\���yF��u(�G�w����e���G��K��Gr�Bp�\0�|$Ϙ +N>�'�ã�?�l���N���̶� +^�����*�J~�7!m�oG�������=�����Y�V��U;Y�bV��Uc�ײ�VêcYu�~� +�+�YÆ®��Q���~�U�Yu2�Nb�]Y��f���c�*����L��@/��6�ã��xl�}x|��!=��+i��#�r����+�+�� +��:,�+�W0�+�-�#���~�4���N�ᷩg[<Ó€�l` p�*sN��L�V���FO�%� +> �����.a1a)aWh���lb�/����-?�]@;����5�_��R`f ���F]������u��e��H~..3���b�� +�d�:�ܪܟb$�G1|h������vGrϸ����;î·˜/ã¾ï¿½ï¿½`��y.�#�V�qGP�mw�1�Ľ�V���k�^]����%� +�w�-�dwÜ1c��Ǩ��p����qS�g�]��b��e�1��1�� +3���>��zÄ��c��(���j�ikYQFO�Z[�m�m�-���o��u�E�:���   +��@j}'3R���a��?3�H(>�˧��X�5��J����qSG�q��7G����XË‚p�ZG2o�8�3�;(e\��7�;0e��6���ݚ�Z/_Y�p��2��Z-��{��v��DK�m���<��pDԈ����κ�#�|�4�D��x׎�����%Ï›._��q޻�]vޟ�dg���4H^�m8�){��׆g�å«eÓ•��G�!b~Tr��K9�b +���\�C��$� �$%����r��]���w�d"ur+w��\�@d���L�j:�dt��2��J$&"�1J�u�%�:+��M"i��-�"�(Mk��1dBO�eBOB&�?�q�LIa;��9f�����l'��]��(�[=G×·;�����9�"I�No^�3��H�ҷ�y�晲yhb�v�����}f�3k�Ќ�ى����c&��B�-���M��`��`���1/�)w{��õSÑ<8��7�cX�p�C�G�����7�P@6���)���dS��g6E-��m1��P�.q$�x*Ý•���2�s�U�J�p���w?h��{[��C4��c�8��s��l�͗S���g�iT��r��ԴFAY7L�����IG�]P͟��2b���y�7v\G*�1o�{q]�ǃ;t������&�'9_?<�&g��cR�����h�A�*�^�t����:�vQm�9��B�jZL{�#��}KKh��W�ZN��@�4��h +��WI3鄸��UTJ�ڗ��w�o3=B{�7}�)�:����,��Q/����� vg�3�-Õ|�*h�6K0_��,��*� h<d�y +Fw��,�ݠ��(���W!C�����^֟��ñ–™¾ï¿½ï¿½:�è�h�Ƨ�^�OY��o�� u��4��E��~���҆���Rw��2z�ޠwY"{��YB,� ������i��1����/�g����Im��;���5:�:�46�M��yP��h�O���{1�qD�n�k�m��ڥ᤯ +V$���%�������>d_�Q|6����-�����TBkh���� 6�]� +l���cٻ���s�|~Z+�h/���Lnq��f�*�7 +� +�6���/�w3MF<,���Ѓ��:L��s�>g���#�������b��mR�Aï‚–w���[�@��:���[y����D^� ���~~�w�?�oZ����h��aZ�V�Vh���vJt��~N�����g���?|���� +԰�am�]�S�5�a�W�a�ގ�<��ZD���W�uf=�pv<3��c �u��2��=�l�=/}�N��P�lN���H>�k��/���N����i6-Xk�Eh=�1�,Í©y�E�Zͫ��}�}������ 'D�Hc�lQ)_��-3-o[��YK�7[k�?�3�6�6�6�v�m�타|�-*=C�6�U;�-ղ�g�V�Wt��!��l*��sD*��V��.��r�u(�&�����_��|�6��cSi�������Aȿ�=L�Bߋ�1�C�:k[�O[ChSo����)����v���F:*�X$��?�MB� �[r)^�������MT�q<�mE^�a��_��� ����t������+�/�@ҭԗ�@_ӣ��-����w�ޞ�".���ue��-c���������"��kO����)m�8c��n��i�o)-���Y!il:%���n7h�"t ��L����{�2��B�\���� ��{�'"È…=~5��!�e��ThiÃu��� +Sh��QZ�+�Rß� �`��������h [��'*Ǜ�'��WYF�ÖѾ^��§�-��NbQ�w|���4��Ո�h*���AtwC�]Gsp?������S߆ |�o�V����ɾ�|q,��|�4���Gl��RL����l��V8���} �p �p �p �p �p �p �p �p �p �/�3� ��S�6���/��Z�.�=YÄ—�ė�:X-_r�yÞ‡�:�JQ)ag��6!��a���������;�]|�$< �׵�����b��]�&"!OL�dDX-�6i"�3L�Z������~��J=H�A�CE��t��2����%�N;;k��_�(��ӆ�I�����7�It�PK�?�-��}�a� +�OJK6c� ʒ�= +�����'���� +A�� ����f�Ϊe�<�0BYX��2=tRh~hy���2kA�ٔY���JK`Ùˆa�g�)�����`�������_>o��=�(�qn4�y~<_ ��U��8�P�.���e��q�t�u�L�J��f��3_�2߲��?�$N�ז�,P��%��۲a:DGFG &:GG��#w�y����.�&����9×’xuØ´v��ψ�5���ѫ"��N����ۘ�suÖ¥m�4�S�c��6㿟���Ј�G|���Z@�f�Z�>���ExD.��a�7����ɉ �`+ـ���m�v�;ܰw˛��GGY��o�8��?�J�/7��tt�|����C��L� +�v<(�� �����u�W�pd�⭲>2Z�6U��?P����Fo���kd𢙌�Fo���kd����Fo���kd����Fo��䃚�7X�e��C�շQs�Z�ar.���o><�R���G�qL�c��N�� +�G+]Ƙ]���5�*�{�C�+���K>����t�4���%�Q99i.�����@)~<�Q)�1�t�Rx���ޥ$t��*�,Uo��)��2����X��/CÆï¿½ï¿½ï¿½ï¿½ï¿½>4������Um&z�NA�B��Q��`<7PA �,P6���I%��T@�)��Éw�C:z��r�Rꩴ����0Dz���Y�F�3(��%jDZ���r�:u�Hr +*�~0�Q�fc�G\7��Rq^a��5���5���|c] +�L�4�[S�2F���@�I��N�J�x<'B�\�~���t+o�������� +�Œ$?���h<�R�٨����c��l|ƫ� +� ���Ĵ�XoXl�\���M{�B�g^|P���HI������x��ZA��Q��1���T}�r���2C5�k#O����6sG��٘{�o�Lm2�,4s���S������c��1 :Í�l�;*Oy̼1׌���˿ۥǜ�Fi��+0�K���� +��+Sj�|��Lͪ����aT\�ٟCe����Z�Mo��\��t���/m��]�N�6�|���]YT�<+�-��o�����r�_����Ӯf�UE�W�F�fq�tG�}OI�J����*k1^�Z��j5�gn�,���g*����E��1�j�%f�6�o�r3>�2|���5��X5� W�Ç“g�Ӽ �1�����֠����F��+S���̫ �������x���{�i�5Z����.\G�[M7c���}�_1{+_��/Y��� 5��W���iÞ–=8!�#�S&��H���� +�y����^x���&��9�ƙ��՟8î‡ï¿½����5����DB�^��$�З�O�������w����� �e��Y��)�2���i����:��g��7x�?���B��� +Lų�ÜQ%߬�=�fw����zG��!�Z���g���>��(�?��J� Y���[Z�xl;gQ�s�����s������2��Qe�ev���T//v��Yv�����`�Բ�JY��ǖ�_���{��#=U�,.֧� +�q�~��Q��f�c�dg�Ϟ��S���{Z.��ì=j���++���-Rzd�K?�Y�/*��=2Ba]ei��>�J�5bÂ…h������ћ��[��S6Gn=���0Fz�J���픫S�txs��&�䲗:�� +��~XND��J���e؅�&t��o�����e�� �ŕ�9�J�QÕ¼w�>�T��"�,0'sq�%캻��p�u9.��/���}�.�ƈ� +��z�� +�[�ZU�*q� A���*���6[�,�B�T�)v����e��� +��T�t#�M�T��1vn��d�[P�t+5È•gE�9� +�n%�.*�,.@�.t9��w���V҉�QД��T2vx��XN�nZ=���*�;���z�!R`��L���mP�����}��ݯw���i�PÙ»O�~���w�>p@����y<�C�Ҫ��RK� �(+i�'�zV��J�[Fa�)es�C' g�!�������p���v�7�8�����ӊ<%�i%�;L+q϶�<�*+��U�b�:���,��~TÒ¸ ���`�����k�"��|�ߪ���}��,�+���h��� �>`��W{��Xvu1�O���-t9[������'ƈ�� i�zE,0�#E��6j��x�K� +u=�c�/0���endstream +endobj +9 0 obj +<< /Filter /FlateDecode /Length 247 >> +stream +x�]�Mk�0 ���:v�b�]��`�2 +9�e���d��6�sȿ�?J�� ��^Ѷ{@߃S=F����0�d,9p�F��_������D�;;:�4�#e�6�]���з�1;������?8�����qL�^��3-�}�S��m�4��G��u�4.^* �NH�B@sM!Z�/��aT�2��c�f�3��� =�*=U:W�Vj y�:��/��w��Qk�G9^1�W7����gU~�; z6endstream +endobj +10 0 obj +<< /Type /ObjStm /Length 459 /Filter /FlateDecode /N 6 /First 37 >> +stream +x�uQ�n�0��+�hÌ—(Qv\7F�$���P��H�JT���R�Z�P����,��� H8�T +\���S� �V�nn�>��<����3�q��F�9,�c�֟��WW� +2�}�7��sg��Tv���=�{�7�Zl���`�i�w���n�Pض4m��H��>�?��/][ݕ� +.�w@��0JFa��n-��������p�mv�w���j�Im��Vn�f�ҿ�y���6�@��rd:�/���t��`�X]�{��ǸG�f�����?��+F��A> /W [ 1 2 1 ] /Size 2 /ID [] >> +stream +x�cb&F �R +endstream +endobj + +startxref +216 +%%EOF +' because of error 'Filter: [?] can not be applied to primitives. Current context is: %PDF-1.5 +%���� +2 0 obj +<< /Linearized 1 /L 14631 /H [ 687 126 ] /O 6 /E 14356 /N 1 /T 14355 >> +endobj + +3 0 obj +<< /Type /XRef /Length 49 /Filter /FlateDecode /DecodeParms << /Columns 4 /Predictor 12 >> /W [ 1 2 1 ] /Index [ 2 15 ] /Info 11 0 R /Root 4 0 R /Size 17 /Prev 14356 /ID [] >> +stream +x�cbd�g`b`8 $���XF@���Zb�d +v�Xv L���@ ����0 +endstream +endobj + +4 0 obj +<< /Pages 12 0 R /Type /Catalog >> +endobj +5 0 obj +<< /Filter /FlateDecode /S 36 /Length 49 >> +stream +x�c```e``Z�&���fb�(H-30�g�c``�>������( +endstream +endobj +6 0 obj +<< /Contents 7 0 R /MediaBox [ 0 0 596 843 ] /Parent 12 0 R /Resources << /ExtGState << /G0 13 0 R >> /Font << /F0 14 0 R >> >> /StructParents 0 /Type /Page >> +endobj +7 0 obj +<< /Filter /FlateDecode /Length 200 >> +stream +x���� +�0 ��}���uI�4-����Y)��AA}0���I���~��KZÔ¨H��؞�� +������n{���E�����R�y�b�!�=���h��x/��<�f�;���`EB'�%z���l��;�6p�! M/E�g�>��;�#�v�d-�E��Eb!ÉŠp@�&�-��H�' +2023-09-06T14:29:49.506+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Request received: +127.0.0.1 - PUT /1 + +Accept: [application/octet-stream, application/json, application/*+json, */*] +Content-Type: [application/octet-stream] +User-Agent: [Java/17.0.1] +Host: [localhost:11276] +Connection: [keep-alive] +Content-Length: [14631] +%PDF-1.5 +%���� +2 0 obj +<< /Linearized 1 /L 14631 /H [ 687 126 ] /O 6 /E 14356 /N 1 /T 14355 >> +endobj + +3 0 obj +<< /Type /XRef /Length 49 /Filter /FlateDecode /DecodeParms << /Columns 4 /Predictor 12 >> /W [ 1 2 1 ] /Index [ 2 15 ] /Info 11 0 R /Root 4 0 R /Size 17 /Prev 14356 /ID [] >> +stream +x�cbd�g`b`8 $���XF@���Zb�d +v�Xv L���@ ����0 +endstream +endobj + +4 0 obj +<< /Pages 12 0 R /Type /Catalog >> +endobj +5 0 obj +<< /Filter /FlateDecode /S 36 /Length 49 >> +stream +x�c```e``Z�&���fb�(H-30�g�c``�>������( +endstream +endobj +6 0 obj +<< /Contents 7 0 R /MediaBox [ 0 0 596 843 ] /Parent 12 0 R /Resources << /ExtGState << /G0 13 0 R >> /Font << /F0 14 0 R >> >> /StructParents 0 /Type /Page >> +endobj +7 0 obj +<< /Filter /FlateDecode /Length 200 >> +stream +x���� +�0 ��}���uI�4-����Y)��AA}0���I���~��KZÔ¨H��؞�� +������n{���E�����R�y�b�!�=���h��x/��<�f�;���`EB'�%z���l��;�6p�! M/E�g�>��;�#�v�d-�E��Eb!ÉŠp@�&�-��H�W�2�6!yoч(�>)6O����Z�endstream +endobj +8 0 obj +<< /Filter /FlateDecode /Length1 29380 /Length 12131 >> +stream +x��} |TE�喙��Y!B �MB"H ì‹@"�L$M�I���q���e7@T�f.�(����,.�����8��~��{;������~�i����:U�ԩS��v�Q0U�F�%���]�o#��������}m�� ��DY{�-/,����_��Y��ŋ�.�퇶��׋�����ގ��"���V�?]�J<���� b��:l(.s�)����+P�\b��<�P�]hǘ���K�/��aDW�"�-�p���ω��t��������/��n;엀��?�������\���sO�/ p���gJO��� 4*��=��7l�Y��c�&k,��A��0J��D"z5�V� �/���n��ںP�e:�4�o�$�.�!�� +�nE9t�� �i� `0�lÖ��TY���c��quӌ�8*�L������7h.� �M� �bL%(oF�}�h��A��֭t/��G�u�梼�L��m�5�IR����g�9�˴�h�p�Na.y�J�f�:���#�� +Z���mB;(��+d=�e�+0�r��@��(��3찂��n� �;��i���Ƽ�7�HιqN�ߴ�B6�k�|H�}_�6��5nj��Z_��D��A*W���Y�"M�)�t�\���j�E�e�������g���k1���p���?��5�� ��0�R�A�����Ê�Tо�+C7����O�7(/źN��z�c�*0�R +K{�?M�\�;��0�_Bf��#0w���ì±ï¿½ï¿½8��Did���'A!m�CÅ™ ���q:V� � +|l�C�g�n�MЫ�xE���T�ذ��6��T�iì™ï¿½XRO�� �o"^�)���Yز�?��S2f�T��|��G9OS�{O|Gc� +j"��T�;�,��Z>�V��G�$cV���/2Ö”O�'L:��\{�=�%��~���}�H�h3�̷�AN�@W]��As��ҺS��7�0�z�w4%`?��ZNDy]+z����gÙyn�?����q�'�#�b����B�-�6�X���`��6I%���W��;�Z�!gn���r���|�{��� +�~��@5�# ��0��ڦQ�gP&2h�%���X��y��O���}��E�}ª����md�k�Ӡ�H7I��A˛�Q��kK~���T�|3��@���L|i�,� ��af�(�:�����x��k�Ϸ��U��l��[�gH�lM�ق��ߧ����e~�9N�H��d��˷�����c��� s_'��6~n�}�a���>�u��1�.�-Ü·Åš�c��{ ��L��5��iw�Yj�S�����3�mV��'�[��ӕ}�֧i������`�A�v����zZ�yt�V`?��)}�ւ(J� �L�îŸï¿½Y��nҎ� ���v�AW���T�TIe��j�d����4���T �J�C�#�>��B"�'�P�8d"(r�2�1��|܋� ��l�� ���mT}2(���f� �w_��AS�}�;z�2����h����i�s�c<�~Ó¤-��Y����5�_+��V"çŠï¿½�:m�s�:�U�G�(�R +�Ws�F�]!�����e�X�A���{�F�P�u>�A� �$��B�2���ػ����� �oA��;B�e�A�[��V�{)�=��oi�v%�Dg�?,�^8/b/�c@��Xm@Õ…��kat���K��Z0�V��{�Rr�键��N���a��F�imi�8@��ZZ-Ë¢=uӼ��.�-e�a�$���(�K3�0�_I�b6��툽(H��Z���V�IW�� �`_� m:�����=!唎]��%��K�ke��l���+���W�-셭�v�m��}j�r\��2�>�;���dІ�| +m6�Oi�6��-H0��h�p��'� +E��q��g7��?= ,��E�i���[: +,��/���|$ +�u�o�ۚC�X}sX��e���`?��K����@�q9� o��.���X��P�1[��']@T� � +�1��"�6���N��m� +0Ç›j��{��"���F����<�?7�� �%�{!�w�[���~~6� ��Q��b ���=��@8������ �C�����?�S�;�v���@oh��S�z�m���_�?�;3hE +?���s�����}~��O�� +�!����N"���.+����hR�����K��O��Y�_��Y�_A7���Z�=��{���ԑ��6NA \P.���;X�5( +��l ����62/;�|<�����iLÓ´@-Q[��h����!"&��b��K�E< ;�s��e����-?[C���8���|k�u�u��f����ǭO[ß±���<�7����� z�������C�a�p=K/ӗ����'�-���;�'�'ǧ���_O���`Mh����9!.�{BJ� �g"O K�O�$����!)*)&�kRϤ~I�����%�LZ�tW�Ƥ'�v$�Mz>�դ��'}����a��#���s��c�&�!g��>u�N�P7�nx]f]V���V��S竟s~����}�>����6(�m`O���<�:<��F��[�ݪ=,�h#&�k��b�X/6��D��X|c�Z���k9cz.ÞšaͿ����V�n�C��z���s=�t}��y��������M�ížk�uJ�5=��P�<���Mj���I��6z�<�1<7��s��y�0�9vF�1x�G� x.�nT���u�����ZW_����\���� �=��AK���`G�ED�ɪ�|VQ�e��ن�� +��������TLEt +����X���oן������_Wo���~I���?׻��}1���cƷ�'�����䲓���r� +�g�Փ5'o��X±�c���?���7G�:���u������xZ��v���O�>:�h�ѮG������^�M�Eۣ�l������k{���m��!�_�Z�[�v�9��eZ�����@���������h�i.�r+� nD��:�y���k����Ib�Y��{v��,�5�]W2�߶\բ��ô��k��Z��L��*z��͸"���7�]t�~�5�ZI/�1:M�V�'�D?�&z�ޤ��I�C�� +�9� +z������i.�G��]z� +���>��鯈�o�;��摋�S ���6P-�r� 7U�1]E��u��E�'�q�,m�%���i)���A{�Z�ƙ��PÕ³{�:���Gç©Y������`����6�@Ä‚Y�����+��a�����8�ʶ�'ؓ�)�,/��v���/:�j�*��=�v�gY- em����ea� ��t��g�s�y�:����"�������,�E���e�Xg� +{�E�օŲ�������� �t���M�;��f� gb��+Kb��0{����ge��p�ƺ��%}ŎЇt�>�O�(���3v��a?�������β_ٿ�o�Kau���g +�'�1�s�q�-��m<�� Ö‹����<����=��Ry���XoÉ£x'Þ™G�ޅ��8���<�'�>,�'���+O���2Þw�=x +_�o��Y����R�&m��B�E[�ݦݥݣ���������M{R{ZÛ®=���^�^�^���b����>�>�Ni_i�j�k�����'�O�3��������9^�� -X ���0����xLl���b�xB<�S�i����̻�3b�x���������'�������xM�.�o����xG��a�xO�/�*>Gć�#�R��O�QqL|&���8%>_�/�W�o�k��V�]|'�!�?����Q�$�)~��/ؗ��U�K�&Ή:�N;x +�G��nzoG;i�J��hr�Dm�6I��MÓ¦kWk��T-�~a_��b1=O��{��G�N6�nc�l!���]��j� +�{��X *�R����5�Lm�X&*E�X.���"�B����J�׉��q�� +'��L�OÜ;̓���+Ö‰�Cb�؈��a��6@��&��D�_3�o�vШ ��Ú¦mX���":FFu��%6N�OHìš”|Y��=Rz�JM��'�o����w�������lힽ�=�‹�����+����o�u��w:�.���_?8��G���c�?q��x��x��x��x��x��x��x��x�����3233F �|��!� +�߯oz��i��z�����䤮� �z\l���Î�";Fth�.�m�Ð����"4Ψgv��|ݛ��ɉW\�K��7�����Rƫ�+1��d$綒�0$3%Y�>����g'�ރY�z-�19����<�����+�v���G=;�(K��|=�;zaQMv~��4*q�3�WO� 6�72�|;���#��l� +���������^-)�^��497;+:>>�WO/�H��đ޶)J�F)5^�(�M��]r6�J��s���0���R�X`�����yRG����F^�eTS����]Ѽ5Z�Ɏr�XS�B�n��ۼ5^>��0����5��z5�8n�m|y^��-�J]�D�ʘ�31[���ӽ��#�j��ci:�xiʢ��;g����zMNnb�wDtb�=+f{���hg� �SË–^=���3��M[� m�8���%7nJ�g��(q,«;tX���9 +�� �q �~�zy �".o����!�^��Z�pG���=?������5֤�_H�2NC +�~ޛ����C��m�6W���z.�剉�a:�G��[{Þ4�?>^.�� ����zr�Q�iN��HK���|ٲ��1M�T�[��'"�w���o@r�m�:��.�e��i����8n�\=�&���%�}Pc��yÛ�բ���hM�"(g6 +�Bn�W$�?� +�Z[�R�0}�7,� +��v�����i�f���Ҳ<�E��y!5 �|\Ό���m5C�X� �)'7^�iØ™I��ַ�D^�7.%F�Yl!m�y���٫�h$���щ���{��zN��X����_�)���N�o�h���y�U�+3��j�t���Lf�V%'kÊ€%�>��j��"w��7�d�";�����(��;��3����k� +1���3�SG��� +OJ��4(4}fG\��8�����Ԗ1�� +Zy�YÍš -|g����i�p���q����.=3���i +�8���h���l�.���+���4�������h ?����C�>�0p������8?��( +���� �0~L�'�����cx���Q<��O�}�?�i�1pp�Ť��L\��DF�Lx��Z���ߺ���/v�)q2{�� p(��@:0 ��+��}H����� X��C��}�Ro ��ww@M-?�#yd\fG~��A�p�A������}����[�����;b�(3�>a�a�ih��vv +��e�����8<Ó€�D`6p`��x��p � H�o}�6PƼ���Q�1]>��\���yF��u(�G�w����e���G��K��Gr�Bp�\0�|$Ϙ +N>�'�ã�?�l���N���̶� +^�����*�J~�7!m�oG�������=�����Y�V��U;Y�bV��Uc�ײ�VêcYu�~� +�+�YÆ®��Q���~�U�Yu2�Nb�]Y��f���c�*����L��@/��6�ã��xl�}x|��!=��+i��#�r����+�+�� +��:,�+�W0�+�-�#���~�4���N�ᷩg[<Ó€�l` p�*sN��L�V���FO�%� +> �����.a1a)aWh���lb�/����-?�]@;����5�_��R`f ���F]������u��e��H~..3���b�� +�d�:�ܪܟb$�G1|h������vGrϸ����;î·˜/ã¾ï¿½ï¿½`��y.�#�V�qGP�mw�1�Ľ�V���k�^]����%� +�w�-�dwÜ1c��Ǩ��p����qS�g�]��b��e�1��1�� +3���>��zÄ��c��(���j�ikYQFO�Z[�m�m�-���o��u�E�:���   +��@j}'3R���a��?3�H(>�˧��X�5��J����qSG�q��7G����XË‚p�ZG2o�8�3�;(e\��7�;0e��6���ݚ�Z/_Y�p��2��Z-��{��v��DK�m���<��pDԈ����κ�#�|�4�D��x׎�����%Ï›._��q޻�]vޟ�dg���4H^�m8�){��׆g�å«eÓ•��G�!b~Tr��K9�b +���\�C��$� �$%����r��]���w�d"ur+w��\�@d���L�j:�dt��2��J$&"�1J�u�%�:+��M"i��-�"�(Mk��1dBO�eBOB&�?�q�LIa;��9f�����l'��]��(�[=G×·;�����9�"I�No^�3��H�ҷ�y�晲yhb�v�����}f�3k�Ќ�ى����c&��B�-���M��`��`���1/�)w{��õSÑ<8��7�cX�p�C�G�����7�P@6���)���dS��g6E-��m1��P�.q$�x*Ý•���2�s�U�J�p���w?h��{[��C4��c�8��s��l�͗S���g�iT��r��ԴFAY7L�����IG�]P͟��2b���y�7v\G*�1o�{q]�ǃ;t������&�'9_?<�&g��cR�����h�A�*�^�t����:�vQm�9��B�jZL{�#��}KKh��W�ZN��@�4��h +��WI3鄸��UTJ�ڗ��w�o3=B{�7}�)�:����,��Q/����� vg�3�-Õ|�*h�6K0_��,��*� h<d�y +Fw��,�ݠ��(���W!C�����^֟��ñ–™¾ï¿½ï¿½:�è�h�Ƨ�^�OY��o�� u��4��E��~���҆���Rw��2z�ޠwY"{��YB,� ������i��1����/�g����Im��;���5:�:�46�M��yP��h�O���{1�qD�n�k�m��ڥ᤯ +V$���%�������>d_�Q|6����-�����TBkh���� 6�]� +l���cٻ���s�|~Z+�h/���Lnq��f�*�7 +� +�6���/�w3MF<,���Ѓ��:L��s�>g���#�������b��mR�Aï‚–w���[�@��:���[y����D^� ���~~�w�?�oZ����h��aZ�V�Vh���vJt��~N�����g���?|���� +԰�am�]�S�5�a�W�a�ގ�<��ZD���W�uf=�pv<3��c �u��2��=�l�=/}�N��P�lN���H>�k��/���N����i6-Xk�Eh=�1�,Í©y�E�Zͫ��}�}������ 'D�Hc�lQ)_��-3-o[��YK�7[k�?�3�6�6�6�v�m�타|�-*=C�6�U;�-ղ�g�V�Wt��!��l*��sD*��V��.��r�u(�&�����_��|�6��cSi�������Aȿ�=L�Bߋ�1�C�:k[�O[ChSo����)����v���F:*�X$��?�MB� �[r)^�������MT�q<�mE^�a��_��� ����t������+�/�@ҭԗ�@_ӣ��-����w�ޞ�".���ue��-c���������"��kO����)m�8c��n��i�o)-���Y!il:%���n7h�"t ��L����{�2��B�\���� ��{�'"È…=~5��!�e��ThiÃu��� +Sh��QZ�+�Rß� �`��������h [��'*Ǜ�'��WYF�ÖѾ^��§�-��NbQ�w|���4��Ո�h*���AtwC�]Gsp?������S߆ |�o�V����ɾ�|q,��|�4���Gl��RL����l��V8���} �p �p �p �p �p �p �p �p �p �/�3� ��S�6���/��Z�.�=YÄ—�ė�:X-_r�yÞ‡�:�JQ)ag��6!��a���������;�]|�$< �׵�����b��]�&"!OL�dDX-�6i"�3L�Z������~��J=H�A�CE��t��2����%�N;;k��_�(��ӆ�I�����7�It�PK�?�-��}�a� +�OJK6c� ʒ�= +�����'���� +A�� ����f�Ϊe�<�0BYX��2=tRh~hy���2kA�ٔY���JK`Ùˆa�g�)�����`�������_>o��=�(�qn4�y~<_ ��U��8�P�.���e��q�t�u�L�J��f��3_�2߲��?�$N�ז�,P��%��۲a:DGFG &:GG��#w�y����.�&����9×’xuØ´v��ψ�5���ѫ"��N����ۘ�suÖ¥m�4�S�c��6㿟���Ј�G|���Z@�f�Z�>���ExD.��a�7����ɉ �`+ـ���m�v�;ܰw˛��GGY��o�8��?�J�/7��tt�|����C��L� +�v<(�� �����u�W�pd�⭲>2Z�6U��?P����Fo���kd𢙌�Fo���kd����Fo���kd����Fo��䃚�7X�e��C�շQs�Z�ar.���o><�R���G�qL�c��N�� +�G+]Ƙ]���5�*�{�C�+���K>����t�4���%�Q99i.�����@)~<�Q)�1�t�Rx���ޥ$t��*�,Uo��)��2����X��/CÆï¿½ï¿½ï¿½ï¿½ï¿½>4������Um&z�NA�B��Q��`<7PA �,P6���I%��T@�)��Éw�C:z��r�Rꩴ����0Dz���Y�F�3(��%jDZ���r�:u�Hr +*�~0�Q�fc�G\7��Rq^a��5���5���|c] +�L�4�[S�2F���@�I��N�J�x<'B�\�~���t+o�������� +�Œ$?���h<�R�٨����c��l|ƫ� +� ���Ĵ�XoXl�\���M{�B�g^|P���HI������x��ZA��Q��1���T}�r���2C5�k#O����6sG��٘{�o�Lm2�,4s���S������c��1 :Í�l�;*Oy̼1׌���˿ۥǜ�Fi��+0�K���� +��+Sj�|��Lͪ����aT\�ٟCe����Z�Mo��\��t���/m��]�N�6�|���]YT�<+�-��o�����r�_����Ӯf�UE�W�F�fq�tG�}OI�J����*k1^�Z��j5�gn�,���g*����E��1�j�%f�6�o�r3>�2|���5��X5� W�Ç“g�Ӽ �1�����֠����F��+S���̫ �������x���{�i�5Z����.\G�[M7c���}�_1{+_��/Y��� 5��W���iÞ–=8!�#�S&��H���� +�y����^x���&��9�ƙ��՟8î‡ï¿½����5����DB�^��$�З�O�������w����� �e��Y��)�2���i����:��g��7x�?���B��� +Lų�ÜQ%߬�=�fw����zG��!�Z���g���>��(�?��J� Y���[Z�xl;gQ�s�����s������2��Qe�ev���T//v��Yv�����`�Բ�JY��ǖ�_���{��#=U�,.֧� +�q�~��Q��f�c�dg�Ϟ��S���{Z.��ì=j���++���-Rzd�K?�Y�/*��=2Ba]ei��>�J�5bÂ…h������ћ��[��S6Gn=���0Fz�J���픫S�txs��&�䲗:�� +��~XND��J���e؅�&t��o�����e�� �ŕ�9�J�QÕ¼w�>�T��"�,0'sq�%캻��p�u9.��/���}�.�ƈ� +��z�� +�[�ZU�*q� A���*���6[�,�B�T�)v����e��� +��T�t#�M�T��1vn��d�[P�t+5È•gE�9� +�n%�.*�,.@�.t9��w���V҉�QД��T2vx��XN�nZ=���*�;���z�!R`��L���mP�����}��ݯw���i�PÙ»O�~���w�>p@����y<�C�Ҫ��RK� �(+i�'�zV��J�[Fa�)es�C' g�!�������p���v�7�8�����ӊ<%�i%�;L+q϶�<�*+��U�b�:���,��~TÒ¸ ���`�����k�"��|�ߪ���}��,�+���h��� �>`��W{��Xvu1�O���-t9[������'ƈ�� i�zE,0�#E��6j��x�K� +u=�c�/0���endstream +endobj +9 0 obj +<< /Filter /FlateDecode /Length 247 >> +stream +x�]�Mk�0 ���:v�b�]��`�2 +9�e���d��6�sȿ�?J�� ��^Ѷ{@߃S=F����0�d,9p�F��_������D�;;:�4�#e�6�]���з�1;������?8�����qL�^��3-�}�S��m�4��G��u�4.^* �NH�B@sM!Z�/��aT�2��c�f�3��� =�*=U:W�Vj y�:��/��w��Qk�G9^1�W7����gU~�; z6endstream +endobj +10 0 obj +<< /Type /ObjStm /Length 459 /Filter /FlateDecode /N 6 /First 37 >> +stream +x�uQ�n�0��+�hÌ—(Qv\7F�$���P��H�JT���R�Z�P����,��� H8�T +\���S� �V�nn�>��<����3�q��F�9,�c�֟��WW� +2�}�7��sg��Tv���=�{�7�Zl���`�i�w���n�Pض4m��H��>�?��/][ݕ� +.�w@��0JFa��n-��������p�mv�w���j�Im��Vn�f�ҿ�y���6�@��rd:�/���t��`�X]�{��ǸG�f�����?��+F��A> /W [ 1 2 1 ] /Size 2 /ID [] >> +stream +x�cb&F �R +endstream +endobj + +startxref +216 +%%EOF + + + +Matched response definition: +{ + "status" : 200, + "base64Body" : "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", + "headers" : { + "Content-Type" : "application/octet-stream" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] +} + +Response: +HTTP/1.1 200 +Content-Type: [application/octet-stream] +Matched-Stub-Id: [a1a3e8ea-3a5a-491d-90e2-b8d3a48c8a54] + +2023-09-06T14:29:49.511+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +2023-09-06T14:29:49.518+02:00 INFO 207411 --- [qtp906926883-77] WireMock : Request received: +127.0.0.1 - PUT /yamlfraudcheck + +Accept: [application/json, application/*+json] +Content-Type: [application/json] +Accept-Encoding: [gzip, x-gzip, deflate] +Transfer-Encoding: [chunked] +Host: [localhost:11276] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.2.1 (Java/17.0.1)] +{"loanAmount":99999.0,"client.id":"1234567890"} + + +Matched response definition: +{ + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"FRAUD\",\"rejection.reason\":\"Amount too high\"}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] +} + +Response: +HTTP/1.1 200 +Content-Type: [application/json] +Matched-Stub-Id: [44c88877-5d4b-491e-8ac5-7ab599794d69] + +2023-09-06T14:29:49.520+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +2023-09-06T14:29:49.528+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.['name'] == 'fraud')]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:49.528+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.['name'] == 'fraud')]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:49.528+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.['name'] =~ /[\p{L}]*/)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:49.528+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Warning: JSON path expression '$[?(@.name =~ /([\p{L}]*)/)]' failed to match document 'null' because of error 'json string can not be null or empty' +2023-09-06T14:29:49.529+02:00 INFO 207411 --- [qtp906926883-82] WireMock : Request received: +127.0.0.1 - GET /yamlfrauds + +Accept: [application/json, application/*+json] +Content-Type: [application/json] +Accept-Encoding: [gzip, x-gzip, deflate] +Host: [localhost:11276] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.2.1 (Java/17.0.1)] + + + +Matched response definition: +{ + "status" : 200, + "body" : "{\"count\":200}", + "headers" : { + "Content-Type" : "application/json" + }, + "fixedDelayMilliseconds" : 2000, + "transformers" : [ "response-template", "spring-cloud-contract" ] +} + +Response: +HTTP/1.1 200 +Content-Type: [application/json] +Matched-Stub-Id: [18870094-18db-484a-ade9-e161dae03756] + +2023-09-06T14:29:50.528+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +2023-09-06T14:29:50.842+02:00 INFO 207411 --- [qtp906926883-81] WireMock : Warning: JSON path expression '$[?(@.['name'] == 'fraud')]' failed to match document '--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file1"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content1 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file2"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content2 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="test"; filename="filename1" +Content-Type: application/json +Content-Transfer-Encoding: binary + +{ + "status": "test" +} +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB-- +' because of error 'Filter: [?] can not be applied to primitives. Current context is: --LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file1"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content1 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file2"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content2 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="test"; filename="filename1" +Content-Type: application/json +Content-Transfer-Encoding: binary + +{ + "status": "test" +} +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB--' +2023-09-06T14:29:50.843+02:00 INFO 207411 --- [qtp906926883-81] WireMock : Warning: JSON path expression '$[?(@.['name'] == 'fraud')]' failed to match document '--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file1"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content1 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file2"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content2 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="test"; filename="filename1" +Content-Type: application/json +Content-Transfer-Encoding: binary + +{ + "status": "test" +} +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB-- +' because of error 'Filter: [?] can not be applied to primitives. Current context is: --LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file1"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content1 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file2"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content2 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="test"; filename="filename1" +Content-Type: application/json +Content-Transfer-Encoding: binary + +{ + "status": "test" +} +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB--' +2023-09-06T14:29:50.843+02:00 INFO 207411 --- [qtp906926883-81] WireMock : Warning: JSON path expression '$[?(@.['name'] =~ /[\p{L}]*/)]' failed to match document '--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file1"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content1 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file2"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content2 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="test"; filename="filename1" +Content-Type: application/json +Content-Transfer-Encoding: binary + +{ + "status": "test" +} +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB-- +' because of error 'Filter: [?] can not be applied to primitives. Current context is: --LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file1"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content1 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file2"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content2 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="test"; filename="filename1" +Content-Type: application/json +Content-Transfer-Encoding: binary + +{ + "status": "test" +} +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB--' +2023-09-06T14:29:50.843+02:00 INFO 207411 --- [qtp906926883-81] WireMock : Warning: JSON path expression '$[?(@.name =~ /([\p{L}]*)/)]' failed to match document '--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file1"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content1 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file2"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content2 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="test"; filename="filename1" +Content-Type: application/json +Content-Transfer-Encoding: binary + +{ + "status": "test" +} +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB-- +' because of error 'Filter: [?] can not be applied to primitives. Current context is: --LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file1"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content1 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file2"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content2 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="test"; filename="filename1" +Content-Type: application/json +Content-Transfer-Encoding: binary + +{ + "status": "test" +} +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB--' +2023-09-06T14:29:50.843+02:00 INFO 207411 --- [qtp906926883-81] WireMock : Warning: JSON path expression '$[?(@.['loanAmount'] == 123.123)]' failed to match document '--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file1"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content1 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file2"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content2 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="test"; filename="filename1" +Content-Type: application/json +Content-Transfer-Encoding: binary + +{ + "status": "test" +} +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB-- +' because of error 'Filter: [?] can not be applied to primitives. Current context is: --LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file1"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content1 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file2"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content2 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="test"; filename="filename1" +Content-Type: application/json +Content-Transfer-Encoding: binary + +{ + "status": "test" +} +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB--' +2023-09-06T14:29:50.843+02:00 INFO 207411 --- [qtp906926883-81] WireMock : Warning: JSON path expression '$[?(@.['client.id'] =~ /([0-9]{10})/)]' failed to match document '--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file1"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content1 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file2"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content2 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="test"; filename="filename1" +Content-Type: application/json +Content-Transfer-Encoding: binary + +{ + "status": "test" +} +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB-- +' because of error 'Filter: [?] can not be applied to primitives. Current context is: --LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file1"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content1 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file2"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content2 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="test"; filename="filename1" +Content-Type: application/json +Content-Transfer-Encoding: binary + +{ + "status": "test" +} +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB--' +2023-09-06T14:29:50.843+02:00 INFO 207411 --- [qtp906926883-81] WireMock : Warning: JSON path expression '$[?(@.['loanAmount'] == 99999)]' failed to match document '--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file1"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content1 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file2"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content2 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="test"; filename="filename1" +Content-Type: application/json +Content-Transfer-Encoding: binary + +{ + "status": "test" +} +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB-- +' because of error 'Filter: [?] can not be applied to primitives. Current context is: --LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file1"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content1 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file2"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content2 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="test"; filename="filename1" +Content-Type: application/json +Content-Transfer-Encoding: binary + +{ + "status": "test" +} +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB--' +2023-09-06T14:29:50.843+02:00 INFO 207411 --- [qtp906926883-81] WireMock : Warning: JSON path expression '$[?(@.['client.id'] =~ /([0-9]{10})/)]' failed to match document '--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file1"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content1 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file2"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content2 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="test"; filename="filename1" +Content-Type: application/json +Content-Transfer-Encoding: binary + +{ + "status": "test" +} +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB-- +' because of error 'Filter: [?] can not be applied to primitives. Current context is: --LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file1"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content1 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file2"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content2 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="test"; filename="filename1" +Content-Type: application/json +Content-Transfer-Encoding: binary + +{ + "status": "test" +} +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB--' +2023-09-06T14:29:50.857+02:00 INFO 207411 --- [qtp906926883-81] WireMock : Request received: +127.0.0.1 - POST /tests + +Accept: [*/*] +Transfer-Encoding: [chunked] +Content-Type: [multipart/form-data; boundary=LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB] +Host: [localhost:11276] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/4.5.14 (Java/17.0.1)] +Accept-Encoding: [gzip,deflate] +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file1"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content1 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="file2"; filename="filename1" +Content-Type: application/octet-stream +Content-Transfer-Encoding: binary + +content2 +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB +Content-Disposition: form-data; name="test"; filename="filename1" +Content-Type: application/json +Content-Transfer-Encoding: binary + +{ + "status": "test" +} +--LJLsvrbskWn3ba0x5XB-AUt-c69D6A3yxqUdB-- + + + +Matched response definition: +{ + "status" : 200, + "body" : "{\"status\":\"ok\"}", + "headers" : { + "Content-Type" : "application/json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] +} + +Response: +HTTP/1.1 200 +Content-Type: [application/json] +Matched-Stub-Id: [e10ced51-f2a6-47d9-adcb-da55409ebd9c] + +2023-09-06T14:29:50.885+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +2023-09-06T14:29:50.886+02:00 DEBUG 207411 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +[INFO] Tests run: 12, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 7.379 s -- in com.example.loan.LoanApplicationServiceTests +[INFO] Running com.example.loan.TestControllerTests +[WARNING] Tests run: 1, Failures: 0, Errors: 0, Skipped: 1, Time elapsed: 0 s -- in com.example.loan.TestControllerTests +2023-09-06T14:29:50.914+02:00 DEBUG 207411 --- [ Thread-28] o.s.c.contract.stubrunner.StubServer : Ports for this server are https [-1] and http [11301] +2023-09-06T14:29:50.914+02:00 DEBUG 207411 --- [ Thread-40] o.s.c.contract.stubrunner.StubServer : Ports for this server are https [-1] and http [11276] +2023-09-06T14:29:50.914+02:00 DEBUG 207411 --- [ Thread-28] o.s.c.contract.stubrunner.StubServer : Stopping the server at port [11301] +2023-09-06T14:29:50.914+02:00 DEBUG 207411 --- [ Thread-40] o.s.c.contract.stubrunner.StubServer : Stopping the server at port [11276] +2023-09-06T14:29:50.914+02:00 DEBUG 207411 --- [ Thread-16] o.s.c.contract.stubrunner.StubServer : Ports for this server are https [-1] and http [13490] +2023-09-06T14:29:50.914+02:00 DEBUG 207411 --- [ Thread-16] o.s.c.contract.stubrunner.StubServer : Stopping the server at port [13490] +2023-09-06T14:29:50.914+02:00 DEBUG 207411 --- [ Thread-4] o.s.c.contract.stubrunner.StubServer : The HTTP Server stub is not running... That means that the artifact is running a messaging module. Returning back -1 value of the port. +2023-09-06T14:29:50.914+02:00 DEBUG 207411 --- [ Thread-4] o.s.c.contract.stubrunner.StubServer : Stopping the server at port [-1] +[INFO] +[INFO] Results: +[INFO] +[WARNING] Tests run: 17, Failures: 0, Errors: 0, Skipped: 1 +[INFO] +[INFO] +[INFO] --- exec-maven-plugin:1.6.0:exec (gradle) @ http-client-dsl --- +To honour the JVM settings for this build a single-use Daemon process will be forked. For more on this, please refer to https://docs.gradle.org/8.3/userguide/gradle_daemon.html#sec:disabling_the_daemon in the Gradle documentation. +Daemon will be stopped at the end of the build +> Task :clean UP-TO-DATE +> Task :compileJava +> Task :compileGroovy NO-SOURCE +> Task :processResources +> Task :classes +> Task :resolveMainClassName +> Task :bootJar +> Task :jar +> Task :assemble +> Task :check +> Task :build +> Task :publishToMavenLocal UP-TO-DATE + +BUILD SUCCESSFUL in 9s +6 actionable tasks: 5 executed, 1 up-to-date +[INFO] +[INFO] --- maven-jar-plugin:3.3.0:jar (default-jar) @ http-client-dsl --- +[INFO] Building jar: /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-client/target/http-client-dsl-0.0.1.jar +[INFO] +[INFO] --- spring-boot-maven-plugin:3.2.0-SNAPSHOT:repackage (repackage) @ http-client-dsl --- +[INFO] Replacing main artifact /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-client/target/http-client-dsl-0.0.1.jar with repackaged archive, adding nested dependencies in BOOT-INF/. +[INFO] The original artifact has been renamed to /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-client/target/http-client-dsl-0.0.1.jar.original +[INFO] +[INFO] --- maven-install-plugin:3.1.1:install (default-install) @ http-client-dsl --- +[INFO] Installing /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-client/pom.xml to /home/marcin/.m2/repository/com/example/http-client-dsl/0.0.1/http-client-dsl-0.0.1.pom +[INFO] Installing /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/http-client/target/http-client-dsl-0.0.1.jar to /home/marcin/.m2/repository/com/example/http-client-dsl/0.0.1/http-client-dsl-0.0.1.jar +[INFO] +[INFO] ----< org.springframework.cloud:spring-cloud-contract-samples-dsl >----- +[INFO] Building Spring Cloud Contract Standalone Dsl Test Samples 4.1.0-SNAPSHOT [3/3] +[INFO] --------------------------------[ pom ]--------------------------------- +[WARNING] org.slf4j:slf4j-api/maven-metadata.xmlfailed to transfer from http://0.0.0.0/ during a previous attempt. This failure was cached in the local repository and resolution will not be reattempted until the update interval of maven-default-http-blocker has elapsed or updates are forced. Original error: Could not transfer metadata org.slf4j:slf4j-api/maven-metadata.xml from/to maven-default-http-blocker (http://0.0.0.0/): transfer failed for http://0.0.0.0/org/slf4j/slf4j-api/maven-metadata.xml +[INFO] +[INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ spring-cloud-contract-samples-dsl --- +[INFO] Deleting /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/target +[INFO] +[INFO] --- spring-javaformat-maven-plugin:0.0.35:apply (default) @ spring-cloud-contract-samples-dsl --- +[INFO] +[INFO] --- spring-javaformat-maven-plugin:0.0.35:validate (default) @ spring-cloud-contract-samples-dsl --- +[INFO] +[INFO] --- maven-checkstyle-plugin:3.1.2:check (checkstyle-validation) @ spring-cloud-contract-samples-dsl --- +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-build-tools/4.1.0-SNAPSHOT/maven-metadata.xml +[INFO] Starting audit... +Audit done. +[INFO] You have 0 Checkstyle violations. +[INFO] +[INFO] --- maven-checkstyle-plugin:3.1.2:check (no-http-checkstyle-validation) @ spring-cloud-contract-samples-dsl --- +[INFO] +[INFO] --- maven-javadoc-plugin:3.3.1:jar (javadoc) @ spring-cloud-contract-samples-dsl --- +[INFO] Not executing Javadoc as the project is not a Java classpath-capable package +[INFO] +[INFO] >>> maven-source-plugin:3.2.1:jar (attach-sources) > generate-sources @ spring-cloud-contract-samples-dsl >>> +[INFO] +[INFO] --- spring-javaformat-maven-plugin:0.0.35:apply (default) @ spring-cloud-contract-samples-dsl --- +[INFO] +[INFO] --- spring-javaformat-maven-plugin:0.0.35:validate (default) @ spring-cloud-contract-samples-dsl --- +[INFO] +[INFO] --- maven-checkstyle-plugin:3.1.2:check (checkstyle-validation) @ spring-cloud-contract-samples-dsl --- +[INFO] Starting audit... +Audit done. +[INFO] You have 0 Checkstyle violations. +[INFO] +[INFO] --- maven-checkstyle-plugin:3.1.2:check (no-http-checkstyle-validation) @ spring-cloud-contract-samples-dsl --- +[INFO] +[INFO] <<< maven-source-plugin:3.2.1:jar (attach-sources) < generate-sources @ spring-cloud-contract-samples-dsl <<< +[INFO] +[INFO] +[INFO] --- maven-source-plugin:3.2.1:jar (attach-sources) @ spring-cloud-contract-samples-dsl --- +[INFO] +[INFO] --- maven-invoker-plugin:3.2.1:run (integration) @ spring-cloud-contract-samples-dsl --- +[INFO] No projects were selected for execution. +[INFO] +[INFO] --- maven-install-plugin:2.4:install (default-install) @ spring-cloud-contract-samples-dsl --- +[INFO] Installing /home/marcin/repo/spring-cloud-contract/samples/standalone/dsl/interpolated-pom.xml to /home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-contract-samples-dsl/4.1.0-SNAPSHOT/spring-cloud-contract-samples-dsl-4.1.0-SNAPSHOT.pom +[INFO] ------------------------------------------------------------------------ +[INFO] Reactor Summary: +[INFO] +[INFO] Spring Cloud Contract Verifier Http Server Sample 0.0.1 SUCCESS [ 18.745 s] +[INFO] Spring Cloud Contract Verifier Http Client Sample 0.0.1 SUCCESS [ 25.551 s] +[INFO] Spring Cloud Contract Standalone Dsl Test Samples 4.1.0-SNAPSHOT SUCCESS [ 0.936 s] +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ +[INFO] Total time: 46.719 s +[INFO] Finished at: 2023-09-06T14:30:02+02:00 +[INFO] ------------------------------------------------------------------------ diff --git a/samples/standalone/dsl/http-client/.gitignore b/samples/standalone/dsl/http-client/.gitignore deleted file mode 100644 index b05ba7bd6d..0000000000 --- a/samples/standalone/dsl/http-client/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ - -target/ - -.gradle -build/ - diff --git a/samples/standalone/dsl/http-client/.gradle/8.1.1/checksums/checksums.lock b/samples/standalone/dsl/http-client/.gradle/8.1.1/checksums/checksums.lock new file mode 100644 index 0000000000000000000000000000000000000000..a64885c8e6a32865c929ecf181b9982aef8c6acd GIT binary patch literal 17 VcmZR6X%^KXvFOWF1~6c}4*)n`1$Y1e literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-client/.gradle/8.1.1/checksums/md5-checksums.bin b/samples/standalone/dsl/http-client/.gradle/8.1.1/checksums/md5-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..30b390f39440ad2ee26e40f6fb21eb409b985d5f GIT binary patch literal 25597 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%0A8aFmFFdrrxC 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 Q^ZM?;4<2hRw07?Q4<z>% literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-client/.gradle/8.1.1/fileChanges/last-build.bin b/samples/standalone/dsl/http-client/.gradle/8.1.1/fileChanges/last-build.bin new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-client/.gradle/8.1.1/fileHashes/fileHashes.bin b/samples/standalone/dsl/http-client/.gradle/8.1.1/fileHashes/fileHashes.bin new file mode 100644 index 0000000000000000000000000000000000000000..d7eaa47eb201a8c3f37deeada9ea525ad25b5855 GIT binary patch literal 23547 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 c{Z1#QgpSR~stU`*&0I8X=Qw+>002Ar1oQv^ literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-client/.gradle/8.3/checksums/md5-checksums.bin b/samples/standalone/dsl/http-client/.gradle/8.3/checksums/md5-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..cc66d19125b350e3da66cfc8ebbf199629e9b5a1 GIT binary patch literal 23697 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 literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-client/.gradle/8.3/dependencies-accessors/dependencies-accessors.lock b/samples/standalone/dsl/http-client/.gradle/8.3/dependencies-accessors/dependencies-accessors.lock new file mode 100644 index 0000000000000000000000000000000000000000..41128403a47a9f577e4273119c55566b15727663 GIT binary patch literal 17 TcmZQpYG-@)^62)B3{U_7HxUG{ literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-client/.gradle/8.3/dependencies-accessors/gc.properties b/samples/standalone/dsl/http-client/.gradle/8.3/dependencies-accessors/gc.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/standalone/dsl/http-client/.gradle/8.3/executionHistory/executionHistory.bin b/samples/standalone/dsl/http-client/.gradle/8.3/executionHistory/executionHistory.bin new file mode 100644 index 0000000000000000000000000000000000000000..b2c6574f9c3b56a9922c330516b53cdf92996ec0 GIT binary patch literal 182232 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 Jd@b7T_Px# literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-client/.gradle/8.3/fileChanges/last-build.bin b/samples/standalone/dsl/http-client/.gradle/8.3/fileChanges/last-build.bin new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-client/.gradle/8.3/fileHashes/fileHashes.bin b/samples/standalone/dsl/http-client/.gradle/8.3/fileHashes/fileHashes.bin new file mode 100644 index 0000000000000000000000000000000000000000..0d445640338af69ec9354600666280f645c4986a GIT binary patch literal 21997 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 literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-client/.gradle/8.3/fileHashes/fileHashes.lock b/samples/standalone/dsl/http-client/.gradle/8.3/fileHashes/fileHashes.lock new file mode 100644 index 0000000000000000000000000000000000000000..462911d9f05718d1357a87b69d5bc31d78982b63 GIT binary patch literal 17 UcmZP;P`_QUcGIz43=psg05jnQ2LJ#7 literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-client/.gradle/8.3/fileHashes/resourceHashesCache.bin b/samples/standalone/dsl/http-client/.gradle/8.3/fileHashes/resourceHashesCache.bin new file mode 100644 index 0000000000000000000000000000000000000000..bc54ef1068ffbfbd42a1fb220d405f918808f2ce GIT binary patch literal 21489 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 literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-client/.gradle/8.3/gc.properties b/samples/standalone/dsl/http-client/.gradle/8.3/gc.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/standalone/dsl/http-client/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/samples/standalone/dsl/http-client/.gradle/buildOutputCleanup/buildOutputCleanup.lock new file mode 100644 index 0000000000000000000000000000000000000000..7170af7cf2b7c0b07c89db09cec65d8ed66bf59e GIT binary patch literal 17 VcmZSH@@1AyM$*0?3}C<*3jjXh1z-RG literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-client/.gradle/buildOutputCleanup/cache.properties b/samples/standalone/dsl/http-client/.gradle/buildOutputCleanup/cache.properties new file mode 100644 index 0000000000..7867ef99d1 --- /dev/null +++ b/samples/standalone/dsl/http-client/.gradle/buildOutputCleanup/cache.properties @@ -0,0 +1,2 @@ +#Wed Sep 06 14:29:54 CEST 2023 +gradle.version=8.3 diff --git a/samples/standalone/dsl/http-client/.gradle/buildOutputCleanup/outputFiles.bin b/samples/standalone/dsl/http-client/.gradle/buildOutputCleanup/outputFiles.bin new file mode 100644 index 0000000000000000000000000000000000000000..225c732fc9eaed4c0402d356dd1e2a0b085b5227 GIT binary patch literal 19037 zcmeI%T}V@59LMpqjj-c}FQH+jW053ONM+PQLLC;zdErHBVWB1#3{niKZKs0h1x+u! z34}_si;AouiiK;X7e(}Dw1PHDn&yh$26?fJEcC4B|4(9ffj8rK;G8{t&$B-~pIxq0 zlCsjK>5^uz%-JPY5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SF|DK$UioWO10R zRr=T>)hS7cqWPd&XQUMo@l|Da>+;O6SS*ZtH_a_?>pxi5UVIYs>pckjrv zk(Rx84Aif2zdbro7d6-16TK{n`vZfozM+2YCDH90xj*S_|FGxc*F!XCH}{v70X68V zT}S&fxxXpUZEyH&`$qG9+@t=7#j-Q^KJ^LiKLXan3m%f_w!JuVKd*f8X#Ipy4wQhQ(RXl(L|UUq`JNnNt@ed9I@&DqL5t)gh~ z`e1ZD?Qi9te$?3IQujxwujIb?WAMPz(TrN^m${oKPCK&C%D<>raJS@I`W01qM|~If zHHD@lQ#Q{H>YKP1_B1=w=Wpo}-JZw26YubZ00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1R#)j0tMQUWbM|)?${&cpQ43?EOU3#|C>B_--@3cU*dn|KYL~X DcU_ux literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-client/.gradle/checksums/checksums.lock b/samples/standalone/dsl/http-client/.gradle/checksums/checksums.lock new file mode 100644 index 0000000000000000000000000000000000000000..dc384bceb682db9472640607a20f1f4884e20c30 GIT binary patch literal 17 UcmZSXdBk>nt%>;(1_<~A05k6d_W%F@ literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-client/.gradle/checksums/md5-checksums.bin b/samples/standalone/dsl/http-client/.gradle/checksums/md5-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..ee655448d5584b146a73fc1f8cc650068e30a2b7 GIT binary patch literal 23497 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 F{~zX$cIE&8 literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-client/.gradle/file-system.probe b/samples/standalone/dsl/http-client/.gradle/file-system.probe new file mode 100644 index 0000000000000000000000000000000000000000..a41cacb69ddb67f163dc6ceec2b226f07d25907c GIT binary patch literal 8 PcmZQzVC>4OsAB>E2F?NQ literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-client/.gradle/vcs-1/gc.properties b/samples/standalone/dsl/http-client/.gradle/vcs-1/gc.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/standalone/dsl/http-client/.mvn/jvm.config b/samples/standalone/dsl/http-client/.mvn/jvm.config deleted file mode 100644 index 0e7dabeff6..0000000000 --- a/samples/standalone/dsl/http-client/.mvn/jvm.config +++ /dev/null @@ -1 +0,0 @@ --Xmx1024m -XX:CICompilerCount=1 -XX:TieredStopAtLevel=1 -Djava.security.egd=file:/dev/./urandom \ No newline at end of file diff --git a/samples/standalone/dsl/http-client/.mvn/maven.config b/samples/standalone/dsl/http-client/.mvn/maven.config deleted file mode 100644 index a682990566..0000000000 --- a/samples/standalone/dsl/http-client/.mvn/maven.config +++ /dev/null @@ -1 +0,0 @@ --P spring diff --git a/samples/standalone/dsl/http-client/.mvn/wrapper/MavenWrapperDownloader.java b/samples/standalone/dsl/http-client/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index b901097f2d..0000000000 --- a/samples/standalone/dsl/http-client/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2007-present 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. - */ -import java.net.*; -import java.io.*; -import java.nio.channels.*; -import java.util.Properties; - -public class MavenWrapperDownloader { - - private static final String WRAPPER_VERSION = "0.5.6"; - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" - + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if(mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if(mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if(!outputFile.getParentFile().exists()) { - if(!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { - String username = System.getenv("MVNW_USERNAME"); - char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); - Authenticator.setDefault(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(username, password); - } - }); - } - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/samples/standalone/dsl/http-client/.mvn/wrapper/maven-wrapper.jar b/samples/standalone/dsl/http-client/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index c1dd12f17644411d6e840bd5a10c6ecda0175f18..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58727 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%0ANsA|A3-jj|r`KAo%oTajX3>^E` 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 YM{}PByk10KD_nuQ4E7Du?}+~TKh4V)`~Uy| diff --git a/samples/standalone/dsl/http-client/.mvn/wrapper/maven-wrapper.properties b/samples/standalone/dsl/http-client/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index 015dfe6821..0000000000 --- a/samples/standalone/dsl/http-client/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,18 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.3/apache-maven-3.8.3-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar diff --git a/samples/standalone/dsl/http-client/README.adoc b/samples/standalone/dsl/http-client/README.adoc deleted file mode 100644 index cdcb0e4a56..0000000000 --- a/samples/standalone/dsl/http-client/README.adoc +++ /dev/null @@ -1,26 +0,0 @@ -= Http Client - -== Prerequisites - -First you have to publish to Maven Local the stubs of the *http-server* module - -== How to run it? - -Run - -[source=groovy] --------- -./gradlew clean build --------- - -or - --------- -./mvnw clean package --------- - -To - -- build the app -- use spring-cloud-contract-stub-runner-spring[Stub Runner Spring] to download the stub of `Http Server` -- run the tests against stubbed server \ No newline at end of file diff --git a/samples/standalone/dsl/http-client/build.gradle b/samples/standalone/dsl/http-client/build.gradle deleted file mode 100644 index 4ed96649bb..0000000000 --- a/samples/standalone/dsl/http-client/build.gradle +++ /dev/null @@ -1,65 +0,0 @@ -plugins { - id "groovy" - id "org.springframework.boot" - id "io.spring.dependency-management" - id "maven-publish" -} - -group = 'com.example' -version = '0.0.1' - -repositories { - mavenCentral() - mavenLocal() - maven { url "https://repo.spring.io/snapshot" } - maven { url "https://repo.spring.io/milestone" } -// maven { url "https://repo.spring.io/release" } -} - -dependencyManagement { - imports { - mavenBom "org.springframework.cloud:spring-cloud-dependencies:$BOM_VERSION" - } -} - -dependencies { - implementation("org.springframework.boot:spring-boot-starter-web") - implementation("org.springframework.boot:spring-boot-starter-actuator") - implementation("org.springframework.cloud:spring-cloud-starter-stream-rabbit") - - testImplementation(group: 'org.springframework.cloud', name: 'spring-cloud-stream-test-binder') - testImplementation "org.springframework.cloud:spring-cloud-starter-contract-stub-runner" - testImplementation "org.springframework.cloud:spring-cloud-starter-contract-verifier" - testImplementation('org.springframework.boot:spring-boot-starter-test') { - exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' - } -} - -test { - useJUnitPlatform() - systemProperty 'spring.profiles.active', 'gradle' - testLogging { - exceptionFormat = 'full' - } - afterSuite { desc, result -> - if (!desc.parent) { - println "Results: (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)" - if (result.testCount == 0) { - throw new IllegalStateException("No tests were found. Failing the build") - } - } - } -} - -task resolveDependencies { - doLast { - project.rootProject.allprojects.each { subProject -> - subProject.buildscript.configurations.each { configuration -> - configuration.resolve() - } - subProject.configurations.each { configuration -> - configuration.resolve() - } - } - } -} diff --git a/samples/standalone/dsl/http-client/gradle.properties b/samples/standalone/dsl/http-client/gradle.properties deleted file mode 100644 index b2494b37c5..0000000000 --- a/samples/standalone/dsl/http-client/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -org.gradle.daemon=false -BOM_VERSION=2023.0.0-SNAPSHOT -bootVersion=3.2.0-SNAPSHOT diff --git a/samples/standalone/dsl/http-client/gradle/wrapper/gradle-wrapper.jar b/samples/standalone/dsl/http-client/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index c1962a79e29d3e0ab67b14947c167a862655af9b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62076 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 Ofib3zqE>N8K;u98H;Lr{ literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-server/.gradle/8.1.1/checksums/sha1-checksums.bin b/samples/standalone/dsl/http-server/.gradle/8.1.1/checksums/sha1-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..3062de475f46751838d1f2107774117693cd3a7c GIT binary patch literal 27137 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 Y$4|s|mFh_g_9EgfBsjr|fVATO0C=5mlmGw# literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-server/.gradle/8.3/checksums/sha1-checksums.bin b/samples/standalone/dsl/http-server/.gradle/8.3/checksums/sha1-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..bff05205506492357d6f7af31f2a57d1b89c8e08 GIT binary patch literal 97493 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 VXjf7sLH)rTLlO#VIU_AZ{XakTh|mB4 literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-server/.gradle/8.3/dependencies-accessors/dependencies-accessors.lock b/samples/standalone/dsl/http-server/.gradle/8.3/dependencies-accessors/dependencies-accessors.lock new file mode 100644 index 0000000000000000000000000000000000000000..0132ecd050aee15018799d3a5a111854520f2420 GIT binary patch literal 17 TcmZSnv+YSXQvky{1}FdkHai3b literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-server/.gradle/8.3/dependencies-accessors/gc.properties b/samples/standalone/dsl/http-server/.gradle/8.3/dependencies-accessors/gc.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/standalone/dsl/http-server/.gradle/8.3/executionHistory/executionHistory.bin b/samples/standalone/dsl/http-server/.gradle/8.3/executionHistory/executionHistory.bin new file mode 100644 index 0000000000000000000000000000000000000000..41bd127f554ccefcb7793024d430f234f33c41fa GIT binary patch literal 694829 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
aNj0#f& z%n>-c`JVWu26Bz!Rrut>oo?aPu(SPICp2EYuANPovSZ|?Av!XY3CK5TxxD)J?ipU4 z=~3{+GSr0#OG`&?_*-Yc89VGRKG!8nM#~BN*+O?rb#MQ|^IqXgNIsOmp0zS5mu|J75|g{rl-sZNkOJ5MVNN62PR zm{?+R3~^{e{R2mOt1tS91@#KOQzwqQ5B*8_LxoG>4;Y#h-YO~hDU=EYqk+mz;NgO( zC|brs9W4UviL6Een!1d|Xi#qrO+e698HDl%ivnf_>|guW6aC<9b+Wb_>w*MnUPx^( zKAJ@M-5pq`5@dg=&1)O3JeI9h*%c@7R_&*{pl_Q9qqIRm;F*BXj3g7SdrErt^esN7Uupw8?qlgN>+>dTdX!=^9WnhpU(E zKA>@M+BAx6bBV22FnmJT^gKRQr@G*2b7+Rs0BT%<^!KkDI;c!>ZNK~f>^+}YB|+>G zc!$010ZvUSoaBpmSxvf^`MFo`aPU#^)>4_2#aUn*5DB7TAXb$DU$IEk#+8**T`-wCwk`&nDgVpvfg6_~ zy{m2=UaHN>x+VXuAt2FP&u~0jCPonEVq) zp`>zPW}{HjBi<;)MblzZ4MwU|a#W?%Kwg8AB4m)y1W8O#5|)9iI~7B--~oX2v1EGT zV{(m-74O`)S_Iwg)OAFW_wtH4bVtR10*I{y+1Ku-viIm!fz7s+Xy4LzPInhlnmEPH z9Bb-U7+VQaAZ~Fp{Y!e{tOL2ieQK9@;=-Ot{n$YmG8f@uI(_Z}vV}qsq1UyKH?7=K zDEDcSn7X}!i}4I*rr~BNTM2Tw{NwhM3*C;6BBBCr#P6( z-gzKbsk!3+0mN4c(se`U{_lQVX!aF}JauMj;As~wQ4p2kivPu!uM(uy?D&h#o2}@3 zyL+C?Yub(I=bDgjN%^lreU%_5ZlBrK_|})+HI7{f&;4+`D>~53mr%-YVU@Caup;c+=l!LYI?RIlg2(7F*B~k zZJ%$7V~OJbVeD54QlnnUt%@R^IrLWv@;cA%A(>~5p8T@^<~<=3 z_B?e#fEMh-w8VdvAO}v*iIAS1lIyu1xw&)SahYqj7E4}b#wGl{2(S_)m-hMkXFD#p zzegdS=bCq_;DS#}uoOu{`}I(%5(KZ3pIx}F(TqxW4sPgI`))TEGK`WP&+i0Fl^}VS zW(vMgHDG#2s^hh$eWxb4P$)q#GQ*{lws5HuMBiodqssLP)t=dX!Td|-%2se8ugEUl zHkkBo15AaiyAKWL>w-!Y_^vuPzA-*-iVJ=Mdo)|$k#2!Zl_0~KU2Rrm9=)*F)CTt# z&FpjG=jYdag01Ow8)zz+rB*B-uqpP)%dEqOie#ngLkhdovAu%%HKnvzlk6_oR0)FB z9vFXbTC6h1-Ot+Hh3gb|!9OgZIPHK_B}o2h`=4(=di+YanY}W$D1JZY=czTS#a2R| zd!SP#$g8u*k&;U@?LJXr)C810_EsGGn<4Iyxc;4bJ->XY!PPDM_|I4(Wbs^qG59q1!LK`V}Lh_stNZ zQoA(AMvx4?hJ^v%gJ%fIOwO4eg@tRZz{&vJ2dXzo-2`ffT)8;PBXP;iI#p}!D*bHLr=5Qaq#aWH zazy1!qhj{<%rUI|zA^QyyPxp10klJ&mDMhcd=t@zZF^tb{o~w==^xGx3BJ_iOoNte z0q?hui`_lu8}J8#*&)43>}s(z;_T~_xjyyXwXJu=9|dKHd;*UhCO~=wA)0g zMxOKvWQS~uTDs$E+_18HvIh?G^jSYHy};NZOPe(b+u|A7@6(7rUY|R*9G?C_?2y=V z1vO_gOdj{L^u7b$pKeA9wHy~k94Hb91ykJ*VTa5+wCwhk_PJNZ6^}HB;qvP>MvtyRO%kT@}>ySw|{Gvw>jm#OJxyS8|Z&!PyYw$W`WOO_;w~l{_ zq9H9h#=d(x+D&=^FEATKYa`U2p>mToCYZT=RFF2DHf>egR`#Urhn_WWbzB`aBlcO3 zA(P@;W=?Owb;yj&nKz$XQ#{{kJZC-ShtZ@P#cZy$sv{Mt`4X&L{B4qA!v%vO8hMLH zeUHCvHhAPxx<|zt9o$Hov1FO$Pns5)i`j%VHn1gQeKO1Uc+%Fl`B5Nx%)^9+6Bhi~ zTXaFA-ws)a+}?Qjiz>S7nVE-~Vv^!9QRx$~4pByK7guX8n?Ja3zAE*;Osw_0;p&iu z!Ha7)(`$RMU1rTmXfSkI`Ua~*c7Ls=%DOlB_39pnue~gKJDVGpnKv(30hOh6Xl>u- zL+1rY_kd66wXWVPOpv+`6@rYDd(B-hA-b#o8&nXQZ(KJL=oa`S&bL>)rq9NVJQtCE*G4qLH* z#OWpTe>FfIl4~$I=jCzlCy{se6nr*xcWgRi_G><%*{8x2@5N=cKa;x;oMF^(;-ieR4Y^_$EP;Bqowba?UIWT>M^M& zbaB=%VJG*j{kqg&;2`n9QuIQKs?1fsY8-rW7$WfVE zo6bP#kl>1SGJc-kcwVgL=*=8q+h(LYNIC?`oER8*w%1X=f}$#wo}O>&M$zAxtCi9{ zZIWP(uiCq$kKv1>^WEL?WxS~7vut(86m^RRX!Z+nxPxwlqeCk8M7K!t#RlAo^$(o! zWB)PdZA{>@1jnik9=$Qi&>YLRmGdZxu0ziu zBdcYvuwYxAVgDVjHf5jx_l$oe@EkI3<9{V{tecRv+Ck~Rv$K@0CS>-h8}5_MV|D}V z9CEf_u6*;3U^jxjuB|>2_2rSv@~tzVbI7DFJ9?BKk@fY&a`kfbe6nSFnnKPYO~-G$ z7*YNc`{dfDS=m2&)J@sIpF#yc#{uV%s%3`aaR+uB+}+)GXXfDe^1mEz4!O{y(YibJ zjx7^48lx;$dC3f+fSLOJ$Yo&tBCt86^`@MCmlD?#SA-(v;)nsQekar%QX%hzYa=Rb zD0r{JYqnRG(jI>d&>XU-!_j>KpB`Nq9Q|bbm`|CO$qtIi7{X$UWe^!)Jk z^A^9rMCsPd$Cx*7cKre1a>&Y0qRQvxfhCVbJS|6kED$WTA*FtpxM?*Z$|XUt@kT$c z;?K`P%OPFbT!<6l9 zIb8GLK>XtHMkik6SiUN;uAj@Yq$7ZGNb|l!;|lx5gb&_*{bRuMS8aY7oE#Ez-TSn! z*WrqKz&4*k*{YKvs z$`vhAn8HK2hgKkfNH^+8x1M)DczTuHf3V3Y?Jd{Xp%MJe3Iq-yzT5yHhjhz)GR8CO z>x`S;JZY18{^>h^D102E$wnz7R!nbKbN8AD*H-^K^A84(L;l|PG2-vy<+@y%-LAyh zh?!0QN1)@7&v7Ld96hk&`{M$SpImvGakcZQ5uD0zF1iB2RtA7S{w$h6$CAK0+zlLu zOl;FouJWA3wjUdpQE~?v?tE&51N8HQF~XG*Di&~?0oYEZApmw*&ax_%Os)oi2nC?6 zv6M>1uqb?oLOlk=HJ$+(8uOuON1ArKP^RUoz274XX1sChc+Ni>G!F4TTH`;T?j_dc zZkdk`t@~n~^L7sh=07bU|e;HYa9a=^X=3`+$gOTwb!8UqX!*O=ci z!9!ll|DKekMw{UeBwLO?Nk}(vaY*07#d?mBmTTC!(YQErDm(qp0gFREHr*x4S>;OI z*FI(Cr$&6K_WuM_98xK(-J5SY5j0xWBGy_%6=`! z{qy?C*XZ;P6Nj|e)bUZ#DPK0VO&pidcQd!;*c5ykP z&S&f*iqZ>RbdIfgTEW91JG}!U{+`lGL6uzn)%VSe#zOVfG4d=B;VeG70UQo#FnnWF z;m;$Z8~3T-BKl;@>~bkDYby`H48u*4M4ts{ce_ zIOOZ?ZM){J4=Hq~>av~G@%4J=#WssGmpr;1FF3mu77h{D-~IS##?H4pi1XafCRtPY zfz!1+9HQLKpm0d|=2=*|8ot@G9Ey36d)uHADH{P(a3~w(Of%}6G}xcgX@hx~aib8* ziH=+Xj1ONA6dBX;;De)W^I{UcDAUBRt8)nJ2ROzH(i{*Dd9dU5wIz!V1~Vh746j$m zCteu$?--qF3;~N!wK43sxF6W~fEw-N>gf(}8!6Da&mF&7Gqv~pw z`<*U}idRlZ&rop4kRgZ37k}r;<6rOn18R5WEyCbn$JRa#f#8rk7bXucF??}gaM0iV zALz!Mbw0w;(jA&sFmQ-Zp|&UQO#5r@1!;x@GhRg&Zz*Ti2OMY~<`IA;aj;(ys6q*)r%^Q^ zXe$6l6Jr2CUM8bafTE?;v>a1Xa+ZRiR*SX}*UGi!%@?bBT;CUWe`AfoL7Au>e{cIP z%;9%zX5A0|h7>qIdExkdabW|$Y--;L@ox1KQm7f{ElCPBKQc?9ZiIeA&R~208C-bu zoqwxN9#Y}i!nw{%_#8h~nI)QvcE_@E%wP)y% z`x!SK+j70b)8Q_=-5mjZL+;C4-+r>YXlaj&ue~K%9(y@&HBBS9H^k%Htr@W~M{{e7 zW_|lC)5L$AH_lkdkV4C|d%@n2+wXl32O=AfgdbIASvvP*Utvyv>dZT>px%%biw}!x zHbZI-pP#AY-i|8C?*)28UNv30DPb-%W9*##ny`s`ega*_lr3h`=S<(-0rQ4vvkfhY z>eh4_6O#B%614P%^ZK)iEDJO?v){w=nL9z=kl0xT_lE9@K2o$}ow0rLOxxkSc9@(& z6XF9*)=Z4muo$H1pc+D>0r)7j0t2XUs3wleameFA)hvmtDH)q&&E$d$45mS@3AN9`S>_*WrxfYYw##z zA%82NEzSo9jx4D{jjJ^nimSmkOrRL9RH-RKiK!Vmz;%HQS%U)RIl!Guty*)I49*S4 z6&La7)5~|@?8rx%URRDeI`30Xp+J#(#7(kE5mvwHNRFme1ACd8MP|*}9CS@pvuE+Z zwtsh1ym#I&=Fse>0kj)Zd5y>B6-|S~=5<~>rBE)s#{UYi8{o@iI}$;A20R<9{g{14 z_g2oEJRMsTgU!>8ux<$P-Lvds?WF>bt~EL_a_78LDF;aXG^iWmsTutJ`23J;??;~x zE1<4<)7>^Meumrt>4s!~ApN(-(1ls%Zo2m!_gvG{d816yUB*GUS$_l814wsL1p^RF za$2pyahz7GNTq@Suraw(ra_gE>Pg8psD{$ejCE^{bwO*Mbxr^BEkpnMH~m+i&w5W> zYLxc9OD1bSf0EHb5qQSi2q2}^NzKo^lAdvDH);gJ0H|69MO8q)Tmu)IN~Y9kNE8Mk zSITjc!~tOn#Tkv#UPoRQ9r44s>K%5Bl(%Fdm=x>cEkJI<$Dae6??CMURn-2>!? zsIxM+&*^ISJ`sB~Q{z**8qP}$9JTz_`AcBjkOyyT@7ypdJa^qo6+UB%broGV?<66% znaw*%kJ19f4XGZhzHxKrg{nSp7svXC9IyN*K)4|%&zw#?(&BZN9#bdIDwKK42j^3U zfB`4P61o+@4GC+WA=8M}<<#T16u5Y8&7FUp-wmlBHdDg2@yxjkz71(`d|~lhxw9O} zS8YwH+X zPWw%TCI{31!&r1k>19XSwDj)N zmWihNRaU)T{Xd69hm`xb@q~xH`zJ<4``=xDqG)61<$u8rOiLU(WM|oG@2-v-`tFd& zg-nZeJ200FLzeu>4D|GSQRt9}jDxSYE20=2nyGR2b}f&N|DPS0^WH!#Z?ZGrWW z@8`?3E2g;dxoU#G=)XmWEpU2yqBl*z8QNI zTVM5V0o6n1=d65v%Ux{D23f~PEq|>1^3!u`KDXA?x(!kfd0vz3xa!<>>E129kZQI3 z&pKbCRWP?{3#f-oD0k^(fsVKKbc`7$rOVJN=RNQOdeaV04^jQQveU}MT>nklDBg5= z?%Mu8O{>AmZM_xT1Ez<>OnR|uaphat%YQu6e9b6N9O-gO-*$HCQyq)k&eLn)!~3@< znab$t>+6H+`|An_v@;zOsx@bB^XLtx22wo{92&&vrBEm}geHQtA&ivP2T8dYS}#4L z157(98SWoM!wcc0Uh31JZ5^*BEgEuWd2gmK-`MhHFK7(qP6;}Qk#dQ4T>4!I926={ zF9oOwLKg|X$ll>lf7CmaW+ljy5%*SIt+!r#ZP(^=rQ*)D5KXmx>!Gz_Kb;Lm9|{?Y zjA1k*YDGL=cElt2`DMR1wZl%l5KS|WCh4_r>3BGLKW%sr-9f7h?BE~fSC?O~mPBNb zmY}^21waw7arNV@V}Gz*?O@)qGgV>`|>9ZxP>;%ddxd}EX%fa?bTBUJ@Mk5 ziex+~TAAFK1x-Ju_hGkY!oqbS{Ak;R5n+1sGKUeJt}gC&y43c@?f$#Rlz$;wYB}U& znx)@u9YO>%#;t9jy-q!?Hqf6jkN4dTBCay}{JyeFGk=e#{dXI;bt>)lOQe2~9U~1U zbd-MxaP;(Wz3>ZVOE|yC4Yj(qeoPCP4fDtc23L6!S$sm)8F6=q-*_?!5v_HqgM)w0 z6tvJ9cDkKOsC4k}(4}vRv}rx;Yk?|g_XN>;`;(At7Xou?`q&Ao$BCFdfeK=5g6E+Z(s*MCZr9>ss0qxMBkVpg2MbFy(5EzB#6g94VQ&Y ztcrKquPhhy`dy@GgR_175ffn&)|!OCPWR>ayFqR3{jU`(gUW$IO zoru)>IGZkaM0ik`e<%Qy880|)5WwPmOpoj6>qY`h6DP>l1094332Pe}n#BM0i4je& z#uW;=-Zf|c8IpsUM0$<57ea(}CnQ@+9K*K6jF7HvyyZtVAz zE;YBLp>QBx-dqh`2{Ll$t6NHkakCSR9Jaz4hANuBli<)Q5T7f~ocYfmWa2+99=Uflz zQZ7q=2zHbwei~k#Vv4kQQ?^>WuGiW}d0jdw+Td&-A^}iLy4VhgrsIsw^H1dRyzs5g zz-f<1CLlpOaA|y=o(=Zr-gmf_$A#76IlY(=Mh8LHbX&N+S~GfWxQ=42-IYIcJGn=M4B0QqNqU|x-Xwvo=$+K(Gq7?NlSS}Bw%Q<%ZmkWzKe69P8 zC=_#du!+LNe@-m5sjZAWj@40|zeNx9ZR$6mEraKX= z>>f5&_9yc=8dvB<8&mGeV6=ulldRVsh)|CsK<_HFAmepL52ibR`JX>X>ZN0M4^OOBzxnf)amNQOms!u4}w*#{NtNRYD=w!xz! z=X@rwY>rjPK4f})?}^2#!lQ@|wRaEv;I-gDwF!m%m$cKuBdSuB_szmrP5h9%?|R>- zbw_5HW!^*FUTKrGT|cM!cD1)zAznIyu)kv`8I(VcOkNE1K$Z>c=<)iQ|A52qN|)*! zQ>^m~e(}F&5lwB#S-3f#ZSnTeTUl>BuQ~in>j$0(S4ZB-Gm>AP*?C11`L`|JoO}LL z@OB?kJZU8=Ubjow*H`tvfJ9h^$p9kvmm@} zQoAhPo^dJDw-e-*QX>)%POR0t{=P(>ipP2W|AFM3P3D8Zd7W%eKsr5;q6yprTP(6J zqIxZ{d_+x;T0XDK%{zPAu*gxFJ)(e7*x#L#f}5-A^lotzJ5Z{^gVni)EMLU!xp>5O zcNS?_r_!<4nJP?wiQde4@BXN<{F~Pb!|9%@!5X#u7UVT+Y|m~%()#7$QRL}0&1%oy zdUR{m-6b}JR6PTa&g@(_Z)!}XZ`&FSR0SN=Er3VMHvE`;ZSnqF>psnXlvgogAUq0q z+OBxEvp36)SzWt)_t@6$Gl)DqzIT^|IzP2OGQ1zDWrKQYLj!~R zMPPkMD%^wrPn^+X6BkKtaGL^%m%n!yp%2u1!;KW`AH;Y!h0|Wo@VQ5Q2J*bPn-jTp zE>Bds(-l|un?ADnsn*j!i#=|MxNd~CUAP2IQ{SOM;b0f#J8a2+tONBlv>|2d(6m4I zfe7+p!U(P~Y;!F|a8LB0RI>iP!gY)eDOzJ?u{@K8PK#f?*?aq-&3D{FcF|~#nHh(t z%jNNp#Z&}D@VG}olpg_9bEv$Ksukp2pJ54L8f~>&!@pR}kIrUVW>|Lb4JEz!;pOsJ zpZf1`{hEKorsL&yJND)(1%wm5nD&fL5A&B#WYe%m+;fkNdYwo0)G08Ilq00Mb-zOk zA`fF4du|qch?;n01~)zTV|_zmL*-gzpD=Du@prO5m&caWf7)vBd^?+gtWWKSy#2Z0 zf?zPc@q0-!DS`>1wK^{j6xE;gr#7V8!SA2Vm8sHb7?dQ62#Fley=+{0&$$+p%pK~c zN&hykeS_9*n)tTpfvU#^gDpRZ(D{c&=JMEX(Zsynxl>@=2tMX_+rSiBFoQ~imCPgZ zY1@LL6$tAYQ<+)lV?JLo;M}FOj(k|JC>txja^-NKk#QsqtN#&A8C& z2aIod^W8URBA6hL$)*>W5QvHc?~r6ghvbvcNSVqu|7muA_y*|mAwE~WWO z4mi>N;)F*Dx0U?{Kd=2-EG){CI;F|h!UzM&*O3w!+WpRfCCIAvT`Ro4;xnt_!7}IWJ{p)) z>^vNAYNT`ZTa0vLEI>sQkeQFtN|_4kqu`7}g;P*On~=#hGMSRlpmGH*7tjqoSP@<8 zz^adaaR(|M$|D{>xJbd?VuA0+srd$`6UJ(F!N%V-eKqE_>bYtz+?3NwIpAJk6o#vy zI*vvqSE^L31|tbp$>M}erNVF;Q^_>Rbi>s~Fi-m2X4$VFD>(1s!FweNw;tqoSL|A~ zi4^t=OgIkMbFev3HHk7RIg4Vbno&|p9B7nLP~A|4Lrof#1&D5f7R)!_*uaMe-=DMh zYw)wgMPY-E%-l%)B^Fjd_=$4|Sh$WHJ9y2pQztC!{}ZHvpDvsT)9M_d&-AWiL<+;i zQztTodrTk3vw1@$ONZ_-s}^=Sti-o9Msn2w>cbW-j znkz_VE7x$%yi8(^@m0sRuN$vj&TH(*`QmYOt;b>DO*T8#jl>zD-cp@BzW%F2#O-sR z7?{dQ=l7tsKx>$=Aip`2>o>@FYx?ejO?s9K>t<80?sD$F|)MYfHWZ zGIVk$!x8EnT2CST#ZSzg8xZR42%%R68!q*-m5|^A-lQ-u&@@34g|Pcj9cbcS989ZM za0CTHg&agxkbji8hSkuNn$gfQ8P3RY4Xq+^87|l0s0zb0lmb)X!sZ~tL36`SJl&uJ zHl=fD=PqGQTK3qyjS!~{HV-1Eu{ZGi1v7m>O*i!p+>0Yk#p`cL5Qv7yRv?HHq?5;^ z4`0vj@act7{db*@+9JO1^tLiiiHW`1`B^q7yszMQrzPmC#ueOOEhwN%pV8<3StEA2 z3M~Aty`c(z@5s_eZ>}E5-o5dE@3uFdIz8u#hNje4s- z)-O@Gqj#&PQANeV(oCt-X>*4-ys%a;+FjG)tKQ^Yzct^H$ZdWP+BThhLA+nUu3aI| z0jO zz%)uyhC(4^s3wZRcN!`o<1&g+fN*16VquA5}|FZ=CsKy~^9f=L8Hh z^^GMY)k@ek5DKO}1*+DNYLISeHH}g<%K(_4QbDi)U_+5O%A5Hht1d}SwxrT~ME$Ly zJ$?1x*_Ln0?x}-{h1QeQsf4k6hiSFJ;gp}j6~;%LflSUoHU*~)8$Zgt;b=-xR!LAQ z3J1F?d;(w+TA|^fNuWwA!;%^~;1V(ngR>Sb!P~+eYTnQCJeO~#I#Z7wBj?^0SAG;W zQ~X7+2_2xf7kGB06#suYi1;!orBSL#&=Axz9Ej4$P)0+sGNqdPKw>0HVM-YW>Gy_4 za2C1K$dfbW=FP>8!+Hn!M(hs0)m7O+EJ$HrN~L;HWjxQjV3l@&cHSDo`RGj4Gjb)^p*5&VjRG(YE~8}>MyV;5L!s0t z2%N%XP;#6lET}j4VMYI@0uL`GG;Mr%bYbniM;;9aiG}u52etxi-2fu84-v`FJ5Q$h z$ADlCT8C5+BupuxVHB8B1#=E39~>FDnj}eD1!scTCJuSngR>D-9A7pHJkiz&uurn-HHnOi8=dkR0lZE1|JIOV<6=zfKf3d$pR)c zRKI6&jU1J0paMPxH#Q5v&?u_ZsDUl0aTP1IY|M$y(AYqvZ<7iyuJu{neDnMkTP9?> z^Fr)=`8o#<7*Dg2GY}ZCPl{0}S(%KbZ~#FE^m77J!481Z{oF29Vkm87t_I%1i$s=e zp>y29XNfiAKW!h`|DCAd>CIy2VT-t_^&^5IUH}}GrVob6#b9RTEJo5YwHj3sazLKd zD4|%lT#YFeQ0#`qz{SJL2oh6})=gpgjq~cMn>zc6BJuHwI~mlheqclKA*XLvyA;CK zg!>7{04!Id!f9~)5hzNaq#V3u8j=LUP>mV~mmdv>D2X^TUHXbeLoV+A{O;l2Y3s4# zcRz`pFABub#hI`C!?fUb<^KkkD%=Jp$12#gxZ^{rFrWc2IW`0u|NJUjD8Hgkl zBZDG~983p@EEr&|s{y491OPbiN(%gwN;9qejn1uv8)~Bfz%zmHzj<5R$3wQ?7PqXS4qCq;uSlFSIBE(bOv;-! zjmRWKoBu`d+pl7yIv!ZF{J&e;?Id@o+;WbQX{QRd} z%Z+>bWnQ!9&BC@9@<{K9@3{JFBtwMgZGMn{Dj4DA72}Sct}!ZDx$)SVPA6DQ{KVDY zWcr2z*X82QY<@WDp9H^tU}bi%j@>q8yfBkaoJ=&kW5e-NpIh6Z-&9hY(FC#`;YIuPa^sUG=exyB=@3 zW8cd4?+TU^J6~RnyQ2&|z|3*IElo81XM=%8DVL!NP)KM%K?3*<97GXJtpS`VfDuum z80dtQ211z3sz2A%(mYdeJraOKPq{Xx_b&Fs+G3ur-v#_7D&$xE?Pz*vn4ceoicB1Q zuIZ_jAFuv(SoLO&ix(uQ6TIGO{M#h20W^ga&_v~O2pOU^01O3_Ay?CcoMBZgCx*~q zAYmyQ;-VB%%eEk}L0bcf_n)5YT5RyN@?R>Cm@;wrK-y-LIVNUUK-^n=bOYMG1o^HR z***VCpCMNZckNrQOS^|+=iQOqCWFu~2-w%r{zQn>;xn(Jfh`LJOajygMh5bRg2vRK z|A5eek{}StWGWg}QYsKGRUnKI!seVQ%p?Jqn7uo&AvR!f6J^Cljq)UZw^{Mj`JvG6 zZ4R$6A=z0QyG?gA*G%{-r}S6^Z5USEhGjbs=3vruiI5PjA?Dw#wkAC?Be$Yb1x{*6 z*o_$2QBe@r;X5a7%H%8~SJ9xvGb#op7!cx&3bb`EuwS_;=IuJgyI!i=tc9ZK=!`Y5 zuJmdARs6we6@xR2v4kE%BRM@ifS>|F==A2YVZxwt2++Vk@G?E{3ZMgV&_GZn>=BiU zP=Z+p2Qw5HdNkm#2KyALV%3CN4*DITCMgySK&bs*xPd?~hLN0DP|vqk?XZo}-S&sE zuZ!0ce@^?6=yh_ylQWJ*4k*MbhQbKo7c?%@C@9ePz}Sb<8l?xeRasJ!VCF(rGm>1lW!gV2mTc)PV!@R1q-u8XRJESz1Yx zU=dYd0E10}CDeG@Ec&n-LEK!G~%qPcVPDU;TUHgBA>xL0~D$> z1Xvd!Ru}YS(1yW)OT+%6R4Rr=;k%i1{^GYh+1D0NlE#ESDcb*`AGzznmb_x;YlqvX znOkEn!k7RXv;~(kJo4hoY?uy$5=UXn10tsq1>Xqxu1Hn|8wOSZ%qVgU2BK0aP@FS2 zCUHB9eyrBu*tCU@viPlP-aP!Tb{)6o?QG*8bWBFz>C=Z0fsBb#DW%r13bh;s3m8x& zBb8vdB~+MPtzsY+NXY=XGNnSUmYSP!gcuVz@esdtdT$%# z0xp&w{3OAU3F*xQlMt?C_~ONX@q$Pht{gZMCWW|b&g%tU2^GnZIHRH=OkR!4X%!>G zR2r~Lz?KJo3V#6$rHN$v@iO*f7{;udt2U4NK)*%LAbW1z7<9q~_Ttbm_$_W40T|0E zTBZahDF@Gr9D=WKLPf|haPQzGB?GWlQcWsZ>jCil+=}+b0lo8gd3r-V^O|Ro2yDV3 zv7o|`15Or)XlH`VbB}=^f+b;B$hljW0`yZ_4SQNe!1;tk28L9tAgvYvEJ z^vSzS?iD5T?u#3))t*|EiqRxlk0~6}U`U?jLi-KQQ0qt`{vU;&(xz2%)hc^s_q)V` z+n2S7Vi&vMDYck1E)5E(fa=7Merd>x3igMZoeItdCYLfSg`zTmhgA?VS^*fb;MP{c z&LzQ>2li$H2m3h<*&cj471t2-Jg%W(Z@y{wU;c4#o0pq8RWvGSW|ysEA#SW=2cHP# zkC+`&DZU7=fmnqU1)ha#WQ>Yca&n0VRjXBMut`J80S$Krqr%hxGzsoAz9+t^fn0@w z+vzuc3BY{1B6pkYTAFszags&f(BqSavmqp3&BeQVl|6{0~e!7@Hk;| zQVvcWjY1B>1&DVFM#h!yHtbWbF}GRGuBNIF`_$?E{?MVG4VIJ zqc5bU1~3$NXIXp!)2;^Gp}>3ywM-$ylxmVzqBMqbY8a_jQE+eJY788aR_%a5UJoeN z_s90-r03}sabY*>PRSi5e&;l8FmCT&P&P1}&P&U1^@P6 z@cI1P3k3>HVAsaJC@Xdz?bw1F1QU>@%!S@+gCHRh3irZSz7h`i)u`&i29{EA{8gly z0RG2jxIOhwXwC~eyVEC6=|_(jNE;r+CuwIbV39v&UK=i>s6 z_`Y>{LI6Vg7Id6A%sGib+~gOa3M(VZOA-jxUvOYombG~&96Y^6Hb5Y z%Q<#24ow?M3qgrgP6C2GER%BkoB(}>BsuS}Tt=zDVg$k)Dq|HWi{lt22bUqPa;R5c z?0{Yk<9?*8AF{lCpUtnl>z;YKZ+mO8FoZkxgCUF{Npfx*!bdRJRwxQdZnO;Cgdhe1 zw^qW5f&Xwg8yHFvYS?r}H!Sbmwup)jAGf<(3CTW%{N9~ex#CN%wFyW~oj{9SWi-GV z&8i%wzy(1TQb@sBM1zn?fwc)lO9jqCcmqvnC>-4HaF|iJtmU8(Q&Nkzz!tf-hMA0d zGHgnP#RI;wdEZa{wrKA(7rfcRnS@ON>LG+R7$;JpfLT=17)7aN4BUTUK?F?~0tHyG zMnH59K-Mc*rJA#l@$D>wa5STDXKRLgEy^(=pcUHhdr`5V5|;xTJlT1K-!n}kB0_8ZVQ;^RRI?tMk`P`(8#Hpq#A;n zSU{bIuSx}`R^SZCZa8Y1SIebeJ!VIft#{|Q4P3k8Gx7ZC1sCEiEbhU8z!2cY;6V=o zWDk48KpQvMHO>+QMlzU;P{;_-hCz-1?HFPv!4ZooR2D5^<;_VNI`PD9 z)h4#7SgUsHf^A7+f!KNYW5dGey*MXbc$j~X-Ym8xJ>igJ6_8&G`Vb*d?57vpW}#Bk-<-`Dl`56E0_0kVT4FS~f&#mnQiZ7??i6k)m~aw@OlFGF zs7=j)MzaR|xapGYSLz*3*m$@1$oP;wPhH^hmZ3lpmdM|rdP7tXT%?@1Lr{baMHLzh z;ukd(Fe;E4RS=4Y;SjvU00))fn1-ftc+sjk+?Zw|XVa)}<*Tl$ekgpdf7NUw;%C~V z9XK|b+CCTr1_eW0Pq0+uEtdkfk;`NZ@JtGBM;S_}!9owJ0=S4UkRvHL>JWyZfHCNU zy`X_%Wpi}#>o#I^L`JVy^*>8XPkm{V)8ZI0LZ_9E2?Nv{qdVL1g$wAzq;P}NINa0< zg_?m-1(X8&G2BQj+(}9`Fex<+ag8X&TD67QgSG~O$>~2{oKMT(L!BF}+(ztW3NCLMt%8_8IS3&T52m5iU_1iRLoQR$G{lO~YOu7f5O!O6|9V*$z~^k`H|Vx00w#m z1POs%hGoGrK(Z_fjs*~MA#MmXNmdRv4iYXbFyh$ng_rY;^M223Qr&Fr7M5!MvO%^R znO}Bx!8OJmFA~a=li@TSDdj$S89suDs_<4x<){koPn4BIU?AM@5O@U^4KP=Of`Q8v z3ONQLnGic{(GupDYiXEY{eQ0t-gp%sQq22P(5_2f#a+jQOiz=Olp3G1cR_5vI#xU+Oxf7*+ePdObHJi>6?WVpAX0V-udlBU5` z%z`BW%v~r*TObcW@d7o4QYv^AtP5}pL*SrASA0boVONIfN3vsk+ebYLO;~qPSvEH6 zf$O0@0aTDpR0up1go9l9yL_%rCHh~yw?x~f%CR957u@ZXpLcJq-WyzrBzMsp|MueR z_4rd@Isn}cE+sIl!7-xXyffh8B7g+|3xfzoISF1b@GEm6!EziEwujZ`+8bs^^ssP? z#Un?y+TS+1y7+qYH!cKOS_n=?=O;(GB7pl{MSxeB)=MA6!dD3N<18LDL@7cc3Wx!~ z84O~@NX{mRV`>y5z+EB-J3hF82#650ZVqRjYi^)=&X(_Gk$>*&{&+)kX6B}&!(349 zII0bF1%wA#5-IamO9@bt6bgbN2%J#T5V@dGLox%zgcDFh1B84E1>uy&NhqX|)Rw;u z)CL0I4jeFA_NG~FPgTP8#yum)xgbk{5Dn@wXOe-aI|_LyfJfv^iWD@v7`B9xGGA(tybM^%DD7a~}}RAAMbJNKL=iN6MHJkCNhV(NCe zWS!zxznW5tn5jsCRRhNyqQESoYI(6N{!2paY7j z^)@#5&(kJ{TN2_4F{`Jr;D)D$o!PAIp6C0!7QXWFu-a?qg&tMhZj0wBQE*&QB?U2+ zg+->os;QJy;F`lpP^IAm$b||Dvdt72M4KpO2J^O-kGbL+8c5C1@9~he6mvE*N8VH2 zm#SL1AncoTC?hX5Yfz@|To4QhrWEi?5ca{IgORKZ?t7&gLN!#72|$rb$jMhKRbVv} zbOxKyC^i*HxG-^SpPT+q<{xf#{*tQmPY}w(+M0jK@D11ste{lEfUieRt05;3r`0OR zyn$GCQVzkvs1hV=2wq2FYQbJ_qLXjU9TjM8n9-o{@1CPtt|x;;+pq0BieoNZrxq8K z@psI>$Cb2{149B|3PgpgF^Kw>tAXo-!GzU-TN$n;4OpU3nu}pqLp~d*fl1Wztzolr ztqs&J`IvcVot=qKbErmM?c?dQ*rsk->RJFphXdn>a)C@31iVn7i}JCD+y_(^D8+H^ z6mx;qB$)Gn|G-WqWKdQMmY;wtAMOenXfJRzaS@Bq3VdpT2I9i6pInTRJqnzuzM^%* zr^+m1LDfG8>|`*1-u@)~p~9u`2X1vv@Psf35Jo^XW)u)U04xPU!J%Rqm~I%zuLI{R zn4Q40Au}`qn}hMR25D z!f;{eD99NkoD2+uSUkAP!RSd4kn#r!bQG692Uk89hiGUEh9$18VbWezp)w4-<+XoQ zw*m!b(?{3YRK!YsMUzAgUf?k5L7bccIXa{o#T5*w6>wl#Ob$T}BxhUHPy`J^64;Yi zh$@kq8(In(cT~?N@2b{v%ZLD7jV;A*t#rY$n{@7if$iABA3 zteR9v{N8D|5I3iO{v@YcgfXBy0QeeTz{~v1E9n`xmZ*0_08kB*!VYCnR0T{4Zf{%$ z89i{!QD99F$%8|@DwudsoY5$yb~^I1=*X}+Iydi!{=THc! zAml0>JlO=CJsHFf;wTAj98}4&Tt2V{@)rd}ThhC!+Os!Tw=O-Bsrxsw)W+zAHWe~b z=Mc#$d>~!`p}e*Sag1QQ2fw9;0Iwzn0o52-)gUJb1@ox_VnJ9EG-Mf@r0sFCiKVJ1 z8NPU97yn#dqE4IYman|@=+8N|jpB%vs>hXnG-`RA`VKZn*t;?sVo25C*Ms~jxa=Vg z94-gWMoEIXpEPQDT**gE1#ezA>FQTqSFFna@m$kyY(y^?^e1i)@M?sA1mw}dr(nH7 z$b|1;3o|@`WEL<+%W<%xp}${sjc!4C=9!D^1Naqe!L_AtND-mq<_ zPFQ(mcEIEu6};t3;)+Hsbiof#2YQn_e@ZXq>WM)7m^Oq{JTNZ>M6@ah4e(sfw4(y| zyNqQaFi)=F{G{N4P=lcoSE-d`QcF&Vf|dr_zRfuvRyW(#Ob3t3a?aW-!+*lWmsHBj zY@ADa#9wWkFoa2=R;Ee?mNTUW5&@N9o`wWqV6IT@lYumK6*zUk%n$k2$@Bu(h1s+! z9y9B8{wvKotn9ht)V@lsPKfWhbX^3HT0L)6;n7I>Z(b&$S`KD#x$%ksAs?h`2)lv8 z5(-fLHIQ=;Y4#vPfP066dl~cs0>&n_>H-KhcVU?HQ3Lz#nVJ3J>Z9cwh~pkq6uaP) z;-njM5VVxH|G>83cmjwhkO;~^nFSgIeQ@p4tP-q1tbzqHxvXUd5-&hXRDvNesUd6% zXlNi$eQpo=pwi9(Mb?+ReJVrYy)NvD)Y+`Dtg4CI0xKZ6qNmd>5;oQf=bigj)PptA6eSOVVw^SrstGHDU5aWjmgL+i zat6{iVEGva3|J(1uQ=-!p|Nb~m81#0$xv-eWWF40A8%+CN3RUqEk5pa)CH*c1|tvu z|D*^JIz$fv)nI97yn+cz%entxYShN0n=n^RnkKgK0E7{KYzz2)bC~SGo=cQIF zG~nZepiT`)rH~&hSAu8@fYY$jHE3T{yLQ@K( zvR)?)a%5Rtu7p?-h62yAT*+`sG5AH{41n<-gK%u6Ou^b4hvm{3DA&i{@^8~~b>j1{ zmzQJ6ets{($fp+(@}aKX&MjK3{Lm{slApt(aVTRPf=+`(3b| zCrh_A*&ycO5P8L!`avXxG88H~+)oTcQ6LIHoD?WC1O>4&He}nOI_s5XWn zg%2Yq;xeOP}yHK)EFu&$dX3GhJ@MQ`jQy?f72d@)^ zOhAz;uuy;<9SlPXl2HQ15CEhwok&wBb|@}i`F4q?vlsh(nz1Hq`I@@BUGM=2C?>;M zz+nTb-kx1-}bTnC^fAGTueJO9Fz`{X;kdvD66fY6Ro16B-)iZ-BY; z=HHhfrOT?zy&Bze&y?796eX4P! zlzOxxf8e>L-@;4UJ@&Q@f71|rcnD{v4d8Vqajxi93lEoyTD_#m^cBZq$`5*BZwPi8 z3aaS-stshI1hT{6K=4okeEnk6ZhAKJdT9IqUNn;JykB+5j9$Y;>uh&ZN>10qGKMn^RXAW3Xf<&Wv8+u=Olcn3Y-tX7?_N?m2 zpe%b3;G+GibHrV8t(o58;L$XVq;ZXs6U4(kJ7evq{Rn7WMQTqT+hnb$n&(H^=-dh?d!&76bj3?F2PTf7JlsWLObDxnk~1?@mQ7$#yyT z+vDmrI*JzA5^vq+H{Bt2e}h*=_zOXuFQ>kl%IX~xM-g3yeGYX?DyOc909fhU=#0ym2?ra{$^!m#ha-ypF}I{ zlP+v|B#j5bRY|p@m)C``DP3e;Ko~Y1*dk5q&8Tp=$cd&?yS(g_EBb|KiR}P{tZnmU-L$QSDy_E-!QD@&)WZlKb4U&~xlNzPXp$Rj( z%|A2n)u{~on@qJk1lxvbeFrDAt=a;kvZTJeuD$Q+Vi~UWT8w`g;N&x5Od zzy9`Y_kKg{DLke@ShrpJn~~>{xc;4bJ->XY!PPDM3(YTnR`^B+b_KO6(gee%}BSX^GLgUSMpu>cnqvz7E_WQZ=8JQ1$tX;zN~rvI`ir13Mwv^f&%ESyy>A<&j$zgyr7jQ5|^p7@=1Yc@$ra?=# zfcM+S#qJ*S4fvz5=8@c!s$CtrtH7|wuZwn@NY%)bUXkXJO;JmCT#Xx6c2D-eL7qPA z#|i8yKXckR&{PKw8@y)ktSxQUBy5XkWWP@%`gncr*mAfK73n9kU`<$zj!N#+xBtq01_@w>qwlni2b~$B;?!Ei(&Tc|Uog zIGAHc_AQ($9ue940P+OR$eelexi!V}oyK$4Q+^mty77YLt4Ub@q-pW3E?B;PoArA< zX&QNpM}3dKY&Ll0Qo2XQ8Xeq78kbk-$i(sahjvI?-{wbw=rIoy8cta7V{g#~jReLw z2bR_DVdu7EDyN&@v354v?Tv@OsG_@`nR%EgCMg~hbQ3B?eR;n4GZc?Iu;bwF?!G%S2gjFp1M}mxJ}U(Aln%1(+xD2>0iV!oUA?z_#!j%l`f|5M z{XPVFB)0iCCSOtSex(Or^(<2TUrZ1?<=O>ifsf=C{CK4M%!x1GM!pCrUjI_utUQ&J z=?Og^$u+WI-P{9xW-FtHkGnLt-2C5<9gk2s$F?Z-s^q1P!&dAcaeB%8UyU4(c*`~PmTB*(V_uRMxmirH|$d0EZPsPRb7$d}>eBD4Jy zbMuXF!oo_e-9Aga4&xMNJo4m7wL)cbd}^aRTKZnuF1Z+?`kH#WJeRpCtnA3k*`~sd zfIJ2W&|C`f&m+boHOEi%eOt74ZrPcRpQjYLaLwhLpECzLiWiTZD>|kDd!d%<#^Ba1 za#W_){&KW<+aM$woKG$jIvneB{Q72B_$&eg1eZym#X#oIA;lxT^c7kki8*@Er|!ziF{NVELK{fxn;vHE zSK-7XtvBWDyOg+|xFQrO7e@?e^*d4GkqUVyTpLkgL&19$UbDTjl=k>zFyfIt9ggk` z`1I(?;OHmY$9&2>#(7&ZWb=T5B1Lq2-loBqQa7Sly9ps488G1A?vpciy3JhJ9N(i~ z<$^*>sAF3;E%D)z#arKxA;uhCy{-pckm1<>fG&|mdNl(&ktWeZ}AIEly1#@jCu2B z*B^ijkF5M8s(fA^Sn^23({j|u0>SAF6&~r*=4$Wu0|PsZeO2(uwg=1R3Sv7PxI?*R zH-Xig(cQUnK(1rLBQiWP!fR>C;ri+NtA{J)c$@AK;gKsBM|mVJxml-btzD&`t@^Z6 zXoXMxY;*G{#IWb3Y`5USBl$NjN_hXI{%KU*?n`T|ro=S@(+&+D(GK5T`61fzaDn^5 zd;6cMks*z-;E}^M4-UjH4sUegMULgG66^Z8Y+`c+2_9+QcW7K;znJjByRUx?c>b!* zFT;UHLauwC_Vqek@zs>bxbORXE~g<1JaVKPmG$7hf1)l*CXD#&Q%t5b$ACvF+>ENB zA9{64^i`iL$k=DdFGPSxHhwv){J8b>k6O3#j=ShRb%&6*r*7D{?(y^Vxe@&xsn`?UBFPsUa3|J3aK?}Q$J`RxWHp;!oJ5_X z^UL;id!FJQ+2`bqefmM0_xQ=ZYok7|bIZD0ST=tW`5l>Zpx~S0$K&@TY?F8NK@Uf! zW88P7Z-!G-g1wHlmft^rqUzeshg|0RMuQaRRQFMsoWQ)#+!FO2=|&yt*7NQMPp`83 z4>lR4z2(|92oO(cg!zti%X~7%GwbV&o8CNWlX?E>JHpN7m>^*R^KS9c4T$eZgW(&a z3V$9M-MCNvCRy(VL_6;;ll}PWs3P|t0cch7c(wl&Q;{Tm{x8A);HcNuv_x*o9 z4<@_0GxyBQnKP%&d0zv7#Z|@5Raenn*vXNUXPhIfs@w*2XtA2dgqP69} z6zN@U&C8mS=1puy}DWC=B=~0voFfHCy+Q%T?IAaSrcKk0sV!e))Ql!B#FUv)tN{k(@em4S3eAU zXXxDU{IhpQHA?Anad!55vYeUprMVxJyLWnKBfP6ex2k6_=Ncol9kw`o$Q5<}j2q&9 z&@V27W7c06-(9`C(HAE_Y`$>wtK_2DFI+m1KjWpOrfq;sid1)IOi z#nrmEOdiKepMS_{o2l6D>V)8?@6GStqdh(QLfb|!KltXq5!qe+*X6Yvepnt`?8?V; zeqs+Sw`W|WNNP+v@bn^Uqrf>S$_zBYOu%(l2iMtnb6@t3m)ivwx|TO&N#*|zRCjga z>TmVssx`}-duPh^f@{Aim9_&UjijB7V!Eq`w%>7mU+Z`DA$C=c(SI#^JLB<8kEIsD z&9es4UHx;v(w$~xH=oOWt-~2r$;x}>KurE^_BVs)uI|%k7jv&tp+XV0pIm1*R$e2! zYZ_R3kK6u!eKdEqI_Hh3sAFCCg%?#-`RMkEMskNjhNcsTf*8AY{LEA=cXdpkhlWaH za#w5B|9Z%peYf_??kW1=geRVjEI@KscYp8wFNbQ%)oW0H_+nmA}f_S`V9)H5?xJvg-dA81CwiZq(HL zy32Tz^c(Z&Koha;16z{;%+to}1E~dloy>Ey8 zS(uJ~XYGyuMC^9;%AU)&HrqO~_a_5JZZoLs=gmYSGYz?2UG%YT{qKd(tvtn#qnFRu zkIDFDOZhT;ra?K2E<3hOrr@@#*L_>K{Gt){#?}4%;YUYLm;5c`oSE7Nf_op@wowx} zYP)(+)qEAEt*zPb&s|l=ZH;)9J>!`W#DeS^kr1B9gk=e4ySn9XD;pT5RWtQyK77l= zTYruGPe*K5H(k~K_Y&h?u4;W__}&J?R{bN_7X6c$S%}xJzH)MG|5E*DM#V%|>UlkW z=&_8;bkF1*8QeO2N|}S!u5MDS^`R>h-kNe!lWqH?hZ9Zm1b_b~GBdE+)zfB`xzn)H z>D|TFzPhsF#`ZGuTOi9X^ho~mxEL`@jtA#gx`5Hk27bLqoNZ|U)6(q<+ly>z|{pKyb-y3q}mygHx zsc>idl#B73Lc98IUS7c5I8|fq6FnL-5(vCtt*E*wnYrwd||*ulc#%?fwC$-}r;huD)hydHL4H5+4Me zdKeax`(|jyL*l7H^^vlYnTpM>p3!`7{NI&V{d_>z_B-v0q;(ljbM#P-l;HX@ADLZ! zddAt@JICJcbLYZ|?4PR!*fVah5t_3KmtFl+SY%SAaV?B&=|z7vdo-y*#`Ptr$lh?) zS&GW84*IHVvtHjN|DNMv<&=FtJkKu|Os^5T#`SK3D(}FN_r4IU7{K;wpcKX~{_Xdx zqtBbGe_1lBb)_$iPcrUa@oRRo0Fhl?c}dXfd5vNce(1P#T(JUFwTy=W{3Bh81CTI) zR+A}s>}vW|uCg<2r;Gf4zW%{MKmBkx?ZlbaMq^j!vi5#;U}|jMCqqso6tPslnAu)* zafUJhi(Q@Xy5^T^eW&N1vg+4YRIVjoW?YeX`gom59`etbfyA!1^h$c{PvpHT1^aR|I2>P1UQ;4{YEv`gNG4b&A+D?Ygd85zlk0h>@8lcTubh1G z;cEq+l?=Gd!dq9@Ecc$OzjkTkV?|yqI9R($lZ@L%M9PW=!W%(bS6_czyufwZpvWP#Zt{5Mf{54ymH!)X*42lO9=Wl*>BHPz#*hBCSk5(1Gaf_2LF`Tnb%Uit4!kbP zx;mk8wj2W&m9vakQ{>e7C0BmQI5&`um9|)QM&=}VbWLVqtgGuDm|pTy!Q8vwtvaT} z?5}HB0`uj#X!pcP&jf^Zb^PK=mu?Jaj}=k>@qMj9g>wBb;j61hPUw8*$nLF|$`)R{ ztKY)Xo&Ki>_dfs~uRgS;bgiGm*DjnFRx?}3gPG?tuJ^%#1f4V?*@57S*t;z{38hVa zpmz0{2pq2t8QcELoozbqGB30JZCt|s5s>4{lWs4tckz;4*1*QAQ|j-i7g=ZG!rY?^ zEdOS2pJo}a{UDoh53qM{x-$_pUj1|2=9{zjyeilHsJX@1&ABFJ+^L@`)!syB9%Q_F z-{eDuvfn9JLHBi`FYb(u;WBO;$Y{<=z{(l87UY(S^ z_s?yL8+*s)XppZ>^L-=!X9t$?fToPU-00U1Mgmts>6q9rZ4|0d&B zDTA3|EZ$i1Vn4oAzdG?@oA-?uUVOaQUgDP${bpzU;*xANq*KD@Q0DYzGY4FDUN9I~ z!D^s&X2t++G8;KgXW~p|JqM_6lQ+%i#h2p3P5N9KU9DQMP^#9@r1GJ;GVV1{qF6S= zl#!v0V0^Ph%kTojbBxhMn4U3OEtqdJxL>a|a}M5@#w^DUS5M7f`R6rP^+Q)^+yCDD zpZPCedv09}=}oO*uox&Ur#G-xhQS;&tVOH00#_dVtQR`Tx^`ZD~b*BBo z<3DRQuj#6;`f0?mjF%pi&8<^Q^Cmd6knh!_%AGz`r2VB$?Nj<`xDPpV#-lDWdb1Aq zUTywmeuw!t3j8@{W$>yqQ-pSN_@2#!Ck0qJC9r z!fi1;u<7GjpwnjwqM^FQ!-Mu3;}@=+UjOSl9cmdqkQGJAjF%F2OpIrFJ4O-_t1i~| zQ2&w#+uaKP~9^)N|oVs*23Te2x94sQ8-Qh_`C(~D)YbeQ5B?_U|VGa>tt zbwORf+WP*9b&b{St`?2YHn8ID-#%#GyJD@D$EVxk5+Z;(8s@$s3rKrRlie2IoK6T2 zn&Nzb+}H=Q1RYnK#3t??zif+%BxU83Q;(=l<;yhb39)fx$Vkvt)m4g@^ciStc*;LKWm*_Fo!PsLev93DR!gd;P-1aW%?b6yxG2h z(mMIJ`wttJ6Z_C(Tx-qA%hz=2Gkn;t>qA>#ojYA|Tt4k&hvL7?e`GiwL;7lc`D?Au3ntBEW=@Gp-hImQ9TP9O$7hNV9`^8S1F!X0kC_4LqNXDV5h z&{%3Kai$;&JX?FEqa$rX5T!t&NRR@;o9w>34Z#&hC%-47PJ+Rby&Q;to;Oz%7 zKiycBvUX;|Om*vy4;w}PoM+wcD!<#Rezqks+e8k03D{wBX4i>`=SiAka?tI}r`ci2 zI}cI`tdY!a&;W3L&=AMD8Z<~eSXE;^4oR_Tkb3mI{6W+5JXkfU;mfXkBi-Wdvv!=A ztLs}>HNpGraXj8@V)(Le1}*1&Ni@pC|N;TTG!5vR#dsK1Q=CC{|k3)|Kecq?=q3^{fN9PS1 z0KQ6Pn04xX8C(3uw7v6MUg}0q8hNAN95T#4?%FOi`r%esR=Q0L_5Z7 z_}UI2R>Itkh}P^RgTzjqbcB-9E@3GB6Qr)**f5ML{(IT@VO{sXweCRaTOtEr8J#nm zDk$i$W`>}ke2MrML;g*%nIq%FE%xNZ9*j+h?rMvRis_N0|B7Mpi1?o>Xg!JIN=YeU zB-t^M?#d$-9R=NKdz3xQVT`nNT5nzI@JNFt+Q0hJ@j?U29jUme$HYO654W87;&uA^ zsJDs#ow?n*sOrFj7L~icoAbMPm^-cFc($xAj0Hw_D?Zj9L0pWg2_AnT(wJCDA$`C1 z{5B%KIUgSrfm;u-tb(R`{wXmoI)VlH_Es>Z68Nskx#oFH0J2uX1T0Ee9iQihG;CVC zahp1Ir+D;69`$@viud1uvl|iHwRSiiZ|4(22DNEjFO>3pBqElLPUQHyF>wjW*w%KH zYPh?D+_J*0b_3t3ROFP|;hli@Mk#O_jw;m%P~!ZQl_D>_IdRe; znX)R?I1jp{?_?Pi|H^zh3~hV3EiszI=H(JuzAYUc!I2GQi?2iE2u{Zk_2tAkXle8!_mua~_cneLnNn?=2s!$E30TYOYKTf9rJsA;d2jJ@6t7oCZm zTNMsu#oaZFNJ94CaRXAS&y;knw&ZRa<__2`q=O)(RG%>7&#A4`H$T<|!rZ^Lcy zYk7YaXNynB78F!yQHI|E|iXVVA{sgRgFZ>00uNSh?C^Uy z`t4g({aZ?dT&shFR1Jf2g5Su?y2rs`QecKMVT3tEVP-E7v?l#mdktP}=QEJy>Aff{ zg2Yv0VA6=5s*o{B*aEmSPcS(mga~#;x*a&ZJ^$Wp&QF&{X;2{p=-A{D!Jsnc{eb^Pq6F2n$b$i7pUy zME+XoX>wG$2q5pN@61qWg+E2}E|k4XjxabVOunz2f4FjEja6Wob=1dTiE5$mMo*>jzsz1Psyr7)o(-eKUJ4CWZ!$N^CznPY zy`IwSDfDICZ3VaPY7umD(HJQ^y0$Zg`nKx-4!YMrtrgCz|2yci?#hN!^&;C-L3dI( zum10#v)ljgpnE-)+$G%q@1WDT=E8kKX2JCh2o9S(DFmC-W_dOqu|NAa#gOkUDb`cx2ahGs7AQa1s=Q>mfeD^#C(= zWGJEkN#j&X0#I1)OiIzof<*S{2*&Q|KMRG14j6lyi{?YM1Un`aK2ij2BkA}M_51Ad z#$CR7r&Q~1{HxRJW5x!{%lo8Xhg)>$d3*O@CdDHr?eg-4A_|JAA|Ef_dDe!uYFe{- zs|L+l``Jn?CE#u)QJ%8sR==YQLp$u6V%%t~(z`>jyqrLQl%v*PjFilagn3*&NQY$k z414fWU zzQi~|m@`nI5kHbWAx26=qaFDUq{1||i-xk&IxDJl7>qop)9M*sCop=NVzrE(HS0_| zJ?cv6^o)>NKcP}T64P#(uj)n>n$x5}nV^BT)eE-<|0ZLE^y_=NM-Z797lB>oc(LPC zC@)4~fnO$4Z`GP8i`Ag#EILYHO*-00>2!L|V9**(w2m@b%&f_%r#Zz=LZwb5(wp~c z7`cD+jeQM%%WeDnPW2yyWg1JSOumD7$JFaV9cG;s%tnD`P%lMiunM$=F$z{xPSJ9t zpa(-~jq<6Ndhwe0flF&woY=TPnT6(a7uLk(>KvT$k{)E@V{B|xM1oD@_!%nkj&mVQ zA_fv;*3+0{gH>y`2u9Fs)N2JRP3ep})Z-B-aE#fYr&9fLY>@>J(#lGmBBjS`22B(Q2Y8@U_`!q4Yd$0%kSGSgjn*=r9Z*ij&*| z3|{2FP^l9yW}&vt?bmzxz*-?CHfQ_wkK?}wXB@IEJw8X^+DW%w;8FF(z!`wuhDoO^ z6mK+Btkq1@S}cPWg?6wCoIyr6dhjB;(l57@3cO=kRio&uMtRi(&Iij>(oErScyUFT zRR@cs#*0A^^sJsT^RxiQFqzGQRnO3ZNuX%0*{r8ffJbYUv$&%hFCK6B<34@YTODhT z8@zeq=O1q>92^*efg~QCJngmAm~aXeyTKef3!~%B20^FSS$Gp`qClgTHJW%c_?yxR zT5ykCsECav*3PB+@!;6aiyrZv=YFa$-KJKsyv%j_hj*&S%vU_)&nbh)6c3r|3%-r9 zZO)&&`o-2|JJ;BEAXw&3f1MK$@$N(#cYgh$&-tt(k?pqr@$eWojJv+n)S};Gwtuk9 zaPWi3G}JcK2_Z^QJY;S}LOS}7r099IP*f}~FKfSh=iZBl7mc>JT+smKVr8X80;O1_ zRMOP^BiOfrBE2&=k4q}C_AtwI7;tN{vwYmvhV#VXM!db>07bQ@^)pO#rHj( znOY{fkmV13B3`byHY&-cxu!KQ4?U_Hzy9K=X0MtR+nSlg(J|fP{2`7!r#N$Ewl*k` zFDU$2#S-coB@fK*8N4;ai>tWt34^7x(?uR6g~!}%Doxmy!m3+yntXRlRbX19$#ajd z43@=I{n*;63UhZ|aDS%F{j}oby9nxW-=%}EW_W?66tz%D zFG8AGWcMaU=S!upL!DnsZ~d%atzBbJ>T+MIpSRa%Q+P}8wbyv7C|;fYd%RYZrOxlA z_r6t`YdH1F@}AA!KEJW;m$nAM0V51zSV}{cjgzj_{9(mX4IaG}yDTdQA4p2-YxD7r-ao+96; z6{qLcnQa?-9P71o@AUace|tv#5G;q<4PZUf^YNtW+X-H}_rk8AVN0yf!y;b(R=ohxeI7rTeQHDjSMc$-XIr$3E8XR&j~`L!#R4mo4CQ+KD&7?S+w z(+)Mxt({mh_s5>=5g-67di zCklU;(eyI!qnT@iXlme^iIqB>+LJT$XG#>OX%R&pkWsZM|G))xzfD@dcGkd!o1VPOoRIdLxf=+7^nknmGf@>o}ItT4~N~ zr6?n1aL&2Z7+VsJrDNdhGVv4M`Q6^iAqIjbh^(ZozY-Kk!MP)g{P87S#44kTo3J0XVT*{M`~(oS=tEY#<9ds zubGF+cx`iz&c%D?ng7k?M;&*UuCq1xxJ)pl&scI&y_8*vP`LKs{k1X{Xt$h&)3Kbu zvj)m!qy?H~S%%VyZa$4?Q%}XV=K2SdPK_`6OHj3i!SC1a(%#2=l0KCfdsu?a7L&+^ zOV?V((k0}wMm!3x!f1BwH6Vas;#gGGwi;Nik>^p& z+@mFei)2%aVa0LRv(3G`Z+qKkrb_HDc}_PEmX#y&!O+%`@tU9c@0{Ty8|(_CvA- zXB-SfMAgI912#S}hOvutN6OVpQz!mL>>JEwBrq5a5V#t~WW=Hh29t^A^&G9`wHB;5 zXCQ`-L2ooL788eR-;_9oUOj|LJxH{dT)gb`_UF6U9`p8%NV(Y~DFCmuAGC|!kT_g0 zbW+b7Oz=Znb!Lms!jU57T2{|mSb?E+tksD4mtJe(4Fc^!y{iu|`tyAG7wCW**4M)rj)kwM!m_5ImgaNAcL|n48xhR z=Qzx_&a9Q_C0&3@G?XSe`i~DMJt@r!gw69f}E4{z<(MHpsT*4f<(i*|>Nz&ZdQ7b$Fvx+#B2EY-By&3fYTL8A9 z5f-?Xw^%qmPs)`83c!dzVD}+B0Ra*!w#2l$B3QM@R5|%_roR52$)iWS`l;rj0M?$I z+RlyT_$k?A(DIBBR6N4~m;lZKg8(!e1PF~L;9HnDL8~_qSON>gf`u{*8qdZ=bw*=p z4i~KWB7EDpXH!pZ+;_d~^G8L3Gmc#2#|9IX9*1P0^$?#dZ!`&7t-w+|;2#(Rtv7=M zXwF2q)TGyO4&f?E22myQ6brfM)9sFQPM%(;PE0ladA@gpWtr%HNLVtp;dBg34jqm2 z7in?{E~`P%1A4$>(V1z3jx|_KJm4uTdXo{T1%e(S9zjbpdL!fA6wB|J*AvZde?95! z^|}X4o4?r_w0v{$&J3TdiWGu1aXwLcEvvPfDGq@@gj;DHV?eYFFbW_{XSGlW`2hfh zbra{JtKuJ(e|R;!RDqhUa*Qg_;OYb)|9JX)hR`Js1&a$TMSyi?vlhoY%WHvEBv^C? z9RGR)iJ2jf0LUyXYXXvn+2jfVi>vDq`TeKl-G+IN=2Vs zT&P5nfcu1((ErQ?PleM8v|vPl9qS74Eh}x}k>~({ue0*J)=1Xfqb1ZlWCTdNru6R0 zFNSn|>w<8(M#b&drhXNiHat6K%%Ow{&I_JSrA%}g$aP!MPvHDgdShWW|BgLJ=_99@ zDk1$J3}_y>yNkBP`6$!)PNqmd|MdL0x7R+tDO8)SX8E8R!Lm|8epvbrwKE3w_-S0F z@9Ohb*I#7sP72RLkC(&J6&z)#cyTr++CsQF!x-**My z3Uq{gcho!;i*@?E*!?Hj+mGCAQ2peH=IyG?Yy6a(ZQ^{SXZmgu1#gop#fntXNHdz^ z^`xSoDKWyh^{4Xs6LsD>TWdn8@|%4${@14vNr5(7QgQ|el^Q70Te-&g$4kys&dmlb zSyUsz{33JG@x13ry!z`MfpQ8FaWzCQAF16VmN5w>k1NtTYIVg29S?Lpa;Qt!`;8VZ zE|WQ{@8Ld#yErW}y`EI0uL$NJ7}TiY5eE3fb8=`P71m&6V8ba#lq zOU@3HL8~)Dx#w7%=)j@Ev97mRX^W9#4M=c5~>Fyc2ms`B!9In z*WVrAS@GoxA13op%|Q7Ccz^5(#z>9FuR75nhMxnrB;dGci(Y`u!x;t6Y_SNemKXFU ztC=-$95QlvkCr&XT~=}Icc;EQyRXXi{D#C^Z^iTp@tMT*MU31n8|uvbb%1)O<))QA zN_29c(DHfP(j(`$G@RIRz!Q7z)6E_QkaXxY!`!9FT~?L*E73O7W9f7nBgI%5EU+GK zJ{`14d?pH<)*$c(GY1)rO@%*?nvVs) z$oi4k;|)5kb1caA)R}o!Ph$&ml-6owVUEBTrQ@t7Ek;9AjG1MOdWErw{dkRLN5ZQK z3zszB6rVhbF5G!=zTk`_87i-fShvZ&D$++OKa#{0L&@DYyK_huWcYEgO<}?yK@@qo zl!Zkqv6Z(P1>}$#Db}Df>W%K@QSQ!bWVu&7IZ?mL$$7cXe;!5DE8G#CTO?)HOr_ilA91Y8?N_=;#);uIha%{1oTN+FdL2z(p^hn-PR0ZkB& zI>&DF=)-FS-wF@^IbHde!uQJW`E}9c)&&DdGWKHx;!-$f9*Mc|9)Lo#m4@+)R8p9p zFfid?1O}qOn$5hR!)F)iqNVA%vtKq?d$xF;SL1e=x-hR!eKIFF;~1sNG!q#`N{=A} z#W`>8uR@b)VA?naVWMoC=_EJ9KEB}sNkv@AY9mP8-)vy+;V6+%?aL|AvEn|XTkv8iM z7Bi1j6%!9~wI-v%qH#4Ngh}$V@|pz~H{@H=WFmEJdeVhfPl6w3Sbh?p106@B6eHaD zB(W!qj{&@;#*w=tejsTp1TK_M&>;JtL~Y z?#VR~fdN+lomQ~0Mx%+dfTztg_9yb}dB$QfSS<$Dn{+iw1REk zfBigbI(~>$1A5q|&dhU1JlHG6Mf{^YkXK;*;VTE)maTgDYR3yL$~V&bTwL;RH-&TY z;Su%(8=j8QG~nVJxIT~_0xmUUE=+KGn!ueL_7{z)9?R&D*inbD+Wu|>Ty6O3U)Q7G= znRVs;<5dC(je2Y$awi|_iVE|v5~N#yF%f|KG!jRhLBk8IPN!vP&PZ!H;NX%twh6L; zLF^6=W}1S-oWu1F@wy;s2xF8qlt_(OT=Le;@bSM1!k^iKHfM_qmR(Z!(+G74Ed^59 z=m?N45o^@wa0*aXEpHaU1uQ~O7K_;eCp7LDaF}x5tOuku3{jC-si{P+Q6e{S?0X$9 zQC0QFdbHfzV9~NR!AE5qJbiN}O`lFUfQZsG>)p-@@~EO+KWE47vdu=%h}u4U`t<1C zbT=O_iGN(`m{RACcKpPxMPvzJKamgI}j-D_S_-ePP|?A^vh`v zsXgOQZ^|G1M}}#`xWl>vQ6P~a=P3^Q@Wgn;LB2v6OEEJwGM=Z1IqR%Shu{l|i0KV5 zrnCs&0d5>;5)>_?nPn*xA|fUew!a>+2%M^xR6Bw&ARS5L7*hV+;M(!;7W+$kciWsx zcWVUS%^g~5KI^V zqWl6TUJoe&glvXmIfWju0K~H;F2c=@qjo=TQ@hdmFN>Lz3fyfTe9ars#Si&F76A^s zC;-y3d>D^i9cSmmpv53lA=(}$;S2B_pqt=4CnI$|f?9IKBJNHixq4DjQUbjtIwg2m zt08<&!$M>j5)L+KSu@;PP=|F|!Kf1`NN@vUgp}E@UZs;p>sYk!XY?F-X~u_TN4Ds; z_{QFT+kJAj)882Klo59{Tgn%~$!FB*c*KHnp5RKA7Sh^;9fSV>d2hwZL*q;Y=(?++ zXSPVv!=(-Xn6ThT-%pn=D|LTxU7rlp^a=FfDuB8^7OqKVV9fL7;m{=v-&-vKfM1o(H5jzeknM!{quZalG_=RCG~R&IH# z<5Y*8e@0Z_kT6RheByO>r}sSKea>mb1wX-z<;8VTlg`94Rt|F63{Atz88M@{!>F}@ zn}LBL`s+gpsh+bqAzQIsZ3ZlDl<;_N)CX&AOEQzpSg4bZ)n)`Zj3BfPRz3VkIs?lY zI4i4Tkas~L7>pZ?IHQp#;v^GIy~sS4ROWEWakIJGw>&FgqhFnecQNnLodKvbJ1Gn95R=oKWHut-u_rS?$g@zibX5!NTJljEstfEJnyY7PTT6;Ld?Way0|?q16h5%R&h> zjT`WKEp61&@Gn4*fWHArl86@Tjb@LQSb5j2jQ#u9=dU|qTB!j`)Uk65)yNqvL!b5U zoDh{15=oSFb7`sUq3&;V@Vy%~oC)O649i(9f`MWwa{ZdYSqGCshhq;Zcm|fCO>Vu% z)d7w+bRY?);ziG#K0b6#jlOOA*PV91+D#u_(mx5xvJuf?tnDj07I=tVahk;6i!>$PN*P&rGEHW^8HuJip)lbLg{#XfZ?!m^fku~4q4~RG<{Ca(*E!pR zqg{#~oTCds%6sPiAP-T5jkil_JUB>+xvJh0z8O_MO(^JS+;vqq` zl-|m56dv?yjuX?RJI@-c>h}XdX$myX+ve@dlf^Wna>@lHeAg%1ob001rVgI;R?v_=ymT3D| z0iR1O{t+XOti|&Q@yX7BmGpraeR>T}aE`)BZ8TbVj1I&0Ny~QSTK7B5hqNEoY3%Sli+wJl`bTgipTNYU?2A1t%9aov5v!4YK*Qyb zXDP)E$OeGRoyFm;<;+O(Ge8MJ0+^Mxz#RwG163n94hb!s1%56@p$l;j!GsX?!)QaT z(uF2fdcb@WubTerV{HIIOg22Mo6R1EXc9vtljCQoSR*xpg{=c+6uStX6=VakAdp9p zg9go*bL3bV7z92Lts_Z`21+k)FDbJQZT580E2gG-ex5mZ)1>Y{S-J@Uq=9)zdPn?= zP>#r*__Vxn=#qrz2rL{=$Yj|?1!xP>UaMW?6XF*m@Kizon%947DP zU=Gq;n&XwHOdnbYZ>wJ*U-5AtR4&^!09}+&EzuR380|@9Q zHd>HwO?(}=tniU#MraLaR65ZN&Q3`B1v1)VFno^95Z^vZb2pVPnt%$HIkQElDdq+khrzOb0D>q zXslkp)xMcEo8P}NpvWa;_;&QEM&RETlO|F8zaySVW)S(242rK9d1!DZ6ZVk-9(#tU zc~+L@u>3gM5wX>3Tn#;^@4j`=$=K5q7Mz)W>YFOPn{9ZV04OQ8FXi*QLYJXK{FRI#=n(FNp@?KVcw+Bv3>{P_7?4ei8Ai4u{HzF~!AM7C z7^6XtJZ2=^d$h!^CoLrkhy3=q+<9B+ZUe8~o-k;2seA$WxKg7q6i~?UZaL^Qnt7y7 z!U0SpkpdnAMu%*6z0M55WwM$qNHO3UL=bRbxP~Zo;6?7&-+$KOujvhDl>58{^I3y; z&jiS+HYO4nC-w-t#{C=8<>9!7tk+s0GI3TJbUXqx2Hs@B;YD$Xh7+?6z8OS}UCj`+ zcO0z8nnZ3htV=OenPoq{pxP&22N+07qG@1m0RaK=QUV#))n)?*iv}ubye)zY70pi~ z{g9P{(^N}^Ney%w0fsV%bQJ-PLc|AjFs7jHqZo;W)uB)mPBfl{l8r=QkFLamX!5Qk z&X|z0b?~Div0**5MH6m@_81s=x?v<6?UR{??_?=y$16W6*SzK(W44OV>d*Wr!W4j( z4D$$%5aMh@(kF{LBVpjpgk;z_;-^sQ6Bv@5@+j?Nfg=IMa**|dX)>8DEN#N|8H2$D z?}G`+4@gFa6UeJI;YQ*k6t{PiI~9h1*l|?e-InsLTIE0a)MxXg?{Q5vfyC>r{-lw3 zHBd|@`M!Q~tJ6a5qKTstCKhV)@%R9oZGO#gC~7{K+1)chf)Pq7B!3XuwUT^(8CV|v4(m}CQ2(CkauU; zcWyTNIW)R)&K5-;w7&XSf8p%>@c~2?QyH3!1}Us4tqZHi4KZlC23*8|g>BIxpd%p1 z9kLEmj@1elBSNEsLJwYBpxehk_Ak@wP_5FHuJjIHGof8Nsc-P6c<)eG{~~P$982Q$ zQRhO4VNB<@(xxjA6|wEc0PW*8q&Bb8FFED0|Ebc@a^+;?tX{DG98p7@;4JA^4s`ppQ!g?)+H2&`A+bwH6%pZV- z>NN8m`m`%r;rt9$Lj!Ayh0Y8M6;4Q0;?v@QHCd3cg;*W*L2#!PiWgkHvd*xO4n1XC znbk|{&EKE5McH`=sTOU=zXqYWTZi0V=bNNYV0Emk#>gY&Yv3%nIZAOBGwz4sMg?O) z+P%&Ma}ZZ7beLKMnY>yPc0+4vMn_JZxM|GsL!GADmiFxw{Q0E-Oezl}#ql23`v|0; z0kReWK-^KX=uxK5V1ecjFCQxIF$S0>R=7`f9Jy&>!L3X9F5J|Lts!_xYl+$wH_SaJ z?D^$ zoJwm^{0+-b!|cPsr-jK4^MvFAqZLByQ4(?E_l_<#Hih0fs?PS^-7Ke?1j|aX`sbAj zi(q2HBG^O?{=u>%8Y!}&V35L}!yA!B1d)PE7O1NSeUP)SvNrd3B-K){p=b_yqdcjph+=s< z*mwxFLj7X&Iv$B!W;1jt=u{@9F2n=Yv3r8A{9WgZ7gr+wDe`1+!$l)12R{kOO&%V> z5S1^1he{Vs0Htj48rOHB?(fK@JzZG62xx~IOfj$1Ap;ifQaz=`#VPQq4ton3X%teK z;aJmAyw#-CQK&~p4t{<4#T4zv5(htEQi8|K&RHw~?V1<^kv5JF*N}8fF^YwQliaA~ zbjT7CczCVMl%U7P*ILZPZ$;ylEs|JJnv*fZU_l~|v!UmO+C8~)?D>_7`)I-^U!7Uk zc|rFq^8#6*xQJdLhBZO1l2jomE*y_sI2`Sa7T1K3{iH{@(~29wNN(}<0$CukNEgzi zHtM|bZc=jlJRNt=Xj6A@hj~618PXR5L}aDyzj6|dONu%q2GIsHh5P{;X0{eNu#}EL z@JweC1aj>fHA5{jqCM$7RH)QnTW7bZT3)TQbUpat%K#EdQuA7ogVo`(LOw1cCWsbW zX~dHC$hFtQmx=3QIykM3$Y~N77%p1D?Xn_=tJGMU*Ocx3&vzOQH7;l#wRsAGyN0tf*ZDEKaQa0nm< zz*!jN4GHjAA-s*~FD_wQh+rd020raEzi2N_Z$aU~mBQ+phY!9z@$17ys*MdG`+uvmFd4);O1`n_O(ZqRYI_-N6r;xj1n#-Nz{z`NTk<(nSK}k|G41c)(ao^H} zpaAY!L%5=-DvxRaW`xoZT*0;WRC>X2fnFr)!wOz%8hy1xr-8+v7%ILUzc2XLfR2ku z#%32i!{Ws{@l&W%D>NYZU~n7}&{CluBH0P`JB;vOT2a~nHznXML{N=|3l54cjj?IG zx&XnhE+n$Iwz+8PHe_McXKPEfZQktr&H+RMaXh<|`8A>w8*D*j0=$v9Z_A^a1qV$P z0d-C=!Ido-1&~QDhx4$mpyrt1I&wDzQ=p+lUXjH!KeONGMt{4#Kw^^`rEUel6X}at zXN=WxL_ieKq;@T?14C9pjA@ZsVn8qxiQo{wxH^NtA?~uvq^+c-fOz*Ikrel{?dGca zYl;;-!qDT_RS3|H?K&jj-HP%OeNS10pZ%=@J)wAQ1Cga=?iHcjx7BNWOyF1GyF&L$fv# zbj8$I9PDc_(V{X*d|5cW%#dmbb5vCaQ7N&vv&{ePMN!y z9TH{N_d)uEzlL^M+n4)kdx0`jg12Yt@I+SU?MmZ==RnWt!15&0Xt5Zrh%6&H*$S-` zSEmgosCFbNlvWy_SGQgRl=eiY6&-v2@z2T6{!%9&J~}??NB~L`91E!}n)f>CaeZ2# z3?^jg@GRo>1`|)LIz*$f2jK42<6419YZR2m;kh&t8@ohKwtU|kHngLJQ+ z6lVS4<)dpGTzc89+WwP?1%De6NG%Q7tczB(=v9NU@4?2X&2J#KH24L1!r0zObwxfk zsD+_w#0EE`!U~d-CQeByazJi`O8Be@?m%JMsT#Z9&X)!*msGiKPWfs+?Ez1-w)-Ibb&JAP6kS& zThSly>^2l(Y7`LmlvCAem;TW>^g+zlS#i%6ZP+2?4H zlZ+1?J66VoFpqJJAVq>f3I*I|dd7kUgr@?7POnb_zgm_dDh_l5fIL}2s4$cd2@{wx`#SR`RSk-XfLZLUn+XJTK zDLvejERQ@^l>f3i$XD*tYdQDOU%8nI1 zYFzyyfQyf*j>jP!aG$!nQ%&^b6%B_wYNX@{F4`f(O)C~_V~kn~Oh_{v6msN}!M-%6 zwqPC|D~#-&**RiPejGWmJ=^|#qweGP22j9BHZn=%k=s;qjZBN1N4Nk^!QWIf*#z@R&+-`u=L2GvEy%N2?wD$Y# z+-Jpq;HGySU-#OK$zPp({rPq6Hg9@S6p2(x(<4g4z_n*(kZ+7TEGS-Wz!3-|lf?ay z4Cce$zBI3xH}~sR3wGbn)32{eTc!?5>txtKmd&s84uChw&_Iykh2(MyfiR>^pt>7; zPH^qR)n{aQ6DUR^ozb}?ot-FfguX_vJ-<#^V0!!N3){x`YL*NjEFq(qNfZQJVep(B z5_yE4WQLCvX}#htd?>00#QNcafUODD4^@`{4&<0(sS5>a3s2Z~cip}NXTO--HG9*N z*HT`eTFIjIrj}GlgH3}?#o?YeR6Jzu+-pDI${4~xl=kbu=5;ekr*Yxr4M8Wf*cLsosNk^?gi?HByyUXadFWR zxOR%5LYVk`h`MSS^M}7)?s#kLkm-d#I`P&i)oeeS$!=x6De~*^0uA_j5o@}w1C7o( zj`2;o$4{&0n)1arTk2I`UMyU-#CII2xBqts)Cyh>d-Hf(5(@amI|uaV%cWy`wkS2N z@|Op9SFd-cdl~~$XfK0&ds8b^&t|KQO1JSOPURZO*C(_|3qCkBH74r4&81H4exigM zuh39dJp7Fff$WqzDD@!5-h4;%?!r+&6`U-5*0I;v*wDDKV^u4B8BOHSRQr%&xxCSV zHAVFb-!a{Pn7>f)r5PzFCY9SZ^<*xSYH=!KQfmG$?HzHBMb7sfPqB~Zbi9^QV)wKd zW98)KE#Fq!JE^zd<$YAY(e-JKz@bwD-+Joc!C$|T!H(yy5DOtYd1*{ z$=jjJIEPdH;|A}AP0D_SnZjJ_Kkb)EN~@Dr5C0*9BJw!V?i|#(bpt4M{T2JS4IlBx zk3;^P;?JNwdyoMNzNvjg4!M?mw?xFKog>+nQZL($JSSt9{r1t84M`2dl(b}@X0p5X zZD z?oG{oYY(QMyrcZE>dTLxY7>8Rk9o~ogH%8G&b#~h{r}GSKnUATh#QT+1^OQ-Kw|wSZz&0~xow!^Q<8iT4GRkQW6C828IG_zg@b(aOixyiyzH+Ip zzF@an_jc$!I_N(IkBEu`wjC)c9gBBg8pMadNx4b5F@fBCUB$~SDM zn&msi@>W?b&{H8^)E)@!Wpz%0m@<7zbUyu{oO$DGMrZrFdnqM>?$a!*4TJQ^cM@M^ z%9Zn>$EO_s>iM7#?>ByUBvr$}y}^n^$f*mbyH~*NA_b>Y>h1rfHSr?I zIg)bsr;a|`{L|-sB2G8dM$gZ#v?dA-|E(cFbB+LHd4eZfy?12ov7PgKhBxWBr^LYU z!y$@8@NJmYN=_sGfKv^&4EP0y)2V-|N% z(vdxfAhpYCvpAgrc#Fsobz__I?Tn;^!qB$}Gg@lmzK z@`E+)qDXQL>+HSC(_^OZ{&D)Bhp1z<7c?P`2PZH2(?b?`Q!+fFrZy?isaUFPKd zap}3kJ91GaI~0e7urmEY$vTnY3uWmZ_nhaJd_rP;thh#^sp}e30^Q-<%rB0VS=XS= zpTF|u@2Qq5k13T7-Z&iZJRABf_Dw*j|=qT%DTJPOrL)i5p=ufMjy^g zr-!qdZ{DTNdA{_B%T&)6-#VOcis8D3)+?sUt>luU@=RKMwf}`%W7Mj3vbFNJD;W+( z)^ni`VNGokGb)VoqaBsvWEJUJ{mCOSkNw58shgwY>U z9k!Xur9Av2S+zlF#r*5--yEq^?PwSaW^5+1q@;nk7PRU6-52fK^4omP%F<1D&DK3l zYozJ*CW8Xa+BJ2WkdAYJ&;~iu#QAkido5Idu@jxEHk1yOj}gPOPL0ccBdO83#l>QO z?v%ghq>vpsRC`q(E9~qfkiLI;gGWb9I)tV+`pe9=9uJ=%xY??F-9-hnMA{&Npb_!G9kQ3 zj4vdlCD9@3vJHOR^JmfgH9GyA5?!L$()Wq?)~O+<*6Ob}Xmg1)IPF7HFepS_;kTBr z8V_psa#8W9VtvjPJfupIk?i?+7B~x2)uSM|9r<;VT=um~MA1H=)Ya2F?|)qAvmA9N z<_H@#Rkhqrzh7OvNgFaPf?P%gfz=36@8}=iq1*OvPwn{f@4u)1sqX1%L;Bs#o7Cjx zMEMvOcpyYQs98)6ZU?5_g=}qrb78- z!6!dvG}TIVqPpP?Ug(@j(uQD2i2Nc>y!UhBVh`(d>)6z+9$%CX`j*$Lvu&}cd_7RXWYqyPmeJ&WocxCl=w3h*2-D*&=1pnwu8 z0Wx~jO2l)S#-!)H}`e>!$x7VOQGBGX!d&}`! z$EQ#}7BwDtRCX6>w`x(|)k<)|bg1lrx;ePQf|>&c6el*(D71>JEGU~!bBdjyw!4e) zJ7sOtlOH9u5?Wsi?)+@Zsavl>xO1lE6Xqb@G3|PC%?7CC0&3C&X%*y>;!76XS+U|4 znU)j>HQ>^sQMnh-N$*-}L(|zw#~vOk@VxtmwcV1g1VlRlI*CZIxp2rOu5m7c1ZEB> zLg1_8g0B|%1f;GCD%A)m{-QGi2F;2B#(FF2gi*?UV7eV;z}06@4Gy|7>tfB1Ki%-b zorTYT%6v9KP?r>eaj^-mvRVwNjbJsQR1K~tqvE9=c&VuB$D#NxszU292%t5JTgAz1 zQYW5lQu0hvmN*(AmLWKAel|975 z8sh$RPObMlNueDF)u_jXdv7Rbh0@@da8&2yQOyh>ZZu#ZtXh;-1o8rI!O5s51$R6+ zJLYu5qjj4LMZzB6eE;hHW|4OS;tr9>R7DChcARixM55q^8!oe>7zkxX86&U+@GO9O z&(H#3E@>2u(*x|%jQhCK(4G6maaGjr$=e0TR6W;sLy>+rAC~xHG+V7uUJ=v( zlTD$f4cG$MaXOTdN8K~rPe*Ah3KVKtl#>SL3Q9={C~)s1NW{jXxl$F3sJDUoJ1H2uB% zf%~8J9yFWlQn6aQOeBpI&i7~H!~*-?LlEWB@>c&889DT~z4b;-`)6~BY4v3Z%6=?s zs+%XB-7WH-H+zZ{U0%8CrFmqhqmy^>?}wC38E`7Y+c{Nxz+FGhpDA-ct+b}5$Gp=?`rRD>*%8X7$hPwl2cw-+sThZr=%qGH>1_AX|Uv zazNfHkaw&{fp>q{t-lZxdVbOF0WW`-Inw;l)o>3T&RQ3$lv9=wO*u3siG}Kb3b(*3 zMTu*xV8z9G+~(G5DO4e`0=SsMeSa&ZGo$1%i&7Vqyg8IKG#5Fr+UowgT&G4}Xn)}M z?^5Rek?pFthsckml`v=s<}V@4EXv>}M&~P~uf2-QtH)djA33CNa{fIzyIfxRcu~-` z*LbHWOch=#N>1nZ;z-AQzP?NOfq5Q|E?4{QFK?}xc;PkPsx(aRF*X{p_Eb{&=fbV? ztG>*JAC6`Rn2)e$2?rrW!L%pB`)Vpn+?(c z_Z4f40u5KJAMS(6t?Dt{-DszUhdN1=NaZ3AK{mtuO>Ag&4R{%^Y4}j>+wPFbGeFt@{3*;PVr;2 zDjZ+}d@`h*g6K&k(5>F*lyf6XYLxt8CGDy6EPL zKB%;s1qKzZRj^l+?@R;w4?jJn+|+HEK%5`8h-)V*oEB{UVNJ_CD1Ewpzj@mR9+@@u z{%bQ>S~5X_fC9al@9!T7yOn%(Q_(wpH!j$o;W>#wmH-?OgpHj1;_+3esJNl}v?LWA z2ZsCs$WQ43Q8*N8vaM3XS#SUS^@E_|IZ{?^&$zDU(Z3Q+kulvN#ZxB;qOq+EQ|Z141sT4wqzi8f4HB#AH#&IiO7Cv?O%*5e)4?4CqMDF6Itav;hk@EeD8f0A1^Vqu5j{G^M&3m zo4#F{UHTx+4VLQRW@AXGM`ChP2ifP0^LT(bl03NiWS9EOuGHQ?M^%5Q>HW&HCS}~0 zl!`*=bbm?upuvbDRTPlXXlRCjn_#p$AnBmwIBHJQ9H|SYWoaXPI*!G4wDwR3hgN<1 zIW_U@=DDk$CRYpNN66BM1JGQ()L4m3IOgEB1qLScR#f>zsXvsI1%3yqsKla3DWwyg zbV#muYrq~fcC}Y%xjSXwjwZF{S57IDVv+km(r0>%8))0Mm_#-l6}wPwK+J=o?O0y` zgu}3P{3?~qN2O*`YLQd|!*9TG<4}eaE`MNUpdy&nz-m!~9>v%^TDoiIt6Q$h-+eay z^No3N>T-+euUov7F`pmQc15sJ!;1eWI9Gs11ZWony&tfbAPLBg0L2uvCJXt60WKQg zv;p4AqDC`mg#AZ$Ac;g)cxTl4ffZI1{k6hFp=<6Bf@E1|ek?D_M4>0Z)5RyoFm`d? zLWxgVf`Ar%*wW+?d_e=YfCc~~SWW?O6f_T9W&lrGu+ki=bpsVw4{$^Pu%kv95Y~xD z!LtVxZzny7ly7RcZ)@c9-_Q0Qd28L!=Q)RF+?VVJ8P)C{+ zR?`BQ90keJWv(};D|s?<2cN<&a9QFC0&3< z0zW}mW9E-fhSEd#En3!vEB<2OkPFvjN`*%iLN5-&M(A5?gTd&q%sT; zj{uIx=_!iQnRrrNTtLZIR$u`)j$*WkPr>W0*awtOXVkBMul#M3yVR)~GA=^>PCVO8 zu4|@GHDQaGh*;FEN|NTq9s^%2W|ZL0qTnULZPx1;z+_PX7%*yi3#m&=%BrDwp%H(; zo^t@8i!Cvw&RA35KQ?LpVy8!`Rqu@a`91s2jITNg**Le8<0sT~*jUiwjEEiZ41+?7 zF#CbjYenr*D*)42oXmn&4_G>r)dEofsCJ;uiLxzHY)sT*G!|F=%cp<6SQ8#~L-S+K z{rsax8?I(})&1C3BE^m!Me89hSsq{rT2gurAe2D#LD6%pJ!;?+?lkF909q2Jk~9$2 z9uHA4|GBF22}4xr-AT90vCoRc$gYI=A;ieEhSM=DIbeVmE&U=*EJ36}jXab{v;f4B zHUL}<#avNL6VOveR96Jz2vEkgC@5@XyqjX-r8)h))wynMdquSy_Mqskwb$oNkzLOW zls*E2q0v#OZVwDhibHq~0Z~9=8VC#$1MEpHV3B|?0MtZ)wYo;-q)JOACxy-~-QPaZ zes0%CZ$Fm%wA0@yWY*-NT5)Nm2(1pN95}{VR7oc_(@_W)qSHWPTZr(Zjx5WXQ1R1j za)oHcb#+H(3$L89_sOj~M|74pFI(!XhXh8TJu2Cbb;Yd@gzw!axrA*1JYJM}*8(oU zh~PI?6xGs!4gkamBg8x4I(eXsVZ}XKLXks6Q`{@I{u?X*rfa{e$hDZwJ&#t)c1d=U zrynbFs9mD@FV|c}o8S4R_`Y4$cl4r8^{;>M-rI8*-l!EGu)~VB#rY`8_|98NZrr`^ z;`hQ+5_@m_`B~)M2d!k;T7LKz9HVnzWpIwhscyRd;{E2>pTmwc3*A-m!MNnbueLTh zb3WjCB^DhC0lD3e3B-t#z7pqj_ZMuQ9b2~yI2AH#;9JjAa$E`YT?DV)?(;hFTkkhk zxHzDiz3;hkBhNKCs~&boeJjv6^4;Sguk6Icb`HrovF<;4zkB7&W2R?69{K0fOYaOn z6*hjoTvDdbu?qeoSE7?W4iIx`Ig7lWRPq$XRIHi(#l!|bEU@mo_;$kDNpem8_31-O z9=Rr(0WzfqO4L^TQnx1L-35_X7DPl%`e)nzOi73Ho+F}JXMk1_PR@G;L@r;S@B4Qa z+JFbOSpP-;O-PmNavvSvnpiy0*uo;soxeW{!OK>iU->RMqd~tu?en z#uNUWmX;e{$Ym$Fzj9%z>oi7+u`*a%J)Cp|r5vA$dZq=|6M$7U#5UD8F1dbw(Jzxl<$BtT~J`4Ic@980CG&yp&YEcf}@@7k0)mNdE1?hJ#GD6ff>L+GMF z`WPx^CZe`*JWw&9&^ZTWL4F+vTN8!}5;KweiW=@n-n9bBSU~Qkkzx%xqu%IV8s+Xh z$Ms@yscHMR&wF*V$jw`4Z)abWac7nCxI{thIj^F#!m%)bO*Jq8L>EhWPmg+2v*iLErd}?2cDEa40~tj-0=LfcSki!>2h&)_IsJcU0#&C_o!>^w|H$C?A z?nYmn{IL1L&99P+X1{RhK>oinX~xOwl1z3Q4o;7qD18-5ZjU)PfQbUw6FB4lb$8}* zHkR)npRtdnMhZ!iQb}{R=Pb`jR4P=~qDFn|>)DPOvoYrkioTRewroX(ERm3Gl@_5$ zBeang*(#E>DB_#&d*9D<&Y5%0%xI4Edi`GCKf;;jzR&gC&wXF_b$zbSbzO9^0dOZ2 zq6WNd72W_oyP%1~M5S4bK(tCubj&=l>u+1%`e>(nFIsd?*YotgZGT#n7;3866>CZt z%vW-Zh@5uKM>9XVAOW->kAs#-x>xbiUfD~>JlR9%YNx|Pqj-CCm=MdXiN2XbXgWg8;&eQ0*>r;KIClD{bxxZs2 zuXN*z@7GtoYv-Mn>U~?g^1_yT{+Z>cP;o?Vk%$qXvo89O8&-3>J-Uy*Oou$0i1=u@ z>GRQUOVZ*6H*(_^yy)epT+Lf|shzfV>Yj6!|L3ApqYCAQ-cTnImbWmcI=Sp|)DrW5 zCWPEZWUkq>zWceZ%E8oXWB*)mR$@v}#m-QcUYL~~3>EO(dG-!^VTb4kaW2@MUe?{pupYtyuS0x=Vq?SGak8W*bUcr zdM}aFQ878murczr`-(!@xj}nJ>q8Iog9xBVb{|dXQT#4C0D@*~GVuY4PQQK!Eos3F z-A;!>^Dqegv11XFv8I%(Yrc5L^c6+LquXEj;0Ymf#RAhi|odgQIm`4o6Sr-FMLAO2B z^j|ZpdcR2fw&!Q5OpeY0CKG=u88Qjt_A7EPgiBh7x6`#ZHaCv+xXPu783SkzNY$|Si*+=r1 zu&hePA)Ywl0~=k~YlOXdyAJI~y{JwMJb5T-$#`a4Z>n(=sp973LeDBHByuqzyU;Kh zp?wMsS$LlLx{}MG!X%MI^vWgSCOHVR(a?nCKv8_NM?_5 zJKg0t_dbI#2Qh7z=(vRV#NY!gI<55-dT-JEP%mQ!7GGdg;sqSJ<;~Qyull_0!A_S- zA3Sob)wieRAW?cECx~7!Yz8N}FJ*+WRbUb125nY(WJAvm!6h*BtfId{jSb=F4iwQ= zmyL4Clu@QIkgyuryAHe9-wK|eN@Ha&P!%oB6?$BY7TmPpl+oA{(LC8(p;@ha#bLd$ zEB9V+KR$1vd(_+&DTha1@kb&@`mc{}BIl$e-fZzWxaHhVCz)b8w+E?84zx2J?&&>C z%#p5LPE9m$rI}lFU<`|+^9v`(w_kUP6-pF1BoF+P#~`Pbsb?58lw8^&(M*P-{Y zAKiB1PdY|99gBrC#486|&)P&e!+V|6=K<#sp>Y3$Ag=XICb^<~Z__ zb!kQ3I7yXsXhoOd@X|XQn1|lRC^Jcs1FGs(=&?;Fdv84d$(kbO<-hh+{mT}NZa3kk z;|H(&Xls-2lHZx-9iYgXy1C?NjP0b^Avu#0ehRE2(H2;=&&0NM%LewD?2N2w%u9c? zRh`SHFTehwqwltwusZuh)#RxUF?U{{oP2aIA?+C#R#d;c|OpM)J-hnGd&px3q&ay|w55uA^2R-2dm8ok<@a>y-pE zMAXl+yi5N?w3m02mWnWnO1oZK#LAj1(wAw@Y2Yq6x#FP0Nt&v7O01jclw4y>V5*|d z%QE*ho^Whg_r0TvJB(a*GSOPBn8wt!>|C2xFhI$-g_PdhTz&14zny@iPP@k=yRloL z4Hu3Us$lZpeve)zu5M`&CEOV8!14;rvN3>Ko2u>(S%zDFkl2if~MArmykbbv`<1J&= zvQ}qyEiOFXa@n>G&O4rVEb0GR@|3I?y&euj3Au^1nSW-43NnJZ0X{+v60VmHtBE9Y zVxY3&f)%3*fJdgMwMzl*mVjcx?-e*j@x$2`Vz{}!TW5Zrws!mvLl1nlx$51i4+oRC zHHFNURDFtaV?}h>e0FMUa8J@$TaguyPTbZ_>t++VAUhu0L!)kps>>=_{Uu|~ZR<0| zd&AbJe~Ss-+*;EGe|GtGQitR4KVID<9m%~VaHP)1H{=c`ae(~F-t%u}R(_U|}{6u07f5i@#wSeZI z;pm@OJs65AMM~WCC5K_h>5;(NRbj~aHAUyebA=OIb=ac=W0tPL=J7K|uYNJ~z_Dd_ z^h~#P`y0VZvW&v)`DmCi`lD#D5=70-2?Fa41V9|sK)`7TmYX2Gfvf~1kW&@24(P4y zS&&^^NaECg83619*LUJ1Vaijs!>2hZ zV#MubXqeDYaAT%2ON1p(W$uYBfAoFxtp|sGTXos{uWY;Xhhe8p`s<_Rmg0%=vv`8o zx6*Ap_pfN&EalUKw#sSWXC!X}rEh$| z0+f@1i^CGpRb5j&q^L-e2S3;YIRO$da8BH4u?q#xCysQ=fZkmmc>2D5)eg3tx_;V! z&rUote}mi+_noK8po_3U;s%sO^tj-uXI{?z(%Yt2lbr4??r|SZ9x|)Y>ShR-TAX#U z#D4US{lTXuT87MfMez ztVGHKKC{nB5GDYt9PNf)(;NYxn;>SOj2U8IiE^UGrLzjQHrV%N`;CvjG3|p>6VX6M z;?HGtc2hEmE69waMP7m#aE$!aJZd%kLr!dXHox}a$2Nx=_}Xkg(;**I4z~bly>@)2 z0Q*)0ME6J*4bm<-TJ{9X;YScb3(4M zuvhY4XT)s}Tg%ZHL*z3Cg&i+R!y?A(1V*GLor9~?y~iu(&i?82#Uy79=56GAtWRuk-l*Me5SW#8A9p+Mec$s zL34L{aPmlIaI&m~h2lnwZN_MGHJ?0oyvm>(w`VWdTP<{kB{s zzqf>LC0Iuekk3WQHpz!o4^l_%IaR{x@B@E3b&=EHBaaazqC{46G>TS?Hf7y;xXZga z=}XrYt@otOp0a6RVy&6KwwevSi2Dn5VT53zX@DUnr&j#K>BzCmvN*XSJ%GA|LY1;Z z6$hozc<~C(9G9E}CmP3tuule~2!7|7qRpN4Zfcub)7uPtwp!-OOmF3c5~LM~L$Y?Z zY?c4CB0K-#uL)ZYeiBY5$c*8J*@F@xoq-B-Ach86mGC3LI(4jNYY1?cbw+-<<%MO% zQ;bO?pQ-N;jeV<9^7Mg{4U?N|HI@%XU#nJ7@-snrblGJ^hr4Nrx`LFAbK`FnxZ$=lAt(C<^AD_M5Ik~E`ET#@90+jS?*oqz%Q z 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 literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-server/.gradle/8.3/executionHistory/executionHistory.lock b/samples/standalone/dsl/http-server/.gradle/8.3/executionHistory/executionHistory.lock new file mode 100644 index 0000000000000000000000000000000000000000..a91b3f95e50b2fa84a6d282f1d2be23b9f17d7bf GIT binary patch literal 17 UcmZSX*z}>kdtbo<1_+P?06&ohBme*a literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-server/.gradle/8.3/fileChanges/last-build.bin b/samples/standalone/dsl/http-server/.gradle/8.3/fileChanges/last-build.bin new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-server/.gradle/8.3/fileHashes/fileHashes.bin b/samples/standalone/dsl/http-server/.gradle/8.3/fileHashes/fileHashes.bin new file mode 100644 index 0000000000000000000000000000000000000000..c7dcbe54d1f27ab6e317506379aaecb9177f8e05 GIT binary patch literal 31847 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 R>q3a4^pE)p)+ex!{{njd4|4zj literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-server/.gradle/8.3/fileHashes/fileHashes.lock b/samples/standalone/dsl/http-server/.gradle/8.3/fileHashes/fileHashes.lock new file mode 100644 index 0000000000000000000000000000000000000000..0416590b07dec3e2daef8591c9a6cb16909a3d13 GIT binary patch literal 17 UcmZRMb4=^D@c!k&00vBA04UW1aR2}S literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-server/.gradle/8.3/fileHashes/resourceHashesCache.bin b/samples/standalone/dsl/http-server/.gradle/8.3/fileHashes/resourceHashesCache.bin new file mode 100644 index 0000000000000000000000000000000000000000..5fdb0e2a3d1402ffaf61a10dbcf43f3bcfa0b404 GIT binary patch literal 24719 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 V-e2FO$BUhflE?qmJjlH}`4{+JK_dVF literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-server/.gradle/8.3/gc.properties b/samples/standalone/dsl/http-server/.gradle/8.3/gc.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/standalone/dsl/http-server/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/samples/standalone/dsl/http-server/.gradle/buildOutputCleanup/buildOutputCleanup.lock new file mode 100644 index 0000000000000000000000000000000000000000..df64ea7d98befedaf0f6c153649f1808ec37fbad GIT binary patch literal 17 UcmZQ>Vz!yGXx3vT1_+1+04x9l_W%F@ literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-server/.gradle/buildOutputCleanup/cache.properties b/samples/standalone/dsl/http-server/.gradle/buildOutputCleanup/cache.properties new file mode 100644 index 0000000000..aef0284e15 --- /dev/null +++ b/samples/standalone/dsl/http-server/.gradle/buildOutputCleanup/cache.properties @@ -0,0 +1,2 @@ +#Wed Sep 06 14:20:29 CEST 2023 +gradle.version=8.3 diff --git a/samples/standalone/dsl/http-server/.gradle/buildOutputCleanup/outputFiles.bin b/samples/standalone/dsl/http-server/.gradle/buildOutputCleanup/outputFiles.bin new file mode 100644 index 0000000000000000000000000000000000000000..371de15e1d8a9661b15df41eec3bfb80a3933d67 GIT binary patch literal 19775 zcmeI%Yfw~W7{KwxjmvV22IV4zTR1UfjAChNQG*KXjUWSa5j1upMBL;O;gXJ;iV71< z0uRmNQPzjk! zUD5Xm?hPhowwz%uszpzgKP)+ZEv25h_&j?03B}kkm*`gJvU2p#GVcGXZmRQuIo{}5 znGxkiKI#JIk_`0h_&!zPjf!blAAzo}l7A7VybQO3&V^iJjyDf%gG|1U9qdz_hz-bVj=W97T`-rG*W z`fl{o?z>Zq^P1jZF7?xS)xNJj^^d*6TpW*nuBWvpX6pq$%uhtG?yuUUbqRsaq7L+$ zGr~*R8!o|m*+ulaX6u+hb=gALHyyp+(Ic%x9wvi*vvq#*wojW_rY=$Ach3pO{s zKM8X#qc`kGbO>?Ve;Ztme#NzT+_%SWjJaeR`u8Q1me*^OQ<%$Eqqm2eKHvUIE?lSB z6unb<%Ooec7~T)kY4olP=Ru`+Rs+mGi{5Q7QzR{|IRe+S41MHU9&feS`VMn(5&F%N z1$XKWWm<#pM<2893Q}lndSHGb`mGhG`R);$;r%RjL?1u0MQh)^;V$f}L7&LCQZ)v( z!Qb6qfPVKuZ-)`zZVg*6TY!E~s`CBL?O-nK+l>BT>Oe?))Lu8{q8xNyV6U*P=zcHE zi9|PwDhXaC8J!F3%g{|6_Absl74O5RnG}1{VRL literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-server/.gradle/vcs-1/gc.properties b/samples/standalone/dsl/http-server/.gradle/vcs-1/gc.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/standalone/dsl/http-server/.idea/.gitignore b/samples/standalone/dsl/http-server/.idea/.gitignore new file mode 100644 index 0000000000..13566b81b0 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/samples/standalone/dsl/http-server/.idea/codeStyles/Project.xml b/samples/standalone/dsl/http-server/.idea/codeStyles/Project.xml new file mode 100644 index 0000000000..17c6134ebd --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/codeStyles/Project.xml @@ -0,0 +1,89 @@ + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/codeStyles/codeStyleConfig.xml b/samples/standalone/dsl/http-server/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000000..0adac017fe --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/compiler.xml b/samples/standalone/dsl/http-server/.idea/compiler.xml new file mode 100644 index 0000000000..2292eea4ee --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/compiler.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/encodings.xml b/samples/standalone/dsl/http-server/.idea/encodings.xml new file mode 100644 index 0000000000..aa00ffab78 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/jarRepositories.xml b/samples/standalone/dsl/http-server/.idea/jarRepositories.xml new file mode 100644 index 0000000000..f17e415287 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__cglib_cglib_3_3_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__cglib_cglib_3_3_0.xml new file mode 100644 index 0000000000..a940ad68b5 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__cglib_cglib_3_3_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__ch_qos_logback_logback_classic_1_4_5.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__ch_qos_logback_logback_classic_1_4_5.xml new file mode 100644 index 0000000000..f8429fc5a3 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__ch_qos_logback_logback_classic_1_4_5.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__ch_qos_logback_logback_core_1_4_5.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__ch_qos_logback_logback_core_1_4_5.xml new file mode 100644 index 0000000000..decb728e83 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__ch_qos_logback_logback_core_1_4_5.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_classmate_1_5_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_classmate_1_5_1.xml new file mode 100644 index 0000000000..bc7d7fd869 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_classmate_1_5_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_annotations_2_14_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_annotations_2_14_1.xml new file mode 100644 index 0000000000..202939e304 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_annotations_2_14_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_core_2_14_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_core_2_14_1.xml new file mode 100644 index 0000000000..3cfdd74c3e --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_core_2_14_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_databind_2_14_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_databind_2_14_1.xml new file mode 100644 index 0000000000..12544d5411 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_databind_2_14_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_2_14_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_2_14_1.xml new file mode 100644 index 0000000000..7ed9a44088 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_2_14_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jdk8_2_14_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jdk8_2_14_1.xml new file mode 100644 index 0000000000..bfcd56c40c --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jdk8_2_14_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jsr310_2_14_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jsr310_2_14_1.xml new file mode 100644 index 0000000000..afd966aca7 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jsr310_2_14_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_module_jackson_module_parameter_names_2_14_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_module_jackson_module_parameter_names_2_14_1.xml new file mode 100644 index 0000000000..01e600cbb4 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_fasterxml_jackson_module_jackson_module_parameter_names_2_14_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_github_jknack_handlebars_4_3_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_github_jknack_handlebars_4_3_0.xml new file mode 100644 index 0000000000..1cf48f0566 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_github_jknack_handlebars_4_3_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_github_tomakehurst_wiremock_jre8_standalone_2_35_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_github_tomakehurst_wiremock_jre8_standalone_2_35_0.xml new file mode 100644 index 0000000000..ebda8e2e89 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_github_tomakehurst_wiremock_jre8_standalone_2_35_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_ibm_icu_icu4j_4_6.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_ibm_icu_icu4j_4_6.xml new file mode 100644 index 0000000000..670405c2d4 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_ibm_icu_icu4j_4_6.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_jayway_jsonpath_json_path_2_7_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_jayway_jsonpath_json_path_2_7_0.xml new file mode 100644 index 0000000000..65ee6e6377 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_jayway_jsonpath_json_path_2_7_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_rabbitmq_amqp_client_5_16_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_rabbitmq_amqp_client_5_16_0.xml new file mode 100644 index 0000000000..d39cfab84c --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_rabbitmq_amqp_client_5_16_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_rackspace_eclipse_webtools_sourceediting_org_eclipse_wst_xml_xpath2_processor_2_1_100.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_rackspace_eclipse_webtools_sourceediting_org_eclipse_wst_xml_xpath2_processor_2_1_100.xml new file mode 100644 index 0000000000..5624ade479 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_rackspace_eclipse_webtools_sourceediting_org_eclipse_wst_xml_xpath2_processor_2_1_100.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_toomuchcoding_jsonassert_jsonassert_0_6_2.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_toomuchcoding_jsonassert_jsonassert_0_6_2.xml new file mode 100644 index 0000000000..c8820b9b03 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_toomuchcoding_jsonassert_jsonassert_0_6_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_vaadin_external_google_android_json_0_0_20131108_vaadin1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_vaadin_external_google_android_json_0_0_20131108_vaadin1.xml new file mode 100644 index 0000000000..b8581a6f5e --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__com_vaadin_external_google_android_json_0_0_20131108_vaadin1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__commons_beanutils_commons_beanutils_1_9_4.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__commons_beanutils_commons_beanutils_1_9_4.xml new file mode 100644 index 0000000000..84eb1158f5 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__commons_beanutils_commons_beanutils_1_9_4.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__commons_codec_commons_codec_1_15.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__commons_codec_commons_codec_1_15.xml new file mode 100644 index 0000000000..c88c2b7192 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__commons_codec_commons_codec_1_15.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__commons_collections_commons_collections_3_2_2.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__commons_collections_commons_collections_3_2_2.xml new file mode 100644 index 0000000000..13afda2962 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__commons_collections_commons_collections_3_2_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__commons_logging_commons_logging_1_2.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__commons_logging_commons_logging_1_2.xml new file mode 100644 index 0000000000..eab40b3297 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__commons_logging_commons_logging_1_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__dk_brics_automaton_1_12_4.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__dk_brics_automaton_1_12_4.xml new file mode 100644 index 0000000000..8dd9e4420c --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__dk_brics_automaton_1_12_4.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__edu_princeton_cup_java_cup_10k.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__edu_princeton_cup_java_cup_10k.xml new file mode 100644 index 0000000000..12ad41db25 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__edu_princeton_cup_java_cup_10k.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_micrometer_micrometer_commons_1_10_2.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_micrometer_micrometer_commons_1_10_2.xml new file mode 100644 index 0000000000..4b191e1102 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_micrometer_micrometer_commons_1_10_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_micrometer_micrometer_core_1_10_2.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_micrometer_micrometer_core_1_10_2.xml new file mode 100644 index 0000000000..184e4659bc --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_micrometer_micrometer_core_1_10_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_micrometer_micrometer_observation_1_10_2.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_micrometer_micrometer_observation_1_10_2.xml new file mode 100644 index 0000000000..ad650a480d --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_micrometer_micrometer_observation_1_10_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_incubator_netty_incubator_codec_classes_quic_0_0_34_Final.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_incubator_netty_incubator_codec_classes_quic_0_0_34_Final.xml new file mode 100644 index 0000000000..ad27e0f209 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_incubator_netty_incubator_codec_classes_quic_0_0_34_Final.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_incubator_netty_incubator_codec_native_quic_linux_x86_64_0_0_34_Final.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_incubator_netty_incubator_codec_native_quic_linux_x86_64_0_0_34_Final.xml new file mode 100644 index 0000000000..5060eaea91 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_incubator_netty_incubator_codec_native_quic_linux_x86_64_0_0_34_Final.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_buffer_4_1_86_Final.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_buffer_4_1_86_Final.xml new file mode 100644 index 0000000000..c84de6fd21 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_buffer_4_1_86_Final.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_codec_4_1_86_Final.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_codec_4_1_86_Final.xml new file mode 100644 index 0000000000..9c25279bfe --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_codec_4_1_86_Final.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_codec_dns_4_1_86_Final.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_codec_dns_4_1_86_Final.xml new file mode 100644 index 0000000000..201cce0050 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_codec_dns_4_1_86_Final.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_codec_http2_4_1_86_Final.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_codec_http2_4_1_86_Final.xml new file mode 100644 index 0000000000..5186a259a3 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_codec_http2_4_1_86_Final.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_codec_http_4_1_86_Final.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_codec_http_4_1_86_Final.xml new file mode 100644 index 0000000000..44d7fb3604 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_codec_http_4_1_86_Final.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_codec_socks_4_1_86_Final.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_codec_socks_4_1_86_Final.xml new file mode 100644 index 0000000000..615b1a630a --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_codec_socks_4_1_86_Final.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_common_4_1_86_Final.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_common_4_1_86_Final.xml new file mode 100644 index 0000000000..e211838462 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_common_4_1_86_Final.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_handler_4_1_86_Final.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_handler_4_1_86_Final.xml new file mode 100644 index 0000000000..7d8b39a0ea --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_handler_4_1_86_Final.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_handler_proxy_4_1_86_Final.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_handler_proxy_4_1_86_Final.xml new file mode 100644 index 0000000000..3ac6790fee --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_handler_proxy_4_1_86_Final.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_resolver_4_1_86_Final.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_resolver_4_1_86_Final.xml new file mode 100644 index 0000000000..edbc292e44 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_resolver_4_1_86_Final.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_resolver_dns_4_1_86_Final.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_resolver_dns_4_1_86_Final.xml new file mode 100644 index 0000000000..597c38a6f7 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_resolver_dns_4_1_86_Final.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_resolver_dns_classes_macos_4_1_86_Final.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_resolver_dns_classes_macos_4_1_86_Final.xml new file mode 100644 index 0000000000..9fd6718784 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_resolver_dns_classes_macos_4_1_86_Final.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_resolver_dns_native_macos_osx_x86_64_4_1_86_Final.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_resolver_dns_native_macos_osx_x86_64_4_1_86_Final.xml new file mode 100644 index 0000000000..3c661a1d0d --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_resolver_dns_native_macos_osx_x86_64_4_1_86_Final.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_transport_4_1_86_Final.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_transport_4_1_86_Final.xml new file mode 100644 index 0000000000..a6b028eee5 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_transport_4_1_86_Final.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_transport_classes_epoll_4_1_86_Final.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_transport_classes_epoll_4_1_86_Final.xml new file mode 100644 index 0000000000..6ef2d9714b --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_transport_classes_epoll_4_1_86_Final.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_transport_native_epoll_linux_x86_64_4_1_86_Final.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_transport_native_epoll_linux_x86_64_4_1_86_Final.xml new file mode 100644 index 0000000000..5b01497a0b --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_transport_native_epoll_linux_x86_64_4_1_86_Final.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_transport_native_unix_common_4_1_86_Final.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_transport_native_unix_common_4_1_86_Final.xml new file mode 100644 index 0000000000..740d9b5dc7 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_netty_netty_transport_native_unix_common_4_1_86_Final.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_projectreactor_netty_incubator_reactor_netty_incubator_quic_0_1_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_projectreactor_netty_incubator_reactor_netty_incubator_quic_0_1_1.xml new file mode 100644 index 0000000000..745a8c5ca5 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_projectreactor_netty_incubator_reactor_netty_incubator_quic_0_1_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_projectreactor_netty_reactor_netty_1_1_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_projectreactor_netty_reactor_netty_1_1_1.xml new file mode 100644 index 0000000000..5fbfe21fa0 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_projectreactor_netty_reactor_netty_1_1_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_projectreactor_netty_reactor_netty_core_1_1_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_projectreactor_netty_reactor_netty_core_1_1_1.xml new file mode 100644 index 0000000000..02f8a59c73 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_projectreactor_netty_reactor_netty_core_1_1_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_projectreactor_netty_reactor_netty_http_1_1_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_projectreactor_netty_reactor_netty_http_1_1_1.xml new file mode 100644 index 0000000000..73ceb27407 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_projectreactor_netty_reactor_netty_http_1_1_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_projectreactor_reactor_core_3_5_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_projectreactor_reactor_core_3_5_1.xml new file mode 100644 index 0000000000..de67196210 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_projectreactor_reactor_core_3_5_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_rest_assured_json_path_5_2_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_rest_assured_json_path_5_2_1.xml new file mode 100644 index 0000000000..e93503b2fe --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_rest_assured_json_path_5_2_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_rest_assured_rest_assured_5_2_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_rest_assured_rest_assured_5_2_1.xml new file mode 100644 index 0000000000..a8896e8540 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_rest_assured_rest_assured_5_2_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_rest_assured_rest_assured_common_5_2_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_rest_assured_rest_assured_common_5_2_1.xml new file mode 100644 index 0000000000..38bda9974d --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_rest_assured_rest_assured_common_5_2_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_rest_assured_spring_commons_5_2_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_rest_assured_spring_commons_5_2_1.xml new file mode 100644 index 0000000000..6378245884 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_rest_assured_spring_commons_5_2_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_rest_assured_spring_mock_mvc_5_2_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_rest_assured_spring_mock_mvc_5_2_1.xml new file mode 100644 index 0000000000..f2a92aaf94 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_rest_assured_spring_mock_mvc_5_2_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_rest_assured_xml_path_5_2_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_rest_assured_xml_path_5_2_1.xml new file mode 100644 index 0000000000..c671b64d96 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__io_rest_assured_xml_path_5_2_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__jakarta_activation_jakarta_activation_api_2_1_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__jakarta_activation_jakarta_activation_api_2_1_0.xml new file mode 100644 index 0000000000..52b418f2da --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__jakarta_activation_jakarta_activation_api_2_1_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__jakarta_annotation_jakarta_annotation_api_2_1_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__jakarta_annotation_jakarta_annotation_api_2_1_1.xml new file mode 100644 index 0000000000..3f660ae41a --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__jakarta_annotation_jakarta_annotation_api_2_1_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__jakarta_validation_jakarta_validation_api_3_0_2.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__jakarta_validation_jakarta_validation_api_3_0_2.xml new file mode 100644 index 0000000000..96ee2a51c1 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__jakarta_validation_jakarta_validation_api_3_0_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__jakarta_xml_bind_jakarta_xml_bind_api_4_0_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__jakarta_xml_bind_jakarta_xml_bind_api_4_0_0.xml new file mode 100644 index 0000000000..a9a526318f --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__jakarta_xml_bind_jakarta_xml_bind_api_4_0_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__javax_activation_javax_activation_api_1_2_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__javax_activation_javax_activation_api_1_2_0.xml new file mode 100644 index 0000000000..ff49512a0e --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__javax_activation_javax_activation_api_1_2_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__javax_annotation_javax_annotation_api_1_3_2.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__javax_annotation_javax_annotation_api_1_3_2.xml new file mode 100644 index 0000000000..e74f3ab28b --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__javax_annotation_javax_annotation_api_1_3_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__javax_inject_javax_inject_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__javax_inject_javax_inject_1.xml new file mode 100644 index 0000000000..93cf65aba0 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__javax_inject_javax_inject_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__net_bytebuddy_byte_buddy_1_12_20.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__net_bytebuddy_byte_buddy_1_12_20.xml new file mode 100644 index 0000000000..9888ec659e --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__net_bytebuddy_byte_buddy_1_12_20.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__net_bytebuddy_byte_buddy_agent_1_12_20.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__net_bytebuddy_byte_buddy_agent_1_12_20.xml new file mode 100644 index 0000000000..6e0076603c --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__net_bytebuddy_byte_buddy_agent_1_12_20.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__net_javacrumbs_json_unit_json_unit_assertj_2_32_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__net_javacrumbs_json_unit_json_unit_assertj_2_32_0.xml new file mode 100644 index 0000000000..616738f459 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__net_javacrumbs_json_unit_json_unit_assertj_2_32_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__net_javacrumbs_json_unit_json_unit_core_2_32_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__net_javacrumbs_json_unit_json_unit_core_2_32_0.xml new file mode 100644 index 0000000000..2e65991e34 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__net_javacrumbs_json_unit_json_unit_core_2_32_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__net_javacrumbs_json_unit_json_unit_json_path_2_32_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__net_javacrumbs_json_unit_json_unit_json_path_2_32_0.xml new file mode 100644 index 0000000000..0eb3c30b76 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__net_javacrumbs_json_unit_json_unit_json_path_2_32_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__net_jodah_typetools_0_6_2.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__net_jodah_typetools_0_6_2.xml new file mode 100644 index 0000000000..5369a0602c --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__net_jodah_typetools_0_6_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__net_minidev_accessors_smart_2_4_8.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__net_minidev_accessors_smart_2_4_8.xml new file mode 100644 index 0000000000..6b7b59a8aa --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__net_minidev_accessors_smart_2_4_8.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__net_minidev_json_smart_2_4_8.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__net_minidev_json_smart_2_4_8.xml new file mode 100644 index 0000000000..7479a40e65 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__net_minidev_json_smart_2_4_8.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_commons_commons_lang3_3_12_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_commons_commons_lang3_3_12_0.xml new file mode 100644 index 0000000000..28b8682509 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_commons_commons_lang3_3_12_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_commons_commons_text_1_10_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_commons_commons_text_1_10_0.xml new file mode 100644 index 0000000000..ee59132e67 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_commons_commons_text_1_10_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_groovy_groovy_4_0_6.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_groovy_groovy_4_0_6.xml new file mode 100644 index 0000000000..ba1c00c280 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_groovy_groovy_4_0_6.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_groovy_groovy_json_4_0_6.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_groovy_groovy_json_4_0_6.xml new file mode 100644 index 0000000000..1d1b915931 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_groovy_groovy_json_4_0_6.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_groovy_groovy_nio_4_0_6.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_groovy_groovy_nio_4_0_6.xml new file mode 100644 index 0000000000..a88da9fe9e --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_groovy_groovy_nio_4_0_6.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_groovy_groovy_xml_4_0_6.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_groovy_groovy_xml_4_0_6.xml new file mode 100644 index 0000000000..ff7b50bdbe --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_groovy_groovy_xml_4_0_6.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_httpcomponents_httpclient_4_5_14.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_httpcomponents_httpclient_4_5_14.xml new file mode 100644 index 0000000000..c78360e5a4 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_httpcomponents_httpclient_4_5_14.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_httpcomponents_httpcore_4_4_16.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_httpcomponents_httpcore_4_4_16.xml new file mode 100644 index 0000000000..de80fcc101 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_httpcomponents_httpcore_4_4_16.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_httpcomponents_httpmime_4_5_14.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_httpcomponents_httpmime_4_5_14.xml new file mode 100644 index 0000000000..f29864a773 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_httpcomponents_httpmime_4_5_14.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_logging_log4j_log4j_api_2_19_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_logging_log4j_log4j_api_2_19_0.xml new file mode 100644 index 0000000000..fa7fafb4d3 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_logging_log4j_log4j_api_2_19_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_logging_log4j_log4j_to_slf4j_2_19_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_logging_log4j_log4j_to_slf4j_2_19_0.xml new file mode 100644 index 0000000000..849e8fb509 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_logging_log4j_log4j_to_slf4j_2_19_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_maven_resolver_maven_resolver_api_1_4_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_maven_resolver_maven_resolver_api_1_4_1.xml new file mode 100644 index 0000000000..7182feb495 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_maven_resolver_maven_resolver_api_1_4_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_core_10_1_4.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_core_10_1_4.xml new file mode 100644 index 0000000000..0358e30520 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_core_10_1_4.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_el_10_1_4.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_el_10_1_4.xml new file mode 100644 index 0000000000..2c295b9bf4 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_el_10_1_4.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_websocket_10_1_4.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_websocket_10_1_4.xml new file mode 100644 index 0000000000..5faa710591 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_websocket_10_1_4.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apiguardian_apiguardian_api_1_1_2.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apiguardian_apiguardian_api_1_1_2.xml new file mode 100644 index 0000000000..6ac1c42c6b --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_apiguardian_apiguardian_api_1_1_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_assertj_assertj_core_3_23_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_assertj_assertj_core_3_23_1.xml new file mode 100644 index 0000000000..360c8095da --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_assertj_assertj_core_3_23_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_ccil_cowan_tagsoup_tagsoup_1_2_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_ccil_cowan_tagsoup_tagsoup_1_2_1.xml new file mode 100644 index 0000000000..f368471acb --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_ccil_cowan_tagsoup_tagsoup_1_2_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_hamcrest_hamcrest_2_2.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_hamcrest_hamcrest_2_2.xml new file mode 100644 index 0000000000..6b5496ff09 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_hamcrest_hamcrest_2_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_hamcrest_hamcrest_core_2_2.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_hamcrest_hamcrest_core_2_2.xml new file mode 100644 index 0000000000..15f1e4c171 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_hamcrest_hamcrest_core_2_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_hdrhistogram_HdrHistogram_2_1_12.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_hdrhistogram_HdrHistogram_2_1_12.xml new file mode 100644 index 0000000000..6908885fb7 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_hdrhistogram_HdrHistogram_2_1_12.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_hibernate_validator_hibernate_validator_8_0_0_Final.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_hibernate_validator_hibernate_validator_8_0_0_Final.xml new file mode 100644 index 0000000000..cf4991d6d9 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_hibernate_validator_hibernate_validator_8_0_0_Final.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_jboss_logging_jboss_logging_3_5_0_Final.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_jboss_logging_jboss_logging_3_5_0_Final.xml new file mode 100644 index 0000000000..24fcd6e129 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_jboss_logging_jboss_logging_3_5_0_Final.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_jetbrains_annotations_13_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_jetbrains_annotations_13_0.xml new file mode 100644 index 0000000000..e2c829756d --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_jetbrains_annotations_13_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_jetbrains_kotlin_kotlin_stdlib_1_7_22.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_jetbrains_kotlin_kotlin_stdlib_1_7_22.xml new file mode 100644 index 0000000000..92a534e5c5 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_jetbrains_kotlin_kotlin_stdlib_1_7_22.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_jetbrains_kotlin_kotlin_stdlib_common_1_7_22.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_jetbrains_kotlin_kotlin_stdlib_common_1_7_22.xml new file mode 100644 index 0000000000..40c6358630 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_jetbrains_kotlin_kotlin_stdlib_common_1_7_22.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_jetbrains_kotlin_kotlin_stdlib_jdk7_1_7_22.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_jetbrains_kotlin_kotlin_stdlib_jdk7_1_7_22.xml new file mode 100644 index 0000000000..66c40a9385 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_jetbrains_kotlin_kotlin_stdlib_jdk7_1_7_22.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_jetbrains_kotlin_kotlin_stdlib_jdk8_1_7_22.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_jetbrains_kotlin_kotlin_stdlib_jdk8_1_7_22.xml new file mode 100644 index 0000000000..f2b124dd30 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_jetbrains_kotlin_kotlin_stdlib_jdk8_1_7_22.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_5_9_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_5_9_1.xml new file mode 100644 index 0000000000..182f93afde --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_5_9_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_api_5_9_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_api_5_9_1.xml new file mode 100644 index 0000000000..f88d0a967a --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_api_5_9_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_engine_5_9_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_engine_5_9_1.xml new file mode 100644 index 0000000000..7d13c06163 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_engine_5_9_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_params_5_9_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_params_5_9_1.xml new file mode 100644 index 0000000000..1cbbb38915 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_params_5_9_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_junit_platform_junit_platform_commons_1_9_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_junit_platform_junit_platform_commons_1_9_1.xml new file mode 100644 index 0000000000..79aa3d3eef --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_junit_platform_junit_platform_commons_1_9_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_junit_platform_junit_platform_engine_1_9_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_junit_platform_junit_platform_engine_1_9_1.xml new file mode 100644 index 0000000000..31a3ca586e --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_junit_platform_junit_platform_engine_1_9_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_latencyutils_LatencyUtils_2_0_3.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_latencyutils_LatencyUtils_2_0_3.xml new file mode 100644 index 0000000000..bf68169843 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_latencyutils_LatencyUtils_2_0_3.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_mockito_mockito_core_4_8_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_mockito_mockito_core_4_8_1.xml new file mode 100644 index 0000000000..0052a200de --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_mockito_mockito_core_4_8_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_mockito_mockito_junit_jupiter_4_8_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_mockito_mockito_junit_jupiter_4_8_1.xml new file mode 100644 index 0000000000..cfde0c4283 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_mockito_mockito_junit_jupiter_4_8_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_objenesis_objenesis_3_2.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_objenesis_objenesis_3_2.xml new file mode 100644 index 0000000000..6613def613 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_objenesis_objenesis_3_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_opentest4j_opentest4j_1_2_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_opentest4j_opentest4j_1_2_0.xml new file mode 100644 index 0000000000..fbc1b1635a --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_opentest4j_opentest4j_1_2_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_ow2_asm_asm_7_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_ow2_asm_asm_7_1.xml new file mode 100644 index 0000000000..1d8827daf8 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_ow2_asm_asm_7_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_reactivestreams_reactive_streams_1_0_4.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_reactivestreams_reactive_streams_1_0_4.xml new file mode 100644 index 0000000000..56975fd092 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_reactivestreams_reactive_streams_1_0_4.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_skyscreamer_jsonassert_1_5_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_skyscreamer_jsonassert_1_5_1.xml new file mode 100644 index 0000000000..56582d6303 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_skyscreamer_jsonassert_1_5_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_slf4j_jul_to_slf4j_2_0_6.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_slf4j_jul_to_slf4j_2_0_6.xml new file mode 100644 index 0000000000..a9945b64dc --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_slf4j_jul_to_slf4j_2_0_6.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_slf4j_slf4j_api_2_0_6.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_slf4j_slf4j_api_2_0_6.xml new file mode 100644 index 0000000000..05513fb53c --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_slf4j_slf4j_api_2_0_6.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_amqp_spring_amqp_3_0_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_amqp_spring_amqp_3_0_0.xml new file mode 100644 index 0000000000..e2391885d2 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_amqp_spring_amqp_3_0_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_amqp_spring_rabbit_3_0_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_amqp_spring_rabbit_3_0_0.xml new file mode 100644 index 0000000000..afdf148488 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_amqp_spring_rabbit_3_0_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_3_0_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_3_0_1.xml new file mode 100644 index 0000000000..f58d98212b --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_3_0_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_actuator_3_0_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_actuator_3_0_1.xml new file mode 100644 index 0000000000..468f90674a --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_actuator_3_0_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_actuator_autoconfigure_3_0_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_actuator_autoconfigure_3_0_1.xml new file mode 100644 index 0000000000..b9434a219e --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_actuator_autoconfigure_3_0_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_3_0_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_3_0_1.xml new file mode 100644 index 0000000000..5310c82a09 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_3_0_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_3_0_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_3_0_1.xml new file mode 100644 index 0000000000..73ce745104 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_3_0_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_actuator_3_0_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_actuator_3_0_1.xml new file mode 100644 index 0000000000..cc7906d4d0 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_actuator_3_0_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_amqp_3_0_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_amqp_3_0_1.xml new file mode 100644 index 0000000000..bd0019b998 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_amqp_3_0_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_json_3_0_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_json_3_0_1.xml new file mode 100644 index 0000000000..896ee78948 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_json_3_0_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_3_0_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_3_0_1.xml new file mode 100644 index 0000000000..1fe8320361 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_3_0_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_reactor_netty_3_0_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_reactor_netty_3_0_1.xml new file mode 100644 index 0000000000..b0f6e01c48 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_reactor_netty_3_0_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_test_3_0_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_test_3_0_1.xml new file mode 100644 index 0000000000..3efc783195 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_test_3_0_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_tomcat_3_0_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_tomcat_3_0_1.xml new file mode 100644 index 0000000000..7d1b72182a --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_tomcat_3_0_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_validation_3_0_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_validation_3_0_1.xml new file mode 100644 index 0000000000..67683d5036 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_validation_3_0_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_web_3_0_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_web_3_0_1.xml new file mode 100644 index 0000000000..bd8448ae87 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_web_3_0_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_webflux_3_0_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_webflux_3_0_1.xml new file mode 100644 index 0000000000..ab46913812 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_webflux_3_0_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_3_0_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_3_0_1.xml new file mode 100644 index 0000000000..ebe5a7f642 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_3_0_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_autoconfigure_3_0_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_autoconfigure_3_0_1.xml new file mode 100644 index 0000000000..c29ad1b6f3 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_autoconfigure_3_0_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_contract_shade_4_0_1_SNAPSHOT.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_contract_shade_4_0_1_SNAPSHOT.xml new file mode 100644 index 0000000000..3c01c1312c --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_contract_shade_4_0_1_SNAPSHOT.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_contract_spec_4_0_1_SNAPSHOT.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_contract_spec_4_0_1_SNAPSHOT.xml new file mode 100644 index 0000000000..fb4258af8f --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_contract_spec_4_0_1_SNAPSHOT.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_contract_spec_groovy_4_0_1_SNAPSHOT.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_contract_spec_groovy_4_0_1_SNAPSHOT.xml new file mode 100644 index 0000000000..feade618fd --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_contract_spec_groovy_4_0_1_SNAPSHOT.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_contract_spec_java_4_0_1_SNAPSHOT.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_contract_spec_java_4_0_1_SNAPSHOT.xml new file mode 100644 index 0000000000..09deabbb3a --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_contract_spec_java_4_0_1_SNAPSHOT.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_contract_verifier_4_0_0_SNAPSHOT.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_contract_verifier_4_0_0_SNAPSHOT.xml new file mode 100644 index 0000000000..7671925afa --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_contract_verifier_4_0_0_SNAPSHOT.xml @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_contract_verifier_4_0_1_SNAPSHOT.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_contract_verifier_4_0_1_SNAPSHOT.xml new file mode 100644 index 0000000000..2722208037 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_contract_verifier_4_0_1_SNAPSHOT.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_function_context_4_0_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_function_context_4_0_0.xml new file mode 100644 index 0000000000..4662683019 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_function_context_4_0_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_function_core_4_0_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_function_core_4_0_0.xml new file mode 100644 index 0000000000..489b7f1b79 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_function_core_4_0_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_starter_contract_verifier_4_0_1_SNAPSHOT.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_starter_contract_verifier_4_0_1_SNAPSHOT.xml new file mode 100644 index 0000000000..52a9d669f3 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_starter_contract_verifier_4_0_1_SNAPSHOT.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_starter_stream_rabbit_4_0_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_starter_stream_rabbit_4_0_0.xml new file mode 100644 index 0000000000..bb73b38444 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_starter_stream_rabbit_4_0_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_stream_4_0_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_stream_4_0_0.xml new file mode 100644 index 0000000000..ccca7c3380 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_stream_4_0_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_stream_binder_rabbit_4_0_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_stream_binder_rabbit_4_0_0.xml new file mode 100644 index 0000000000..88b1bd160d --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_stream_binder_rabbit_4_0_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_stream_binder_rabbit_core_4_0_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_stream_binder_rabbit_core_4_0_0.xml new file mode 100644 index 0000000000..6a3635216d --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_stream_binder_rabbit_core_4_0_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_stream_test_binder_4_0_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_stream_test_binder_4_0_0.xml new file mode 100644 index 0000000000..34caaa429a --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_cloud_spring_cloud_stream_test_binder_4_0_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_integration_spring_integration_amqp_6_0_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_integration_spring_integration_amqp_6_0_1.xml new file mode 100644 index 0000000000..c67b5e1ed0 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_integration_spring_integration_amqp_6_0_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_integration_spring_integration_core_6_0_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_integration_spring_integration_core_6_0_1.xml new file mode 100644 index 0000000000..9f9acd2f80 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_integration_spring_integration_core_6_0_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_integration_spring_integration_jmx_6_0_1.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_integration_spring_integration_jmx_6_0_1.xml new file mode 100644 index 0000000000..2d980632f6 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_integration_spring_integration_jmx_6_0_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_retry_spring_retry_2_0_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_retry_spring_retry_2_0_0.xml new file mode 100644 index 0000000000..5190b165f7 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_retry_spring_retry_2_0_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_aop_6_0_3.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_aop_6_0_3.xml new file mode 100644 index 0000000000..df12beb948 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_aop_6_0_3.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_beans_6_0_3.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_beans_6_0_3.xml new file mode 100644 index 0000000000..dfb96af095 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_beans_6_0_3.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_context_6_0_3.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_context_6_0_3.xml new file mode 100644 index 0000000000..42ae7499c8 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_context_6_0_3.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_core_6_0_3.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_core_6_0_3.xml new file mode 100644 index 0000000000..1cdb53bd2a --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_core_6_0_3.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_expression_6_0_3.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_expression_6_0_3.xml new file mode 100644 index 0000000000..e3fd1d003a --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_expression_6_0_3.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_jcl_6_0_3.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_jcl_6_0_3.xml new file mode 100644 index 0000000000..1d6f87671c --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_jcl_6_0_3.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_messaging_6_0_3.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_messaging_6_0_3.xml new file mode 100644 index 0000000000..b69a926367 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_messaging_6_0_3.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_test_6_0_3.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_test_6_0_3.xml new file mode 100644 index 0000000000..9e921d6ae7 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_test_6_0_3.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_tx_6_0_3.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_tx_6_0_3.xml new file mode 100644 index 0000000000..b9757c8301 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_tx_6_0_3.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_web_6_0_3.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_web_6_0_3.xml new file mode 100644 index 0000000000..0726bce990 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_web_6_0_3.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_webflux_6_0_3.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_webflux_6_0_3.xml new file mode 100644 index 0000000000..e4bfc0b0d0 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_webflux_6_0_3.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_webmvc_6_0_3.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_webmvc_6_0_3.xml new file mode 100644 index 0000000000..71c81536a6 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_springframework_spring_webmvc_6_0_3.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_xmlunit_xmlunit_core_2_9_0.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_xmlunit_xmlunit_core_2_9_0.xml new file mode 100644 index 0000000000..e4d53eb1a7 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_xmlunit_xmlunit_core_2_9_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_yaml_snakeyaml_1_33.xml b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_yaml_snakeyaml_1_33.xml new file mode 100644 index 0000000000..797db86ead --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/libraries/Maven__org_yaml_snakeyaml_1_33.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/misc.xml b/samples/standalone/dsl/http-server/.idea/misc.xml new file mode 100644 index 0000000000..25daa30c84 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/misc.xml @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/modules.xml b/samples/standalone/dsl/http-server/.idea/modules.xml new file mode 100644 index 0000000000..968b170537 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.idea/sonarlint/issuestore/index.pb b/samples/standalone/dsl/http-server/.idea/sonarlint/issuestore/index.pb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/standalone/dsl/http-server/.idea/sonarlint/securityhotspotstore/index.pb b/samples/standalone/dsl/http-server/.idea/sonarlint/securityhotspotstore/index.pb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/standalone/dsl/http-server/.idea/vcs.xml b/samples/standalone/dsl/http-server/.idea/vcs.xml new file mode 100644 index 0000000000..4fce1d86b4 --- /dev/null +++ b/samples/standalone/dsl/http-server/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.mvn/jvm.config b/samples/standalone/dsl/http-server/.mvn/jvm.config deleted file mode 100644 index 0e7dabeff6..0000000000 --- a/samples/standalone/dsl/http-server/.mvn/jvm.config +++ /dev/null @@ -1 +0,0 @@ --Xmx1024m -XX:CICompilerCount=1 -XX:TieredStopAtLevel=1 -Djava.security.egd=file:/dev/./urandom \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/.mvn/maven.config b/samples/standalone/dsl/http-server/.mvn/maven.config deleted file mode 100644 index a682990566..0000000000 --- a/samples/standalone/dsl/http-server/.mvn/maven.config +++ /dev/null @@ -1 +0,0 @@ --P spring diff --git a/samples/standalone/dsl/http-server/.mvn/wrapper/MavenWrapperDownloader.java b/samples/standalone/dsl/http-server/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index b901097f2d..0000000000 --- a/samples/standalone/dsl/http-server/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2007-present 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. - */ -import java.net.*; -import java.io.*; -import java.nio.channels.*; -import java.util.Properties; - -public class MavenWrapperDownloader { - - private static final String WRAPPER_VERSION = "0.5.6"; - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" - + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if(mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if(mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if(!outputFile.getParentFile().exists()) { - if(!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { - String username = System.getenv("MVNW_USERNAME"); - char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); - Authenticator.setDefault(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(username, password); - } - }); - } - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/samples/standalone/dsl/http-server/.mvn/wrapper/maven-wrapper.jar b/samples/standalone/dsl/http-server/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index c1dd12f17644411d6e840bd5a10c6ecda0175f18..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58727 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%0ANsA|A3-jj|r`KAo%oTajX3>^E` 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 YM{}PByk10KD_nuQ4E7Du?}+~TKh4V)`~Uy| diff --git a/samples/standalone/dsl/http-server/.mvn/wrapper/maven-wrapper.properties b/samples/standalone/dsl/http-server/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index 015dfe6821..0000000000 --- a/samples/standalone/dsl/http-server/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,18 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.3/apache-maven-3.8.3-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar diff --git a/samples/standalone/dsl/http-server/README.adoc b/samples/standalone/dsl/http-server/README.adoc deleted file mode 100644 index 2fd3fbc40d..0000000000 --- a/samples/standalone/dsl/http-server/README.adoc +++ /dev/null @@ -1,20 +0,0 @@ -= Http Server - -Run - -[source=groovy] --------- -./gradlew clean build publishToMavenLocal --------- - -or - --------- -./mvnw clean install --------- - -To - -- build the app -- generate and run Spring Cloud Contract Verifier tests -- publish the fatJar and the stubs to Maven Local \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/build.gradle b/samples/standalone/dsl/http-server/build.gradle deleted file mode 100644 index 85f2713082..0000000000 --- a/samples/standalone/dsl/http-server/build.gradle +++ /dev/null @@ -1,95 +0,0 @@ -plugins { - id "java" - id "org.springframework.boot" - id "io.spring.dependency-management" - id "org.springframework.cloud.contract" - id "maven-publish" -} - -group = 'com.example' -version = '0.0.1' - -// tag::deps_repos[] -repositories { - mavenCentral() - mavenLocal() - maven { url "https://repo.spring.io/snapshot" } - maven { url "https://repo.spring.io/milestone" } - maven { url "https://repo.spring.io/release" } -} -// end::deps_repos[] - -dependencyManagement { - imports { - mavenBom "org.springframework.cloud:spring-cloud-dependencies:$BOM_VERSION" - } -} - -contracts { - packageWithBaseClasses = 'com.example.fraud' -// convertToYaml = true - contractsDslDir = file("src/test/resources/contracts") -} - -dependencies { - implementation("org.springframework.boot:spring-boot-starter-web") - implementation("org.springframework.boot:spring-boot-starter-actuator") - implementation("org.springframework.cloud:spring-cloud-starter-stream-rabbit") - - testImplementation 'org.springframework.cloud:spring-cloud-starter-contract-verifier' - testImplementation(group: 'org.springframework.cloud', name: 'spring-cloud-stream-test-binder') - testImplementation('org.springframework.boot:spring-boot-starter-test') { - exclude(group: 'org.junit.vintage', module: 'junit-vintage-engine') - } -} - -contractTest { - systemProperty 'spring.profiles.active', 'gradle' - testLogging { - exceptionFormat = 'full' - } - afterSuite { desc, result -> - if (!desc.parent) { - println "Results: (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)" - if (result.testCount == 0) { - throw new IllegalStateException("No tests were found. Failing the build") - } - } - } -} - -publishing { - publications { - maven(MavenPublication) { - artifact bootJar - artifact verifierStubsJar - - // https://github.com/spring-gradle-plugins/dependency-management-plugin/issues/273 - versionMapping { - usage("java-api") { - fromResolutionOf("runtimeClasspath") - } - usage("java-runtime") { - fromResolutionResult() - } - } - } - } -} - -clean.doFirst { - delete "~/.m2/repository/com/example/http-server-dsl-gradle" -} - -task resolveDependencies { - doLast { - project.rootProject.allprojects.each { subProject -> - subProject.buildscript.configurations.each { configuration -> - configuration.resolve() - } - subProject.configurations.each { configuration -> - configuration.resolve() - } - } - } -} diff --git a/samples/standalone/dsl/http-server/gradle.properties b/samples/standalone/dsl/http-server/gradle.properties deleted file mode 100644 index 23a8e509b5..0000000000 --- a/samples/standalone/dsl/http-server/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -org.gradle.daemon=false -verifierVersion=4.1.0-SNAPSHOT -BOM_VERSION=2023.0.0-SNAPSHOT -bootVersion=3.2.0-SNAPSHOT diff --git a/samples/standalone/dsl/http-server/gradle/wrapper/gradle-wrapper.jar b/samples/standalone/dsl/http-server/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 7f93135c49b765f8051ef9d0a6055ff8e46073d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63721 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鯊%1Et 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⁢ zv5o9#E7!G0XmdzfsS{efPNi`1b44~SZ4Z8fuX!I}#8g+(wxzQwUT#Xb2(tbY1+EUhGKoT@KEU9Ktl>_0 z%bjDJg;#*gtJZv!-Zs`?^}v5eKmnbjqlvnSzE@_SP|LG_PJ6CYU+6zY6>92%E+ z=j@TZf-iW4(%U{lnYxQA;7Q!b;^brF8n0D>)`q5>|WDDXLrqYU_tKN2>=#@~OE7grMnNh?UOz-O~6 z6%rHy{#h9K0AT+lDC7q4{hw^|q6*Ry;;L%Q@)Ga}$60_q%D)rv(CtS$CQbpq9|y1e zRSrN4;$Jyl{m5bZw`$8TGvb}(LpY{-cQ)fcyJv7l3S52TLXVDsphtv&aPuDk1OzCA z4A^QtC(!11`IsNx_HnSy?>EKpHJWT^wmS~hc^p^zIIh@9f6U@I2 zC=Mve{j2^)mS#U$e{@Q?SO6%LDsXz@SY+=cK_QMmXBIU)j!$ajc-zLx3V60EXJ!qC zi<%2x8Q24YN+&8U@CIlN zrZkcT9yh%LrlGS9`G)KdP(@9Eo-AQz@8GEFWcb7U=a0H^ZVbLmz{+&M7W(nXJ4sN8 zJLR7eeK(K8`2-}j(T7JsO`L!+CvbueT%izanm-^A1Dn{`1Nw`9P?cq;7no+XfC`K(GO9?O^5zNIt4M+M8LM0=7Gz8UA@Z0N+lg+cX)NfazRu z5D)~HA^(u%w^cz+@2@_#S|u>GpB+j4KzQ^&Wcl9f z&hG#bCA(Yk0D&t&aJE^xME^&E-&xGHhXn%}psEIj641H+Nl-}boj;)Zt*t(4wZ5DN z@GXF$bL=&pBq-#vkTkh>7hl%K5|3 z{`Vn9b$iR-SoGENp}bn4;fR3>9sA%X2@1L3aE9yTra;Wb#_`xWwLSLdfu+PAu+o3| zGVnpzPr=ch{uuoHjtw7+_!L_2;knQ!DuDl0R`|%jr+}jFzXtrHIKc323?JO{l&;VF z*L1+}JU7%QJOg|5|Tc|D8fN zJORAg=_vsy{ak|o);@)Yh8Lkcg@$FG3k@ep36BRa^>~UmnRPziS>Z=`Jb2x*Q#`%A zU*i3&Vg?TluO@X0O;r2Jl6LKLUOVhSqg1*qOt^|8*c7 zo(298@+r$k_wQNGHv{|$tW(T8L+4_`FQ{kEW5Jgg{yf7ey4ss_(SNKfz(N9lx&a;< je(UuV8hP?p&}TPdm1I$XmG#(RzlD&B2izSj9sl%y5~4qc diff --git a/samples/standalone/dsl/http-server/gradle/wrapper/gradle-wrapper.properties b/samples/standalone/dsl/http-server/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index ac72c34e8a..0000000000 --- a/samples/standalone/dsl/http-server/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/samples/standalone/dsl/http-server/gradlew b/samples/standalone/dsl/http-server/gradlew deleted file mode 100755 index 0adc8e1a53..0000000000 --- a/samples/standalone/dsl/http-server/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/samples/standalone/dsl/http-server/gradlew.bat b/samples/standalone/dsl/http-server/gradlew.bat deleted file mode 100644 index 6689b85bee..0000000000 --- a/samples/standalone/dsl/http-server/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/samples/standalone/dsl/http-server/log.log b/samples/standalone/dsl/http-server/log.log new file mode 100644 index 0000000000..7fcc7b5f31 --- /dev/null +++ b/samples/standalone/dsl/http-server/log.log @@ -0,0 +1,154 @@ +[INFO] Scanning for projects... +[INFO] +[INFO] --------------------< com.example:http-server-dsl >--------------------- +[INFO] Building Spring Cloud Contract Verifier Http Server Sample 0.0.1 +[INFO] --------------------------------[ jar ]--------------------------------- +[INFO] +[INFO] --- maven-dependency-plugin:3.3.0:tree (default-cli) @ http-server-dsl --- +[INFO] com.example:http-server-dsl:jar:0.0.1 +[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:3.0.0-SNAPSHOT:compile +[INFO] | +- org.springframework.boot:spring-boot-starter:jar:3.0.0-SNAPSHOT:compile +[INFO] | | +- org.springframework.boot:spring-boot:jar:3.0.0-SNAPSHOT:compile +[INFO] | | +- org.springframework.boot:spring-boot-autoconfigure:jar:3.0.0-SNAPSHOT:compile +[INFO] | | +- org.springframework.boot:spring-boot-starter-logging:jar:3.0.0-SNAPSHOT:compile +[INFO] | | | +- ch.qos.logback:logback-classic:jar:1.2.11:compile +[INFO] | | | | \- ch.qos.logback:logback-core:jar:1.2.11:compile +[INFO] | | | +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.17.2:compile +[INFO] | | | | \- org.apache.logging.log4j:log4j-api:jar:2.17.2:compile +[INFO] | | | \- org.slf4j:jul-to-slf4j:jar:1.7.36:compile +[INFO] | | +- jakarta.annotation:jakarta.annotation-api:jar:2.0.0:compile +[INFO] | | \- org.yaml:snakeyaml:jar:1.30:compile +[INFO] | +- org.springframework.boot:spring-boot-starter-json:jar:3.0.0-SNAPSHOT:compile +[INFO] | | +- com.fasterxml.jackson.core:jackson-databind:jar:2.13.2.1:compile +[INFO] | | | +- com.fasterxml.jackson.core:jackson-annotations:jar:2.13.2:compile +[INFO] | | | \- com.fasterxml.jackson.core:jackson-core:jar:2.13.2:compile +[INFO] | | +- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.13.2:compile +[INFO] | | +- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.13.2:compile +[INFO] | | \- com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.13.2:compile +[INFO] | +- org.springframework.boot:spring-boot-starter-tomcat:jar:3.0.0-SNAPSHOT:compile +[INFO] | | +- org.apache.tomcat.embed:tomcat-embed-core:jar:10.0.18:compile +[INFO] | | +- org.apache.tomcat.embed:tomcat-embed-el:jar:10.0.18:compile +[INFO] | | \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:10.0.18:compile +[INFO] | +- org.springframework:spring-web:jar:5.0.2-SNAPSHOT:compile +[INFO] | | \- org.springframework:spring-beans:jar:5.0.2-SNAPSHOT:compile +[INFO] | \- org.springframework:spring-webmvc:jar:5.0.2-SNAPSHOT:compile +[INFO] | +- org.springframework:spring-aop:jar:5.0.2-SNAPSHOT:compile +[INFO] | +- org.springframework:spring-context:jar:5.0.2-SNAPSHOT:compile +[INFO] | \- org.springframework:spring-expression:jar:5.0.2-SNAPSHOT:compile +[INFO] +- org.springframework.boot:spring-boot-starter-actuator:jar:3.0.0-SNAPSHOT:compile +[INFO] | +- org.springframework.boot:spring-boot-actuator-autoconfigure:jar:3.0.0-SNAPSHOT:compile +[INFO] | | \- org.springframework.boot:spring-boot-actuator:jar:3.0.0-SNAPSHOT:compile +[INFO] | +- io.micrometer:micrometer-observation:jar:1.10.0-SNAPSHOT:compile +[INFO] | | \- io.micrometer:micrometer-commons:jar:1.10.0-SNAPSHOT:compile +[INFO] | \- io.micrometer:micrometer-core:jar:1.10.0-SNAPSHOT:compile +[INFO] | +- org.hdrhistogram:HdrHistogram:jar:2.1.12:compile +[INFO] | \- org.latencyutils:LatencyUtils:jar:2.0.3:runtime +[INFO] +- org.springframework.boot:spring-boot-starter-test:jar:3.0.0-SNAPSHOT:test +[INFO] | +- org.springframework.boot:spring-boot-test:jar:3.0.0-SNAPSHOT:test +[INFO] | +- org.springframework.boot:spring-boot-test-autoconfigure:jar:3.0.0-SNAPSHOT:test +[INFO] | +- com.jayway.jsonpath:json-path:jar:2.7.0:test +[INFO] | | +- net.minidev:json-smart:jar:2.4.8:test +[INFO] | | | \- net.minidev:accessors-smart:jar:2.4.8:test +[INFO] | | \- org.slf4j:slf4j-api:jar:1.7.36:compile +[INFO] | +- jakarta.xml.bind:jakarta.xml.bind-api:jar:3.0.1:test +[INFO] | | \- com.sun.activation:jakarta.activation:jar:2.0.1:test +[INFO] | +- org.assertj:assertj-core:jar:3.22.0:test +[INFO] | +- org.hamcrest:hamcrest:jar:2.2:test +[INFO] | +- org.junit.jupiter:junit-jupiter:jar:5.8.2:test +[INFO] | | +- org.junit.jupiter:junit-jupiter-api:jar:5.8.2:test +[INFO] | | | +- org.opentest4j:opentest4j:jar:1.2.0:test +[INFO] | | | +- org.junit.platform:junit-platform-commons:jar:1.8.2:test +[INFO] | | | \- org.apiguardian:apiguardian-api:jar:1.1.2:test +[INFO] | | +- org.junit.jupiter:junit-jupiter-params:jar:5.8.2:test +[INFO] | | \- org.junit.jupiter:junit-jupiter-engine:jar:5.8.2:test +[INFO] | | \- org.junit.platform:junit-platform-engine:jar:1.8.2:test +[INFO] | +- org.mockito:mockito-core:jar:4.5.0:test +[INFO] | | +- net.bytebuddy:byte-buddy:jar:1.12.9:test +[INFO] | | +- net.bytebuddy:byte-buddy-agent:jar:1.12.9:test +[INFO] | | \- org.objenesis:objenesis:jar:3.2:test +[INFO] | +- org.mockito:mockito-junit-jupiter:jar:4.5.0:test +[INFO] | +- org.skyscreamer:jsonassert:jar:1.5.0:test +[INFO] | | \- com.vaadin.external.google:android-json:jar:0.0.20131108.vaadin1:test +[INFO] | +- org.springframework:spring-core:jar:5.0.2-SNAPSHOT:compile +[INFO] | | \- org.springframework:spring-jcl:jar:5.0.2-SNAPSHOT:compile +[INFO] | +- org.springframework:spring-test:jar:5.0.2-SNAPSHOT:test +[INFO] | \- org.xmlunit:xmlunit-core:jar:2.9.0:test +[INFO] +- org.springframework.cloud:spring-cloud-starter-stream-rabbit:jar:4.0.0-SNAPSHOT:compile +[INFO] | \- org.springframework.cloud:spring-cloud-stream-binder-rabbit:jar:4.0.0-SNAPSHOT:compile +[INFO] | +- org.springframework.cloud:spring-cloud-stream-binder-rabbit-core:jar:4.0.0-SNAPSHOT:compile +[INFO] | | +- org.springframework.integration:spring-integration-amqp:jar:6.0.0-M2:compile +[INFO] | | \- com.rabbitmq:http-client:jar:2.1.0.RELEASE:compile +[INFO] | +- org.springframework.cloud:spring-cloud-stream:jar:4.0.0-SNAPSHOT:compile +[INFO] | +- org.springframework.boot:spring-boot-starter-amqp:jar:3.0.0-SNAPSHOT:compile +[INFO] | | \- org.springframework.amqp:spring-rabbit:jar:3.0.0-M2:compile +[INFO] | | +- org.springframework.amqp:spring-amqp:jar:3.0.0-M2:compile +[INFO] | | \- com.rabbitmq:amqp-client:jar:5.14.2:compile +[INFO] | \- org.apache.httpcomponents:httpclient:jar:4.5.13:compile +[INFO] | +- org.apache.httpcomponents:httpcore:jar:4.4.15:compile +[INFO] | \- commons-codec:commons-codec:jar:1.15:compile +[INFO] +- org.springframework.cloud:spring-cloud-stream:test-jar:test-binder:4.0.0-SNAPSHOT:test +[INFO] | +- org.springframework.boot:spring-boot-starter-validation:jar:3.0.0-SNAPSHOT:compile +[INFO] | | \- org.hibernate.validator:hibernate-validator:jar:7.0.4.Final:compile +[INFO] | | +- jakarta.validation:jakarta.validation-api:jar:3.0.1:compile +[INFO] | | +- org.jboss.logging:jboss-logging:jar:3.4.3.Final:compile +[INFO] | | \- com.fasterxml:classmate:jar:1.5.1:compile +[INFO] | +- org.springframework:spring-messaging:jar:5.0.2-SNAPSHOT:compile +[INFO] | +- org.springframework.integration:spring-integration-core:jar:6.0.0-M2:compile +[INFO] | | +- org.springframework:spring-tx:jar:5.0.2-SNAPSHOT:compile +[INFO] | | \- io.projectreactor:reactor-core:jar:3.4.17:compile +[INFO] | | \- org.reactivestreams:reactive-streams:jar:1.0.3:compile +[INFO] | +- org.springframework.integration:spring-integration-jmx:jar:6.0.0-M2:compile +[INFO] | +- org.springframework.retry:spring-retry:jar:1.3.3:compile +[INFO] | \- org.springframework.cloud:spring-cloud-function-context:jar:4.0.0-SNAPSHOT:compile +[INFO] | +- net.jodah:typetools:jar:0.6.2:compile +[INFO] | +- org.springframework.cloud:spring-cloud-function-core:jar:4.0.0-SNAPSHOT:compile +[INFO] | +- javax.annotation:javax.annotation-api:jar:1.3.2:compile +[INFO] | \- javax.activation:javax.activation-api:jar:1.2.0:compile +[INFO] \- org.springframework.cloud:spring-cloud-starter-contract-verifier:jar:4.0.0-SNAPSHOT:test +[INFO] +- org.springframework.cloud:spring-cloud-contract-verifier:jar:4.0.0-SNAPSHOT:test +[INFO] | +- org.springframework.cloud:spring-cloud-contract-spec:jar:4.0.0-SNAPSHOT:test +[INFO] | | +- org.springframework.cloud:spring-cloud-contract-spec-java:jar:4.0.0-SNAPSHOT:test +[INFO] | | | \- dk.brics.automaton:automaton:jar:1.11-8:test +[INFO] | | \- org.springframework.cloud:spring-cloud-contract-spec-groovy:jar:4.0.0-SNAPSHOT:test +[INFO] | +- org.springframework.cloud:spring-cloud-contract-shade:jar:4.0.0-SNAPSHOT:test +[INFO] | +- org.apache.commons:commons-text:jar:1.9:test +[INFO] | | \- org.apache.commons:commons-lang3:jar:3.12.0:test +[INFO] | +- javax.inject:javax.inject:jar:1:test +[INFO] | +- com.github.tomakehurst:wiremock-jre8-standalone:jar:2.35.0:test +[INFO] | +- org.apache.maven.resolver:maven-resolver-api:jar:1.4.1:test +[INFO] | +- com.rackspace.eclipse.webtools.sourceediting:org.eclipse.wst.xml.xpath2.processor:jar:2.1.100:test +[INFO] | | +- edu.princeton.cup:java-cup:jar:10k:test +[INFO] | | \- com.ibm.icu:icu4j:jar:4.6:test +[INFO] | +- org.apache.groovy:groovy:jar:4.0.1:test +[INFO] | +- org.apache.groovy:groovy-nio:jar:4.0.1:test +[INFO] | +- org.apache.groovy:groovy-json:jar:4.0.1:test +[INFO] | +- org.apache.groovy:groovy-xml:jar:4.0.1:test +[INFO] | +- com.github.jknack:handlebars:jar:4.2.0:test +[INFO] | +- commons-beanutils:commons-beanutils:jar:1.9.4:test +[INFO] | | +- commons-logging:commons-logging:jar:1.2:test +[INFO] | | \- commons-collections:commons-collections:jar:3.2.2:test +[INFO] | +- com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:jar:2.13.2:test +[INFO] | +- net.javacrumbs.json-unit:json-unit-assertj:jar:2.32.0:test +[INFO] | | +- net.javacrumbs.json-unit:json-unit-core:jar:2.32.0:test +[INFO] | | | \- org.hamcrest:hamcrest-core:jar:2.2:test +[INFO] | | \- net.javacrumbs.json-unit:json-unit-json-path:jar:2.32.0:test +[INFO] | \- org.springframework.cloud:spring-cloud-function-compiler:jar:3.0.6.RELEASE:test +[INFO] | \- org.eclipse.jdt.core.compiler:ecj:jar:4.4.2:test +[INFO] +- io.rest-assured:rest-assured:jar:5.0.2-SNAPSHOT:test +[INFO] | +- org.apache.httpcomponents:httpmime:jar:4.5.13:test +[INFO] | +- org.ccil.cowan.tagsoup:tagsoup:jar:1.2.1:test +[INFO] | +- io.rest-assured:json-path:jar:5.0.2-SNAPSHOT:test +[INFO] | | \- io.rest-assured:rest-assured-common:jar:5.0.2-SNAPSHOT:test +[INFO] | \- io.rest-assured:xml-path:jar:5.0.2-SNAPSHOT:test +[INFO] +- io.rest-assured:spring-mock-mvc:jar:5.0.2-SNAPSHOT:test +[INFO] | \- io.rest-assured:spring-commons:jar:5.0.2-SNAPSHOT:test +[INFO] +- com.toomuchcoding.jsonassert:jsonassert:jar:0.6.2:test +[INFO] \- cglib:cglib:jar:3.3.0:test +[INFO] \- org.ow2.asm:asm:jar:7.1:test +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ +[INFO] Total time: 1.045 s +[INFO] Finished at: 2022-05-04T13:31:15+02:00 +[INFO] ------------------------------------------------------------------------ +[WARNING] The requested profile "spring" could not be activated because it does not exist. diff --git a/samples/standalone/dsl/http-server/mvnw b/samples/standalone/dsl/http-server/mvnw deleted file mode 100755 index 5643201c7d..0000000000 --- a/samples/standalone/dsl/http-server/mvnw +++ /dev/null @@ -1,316 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Maven Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /usr/local/etc/mavenrc ] ; then - . /usr/local/etc/mavenrc - fi - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`\\unset -f command; \\command -v java`" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` - fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" - fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi -else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - if [ -n "$MVNW_REPOURL" ]; then - jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - else - jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - fi - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - if $cygwin; then - wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` - fi - - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - else - wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - fi - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl -o "$wrapperJarPath" "$jarUrl" -f - else - curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f - fi - - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - # For Cygwin, switch paths to Windows format before running javac - if $cygwin; then - javaClass=`cygpath --path --windows "$javaClass"` - fi - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` -fi - -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" -export MAVEN_CMD_LINE_ARGS - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -exec "$JAVACMD" \ - $MAVEN_OPTS \ - $MAVEN_DEBUG_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" \ - "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/samples/standalone/dsl/http-server/mvnw.cmd b/samples/standalone/dsl/http-server/mvnw.cmd deleted file mode 100644 index 23b7079a3d..0000000000 --- a/samples/standalone/dsl/http-server/mvnw.cmd +++ /dev/null @@ -1,188 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* -if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% ^ - %JVM_CONFIG_MAVEN_PROPS% ^ - %MAVEN_OPTS% ^ - %MAVEN_DEBUG_OPTS% ^ - -classpath %WRAPPER_JAR% ^ - "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ - %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" -if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%"=="on" pause - -if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% - -cmd /C exit /B %ERROR_CODE% diff --git a/samples/standalone/dsl/http-server/pom.xml b/samples/standalone/dsl/http-server/pom.xml deleted file mode 100644 index 5db6aa16f1..0000000000 --- a/samples/standalone/dsl/http-server/pom.xml +++ /dev/null @@ -1,352 +0,0 @@ - - - 4.0.0 - - com.example - http-server-dsl - 0.0.1 - - Spring Cloud Contract Verifier Http Server Sample - Spring Cloud Contract Verifier Http Server Sample - - - org.springframework.boot - spring-boot-starter-parent - 3.2.0-SNAPSHOT - - - - - UTF-8 - 17 - 4.1.0-SNAPSHOT - 4.1.0-SNAPSHOT - - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-actuator - - - - org.springframework.boot - spring-boot-starter-test - test - - - org.junit.vintage - junit-vintage-engine - - - - - org.springframework.cloud - spring-cloud-starter-stream-rabbit - ${spring-cloud-stream.version} - - - - org.springframework.cloud - spring-cloud-stream-test-binder - ${spring-cloud-stream.version} - test - - - - - org.springframework.cloud - spring-cloud-starter-contract-verifier - test - - - - - - - - - org.springframework.cloud - spring-cloud-contract-dependencies - ${spring-cloud-contract.version} - pom - import - - - - - io.rest-assured - rest-assured-bom - 5.2.1 - pom - import - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.springframework.cloud - spring-cloud-contract-maven-plugin - ${spring-cloud-contract.version} - true - - com.example.fraud - - - - - - maven-deploy-plugin - 2.8.2 - - true - - - - org.apache.maven.plugins - maven-clean-plugin - 3.0.0 - - - - build - - - target - - - - - - maven-surefire-plugin - - true - - - - org.apache.maven.plugins - maven-antrun-plugin - 3.1.0 - - - process-test-resources - - - - - - - - - - - - - - - - - - - - - - - - - run - - - - - - ant-contrib - ant-contrib - 20020829 - - - - - - - - - org.eclipse.m2e - lifecycle-mapping - 1.0.0 - - - - - - org.springframework.cloud - spring-cloud-contract-maven-plugin - - - [${spring-cloud-contract.version},) - - - convert - generateTests - - - - - - - - - - - - - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - - - - - integration - - - - org.codehaus.mojo - exec-maven-plugin - 1.6.0 - - - gradle - test - - ./gradlew - - clean - build - publishToMavenLocal - - -x - test - - -x - contractTest - - -PverifierVersion=${spring-cloud-contract.version} - - - - - exec - - - - - - - - - windows - - - - org.codehaus.mojo - exec-maven-plugin - 1.6.0 - - - gradle - test - - gradlew.bat - - clean - build - publishToMavenLocal - - -x - test - - -x - contractTest - - -PverifierVersion=${spring-cloud-contract.version} - - - - - exec - - - - - - - - - diff --git a/samples/standalone/dsl/http-server/settings.gradle b/samples/standalone/dsl/http-server/settings.gradle deleted file mode 100644 index ec18a29444..0000000000 --- a/samples/standalone/dsl/http-server/settings.gradle +++ /dev/null @@ -1,24 +0,0 @@ -// tag::repos[] -pluginManagement { - repositories { - mavenLocal() - maven { url "https://repo.spring.io/snapshot" } - maven { url "https://repo.spring.io/milestone" } - gradlePluginPortal() - } -// end::repos[] - plugins { - id "org.springframework.boot" version "${bootVersion}" - id "io.spring.dependency-management" version "1.1.3" - } - resolutionStrategy { - eachPlugin { - // protects us in case the gradle-portal-plugin hasn't yet been published by Maven - if (requested.id.id == 'org.springframework.cloud.contract') { - useModule("org.springframework.cloud:spring-cloud-contract-gradle-plugin:${verifierVersion}") - } - } - } -} - -rootProject.name = 'http-server-dsl-gradle' diff --git a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/Application.java b/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/Application.java deleted file mode 100644 index b4562bfce3..0000000000 --- a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/Application.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } - -} diff --git a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/FooController.java b/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/FooController.java deleted file mode 100644 index 168967c6f2..0000000000 --- a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/FooController.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * @author Marcin Grzejszczak - */ -@RestController -class FooController { - - @GetMapping("/foo") - void foo() { - - } - -} diff --git a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/FraudDetectionController.java b/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/FraudDetectionController.java deleted file mode 100644 index bf84fc94ba..0000000000 --- a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/FraudDetectionController.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud; - -import java.math.BigDecimal; - -import com.example.fraud.model.FraudCheck; -import com.example.fraud.model.FraudCheckResult; -import com.example.fraud.model.FraudCheckStatus; - -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import static org.springframework.web.bind.annotation.RequestMethod.PUT; - -@RestController -public class FraudDetectionController { - - private static final String NO_REASON = null; - - private static final String AMOUNT_TOO_HIGH = "Amount too high"; - - private static final BigDecimal MAX_AMOUNT = new BigDecimal("5000"); - - // tag::server_api[] - @RequestMapping(value = "/fraudcheck", method = PUT) - public FraudCheckResult fraudCheck(@RequestBody FraudCheck fraudCheck) { - // end::server_api[] - // tag::new_impl[] - if (amountGreaterThanThreshold(fraudCheck)) { - return new FraudCheckResult(FraudCheckStatus.FRAUD, AMOUNT_TOO_HIGH); - } - // end::new_impl[] - // tag::initial_impl[] - return new FraudCheckResult(FraudCheckStatus.OK, NO_REASON); - // end::initial_impl[] - } - - @RequestMapping(value = "/yamlfraudcheck", method = PUT) - public FraudCheckResult yamlFraudCheck(@RequestBody FraudCheck fraudCheck) { - return fraudCheck(fraudCheck); - } - - private boolean amountGreaterThanThreshold(FraudCheck fraudCheck) { - return MAX_AMOUNT.compareTo(fraudCheck.getLoanAmount()) < 0; - } - -} diff --git a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/FraudNameController.java b/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/FraudNameController.java deleted file mode 100644 index 3b638e5b7d..0000000000 --- a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/FraudNameController.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud; - -import org.springframework.stereotype.Component; -import org.springframework.web.bind.annotation.CookieValue; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; - -interface FraudVerifier { - - boolean isFraudByName(String name); - -} - -/** - * @author Marcin Grzejszczak - */ -@RestController -class FraudNameController { - - private final FraudVerifier fraudVerifier; - - FraudNameController(FraudVerifier fraudVerifier) { - this.fraudVerifier = fraudVerifier; - } - - @PutMapping(value = "/frauds/name") - public NameResponse checkByName(@RequestBody NameRequest request) { - boolean fraud = this.fraudVerifier.isFraudByName(request.getName()); - if (fraud) { - return new NameResponse("Sorry " + request.getName() + " but you're a fraud"); - } - return new NameResponse( - "Don't worry " + request.getName() + " you're not a fraud"); - } - - @GetMapping(value = "/frauds/name") - public String checkByName(@CookieValue("name") String value, - @CookieValue("name2") String value2) { - return value + " " + value2; - } - - @PutMapping(value = "/yamlfrauds/name") - public NameResponse yamlCheckByName(@RequestBody NameRequest request) { - return checkByName(request); - } - - @GetMapping(value = "/yamlfrauds/name") - public String yamlCheckByName(@CookieValue("name") String value, - @CookieValue("name2") String value2) { - return checkByName(value, value2); - } - -} - -class NameRequest { - - private String name; - - public NameRequest(String name) { - this.name = name; - } - - public NameRequest() { - } - - public String getName() { - return this.name; - } - - public void setName(String name) { - this.name = name; - } - -} - -class NameResponse { - - private String result; - - public NameResponse(String result) { - this.result = result; - } - - public NameResponse() { - } - - public String getResult() { - return this.result; - } - - public void setResult(String result) { - this.result = result; - } - -} - -@Component -class DefaultFraudVerifier implements FraudVerifier { - - @Override - public boolean isFraudByName(String name) { - return true; - } -} \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/FraudStatsController.java b/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/FraudStatsController.java deleted file mode 100644 index c8b7f11ca7..0000000000 --- a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/FraudStatsController.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud; - -import org.springframework.stereotype.Component; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -enum FraudType { - - DRUNKS, ALL - -} - -interface StatsProvider { - - int count(FraudType fraudType); - -} - -@RestController -public class FraudStatsController { - - private final StatsProvider statsProvider; - - public FraudStatsController(StatsProvider statsProvider) { - this.statsProvider = statsProvider; - } - - @GetMapping(value = "/frauds") - public Response countAllFrauds() { - return new Response(this.statsProvider.count(FraudType.ALL)); - } - - @GetMapping(value = "/yamlfrauds") - public Response countAllYamlFrauds() { - return countAllFrauds(); - } - - @GetMapping(value = "/drunks") - public Response countAllDrunks() { - return new Response(this.statsProvider.count(FraudType.DRUNKS)); - } - - @GetMapping(value = "/yamldrunks") - public Response countAllYamlDrunks() { - return countAllDrunks(); - } - -} - -class Response { - - private int count; - - public Response(int count) { - this.count = count; - } - - public Response() { - } - - public int getCount() { - return this.count; - } - - public void setCount(int count) { - this.count = count; - } - -} - -@Component -class DefaultStatsProvider implements StatsProvider { - - @Override - public int count(FraudType fraudType) { - return 0; - } -} diff --git a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/MessageSender.java b/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/MessageSender.java deleted file mode 100644 index 9de0b3c5a1..0000000000 --- a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/MessageSender.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud; - -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.file.Files; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.cloud.stream.function.StreamBridge; -import org.springframework.stereotype.Component; - -@Component -class MessageSender { - - private static final Logger log = LoggerFactory.getLogger(MessageSender.class); - - private final StreamBridge streamBridge; - - private final byte[] expectedOutput; - - MessageSender(StreamBridge streamBridge) { - this.streamBridge = streamBridge; - this.expectedOutput = forFile("/contracts/messaging/output.pdf"); - } - - public void emit() { - log.info("Emitting the message"); - this.streamBridge.send("sensor_data-out-0", "{\"id\":\"99\",\"temperature\":\"123.45\"}"); - } - - public void emitBytes() { - log.info("Emitting the message"); - this.streamBridge.send("my_output-out-0", this.expectedOutput); - } - - private byte[] forFile(String relative) { - URL resource = MessageSender.class.getResource(relative); - try { - return Files.readAllBytes(new File(resource.toURI()).toPath()); - } - catch (IOException | URISyntaxException ex) { - throw new IllegalStateException(ex); - } - } -} diff --git a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/MessagingConfiguration.java b/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/MessagingConfiguration.java deleted file mode 100644 index bfcc6f6e83..0000000000 --- a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/MessagingConfiguration.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud; - -import java.util.function.Supplier; - -import reactor.core.publisher.EmitterProcessor; -import reactor.core.publisher.Flux; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -class MessagingConfiguration { - - @Bean - EmitterProcessor sensorDataEmitter() { - return EmitterProcessor.create(); - } - - @Bean(name = "sensor_data") - Supplier> sensorData(EmitterProcessor processor) { - return () -> processor; - } -} diff --git a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/TestController.java b/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/TestController.java deleted file mode 100644 index a52d073eeb..0000000000 --- a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/TestController.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud; - -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.file.Files; -import java.util.Arrays; - -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestPart; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.multipart.MultipartFile; - -@RestController -public class TestController { - - private final byte[] request; - - private final byte[] response; - - public TestController() { - this.request = toByte( - TestController.class.getResource("/contracts/binary/request.pdf")); - this.response = toByte( - TestController.class.getResource("/contracts/binary/response.pdf")); - } - - private byte[] toByte(URL url) { - try { - return Files.readAllBytes(new File(url.toURI()).toPath()); - } - catch (URISyntaxException | IOException ex) { - throw new IllegalStateException(ex); - } - } - - @PostMapping("/tests") - public Test createNew(@RequestPart MultipartFile file1, - @RequestPart MultipartFile file2, @RequestPart Test test) { - return new Test("ok"); - } - - @GetMapping("/example") - public void example() { - } - - @PutMapping(value = "/1", consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) - public byte[] response(@RequestBody byte[] requestBody) { - if (!Arrays.equals(this.request, requestBody)) { - throw new IllegalStateException("Invalid request body"); - } - return this.response; - } - -} - -class Test { - - private String status; - - public Test(String status) { - this.status = status; - } - - public Test() { - } - - public String getStatus() { - return status; - } - - public void setStatus(String status) { - this.status = status; - } - -} diff --git a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/model/FraudCheck.java b/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/model/FraudCheck.java deleted file mode 100644 index d0e348db27..0000000000 --- a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/model/FraudCheck.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud.model; - -import java.math.BigDecimal; - -import com.fasterxml.jackson.annotation.JsonProperty; - -public class FraudCheck { - - @JsonProperty("client.id") - private String clientId; - - private BigDecimal loanAmount; - - public FraudCheck() { - } - - public String getClientId() { - return clientId; - } - - public void setClientId(String clientId) { - this.clientId = clientId; - } - - public BigDecimal getLoanAmount() { - return loanAmount; - } - - public void setLoanAmount(BigDecimal loanAmount) { - this.loanAmount = loanAmount; - } - -} diff --git a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/model/FraudCheckResult.java b/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/model/FraudCheckResult.java deleted file mode 100644 index c908038d0a..0000000000 --- a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/model/FraudCheckResult.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud.model; - -import com.fasterxml.jackson.annotation.JsonProperty; - -public class FraudCheckResult { - - private FraudCheckStatus fraudCheckStatus; - - @JsonProperty("rejection.reason") - private String rejectionReason; - - public FraudCheckResult() { - } - - public FraudCheckResult(FraudCheckStatus fraudCheckStatus, String rejectionReason) { - this.fraudCheckStatus = fraudCheckStatus; - this.rejectionReason = rejectionReason; - } - - public FraudCheckStatus getFraudCheckStatus() { - return fraudCheckStatus; - } - - public void setFraudCheckStatus(FraudCheckStatus fraudCheckStatus) { - this.fraudCheckStatus = fraudCheckStatus; - } - - public String getRejectionReason() { - return rejectionReason; - } - - public void setRejectionReason(String rejectionReason) { - this.rejectionReason = rejectionReason; - } - -} diff --git a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/model/FraudCheckStatus.java b/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/model/FraudCheckStatus.java deleted file mode 100644 index a43b649f5c..0000000000 --- a/samples/standalone/dsl/http-server/src/main/java/com/example/fraud/model/FraudCheckStatus.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud.model; - -public enum FraudCheckStatus { - - OK, FRAUD - -} diff --git a/samples/standalone/dsl/http-server/src/main/resources/application.properties b/samples/standalone/dsl/http-server/src/main/resources/application.properties deleted file mode 100644 index 506b4f78c1..0000000000 --- a/samples/standalone/dsl/http-server/src/main/resources/application.properties +++ /dev/null @@ -1,5 +0,0 @@ -spring.cloud.function.definition=my_output;sensor_data -spring.cloud.stream.bindings.sensor_data-out-0.destination=sensor_data -spring.cloud.stream.bindings.my_output-out-0.contentType=application/octet-stream -spring.cloud.stream.bindings.my_output-out-0.destination=bytes_output -server.port=0 diff --git a/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/BinaryBase.java b/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/BinaryBase.java deleted file mode 100644 index bfcd40f7c4..0000000000 --- a/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/BinaryBase.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud; - -import io.restassured.module.mockmvc.RestAssuredMockMvc; -import org.junit.jupiter.api.BeforeEach; - -public class BinaryBase { - - @BeforeEach - public void setUp() throws Exception { - RestAssuredMockMvc.standaloneSetup(new TestController()); - } - -} diff --git a/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/FraudBase.java b/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/FraudBase.java deleted file mode 100644 index 3e462aa229..0000000000 --- a/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/FraudBase.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud; - -import io.restassured.module.mockmvc.RestAssuredMockMvc; -import org.junit.jupiter.api.BeforeEach; - -public class FraudBase { - - @BeforeEach - public void setup() { - RestAssuredMockMvc.standaloneSetup(new FraudDetectionController(), - new FraudStatsController(stubbedStatsProvider())); - } - - private StatsProvider stubbedStatsProvider() { - return fraudType -> { - switch (fraudType) { - case DRUNKS: - return 100; - case ALL: - return 200; - } - return 0; - }; - } - - public void assertThatRejectionReasonIsNull(Object rejectionReason) { - assert rejectionReason == null; - } - -} diff --git a/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/FraudnameBase.java b/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/FraudnameBase.java deleted file mode 100644 index f38066f2bb..0000000000 --- a/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/FraudnameBase.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud; - -import io.restassured.module.mockmvc.RestAssuredMockMvc; -import org.junit.jupiter.api.BeforeEach; - -public class FraudnameBase { - - private static final String FRAUD_NAME = "fraud"; - - FraudVerifier fraudVerifier = FRAUD_NAME::equals; - - @BeforeEach - public void setup() { - RestAssuredMockMvc.standaloneSetup(new FraudNameController(this.fraudVerifier)); - } - -} diff --git a/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/MessagingBase.java b/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/MessagingBase.java deleted file mode 100644 index aa08e66bfe..0000000000 --- a/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/MessagingBase.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2016-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud; - -import io.restassured.module.mockmvc.RestAssuredMockMvc; -import org.junit.jupiter.api.BeforeEach; - - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.ImportAutoConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.contract.verifier.messaging.boot.AutoConfigureMessageVerifier; -import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration; -import org.springframework.context.annotation.Configuration; - -import org.springframework.web.context.WebApplicationContext; - -/** - * Base class for sensor autogenerated tests (used by Spring Cloud Contract). - * - * This bootstraps the Spring Boot application code. - * - * @author Marius Bogoevici - */ - -@SpringBootTest(classes = {MessagingBase.Config.class, Application.class}) -@AutoConfigureMessageVerifier -public abstract class MessagingBase { - - @Autowired - MessageSender messageSender; - - @Autowired - WebApplicationContext context; - - @BeforeEach - public void setup() { - RestAssuredMockMvc.webAppContextSetup(this.context); - } - - public void createSensorData() { - messageSender.emit(); - } - - public void createBinaryPayload() { - messageSender.emitBytes(); - } - - @Configuration - @ImportAutoConfiguration(TestChannelBinderConfiguration.class) - static class Config { - - } - -} diff --git a/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/MultipartBase.java b/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/MultipartBase.java deleted file mode 100644 index fa82da0402..0000000000 --- a/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/MultipartBase.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud; - -import io.restassured.module.mockmvc.RestAssuredMockMvc; -import org.junit.jupiter.api.BeforeEach; - -public class MultipartBase { - - @BeforeEach - public void setUp() throws Exception { - RestAssuredMockMvc.standaloneSetup(new TestController()); - } - -} diff --git a/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/TestBase.java b/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/TestBase.java deleted file mode 100644 index 6a1c81d89e..0000000000 --- a/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/TestBase.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud; - -import io.restassured.module.mockmvc.RestAssuredMockMvc; -import org.junit.jupiter.api.BeforeEach; - -public class TestBase { - - @BeforeEach - public void setUp() throws Exception { - RestAssuredMockMvc.standaloneSetup(new TestController()); - } - -} diff --git a/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/YmlFraudBase.java b/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/YmlFraudBase.java deleted file mode 100644 index 4e46c07838..0000000000 --- a/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/YmlFraudBase.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud; - -import io.restassured.module.mockmvc.RestAssuredMockMvc; -import org.junit.jupiter.api.BeforeEach; - -public class YmlFraudBase { - - @BeforeEach - public void setup() { - RestAssuredMockMvc.standaloneSetup(new FraudDetectionController(), - new FraudStatsController(stubbedStatsProvider())); - } - - private StatsProvider stubbedStatsProvider() { - return fraudType -> { - switch (fraudType) { - case DRUNKS: - return 100; - case ALL: - return 200; - } - return 0; - }; - } - - public void assertThatRejectionReasonIsNull(Object rejectionReason) { - assert rejectionReason == null; - } - -} diff --git a/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/YmlFraudnameBase.java b/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/YmlFraudnameBase.java deleted file mode 100644 index abe32e3f04..0000000000 --- a/samples/standalone/dsl/http-server/src/test/java/com/example/fraud/YmlFraudnameBase.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud; - -import io.restassured.module.mockmvc.RestAssuredMockMvc; -import org.junit.jupiter.api.BeforeEach; - -public class YmlFraudnameBase { - - private static final String FRAUD_NAME = "fraud"; - - FraudVerifier fraudVerifier = FRAUD_NAME::equals; - - @BeforeEach - public void setup() { - RestAssuredMockMvc.standaloneSetup(new FraudNameController(this.fraudVerifier)); - } - -} diff --git a/samples/standalone/dsl/http-server/src/test/resources/contracts/binary/request.pdf b/samples/standalone/dsl/http-server/src/test/resources/contracts/binary/request.pdf deleted file mode 100644 index 69503635d87cbdfa660d5cd8be66d3e74b3b20e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14631 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 diff --git a/samples/standalone/dsl/http-server/src/test/resources/contracts/binary/response.pdf b/samples/standalone/dsl/http-server/src/test/resources/contracts/binary/response.pdf deleted file mode 100644 index c3b233056b758d1cc9bf3176e99a95add89ba607..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15767 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 { - @Override - public Contract get() { - return Contract.make(c -> { - c.request(r -> { - r.method(r.GET()); - r.url("/example"); - }); - c.response(r -> { - r.status(r.OK()); - }); - }); - } -} diff --git a/samples/standalone/dsl/http-server/src/test/resources/contracts/test/request.json b/samples/standalone/dsl/http-server/src/test/resources/contracts/test/request.json deleted file mode 100644 index 7cef5bbd05..0000000000 --- a/samples/standalone/dsl/http-server/src/test/resources/contracts/test/request.json +++ /dev/null @@ -1 +0,0 @@ -{ "hello" : "world" } \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/src/test/resources/contracts/yml/fraud/shouldMarkClientAsFraud.yml b/samples/standalone/dsl/http-server/src/test/resources/contracts/yml/fraud/shouldMarkClientAsFraud.yml deleted file mode 100644 index eb0656569e..0000000000 --- a/samples/standalone/dsl/http-server/src/test/resources/contracts/yml/fraud/shouldMarkClientAsFraud.yml +++ /dev/null @@ -1,52 +0,0 @@ -request: # (1) - method: PUT # (2) - url: /yamlfraudcheck # (3) - body: # (4) - "client.id": 1234567890 - loanAmount: 99999 - headers: # (5) - Content-Type: application/json - matchers: - body: - - path: $.['client.id'] # (6) - type: by_regex - value: "[0-9]{10}" -response: # (7) - status: 200 # (8) - body: # (9) - fraudCheckStatus: "FRAUD" - "rejection.reason": "Amount too high" - headers: # (10) - Content-Type: application/json - - -#From the Consumer perspective, when shooting a request in the integration test: -# -#(1) - If the consumer sends a request -#(2) - With the "PUT" method -#(3) - to the URL "/yamlfraudcheck" -#(4) - with the JSON body that -# * has a field `client.id` -# * has a field `loanAmount` that is equal to `99999` -#(5) - with header `Content-Type` equal to `application/json` -#(6) - and a `client.id` json entry matches the regular expression `[0-9]{10}` -#(7) - then the response will be sent with -#(8) - status equal `200` -#(9) - and JSON body equal to -# { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" } -#(10) - with header `Content-Type` equal to `application/json` -# -#From the Producer perspective, in the autogenerated producer-side test: -# -#(1) - A request will be sent to the producer -#(2) - With the "PUT" method -#(3) - to the URL "/yamlfraudcheck" -#(4) - with the JSON body that -# * has a field `client.id` `1234567890` -# * has a field `loanAmount` that is equal to `99999` -#(5) - with header `Content-Type` equal to `application/json` -#(7) - then the test will assert if the response has been sent with -#(8) - status equal `200` -#(9) - and JSON body equal to -# { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" } -#(10) - with header `Content-Type` equal to `application/json` \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/src/test/resources/contracts/yml/fraud/shouldMarkClientAsNotFraud.yaml b/samples/standalone/dsl/http-server/src/test/resources/contracts/yml/fraud/shouldMarkClientAsNotFraud.yaml deleted file mode 100644 index 550322aa86..0000000000 --- a/samples/standalone/dsl/http-server/src/test/resources/contracts/yml/fraud/shouldMarkClientAsNotFraud.yaml +++ /dev/null @@ -1,25 +0,0 @@ -request: - method: PUT - url: /yamlfraudcheck - body: - "client.id": 1234567890 - loanAmount: 123.123 - headers: - Content-Type: application/json - matchers: - body: - - path: $.['client.id'] - type: by_regex - value: "[0-9]{10}" -response: - status: 200 - body: - fraudCheckStatus: "OK" - "rejection.reason": null - headers: - Content-Type: application/json - matchers: - body: - - path: $.['rejection.reason'] - type: by_command - value: assertThatRejectionReasonIsNull($it) diff --git a/samples/standalone/dsl/http-server/src/test/resources/contracts/yml/fraud/shouldReturnFraudStats.yml b/samples/standalone/dsl/http-server/src/test/resources/contracts/yml/fraud/shouldReturnFraudStats.yml deleted file mode 100644 index e14f824f07..0000000000 --- a/samples/standalone/dsl/http-server/src/test/resources/contracts/yml/fraud/shouldReturnFraudStats.yml +++ /dev/null @@ -1,31 +0,0 @@ ---- -# tag::metadata[] -name: "should count all frauds" -request: - method: GET - url: /yamlfrauds -response: - status: 200 - body: - count: 200 - headers: - Content-Type: application/json -metadata: - wiremock: - stubMapping: > - { - "response" : { - "fixedDelayMilliseconds": 2000 - } - } -# end::metadata[] ---- -request: - method: GET - url: /yamldrunks -response: - status: 200 - body: - count: 100 - headers: - Content-Type: application/json \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/src/test/resources/contracts/yml/fraudname/shouldReturnAFraudForTheName.yml b/samples/standalone/dsl/http-server/src/test/resources/contracts/yml/fraudname/shouldReturnAFraudForTheName.yml deleted file mode 100644 index 5e06866b80..0000000000 --- a/samples/standalone/dsl/http-server/src/test/resources/contracts/yml/fraudname/shouldReturnAFraudForTheName.yml +++ /dev/null @@ -1,15 +0,0 @@ -# highest priority -priority: 1 -request: - method: PUT - url: /yamlfrauds/name - body: - name: "fraud" - headers: - Content-Type: application/json -response: - status: 200 - body: - result: "Sorry {{{ jsonpath this '$.name' }}} but you're a fraud" - headers: - Content-Type: "{{{ request.headers.Content-Type.0 }}}" \ No newline at end of file diff --git a/samples/standalone/dsl/http-server/src/test/resources/contracts/yml/fraudname/shouldReturnNonFraudForTheName.yml b/samples/standalone/dsl/http-server/src/test/resources/contracts/yml/fraudname/shouldReturnNonFraudForTheName.yml deleted file mode 100644 index c0a8e14a07..0000000000 --- a/samples/standalone/dsl/http-server/src/test/resources/contracts/yml/fraudname/shouldReturnNonFraudForTheName.yml +++ /dev/null @@ -1,18 +0,0 @@ -request: - method: PUT - url: /yamlfrauds/name - body: - name: "non fraud" - headers: - Content-Type: application/json - matchers: - body: - - path: $.name - type: by_regex - predefined: only_alpha_unicode -response: - status: 200 - body: - result: "Don't worry {{{ jsonpath this '$.name' }}} you're not a fraud" - headers: - Content-Type: "{{{ request.headers.Content-Type.0 }}}" \ No newline at end of file diff --git a/samples/standalone/dsl/pom.xml b/samples/standalone/dsl/pom.xml deleted file mode 100644 index dac28fb084..0000000000 --- a/samples/standalone/dsl/pom.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - 4.0.0 - - - org.springframework.cloud - spring-cloud-contract-samples-standalone - 4.1.0-SNAPSHOT - .. - - - spring-cloud-contract-samples-dsl - pom - - Spring Cloud Contract Standalone Dsl Test Samples - Spring Cloud Contract Standalone Test Samples used for end to end tests - - - - 4.1.0-SNAPSHOT - - - - http-server - http-client - - - - - - maven-deploy-plugin - 2.8.2 - - true - - - - - - diff --git a/samples/standalone/mvnw b/samples/standalone/mvnw deleted file mode 100755 index 5643201c7d..0000000000 --- a/samples/standalone/mvnw +++ /dev/null @@ -1,316 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Maven Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /usr/local/etc/mavenrc ] ; then - . /usr/local/etc/mavenrc - fi - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`\\unset -f command; \\command -v java`" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` - fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" - fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi -else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - if [ -n "$MVNW_REPOURL" ]; then - jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - else - jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - fi - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - if $cygwin; then - wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` - fi - - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - else - wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - fi - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl -o "$wrapperJarPath" "$jarUrl" -f - else - curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f - fi - - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - # For Cygwin, switch paths to Windows format before running javac - if $cygwin; then - javaClass=`cygpath --path --windows "$javaClass"` - fi - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` -fi - -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" -export MAVEN_CMD_LINE_ARGS - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -exec "$JAVACMD" \ - $MAVEN_OPTS \ - $MAVEN_DEBUG_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" \ - "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/samples/standalone/mvnw.cmd b/samples/standalone/mvnw.cmd deleted file mode 100644 index 23b7079a3d..0000000000 --- a/samples/standalone/mvnw.cmd +++ /dev/null @@ -1,188 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* -if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% ^ - %JVM_CONFIG_MAVEN_PROPS% ^ - %MAVEN_OPTS% ^ - %MAVEN_DEBUG_OPTS% ^ - -classpath %WRAPPER_JAR% ^ - "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ - %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" -if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%"=="on" pause - -if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% - -cmd /C exit /B %ERROR_CODE% diff --git a/samples/standalone/pom.xml b/samples/standalone/pom.xml deleted file mode 100644 index a335e59d00..0000000000 --- a/samples/standalone/pom.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - 4.0.0 - - - org.springframework.cloud - spring-cloud-contract-samples - 4.1.0-SNAPSHOT - .. - - - spring-cloud-contract-samples-standalone - pom - 4.1.0-SNAPSHOT - Spring Cloud Contract Standalone Test Samples - Spring Cloud Contract Standalone Test Samples used for end to end tests - - - - ${project.version} - - - - contracts - restdocs - dsl - webclient - - - - - - maven-deploy-plugin - 2.8.2 - - true - - - - - - - org.apache.maven.plugins - maven-clean-plugin - 3.0.0 - - - - build - - - target - - - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - - - - - diff --git a/samples/standalone/restdocs/build.log b/samples/standalone/restdocs/build.log new file mode 100644 index 0000000000..6e855ef6c7 --- /dev/null +++ b/samples/standalone/restdocs/build.log @@ -0,0 +1,885 @@ +[INFO] Scanning for projects... +[INFO] Downloading from spring-releases: https://repo.spring.io/release/org/slf4j/slf4j-api/maven-metadata.xml +[WARNING] Could not transfer metadata org.slf4j:slf4j-api/maven-metadata.xml from/to spring-releases (https://repo.spring.io/release): authentication failed for https://repo.spring.io/release/org/slf4j/slf4j-api/maven-metadata.xml, status: 401 Unauthorized +[WARNING] org.slf4j:slf4j-api/maven-metadata.xmlfailed to transfer from https://repo.spring.io/release during a previous attempt. This failure was cached in the local repository and resolution will not be reattempted until the update interval of spring-releases has elapsed or updates are forced. Original error: Could not transfer metadata org.slf4j:slf4j-api/maven-metadata.xml from/to spring-releases (https://repo.spring.io/release): authentication failed for https://repo.spring.io/release/org/slf4j/slf4j-api/maven-metadata.xml, status: 401 Unauthorized +[WARNING] org.slf4j:slf4j-api/maven-metadata.xmlfailed to transfer from https://repo.spring.io/release during a previous attempt. This failure was cached in the local repository and resolution will not be reattempted until the update interval of spring-releases has elapsed or updates are forced. Original error: Could not transfer metadata org.slf4j:slf4j-api/maven-metadata.xml from/to spring-releases (https://repo.spring.io/release): authentication failed for https://repo.spring.io/release/org/slf4j/slf4j-api/maven-metadata.xml, status: 401 Unauthorized +[WARNING] org.slf4j:slf4j-api/maven-metadata.xmlfailed to transfer from https://repo.spring.io/release during a previous attempt. This failure was cached in the local repository and resolution will not be reattempted until the update interval of spring-releases has elapsed or updates are forced. Original error: Could not transfer metadata org.slf4j:slf4j-api/maven-metadata.xml from/to spring-releases (https://repo.spring.io/release): authentication failed for https://repo.spring.io/release/org/slf4j/slf4j-api/maven-metadata.xml, status: 401 Unauthorized +[INFO] Downloading from maven-default-http-blocker: http://0.0.0.0/org/slf4j/slf4j-api/maven-metadata.xml +[WARNING] Could not transfer metadata org.slf4j:slf4j-api/maven-metadata.xml from/to maven-default-http-blocker (http://0.0.0.0/): transfer failed for http://0.0.0.0/org/slf4j/slf4j-api/maven-metadata.xml +[INFO] ------------------------------------------------------------------------ +[INFO] Reactor Build Order: +[INFO] +[INFO] Spring Cloud Contract RestDocs Http Server Sample [jar] +[INFO] Spring Cloud Contract RestDocs Http Client Sample [jar] +[INFO] Spring Cloud Contract Standalone Restdocs Test Samples [pom] +[INFO] +[INFO] ------------------< com.example:http-server-restdocs >------------------ +[INFO] Building Spring Cloud Contract RestDocs Http Server Sample 0.0.1 [1/3] +[INFO] --------------------------------[ jar ]--------------------------------- +[INFO] +[INFO] --- maven-clean-plugin:3.3.1:clean (default-clean) @ http-server-restdocs --- +[INFO] Deleting /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-server/target +[INFO] +[INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ http-server-restdocs --- +[INFO] Copying 1 resource from src/main/resources to target/classes +[INFO] Copying 0 resource from src/main/resources to target/classes +[INFO] +[INFO] --- maven-compiler-plugin:3.11.0:compile (default-compile) @ http-server-restdocs --- +[INFO] Changes detected - recompiling the module! :source +[INFO] Compiling 6 source files with javac [debug release 17] to target/classes +[INFO] +[INFO] --- spring-cloud-contract-maven-plugin:4.1.0-SNAPSHOT:generateTests (default-generateTests) @ http-server-restdocs --- +[INFO] Generating server tests source code for Spring Cloud Contract Verifier contract verification +[INFO] Will use contracts provided in the folder [/home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-server/src/test/resources/contracts] +[INFO] Directory with contract is present at [/home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-server/src/test/resources/contracts] +[INFO] Test Source directory: /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-server/target/generated-test-sources/contracts added. +[INFO] Using [null] as base class for test classes, [null] as base package for tests, [null] as package with base classes, base class mappings [BaseClassMapping{contractPackageRegex='.*standalone.*', baseClassFQN='com.example.fraud.FraudBaseWithStandaloneSetup'}, BaseClassMapping{contractPackageRegex='.*webapp.*', baseClassFQN='com.example.fraud.FraudBaseWithWebAppSetup'}] +[INFO] Creating new class file [/home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-server/target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/StandaloneTest.java] +[INFO] Creating new class file [/home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-server/target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/WebappTest.java] +[INFO] Generated 2 test classes. +[INFO] +[INFO] --- spring-cloud-contract-maven-plugin:4.1.0-SNAPSHOT:convert (default-convert) @ http-server-restdocs --- +[INFO] Will use contracts provided in the folder [/home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-server/src/test/resources/contracts] +[INFO] Copying Spring Cloud Contract Verifier contracts to [/home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-server/target/stubs/META-INF/com.example/http-server-restdocs/0.0.1/contracts]. Only files matching [.*] pattern will end up in the final JAR with stubs. +[INFO] Using 'UTF-8' encoding to copy filtered resources. +[INFO] Copying 2 resources +[INFO] Converting from Spring Cloud Contract Verifier contracts to WireMock stubs mappings +[INFO] Spring Cloud Contract Verifier contracts directory: /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-server/src/test/resources/contracts +[INFO] Stub Server stubs mappings directory: /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-server/target/stubs/META-INF/com.example/http-server-restdocs/0.0.1/mappings +[INFO] Creating new stub [/home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-server/target/stubs/META-INF/com.example/http-server-restdocs/0.0.1/mappings/standalone/shouldMarkClientAsFraud.json] +[INFO] Creating new stub [/home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-server/target/stubs/META-INF/com.example/http-server-restdocs/0.0.1/mappings/webapp/shouldMarkClientAsNotFraud.json] +[INFO] +[INFO] --- maven-resources-plugin:3.3.1:testResources (default-testResources) @ http-server-restdocs --- +[INFO] Copying 2 resources from src/test/resources to target/test-classes +[INFO] skip non existing resourceDirectory /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-server/target/generated-test-resources/contracts +[INFO] +[INFO] --- maven-compiler-plugin:3.11.0:testCompile (default-testCompile) @ http-server-restdocs --- +[INFO] Changes detected - recompiling the module! :dependency +[INFO] Compiling 6 source files with javac [debug release 17] to target/test-classes +[INFO] +[INFO] --- maven-surefire-plugin:3.1.2:test (default-test) @ http-server-restdocs --- +[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider +[INFO] +[INFO] ------------------------------------------------------- +[INFO] T E S T S +[INFO] ------------------------------------------------------- +[INFO] Running org.springframework.cloud.contract.verifier.tests.StandaloneTest +14:30:25.281 [main] INFO org.springframework.mock.web.MockServletContext -- Initializing Spring TestDispatcherServlet '' +14:30:25.282 [main] INFO org.springframework.test.web.servlet.TestDispatcherServlet -- Initializing Servlet '' +14:30:25.285 [main] INFO org.springframework.test.web.servlet.TestDispatcherServlet -- Completed initialization in 2 ms +[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.745 s -- in org.springframework.cloud.contract.verifier.tests.StandaloneTest +[INFO] Running org.springframework.cloud.contract.verifier.tests.WebappTest + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v3.2.0-SNAPSHOT) + +2023-09-06T14:30:25.709+02:00 INFO 208958 --- [ main] o.s.c.c.verifier.tests.WebappTest : Starting WebappTest using Java 17.0.1 with PID 208958 (started by marcin in /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-server) +2023-09-06T14:30:25.710+02:00 INFO 208958 --- [ main] o.s.c.c.verifier.tests.WebappTest : No active profile set, falling back to 1 default profile: "default" +2023-09-06T14:30:26.723+02:00 INFO 208958 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 1 endpoint(s) beneath base path '/actuator' +2023-09-06T14:30:26.777+02:00 INFO 208958 --- [ main] o.s.c.c.verifier.tests.WebappTest : Started WebappTest in 1.195 seconds (process running for 2.369) +OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended +2023-09-06T14:30:27.357+02:00 INFO 208958 --- [ main] o.s.b.t.m.w.SpringBootMockServletContext : Initializing Spring TestDispatcherServlet '' +2023-09-06T14:30:27.358+02:00 INFO 208958 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet '' +2023-09-06T14:30:27.358+02:00 INFO 208958 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 0 ms +[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.858 s -- in org.springframework.cloud.contract.verifier.tests.WebappTest +[INFO] Running com.example.fraud.XmlStubGeneratorTests + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v3.2.0-SNAPSHOT) + +2023-09-06T14:30:27.404+02:00 INFO 208958 --- [ main] c.example.fraud.XmlStubGeneratorTests : Starting XmlStubGeneratorTests using Java 17.0.1 with PID 208958 (started by marcin in /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-server) +2023-09-06T14:30:27.404+02:00 INFO 208958 --- [ main] c.example.fraud.XmlStubGeneratorTests : No active profile set, falling back to 1 default profile: "default" +2023-09-06T14:30:27.748+02:00 INFO 208958 --- [ main] o.s.b.t.m.w.SpringBootMockServletContext : Initializing Spring TestDispatcherServlet '' +2023-09-06T14:30:27.748+02:00 INFO 208958 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet '' +2023-09-06T14:30:27.753+02:00 INFO 208958 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 1 endpoint(s) beneath base path '/actuator' +2023-09-06T14:30:27.756+02:00 INFO 208958 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 8 ms +2023-09-06T14:30:27.775+02:00 INFO 208958 --- [ main] c.example.fraud.XmlStubGeneratorTests : Started XmlStubGeneratorTests in 0.389 seconds (process running for 3.367) +[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.713 s -- in com.example.fraud.XmlStubGeneratorTests +[INFO] Running com.example.fraud.StubGeneratorTests + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v3.2.0-SNAPSHOT) + +2023-09-06T14:30:28.132+02:00 INFO 208958 --- [ main] com.example.fraud.StubGeneratorTests : Starting StubGeneratorTests using Java 17.0.1 with PID 208958 (started by marcin in /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-server) +2023-09-06T14:30:28.133+02:00 INFO 208958 --- [ main] com.example.fraud.StubGeneratorTests : No active profile set, falling back to 1 default profile: "default" +2023-09-06T14:30:28.371+02:00 INFO 208958 --- [ main] o.s.b.t.m.w.SpringBootMockServletContext : Initializing Spring TestDispatcherServlet '' +2023-09-06T14:30:28.371+02:00 INFO 208958 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet '' +2023-09-06T14:30:28.374+02:00 INFO 208958 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 1 endpoint(s) beneath base path '/actuator' +2023-09-06T14:30:28.376+02:00 INFO 208958 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 5 ms +2023-09-06T14:30:28.385+02:00 INFO 208958 --- [ main] com.example.fraud.StubGeneratorTests : Started StubGeneratorTests in 0.272 seconds (process running for 3.977) +[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.356 s -- in com.example.fraud.StubGeneratorTests +[INFO] +[INFO] Results: +[INFO] +[INFO] Tests run: 6, Failures: 0, Errors: 0, Skipped: 0 +[INFO] +[INFO] +[INFO] --- maven-assembly-plugin:3.6.0:single (stub) @ http-server-restdocs --- +[INFO] Reading assembly descriptor: /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-server/src/assembly/stub.xml +[INFO] Building jar: /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-server/target/http-server-restdocs-0.0.1-stubs.jar +[INFO] +[INFO] --- spring-cloud-contract-maven-plugin:4.1.0-SNAPSHOT:generateStubs (default-generateStubs) @ http-server-restdocs --- +[INFO] Skipping Spring Cloud Contract Verifier execution: spring.cloud.contract.verifier.skip=false, spring.cloud.contract.verifier.jar.skip=true +[INFO] +[INFO] --- maven-jar-plugin:3.3.0:jar (default-jar) @ http-server-restdocs --- +[INFO] Building jar: /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-server/target/http-server-restdocs-0.0.1.jar +[INFO] +[INFO] --- spring-boot-maven-plugin:3.2.0-SNAPSHOT:repackage (repackage) @ http-server-restdocs --- +[INFO] Replacing main artifact /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-server/target/http-server-restdocs-0.0.1.jar with repackaged archive, adding nested dependencies in BOOT-INF/. +[INFO] The original artifact has been renamed to /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-server/target/http-server-restdocs-0.0.1.jar.original +[INFO] +[INFO] --- maven-install-plugin:3.1.1:install (default-install) @ http-server-restdocs --- +[INFO] Installing /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-server/pom.xml to /home/marcin/.m2/repository/com/example/http-server-restdocs/0.0.1/http-server-restdocs-0.0.1.pom +[INFO] Installing /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-server/target/http-server-restdocs-0.0.1.jar to /home/marcin/.m2/repository/com/example/http-server-restdocs/0.0.1/http-server-restdocs-0.0.1.jar +[INFO] Installing /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-server/target/http-server-restdocs-0.0.1-stubs.jar to /home/marcin/.m2/repository/com/example/http-server-restdocs/0.0.1/http-server-restdocs-0.0.1-stubs.jar +[INFO] +[INFO] ------------------< com.example:http-client-restdocs >------------------ +[INFO] Building Spring Cloud Contract RestDocs Http Client Sample 0.0.1 [2/3] +[INFO] --------------------------------[ jar ]--------------------------------- +[INFO] +[INFO] --- maven-clean-plugin:3.3.1:clean (default-clean) @ http-client-restdocs --- +[INFO] Deleting /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-client/target +[INFO] +[INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ http-client-restdocs --- +[INFO] Copying 1 resource from src/main/resources to target/classes +[INFO] Copying 0 resource from src/main/resources to target/classes +[INFO] +[INFO] --- maven-compiler-plugin:3.11.0:compile (default-compile) @ http-client-restdocs --- +[INFO] Changes detected - recompiling the module! :source +[INFO] Compiling 9 source files with javac [debug release 17] to target/classes +[INFO] +[INFO] --- maven-resources-plugin:3.3.1:testResources (default-testResources) @ http-client-restdocs --- +[INFO] Copying 1 resource from src/test/resources to target/test-classes +[INFO] +[INFO] --- maven-compiler-plugin:3.11.0:testCompile (default-testCompile) @ http-client-restdocs --- +[INFO] Changes detected - recompiling the module! :dependency +[INFO] Compiling 4 source files with javac [debug release 17] to target/test-classes +[INFO] /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-client/src/test/java/com/example/loan/XmlServiceTests.java: Some input files use or override a deprecated API. +[INFO] /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-client/src/test/java/com/example/loan/XmlServiceTests.java: Recompile with -Xlint:deprecation for details. +[INFO] +[INFO] --- maven-surefire-plugin:3.1.2:test (default-test) @ http-client-restdocs --- +[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider +[INFO] +[INFO] ------------------------------------------------------- +[INFO] T E S T S +[INFO] ------------------------------------------------------- +[INFO] Running com.example.loan.XmlServiceTests +14:30:29.967 [main] INFO org.springframework.test.context.support.AnnotationConfigContextLoaderUtils -- Could not detect default configuration classes for test class [com.example.loan.XmlServiceTests]: XmlServiceTests does not declare any static, non-private, non-final, nested classes annotated with @Configuration. +14:30:30.022 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper -- Found @SpringBootConfiguration com.example.loan.Application for test class com.example.loan.XmlServiceTests + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v3.2.0-SNAPSHOT) + +2023-09-06T14:30:30.265+02:00 INFO 209310 --- [ main] com.example.loan.XmlServiceTests : Starting XmlServiceTests using Java 17.0.1 with PID 209310 (started by marcin in /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-client) +2023-09-06T14:30:30.266+02:00 INFO 209310 --- [ main] com.example.loan.XmlServiceTests : No active profile set, falling back to 1 default profile: "default" +2023-09-06T14:30:30.403+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockApplicationListener : Registered property source for property [wiremock.server.port] with value [12341] +2023-09-06T14:30:30.404+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockApplicationListener : Registered property source for dynamic http port +2023-09-06T14:30:30.404+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockApplicationListener : Registered property source for property [wiremock.server.https-port] with value [13524] +2023-09-06T14:30:30.404+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockApplicationListener : Registered property source for dynamic https port +2023-09-06T14:30:31.041+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : Running initialization of the WireMock configuration +2023-09-06T14:30:31.274+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : Created new server [com.github.tomakehurst.wiremock.WireMockServer@7f8c3646] at http port [-1] and https port [-1] +2023-09-06T14:30:31.396+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : Server [com.github.tomakehurst.wiremock.WireMockServer@7f8c3646] is already running at http port [12341] / https port [13524]. It has [0] mappings registered +2023-09-06T14:30:31.397+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : Started server [com.github.tomakehurst.wiremock.WireMockServer@7f8c3646] at http port [12341] and https port [13524] +2023-09-06T14:30:31.397+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : WireMock server has [0] stubs registered +2023-09-06T14:30:31.398+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : Will register [0] stub locations +2023-09-06T14:30:31.398+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : WireMock server has [0] stubs registered +2023-09-06T14:30:31.399+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : Server [com.github.tomakehurst.wiremock.WireMockServer@7f8c3646] is already running at http port [12341] / https port [13524]. It has [0] mappings registered +2023-09-06T14:30:31.399+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : Registering WireMock [com.github.tomakehurst.wiremock.WireMockServer@7f8c3646] at http port [12341] and https port [13524] +2023-09-06T14:30:31.399+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : Server [com.github.tomakehurst.wiremock.WireMockServer@7f8c3646] is already running at http port [12341] / https port [13524]. It has [0] mappings registered +2023-09-06T14:30:31.806+02:00 INFO 209310 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 1 endpoint(s) beneath base path '/actuator' +2023-09-06T14:30:31.872+02:00 INFO 209310 --- [ main] com.example.loan.XmlServiceTests : Started XmlServiceTests in 1.774 seconds (process running for 2.39) +2023-09-06T14:30:31.918+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [false] +2023-09-06T14:30:31.923+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : Http port [12341] dynamic [true] https port [13524] dynamic [true] +2023-09-06T14:30:31.924+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : Re-registering default mappings +2023-09-06T14:30:31.925+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : Server [com.github.tomakehurst.wiremock.WireMockServer@7f8c3646] is already running at http port [12341] / https port [13524] +2023-09-06T14:30:31.925+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : Server [com.github.tomakehurst.wiremock.WireMockServer@7f8c3646] is already running at http port [12341] / https port [13524]. It has [0] mappings registered +OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended +2023-09-06T14:30:32.551+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : HTTP POST http://localhost:12341/xmlfraud +2023-09-06T14:30:32.571+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Accept=[application/xml, text/xml, application/json, application/*+xml, application/*+json] +2023-09-06T14:30:32.577+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Writing [com.example.loan.XmlRequestBody@3dbb7bb] as "application/xml;charset=UTF-8" +2023-09-06T14:30:32.715+02:00 INFO 209310 --- [tp2123686705-43] WireMock : Request received: +127.0.0.1 - POST /xmlfraud + +Accept: [application/xml, text/xml, application/json, application/*+xml, application/*+json] +Content-Type: [application/xml;charset=UTF-8] +User-Agent: [Java/17.0.1] +Host: [localhost:12341] +Connection: [keep-alive] +Transfer-Encoding: [chunked] + + + +Matched response definition: +{ + "status" : 200, + "body" : "EMPTY", + "headers" : { + "Content-Type" : "application/xml" + } +} + +Response: +HTTP/1.1 200 +Content-Type: [application/xml] +Matched-Stub-Id: [76628d79-6dd9-4c36-b135-62488a8a6cc4] + +2023-09-06T14:30:32.718+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Response 200 OK +2023-09-06T14:30:32.719+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Reading to [com.example.loan.XmlResponseBody] +2023-09-06T14:30:32.763+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [false] +2023-09-06T14:30:32.776+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : HTTP POST http://localhost:12341/xmlfraud +2023-09-06T14:30:32.778+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Accept=[application/xml, text/xml, application/json, application/*+xml, application/*+json] +2023-09-06T14:30:32.779+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Writing [com.example.loan.XmlRequestBody@6cd65042] as "application/xml;charset=UTF-8" +2023-09-06T14:30:32.796+02:00 INFO 209310 --- [tp2123686705-30] WireMock : Request received: +127.0.0.1 - POST /xmlfraud + +Accept: [application/xml, text/xml, application/json, application/*+xml, application/*+json] +Content-Type: [application/xml;charset=UTF-8] +User-Agent: [Java/17.0.1] +Host: [localhost:12341] +Connection: [keep-alive] +Transfer-Encoding: [chunked] +foo + + +Matched response definition: +{ + "status" : 200, + "body" : "FULL", + "headers" : { + "Content-Type" : "application/xml" + } +} + +Response: +HTTP/1.1 200 +Content-Type: [application/xml] +Matched-Stub-Id: [a8c3f1a1-e9a7-442b-b61f-5991387cfd68] + +2023-09-06T14:30:32.797+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Response 200 OK +2023-09-06T14:30:32.797+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Reading to [com.example.loan.XmlResponseBody] +2023-09-06T14:30:32.798+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [false] +2023-09-06T14:30:32.801+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [false] +2023-09-06T14:30:32.801+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : Http port [12341] dynamic [true] https port [13524] dynamic [true] +2023-09-06T14:30:32.801+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : Resetting mappings for the next test to restart them. That's necessary when reusing the same context with new servers running on random ports +2023-09-06T14:30:32.802+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : Stopping server [com.github.tomakehurst.wiremock.WireMockServer@7f8c3646] at port [13524] +2023-09-06T14:30:32.807+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : Stopped WireMock [com.github.tomakehurst.wiremock.WireMockServer@7f8c3646] instance port [13524] +2023-09-06T14:30:32.811+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : Server [com.github.tomakehurst.wiremock.WireMockServer@7f8c3646] is already running at http port [12341] / https port [13524]. It has [2] mappings registered +2023-09-06T14:30:32.811+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : Started server [com.github.tomakehurst.wiremock.WireMockServer@7f8c3646] at http port [12341] and https port [13524] +2023-09-06T14:30:32.811+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : WireMock server has [2] stubs registered +2023-09-06T14:30:32.812+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : Will register [0] stub locations +2023-09-06T14:30:32.812+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : WireMock server has [0] stubs registered +2023-09-06T14:30:32.812+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : Server [com.github.tomakehurst.wiremock.WireMockServer@7f8c3646] is already running at http port [12341] / https port [13524]. It has [0] mappings registered +[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.935 s -- in com.example.loan.XmlServiceTests +[INFO] Running com.example.loan.LoanApplicationServiceusingStubRunnerTests +2023-09-06T14:30:32.818+02:00 INFO 209310 --- [ main] t.c.s.AnnotationConfigContextLoaderUtils : Could not detect default configuration classes for test class [com.example.loan.LoanApplicationServiceusingStubRunnerTests]: LoanApplicationServiceusingStubRunnerTests does not declare any static, non-private, non-final, nested classes annotated with @Configuration. +2023-09-06T14:30:32.822+02:00 INFO 209310 --- [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.example.loan.Application for test class com.example.loan.LoanApplicationServiceusingStubRunnerTests + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v3.2.0-SNAPSHOT) + +2023-09-06T14:30:32.840+02:00 INFO 209310 --- [ main] anApplicationServiceusingStubRunnerTests : Starting LoanApplicationServiceusingStubRunnerTests using Java 17.0.1 with PID 209310 (started by marcin in /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-client) +2023-09-06T14:30:32.841+02:00 INFO 209310 --- [ main] anApplicationServiceusingStubRunnerTests : No active profile set, falling back to 1 default profile: "default" +2023-09-06T14:30:32.842+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockApplicationListener : Registered WireMock server port property to the default <8080> value +2023-09-06T14:30:32.843+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockApplicationListener : Registered property source for property [wiremock.server.https-port] with value [14957] +2023-09-06T14:30:32.843+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockApplicationListener : Registered property source for dynamic https port +2023-09-06T14:30:33.085+02:00 WARN 209310 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration' of type [org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). The currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor] is declared through a non-static factory method on that class; consider declaring it as static instead. +2023-09-06T14:30:33.092+02:00 WARN 209310 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'stubrunner-org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties' of type [org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:30:33.099+02:00 INFO 209310 --- [ main] o.s.c.c.s.ClasspathStubProvider : Will download stubs from classpath +2023-09-06T14:30:33.154+02:00 INFO 209310 --- [ main] .s.c.c.s.ResourceResolvingStubDownloader : Unpacked files for [com.example:http-server-restdocs:+] to folder [/tmp/classpath-stubs-1694003433144-0] +2023-09-06T14:30:33.882+02:00 INFO 209310 --- [qtp748921347-68] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [225] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "08c875df-e386-49ae-b415-b7b4eec64826", + "request" : { + "url" : "/ping", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "OK" + }, + "uuid" : "08c875df-e386-49ae-b415-b7b4eec64826" +} + +2023-09-06T14:30:33.889+02:00 INFO 209310 --- [qtp748921347-61] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [227] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "a264af16-06e2-41fc-9904-1cfaae08aa70", + "request" : { + "url" : "/health", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "OK" + }, + "uuid" : "a264af16-06e2-41fc-9904-1cfaae08aa70" +} + +2023-09-06T14:30:33.895+02:00 INFO 209310 --- [qtp748921347-67] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [721] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "90be98a5-be99-4ac8-b1dd-33ce9149f402", + "request" : { + "url" : "/fraudcheck", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "matches" : "application/vnd\\.fraud\\.v1\\+json.*" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.['clientId'] =~ /[0-9]{10}/)]" + }, { + "matchesJsonPath" : "$[?(@.['loanAmount'] == 123.123)]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"OK\",\"rejectionReason\":null}", + "headers" : { + "Content-Type" : "application/vnd.fraud.v1+json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "90be98a5-be99-4ac8-b1dd-33ce9149f402" +} + +2023-09-06T14:30:33.897+02:00 INFO 209310 --- [qtp748921347-66] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [622] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "c121c0dc-3ad7-4147-a2f8-cdf7d0191b48", + "request" : { + "urlPath" : "/fraudcheck", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "matches" : "\\Qapplication/vnd.fraud.v1+json\\E.*" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$.clientId" + }, { + "matchesJsonPath" : "$[?(@.loanAmount <= 1000)]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"OK\",\"rejectionReason\":null}", + "headers" : { + "Content-Type" : "application/vnd.fraud.v1+json" + } + }, + "uuid" : "c121c0dc-3ad7-4147-a2f8-cdf7d0191b48" +} + +2023-09-06T14:30:33.900+02:00 INFO 209310 --- [qtp748921347-67] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [639] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "b43b9b09-7e83-480c-a0b5-b2ecb28ec175", + "request" : { + "urlPath" : "/fraudcheck", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "matches" : "\\Qapplication/vnd.fraud.v1+json\\E.*" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$.clientId" + }, { + "matchesJsonPath" : "$[?(@.loanAmount > 1000)]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"FRAUD\",\"rejectionReason\":\"Amount too high\"}", + "headers" : { + "Content-Type" : "application/vnd.fraud.v1+json" + } + }, + "uuid" : "b43b9b09-7e83-480c-a0b5-b2ecb28ec175" +} + +2023-09-06T14:30:33.904+02:00 INFO 209310 --- [qtp748921347-66] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [737] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "80f6005c-974f-4f9c-90bc-5b97a5214cae", + "request" : { + "url" : "/fraudcheck", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "matches" : "application/vnd\\.fraud\\.v1\\+json.*" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$[?(@.['clientId'] =~ /[0-9]{10}/)]" + }, { + "matchesJsonPath" : "$[?(@.['loanAmount'] == 99999)]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"FRAUD\",\"rejectionReason\":\"Amount too high\"}", + "headers" : { + "Content-Type" : "application/vnd.fraud.v1+json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] + }, + "uuid" : "80f6005c-974f-4f9c-90bc-5b97a5214cae" +} + +2023-09-06T14:30:33.909+02:00 INFO 209310 --- [qtp748921347-67] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [571] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "a8c3f1a1-e9a7-442b-b61f-5991387cfd68", + "request" : { + "urlPath" : "/xmlfraud", + "method" : "POST", + "headers" : { + "Content-Type" : { + "equalTo" : "application/xml;charset=UTF-8" + } + }, + "bodyPatterns" : [ { + "equalToXml" : "foo" + } ] + }, + "response" : { + "status" : 200, + "body" : "FULL", + "headers" : { + "Content-Type" : "application/xml" + } + }, + "uuid" : "a8c3f1a1-e9a7-442b-b61f-5991387cfd68" +} + +2023-09-06T14:30:33.914+02:00 INFO 209310 --- [qtp748921347-62] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [569] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "76628d79-6dd9-4c36-b135-62488a8a6cc4", + "request" : { + "urlPath" : "/xmlfraud", + "method" : "POST", + "headers" : { + "Content-Type" : { + "equalTo" : "application/xml;charset=UTF-8" + } + }, + "bodyPatterns" : [ { + "equalToXml" : "" + } ] + }, + "response" : { + "status" : 200, + "body" : "EMPTY", + "headers" : { + "Content-Type" : "application/xml" + } + }, + "uuid" : "76628d79-6dd9-4c36-b135-62488a8a6cc4" +} + +2023-09-06T14:30:33.920+02:00 INFO 209310 --- [ main] o.s.c.contract.stubrunner.StubServer : Started stub server for project [com.example:http-server-restdocs:+:stubs] on port 10622 with [6] mappings +2023-09-06T14:30:33.922+02:00 INFO 209310 --- [ main] o.s.c.c.stubrunner.StubRunnerExecutor : All stubs are now running RunningStubs [namesAndPorts={com.example:http-server-restdocs:+:stubs=10622}] +2023-09-06T14:30:33.923+02:00 WARN 209310 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'batchStubRunner' of type [org.springframework.cloud.contract.stubrunner.BatchStubRunner] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:30:34.031+02:00 INFO 209310 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 1 endpoint(s) beneath base path '/actuator' +2023-09-06T14:30:34.036+02:00 INFO 209310 --- [ main] o.s.c.c.v.m.i.ContractVerifierMessaging : The message verifier sender implementation is of type [class org.springframework.cloud.contract.verifier.messaging.noop.NoOpStubMessages] +2023-09-06T14:30:34.037+02:00 INFO 209310 --- [ main] o.s.c.c.v.m.i.ContractVerifierMessaging : The message verifier receiver implementation is of type [class org.springframework.cloud.contract.verifier.messaging.noop.NoOpStubMessages] +2023-09-06T14:30:34.048+02:00 INFO 209310 --- [ main] anApplicationServiceusingStubRunnerTests : Started LoanApplicationServiceusingStubRunnerTests in 1.223 seconds (process running for 4.565) +2023-09-06T14:30:34.049+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +2023-09-06T14:30:34.064+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : HTTP PUT http://localhost:10622/fraudcheck +2023-09-06T14:30:34.071+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Accept=[application/xml, text/xml, application/json, application/*+xml, application/*+json] +2023-09-06T14:30:34.072+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Writing [com.example.loan.model.FraudServiceRequest@450b99f2] as "application/vnd.fraud.v1+json" +2023-09-06T14:30:34.129+02:00 INFO 209310 --- [qtp748921347-67] WireMock : Request received: +127.0.0.1 - PUT /fraudcheck + +Accept: [application/xml, text/xml, application/json, application/*+xml, application/*+json] +Content-Type: [application/vnd.fraud.v1+json] +Accept-Encoding: [gzip, x-gzip, deflate] +Transfer-Encoding: [chunked] +Host: [localhost:10622] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.2.1 (Java/17.0.1)] +{"clientId":"1234567890","loanAmount":123.123} + + +Matched response definition: +{ + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"OK\",\"rejectionReason\":null}", + "headers" : { + "Content-Type" : "application/vnd.fraud.v1+json" + } +} + +Response: +HTTP/1.1 200 +Content-Type: [application/vnd.fraud.v1+json] +Matched-Stub-Id: [c121c0dc-3ad7-4147-a2f8-cdf7d0191b48] + +2023-09-06T14:30:34.136+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Response 200 OK +2023-09-06T14:30:34.138+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Reading to [com.example.loan.model.FraudServiceResponse] +2023-09-06T14:30:34.146+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +2023-09-06T14:30:34.150+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : HTTP PUT http://localhost:10622/fraudcheck +2023-09-06T14:30:34.150+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Accept=[application/xml, text/xml, application/json, application/*+xml, application/*+json] +2023-09-06T14:30:34.151+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Writing [com.example.loan.model.FraudServiceRequest@404a7c61] as "application/vnd.fraud.v1+json" +2023-09-06T14:30:34.201+02:00 INFO 209310 --- [qtp748921347-66] WireMock : Request received: +127.0.0.1 - PUT /fraudcheck + +Accept: [application/xml, text/xml, application/json, application/*+xml, application/*+json] +Content-Type: [application/vnd.fraud.v1+json] +Accept-Encoding: [gzip, x-gzip, deflate] +Transfer-Encoding: [chunked] +Host: [localhost:10622] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.2.1 (Java/17.0.1)] +{"clientId":"1234567890","loanAmount":99999.0} + + +Matched response definition: +{ + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"FRAUD\",\"rejectionReason\":\"Amount too high\"}", + "headers" : { + "Content-Type" : "application/vnd.fraud.v1+json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] +} + +Response: +HTTP/1.1 200 +Content-Type: [application/vnd.fraud.v1+json] +Matched-Stub-Id: [80f6005c-974f-4f9c-90bc-5b97a5214cae] + +2023-09-06T14:30:34.202+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Response 200 OK +2023-09-06T14:30:34.202+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Reading to [com.example.loan.model.FraudServiceResponse] +2023-09-06T14:30:34.203+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +2023-09-06T14:30:34.205+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.390 s -- in com.example.loan.LoanApplicationServiceusingStubRunnerTests +[INFO] Running com.example.loan.LoanApplicationServiceTests +2023-09-06T14:30:34.210+02:00 INFO 209310 --- [ main] t.c.s.AnnotationConfigContextLoaderUtils : Could not detect default configuration classes for test class [com.example.loan.LoanApplicationServiceTests]: LoanApplicationServiceTests does not declare any static, non-private, non-final, nested classes annotated with @Configuration. +2023-09-06T14:30:34.211+02:00 INFO 209310 --- [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.example.loan.Application for test class com.example.loan.LoanApplicationServiceTests +2023-09-06T14:30:34.213+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [false] +2023-09-06T14:30:34.213+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : Http port [12341] dynamic [true] https port [13524] dynamic [true] +2023-09-06T14:30:34.213+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : Re-registering default mappings +2023-09-06T14:30:34.213+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : Server [com.github.tomakehurst.wiremock.WireMockServer@7f8c3646] is already running at http port [12341] / https port [13524] +2023-09-06T14:30:34.214+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : Server [com.github.tomakehurst.wiremock.WireMockServer@7f8c3646] is already running at http port [12341] / https port [13524]. It has [0] mappings registered +2023-09-06T14:30:34.218+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : HTTP PUT http://localhost:12341/fraudcheck +2023-09-06T14:30:34.219+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Accept=[application/xml, text/xml, application/json, application/*+xml, application/*+json] +2023-09-06T14:30:34.220+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Writing [com.example.loan.model.FraudServiceRequest@f9d7d3f] as "application/vnd.fraud.v1+json" +2023-09-06T14:30:34.226+02:00 INFO 209310 --- [tp2123686705-72] WireMock : Request received: +127.0.0.1 - PUT /fraudcheck + +Accept: [application/xml, text/xml, application/json, application/*+xml, application/*+json] +Content-Type: [application/vnd.fraud.v1+json] +Accept-Encoding: [gzip, x-gzip, deflate] +Transfer-Encoding: [chunked] +Host: [localhost:12341] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.2.1 (Java/17.0.1)] +{"clientId":"1234567890","loanAmount":123.123} + + +Matched response definition: +{ + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"OK\",\"rejectionReason\":null}", + "headers" : { + "Content-Type" : "application/vnd.fraud.v1+json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] +} + +Response: +HTTP/1.1 200 +Content-Type: [application/vnd.fraud.v1+json] +Matched-Stub-Id: [90be98a5-be99-4ac8-b1dd-33ce9149f402] + +2023-09-06T14:30:34.227+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Response 200 OK +2023-09-06T14:30:34.228+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Reading to [com.example.loan.model.FraudServiceResponse] +2023-09-06T14:30:34.229+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [false] +2023-09-06T14:30:34.235+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : HTTP PUT http://localhost:12341/fraudcheck +2023-09-06T14:30:34.235+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Accept=[application/xml, text/xml, application/json, application/*+xml, application/*+json] +2023-09-06T14:30:34.235+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Writing [com.example.loan.model.FraudServiceRequest@5b1e5366] as "application/vnd.fraud.v1+json" +2023-09-06T14:30:34.239+02:00 INFO 209310 --- [tp2123686705-45] WireMock : Request received: +127.0.0.1 - PUT /fraudcheck + +Accept: [application/xml, text/xml, application/json, application/*+xml, application/*+json] +Content-Type: [application/vnd.fraud.v1+json] +Accept-Encoding: [gzip, x-gzip, deflate] +Transfer-Encoding: [chunked] +Host: [localhost:12341] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.2.1 (Java/17.0.1)] +{"clientId":"1234567890","loanAmount":99999.0} + + +Matched response definition: +{ + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"FRAUD\",\"rejectionReason\":\"Amount too high\"}", + "headers" : { + "Content-Type" : "application/vnd.fraud.v1+json" + }, + "transformers" : [ "response-template", "spring-cloud-contract" ] +} + +Response: +HTTP/1.1 200 +Content-Type: [application/vnd.fraud.v1+json] +Matched-Stub-Id: [80f6005c-974f-4f9c-90bc-5b97a5214cae] + +2023-09-06T14:30:34.240+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Response 200 OK +2023-09-06T14:30:34.240+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Reading to [com.example.loan.model.FraudServiceResponse] +2023-09-06T14:30:34.241+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [false] +2023-09-06T14:30:34.242+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [false] +2023-09-06T14:30:34.243+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : Http port [12341] dynamic [true] https port [13524] dynamic [true] +2023-09-06T14:30:34.243+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : Resetting mappings for the next test to restart them. That's necessary when reusing the same context with new servers running on random ports +2023-09-06T14:30:34.243+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : Stopping server [com.github.tomakehurst.wiremock.WireMockServer@7f8c3646] at port [13524] +2023-09-06T14:30:34.245+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : Stopped WireMock [com.github.tomakehurst.wiremock.WireMockServer@7f8c3646] instance port [13524] +2023-09-06T14:30:34.250+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : Server [com.github.tomakehurst.wiremock.WireMockServer@7f8c3646] is already running at http port [12341] / https port [13524]. It has [2] mappings registered +2023-09-06T14:30:34.250+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : Started server [com.github.tomakehurst.wiremock.WireMockServer@7f8c3646] at http port [12341] and https port [13524] +2023-09-06T14:30:34.250+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : WireMock server has [2] stubs registered +2023-09-06T14:30:34.252+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : Will register [0] stub locations +2023-09-06T14:30:34.252+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : WireMock server has [0] stubs registered +2023-09-06T14:30:34.252+02:00 DEBUG 209310 --- [ main] o.s.c.c.wiremock.WireMockConfiguration : Server [com.github.tomakehurst.wiremock.WireMockServer@7f8c3646] is already running at http port [12341] / https port [13524]. It has [0] mappings registered +[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.044 s -- in com.example.loan.LoanApplicationServiceTests +[INFO] Running com.example.loan.XmlServiceUsingStubRunnerTests +2023-09-06T14:30:34.255+02:00 INFO 209310 --- [ main] t.c.s.AnnotationConfigContextLoaderUtils : Could not detect default configuration classes for test class [com.example.loan.XmlServiceUsingStubRunnerTests]: XmlServiceUsingStubRunnerTests does not declare any static, non-private, non-final, nested classes annotated with @Configuration. +2023-09-06T14:30:34.258+02:00 INFO 209310 --- [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.example.loan.Application for test class com.example.loan.XmlServiceUsingStubRunnerTests +2023-09-06T14:30:34.260+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +2023-09-06T14:30:34.266+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : HTTP POST http://localhost:10622/xmlfraud +2023-09-06T14:30:34.267+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Accept=[application/xml, text/xml, application/json, application/*+xml, application/*+json] +2023-09-06T14:30:34.268+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Writing [com.example.loan.XmlRequestBody@530e500c] as "application/xml;charset=UTF-8" +2023-09-06T14:30:34.293+02:00 INFO 209310 --- [qtp748921347-62] WireMock : Request received: +127.0.0.1 - POST /xmlfraud + +Accept: [application/xml, text/xml, application/json, application/*+xml, application/*+json] +Content-Type: [application/xml;charset=UTF-8] +User-Agent: [Java/17.0.1] +Host: [localhost:10622] +Connection: [keep-alive] +Transfer-Encoding: [chunked] + + + +Matched response definition: +{ + "status" : 200, + "body" : "EMPTY", + "headers" : { + "Content-Type" : "application/xml" + } +} + +Response: +HTTP/1.1 200 +Content-Type: [application/xml] +Matched-Stub-Id: [76628d79-6dd9-4c36-b135-62488a8a6cc4] + +2023-09-06T14:30:34.294+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Response 200 OK +2023-09-06T14:30:34.294+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Reading to [com.example.loan.XmlResponseBody] +2023-09-06T14:30:34.295+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +2023-09-06T14:30:34.302+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : HTTP POST http://localhost:10622/xmlfraud +2023-09-06T14:30:34.303+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Accept=[application/xml, text/xml, application/json, application/*+xml, application/*+json] +2023-09-06T14:30:34.304+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Writing [com.example.loan.XmlRequestBody@14f05ca0] as "application/xml;charset=UTF-8" +2023-09-06T14:30:34.330+02:00 INFO 209310 --- [qtp748921347-66] WireMock : Request received: +127.0.0.1 - POST /xmlfraud + +Accept: [application/xml, text/xml, application/json, application/*+xml, application/*+json] +Content-Type: [application/xml;charset=UTF-8] +User-Agent: [Java/17.0.1] +Host: [localhost:10622] +Connection: [keep-alive] +Transfer-Encoding: [chunked] +foo + + +Matched response definition: +{ + "status" : 200, + "body" : "FULL", + "headers" : { + "Content-Type" : "application/xml" + } +} + +Response: +HTTP/1.1 200 +Content-Type: [application/xml] +Matched-Stub-Id: [a8c3f1a1-e9a7-442b-b61f-5991387cfd68] + +2023-09-06T14:30:34.331+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Response 200 OK +2023-09-06T14:30:34.331+02:00 DEBUG 209310 --- [ main] o.s.web.client.RestTemplate : Reading to [com.example.loan.XmlResponseBody] +2023-09-06T14:30:34.332+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +2023-09-06T14:30:34.334+02:00 DEBUG 209310 --- [ main] o.s.c.c.w.WireMockTestExecutionListener : WireMockConfiguration is missing [true] +[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.081 s -- in com.example.loan.XmlServiceUsingStubRunnerTests +[INFO] +[INFO] Results: +[INFO] +[INFO] Tests run: 8, Failures: 0, Errors: 0, Skipped: 0 +[INFO] +[INFO] +[INFO] --- exec-maven-plugin:1.6.0:exec (gradle) @ http-client-restdocs --- +To honour the JVM settings for this build a single-use Daemon process will be forked. For more on this, please refer to https://docs.gradle.org/8.3/userguide/gradle_daemon.html#sec:disabling_the_daemon in the Gradle documentation. +Daemon will be stopped at the end of the build +> Task :clean +> Task :compileJava +> Task :compileGroovy NO-SOURCE +> Task :processResources +> Task :classes +> Task :resolveMainClassName +> Task :bootJar +> Task :jar +> Task :assemble +> Task :check +> Task :build +> Task :publishToMavenLocal UP-TO-DATE + +BUILD SUCCESSFUL in 7s +6 actionable tasks: 6 executed +[INFO] +[INFO] --- maven-jar-plugin:3.3.0:jar (default-jar) @ http-client-restdocs --- +[INFO] Building jar: /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-client/target/http-client-restdocs-0.0.1.jar +[INFO] +[INFO] --- spring-boot-maven-plugin:3.2.0-SNAPSHOT:repackage (repackage) @ http-client-restdocs --- +[INFO] Replacing main artifact /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-client/target/http-client-restdocs-0.0.1.jar with repackaged archive, adding nested dependencies in BOOT-INF/. +[INFO] The original artifact has been renamed to /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-client/target/http-client-restdocs-0.0.1.jar.original +[INFO] +[INFO] --- maven-install-plugin:3.1.1:install (default-install) @ http-client-restdocs --- +[INFO] Installing /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-client/pom.xml to /home/marcin/.m2/repository/com/example/http-client-restdocs/0.0.1/http-client-restdocs-0.0.1.pom +[INFO] Installing /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/http-client/target/http-client-restdocs-0.0.1.jar to /home/marcin/.m2/repository/com/example/http-client-restdocs/0.0.1/http-client-restdocs-0.0.1.jar +[INFO] +[INFO] --< org.springframework.cloud:spring-cloud-contract-samples-restdocs >-- +[INFO] Building Spring Cloud Contract Standalone Restdocs Test Samples 4.1.0-SNAPSHOT [3/3] +[INFO] --------------------------------[ pom ]--------------------------------- +[WARNING] org.slf4j:slf4j-api/maven-metadata.xmlfailed to transfer from http://0.0.0.0/ during a previous attempt. This failure was cached in the local repository and resolution will not be reattempted until the update interval of maven-default-http-blocker has elapsed or updates are forced. Original error: Could not transfer metadata org.slf4j:slf4j-api/maven-metadata.xml from/to maven-default-http-blocker (http://0.0.0.0/): transfer failed for http://0.0.0.0/org/slf4j/slf4j-api/maven-metadata.xml +[INFO] +[INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ spring-cloud-contract-samples-restdocs --- +[INFO] Deleting /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/target +[INFO] +[INFO] --- spring-javaformat-maven-plugin:0.0.35:apply (default) @ spring-cloud-contract-samples-restdocs --- +[INFO] +[INFO] --- spring-javaformat-maven-plugin:0.0.35:validate (default) @ spring-cloud-contract-samples-restdocs --- +[INFO] +[INFO] --- maven-checkstyle-plugin:3.1.2:check (checkstyle-validation) @ spring-cloud-contract-samples-restdocs --- +[INFO] Starting audit... +Audit done. +[INFO] You have 0 Checkstyle violations. +[INFO] +[INFO] --- maven-checkstyle-plugin:3.1.2:check (no-http-checkstyle-validation) @ spring-cloud-contract-samples-restdocs --- +[INFO] +[INFO] --- maven-javadoc-plugin:3.3.1:jar (javadoc) @ spring-cloud-contract-samples-restdocs --- +[INFO] Not executing Javadoc as the project is not a Java classpath-capable package +[INFO] +[INFO] >>> maven-source-plugin:3.2.1:jar (attach-sources) > generate-sources @ spring-cloud-contract-samples-restdocs >>> +[INFO] +[INFO] --- spring-javaformat-maven-plugin:0.0.35:apply (default) @ spring-cloud-contract-samples-restdocs --- +[INFO] +[INFO] --- spring-javaformat-maven-plugin:0.0.35:validate (default) @ spring-cloud-contract-samples-restdocs --- +[INFO] +[INFO] --- maven-checkstyle-plugin:3.1.2:check (checkstyle-validation) @ spring-cloud-contract-samples-restdocs --- +[INFO] Starting audit... +Audit done. +[INFO] You have 0 Checkstyle violations. +[INFO] +[INFO] --- maven-checkstyle-plugin:3.1.2:check (no-http-checkstyle-validation) @ spring-cloud-contract-samples-restdocs --- +[INFO] +[INFO] <<< maven-source-plugin:3.2.1:jar (attach-sources) < generate-sources @ spring-cloud-contract-samples-restdocs <<< +[INFO] +[INFO] +[INFO] --- maven-source-plugin:3.2.1:jar (attach-sources) @ spring-cloud-contract-samples-restdocs --- +[INFO] +[INFO] --- maven-invoker-plugin:3.2.1:run (integration) @ spring-cloud-contract-samples-restdocs --- +[INFO] No projects were selected for execution. +[INFO] +[INFO] --- maven-install-plugin:2.4:install (default-install) @ spring-cloud-contract-samples-restdocs --- +[INFO] Installing /home/marcin/repo/spring-cloud-contract/samples/standalone/restdocs/interpolated-pom.xml to /home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-contract-samples-restdocs/4.1.0-SNAPSHOT/spring-cloud-contract-samples-restdocs-4.1.0-SNAPSHOT.pom +[INFO] ------------------------------------------------------------------------ +[INFO] Reactor Summary: +[INFO] +[INFO] Spring Cloud Contract RestDocs Http Server Sample 0.0.1 SUCCESS [ 6.657 s] +[INFO] Spring Cloud Contract RestDocs Http Client Sample 0.0.1 SUCCESS [ 13.280 s] +[INFO] Spring Cloud Contract Standalone Restdocs Test Samples 4.1.0-SNAPSHOT SUCCESS [ 0.903 s] +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ +[INFO] Total time: 22.343 s +[INFO] Finished at: 2023-09-06T14:30:43+02:00 +[INFO] ------------------------------------------------------------------------ diff --git a/samples/standalone/restdocs/http-client/.gitignore b/samples/standalone/restdocs/http-client/.gitignore deleted file mode 100644 index a275b7b864..0000000000 --- a/samples/standalone/restdocs/http-client/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ - -target/ - -.gradle -build/ - -/.apt_generated/ diff --git a/samples/standalone/restdocs/http-client/.gradle/8.3/checksums/checksums.lock b/samples/standalone/restdocs/http-client/.gradle/8.3/checksums/checksums.lock new file mode 100644 index 0000000000000000000000000000000000000000..8a2c31bbc69ad5e64bc2c24f0d226713bbb1c899 GIT binary patch literal 17 VcmZRclTdWvX!rk<3}C=$0RTW21%m(p literal 0 HcmV?d00001 diff --git a/samples/standalone/restdocs/http-client/.gradle/8.3/checksums/md5-checksums.bin b/samples/standalone/restdocs/http-client/.gradle/8.3/checksums/md5-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..1bb4fdf2be7147f675526e514b2fd7b98fd04eb6 GIT binary patch literal 22797 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 I@7(JB2Q^kbQ2+n{ literal 0 HcmV?d00001 diff --git a/samples/standalone/restdocs/http-client/.gradle/8.3/checksums/sha1-checksums.bin b/samples/standalone/restdocs/http-client/.gradle/8.3/checksums/sha1-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..f68041e6c87fd4e547fde2f7dd5d72b2fd8680c2 GIT binary patch literal 30161 zcmeI3c{mp9-@qR#J0T%!NS351%D$AcFJ;NTXWvB<+7K#RB^6n+ghWN6s3f8!r7R(2 zt&|kW(mV6qGjn>M<^7#=uJ@1kdaq}$>kQYY`!nC~{hfR6xo6DTiNkTT{zf+3U)$=x zex>|IsQ{${lnPKPK&b$w0+b3+DnO|Kr2>=+P%1#F0Hp$y3Q#IQsQ{${lnPKPK&b$w z0{>qsUf9Whf4}nF;!(^GMj}862+HF;R2VAOTNnWDtAO%Tmv|)S zDqbE1+%y8^r_(kM)*k3Z{#N3&1?7o>Ju78)RonpWErn2?qR%TX_4o_Y-Z}{7=ZrLO zTVFqcgIgkU!w=yeQ8t<@Ed- zpxObr%~6yW9%8VZ)UZM7?26*w#l4DF^2Q=%puH9L4<(a4{V8kpk@IMJ3l**h(;4mW zeeD9;yMRBFfl*=XS z>0!X#r_tk-7gyCDp_hsQ+>Z_Ax4dI{Ugp()1AKor$}3eI+i8F1eFEHV7~|iYRgasT zLXK~ni1Eb_>r3D5NJfq$hw?kacW;=q4Tb}5faO!QV8gsrB$5EQH7(ly?zf0;kNSO~d zi=e$JR_7+x=r*Za<}`rs^+Ve?oj&~G8Eu;;;DJgge`?T(J1XvrTwlgo829cNueN2$ zMUKB4ocS6-+Xj_)6m7d9dI8fb#yFM#Hb#q4>Kj4(D+W<5w@# zGf500=P?Mo-}U$3si?}`BnXagUyQbY-)T%d_R-Zxs7MZh6Dn5W4VdHJ^LdLyKE;pWo7vn}#n{@nSwE%ZFLHTg5&7f9N&?MkCpHV)djv6;g`@31Dt?Pk zk@zJH_#SND`|MC=_&POQ4RCYpynhZ1AKQ_*%-hEZ}Z?zTz+|e2pW(?gP-oC<+33$*)l>aPr zt!eA`%K|)b1jYgu1NC(;*VCQlEsG(e%ogy-Bb!yP#EEt{(-rsZF5wthP>b#Uz6Y`O!rv`9)HMBj| zj!j#W&X^$ccJOJ8A6l-~XM9l!v=6}Mz2*C76-FKOko%os3)+79l&^BgDAfnh-UH*b z88c@T<>z_!9dL^PjH_yx$$XI;0Nj5T<0rC9-wv`P_iG~`jHmHL zPX(zhfcCmrJsIYh7)v&UTLW%7j<#p|Xcr-?>Lk*Gchsi#+_6F-0UIBSy}D* zUA?D20`5tLafz|rWltiIb=uw@jOU0)nI&nIBget=XWt>wn)^!N8Q>O5XnXcq;ZBKR zJ7k^Xhvm6C*tdGU_nD`lz4urZ0g>s(rA8h7VBrE~$9Ex&2x1tAb zsiD^aH^$~wzQl5!#KZ7g|%1X zox^}TT|wLPPcXI%zIcq}>DY*Jfm(;zY>vWM(B6Ry<3BpTH?T0LA#sOME-1c2?|YoN z0N`c`C|}zZ^r~g-t~21?{22fJvRz#5u?*m@Vkj4?_pj42vEKx^lLyL06n>T;e{chx zXEvgI-T2$%`b}pygZ7?X7@u5qA!)sz7vT2vC>Ki@^-1;WG6r0G2;&b6sw(~1ka^GQ zCCbG^2PK^RXV!uC)+#8M$SO6JmS}1M+;X&YQ0vSTR?cQ5ZZpTN8w}5BWJfF`C#iq zS?%892fD1ty3XMX+J38)__(N_IxlGNkDV|1*SR89ka-P@6G}Ep64i64x;G@4CO`U{{xpW zUUA~Ak9<5b59o(s{PovJM+Y@zUb4|cxr$OjiHgUP9XP&THpYg-| z>xuK8+AeQA3yx!GkMUha5woXLivYK*N4cRg!;Ne{t+D2nnuG+w(Br)r;o_BzoR z_ol6^vrR(ozb-~7Hq5$9Tg>qNAQ?geUC;I?5#MZH{c@bJ+E}Y*1H`$A|FOOf}6#w-(;4U>N zcN2P)9=%EinU}ORFs}X7z36ff@_cF#i}ABBLJK&K{|3kL#^xXQNm1?cZ+=L9^yJX? z?%x%kOG;WwgZ5^EDEC&NI&zSOUmS2(tp48h){hlV2qW{YhXmICRjdB6qFyU#ABe3J zyhpOeyWUo@xrXMK8v`{kqpb@S^~5`vWMCNPc->bc|^ja8DnU zqd##t4ioTils%;alnPKPK&b$w0+b3+DnO|Kr2>=+P%1#F0Hp$y3Q#IQsQ{${lnPKP zK&b$w0+b3+DnO|Kr2>=+{9mX5{ILW4VVEfVA4krd!lT(YPI0@&8|syKdnTL&T7Teh zR3}FZl98{+XyLC8WdFORNY^+Wa7ac$N-3}7jL1XFJMF>MkQMLg$NCFu4Q=?pQT|;k zgolf~MJB^|Ps}2fA%|r>?dVAna}hI_EA2OwyiPohj)yXg9qwFN3}Tr%K|cvHBxAv` zkZ({(S+exo%}onN9N(NCx3Vi-VC!t9g1+p4tHE{?#A1Q}a!nA6tQEq8e1A;JYMWo+ zaqlP#A8=@(l9rBoUftRP{gs|7=KcC7-S}8k8W)LUk+I-@S(CTKB=jym$lkI{)_2nE zT{p|!yK3g6_FiMX+x!vZ^GR;8 zv6FBtk5Z|7AQoLSajX-p<+ZFW#Lfd_Ho(pp}uuH4WUe^fE%wA>MR3CE>NY-Kx})-L0_ z&@ed`Bb^>xW293n2z`G9Su_)Ofu#?BU-9>1K_d$NI*L>*GX46)BGoT4HT=UORYNlU z`okjCucMzE8rP+NvaeWlnKTLUPp$4ZScI#Q!N!k#J;MfnWkgU7G8P#s_EI5`RdF!zAxBNkmrVr=BD?&n~OA4l4 z9>8Nh#_pR=DX^H}8IGV|87s7HBI^&o9*+>nVqD7{d+C!UGB!rxYZ%(Z;89Fqk%M7O7a`YSrp{26Aq5N-?!6hU`|3%VVfQYS;i`g-{b`NXCL=Z6j|@aGgDN z+oi6l`KiK_HzTr@g+nsXmz&T$?{6^(ETaVCSfktStJeAnGOp}S*V?>W>1XyedjWig zG-K(&+G+H+EjU9p^47oW*SjFiEmCi&_-W1-e`3uKx%Of(1L@a6so{U92AR?OA4b%_8@(HZG9BJ9 zGJeDfI4ZnUGPSG7On|<6gT_V(ZxA?NOc#i&(WWq%-Ct(*eiM_Fj(9AqpfOY6?IZk!zJUs|pnJ+kXe|J5+#1l1 zU~Gg`HyT$3oY}Fg*f%FwvY12o)fjXK!rzG?8{T+5pdEolCKlYUS9s~4#QMV`6)V#H zg5(X>W-+hl1>w1eXLnZ&jzl8W_yS_l_Y-I6|NPSA_-oP27Sxw?#cx~0RDO92ees7M z8`FqYOKjbFwjxhKYiI33s<#3iL+Z0r0(8(>g;#pXeZZoHW^lr4kg=eC@ga92QdaO4 zk8|a3EO|5zUtL`D{C;=!fFC@fB7d%k@By(H?hwZc+WS#mv4SRP-IphKF4M$w3h)X& zgfq0KzO)xuE8U5$2gjqM0Jh9&c~1k21)3iT`$Z-e+^-Gf zW0C3C9~P;8k;(86i&TdFA|k4}_cN|9HC_u}&A8T=v3~e5=og&n2=t4U#FfG_&8j^nyGM1av%1#4%jOLuD%$&Di^D+1 z0az?T&`*MSgG?;AUw;2M)*lwBSi7nUqAMB1+~}=i*c_GiSwx>)*EE3}ZnoQr7VE$L&fnZ!hog z<6LT|+beDuljsUEJiZ55Yp(ro#d?{tsbVDXy}_B&r%M=DBygvVjH`owje!3Hf!Y=R zNl*Rb!Bu@C!4MAkG*(zQ0?<}7bq6Ap5O5nZ{gO#b1*?HG8P;Q zdIE+wQr5|fIUJP^q0YS@yKkL@Z%-kyCi08G8P=`j|((Uz)y%~(0PM4j_35yo}gb$Nh>&B?ew`k+||>?B(!F&HoK`h zTn%$tIR#k4F})!1MJJ>an6|{n2CcfkEAZ9Q3g3c6xL*Jou(_B}++p<_4e#QwZFAvr>%Q8qjfBjre&*Gfk$~1dS zvxm-s%VgtQ!Do1jW(mG4;Bd4!`06C62ANoYW%y5G{biAiRdpd$#Ln(&^VS1Lzg$^Z z&=$}dItFD3z5C+U#b?O3GnF_)vQ`K`ctRv;6%>u{+2@i9^|cqe_2V1HL<5U9pN z9zGV;1{>m7WGuK}VC6v4Dvl84J^f2f{NU8&{Ijfq1(w=sC^L9%b6pA_i+LG5n-WxB z_Ztn%wX&u=M%<=PnwJcAym;scJ;B3o9Yq@P7OOn;j6`UWiS<{8|0LF57Rgvtqk_Hn zj?~1=@;Gai2*g)qu>?T(5O|IK`!qg7?qX; z?Acn2l5YKmV!`tvJU2m`O)0b^s392(j^%}yNLuW;(T|fo?_c7a=+$IXtdiHR9o-H0 z>;3wC`1v1) zG=H#L+h+N)dxx2}O)f^cw8Ja&c#rFk%0Px}8N?ZOWNI;N{nr03OJ$jDEnmg_D)BYY zlLov>*<%GP7I<|@(65c}E=$zSosN1we0EWuZNU4zmqR6DL2t9*ZBsb3Bd{*rq&E<% zx04&@u$6Tw-=-sA=B`fy3F($HIcKwGWUQlA-qV+Liomjzg? za>Ulfk=#=$Vb!kf+_+B~4RTE>?=Ig)tV6)!4`z6KRp>4TY{@IF>1VHA0(hHnbzKrj@+C8ErX}N8Y7zcslPKo4;|o z2(g~vC7ewJvDNYV%xoc5SnUIcvC1p?mAA$VYoPluJ{B~xppA+SUgHqN@@^>0*+hMI zRdfA;lg#1oN+wE-S%GDyh_`UN^oXtI-?evZQ;iQYbf|~MeV2Dha?t#QSm+8CKHCJb zr0p6~60c^h)HWRst^GTrXHBel*c z(W9z)N0Uk7VGzsQ7g(IoStqoTE=`Bkl$}n$M|-vZs3M+pjIr{UdJ_Ws z4R0*a^+uQ>zsSbYzQ~rgcUR9o+s2pVyV0bq0I{I?1KvbP)Nm<=vBN~lWJ;8|a#L*q zua(FX#bt=q3@oM&=qJHhKK}K?B|b$u?Fm)e%R3pURrTYY@K=gMSj!hUreUOa9^?!C6TTBtV^y8jGnk^Cw8S|Ur^G0CRT>>QV2HMzfLOX(3 zoL??~v!&mxK=X1bY18=)Mn#q^&@%&ELmMO(D~Yq5ZE(-zLcP!>-w;g+>MOf^`1W62 z4=h_2d?*|PiJ2|D_vc6*bA=A)3|A0cTLD+cGG1}SvI5qc<-{3g*x&cvH-B+!Qf}2$ z6ty7dcil(G9AyjLGvSRH8kdCqnmCvAw*0>Ervn3?$**i>O5}T;q5i|p`C;R(_)G=veKRW;`bzHPYSi9?ssLMz#dr(H z@SfNjZ9I0xEu1EA{M)KmE$o$tyAHD9XHkzVRuBuvev#PX&A$30uKiY2L7nu&Q08QV z(eG)iKrHrcAl54A?oQaR=(_g27OlmvKMXIlcH`piMWuMdHH>5Yeb@w840Xg-gJrP( zQB|wCdX?luOz-Ao8uGiL^8{C36V43UxJisd!xtl*Lo40~HuD68XgJ2^)GXWO0b)hM zDdDd1$VMDxbXzero`2EOXF~z1ktb`9Toih6@DcYt zwqA!%w$Mxsj|~nBV6k^YKM67%WXKKSWoh5Y&sy!I|1|K|sy&-7gIGy%z+xovbmJBA zcDm@sb~|&b+Y(Y0Y->LCxyQh!m0w z4T4x_U*aVkGas>)EEu+4ETLaKgyThVRDVgx)tgy+K`awwz2O7j{Rm>^SV=0Vq{~D) z+Bb<$d_Ppn>L@!7Vx?UNu|!@ITe$~v162;RZg@{~=GT^Rfxy>I*YMY}M^-j`8cdhj|y5@vC zu3G#c2xWM(&Sx8(8MN`i*EB)D$XM~7Ve9Jg5=m=Gcx36Bad+P$-?05wLr)W3abG`B z!$5XmNih@0;#SnWdc2|VVV&MWUjBWqqQZ`63V17Q-4|f7|0K37S&HZShxCS&HO~~; z?yad$SvxWXTMp%$R{)FNj@Z)7{S;Gik@=3c#m@B8XLf5IP&S9=TzK@JZ2=Y&iKl>k zi<`>lA7`|DcTPLVozTg4Z2!I0z)FE;9e86RF`~q|mWH$U)8lrwCv)`JY1l+06~SX3 zilvNNbdX9=dCvn=#dU8~^QGjvt##~Ulgid`%YuFd3E@NG7%vc8oX!^%!z;$}N3N+>p= zHM32d?|!UG&Jkh8BXUf2QG)95>`5V|TAAA@R$h7(tVj0I zZWdt0e@pi8r(e|iTvKPCN>fYV&sW(CTVTm!51!_Zw&=!IsuX5R0C~+NP3K{?WoGL6;rd z;-iLQAKer)*INgy9ms4$$3q+|E&is_F3Ch;zG<`N?2gOZz6(#_Er+t6HAufm%%b&! zkALV0>&bb(;17;0E_F-^bng#5?HZCf?H~vZO3J1*-$A^9QgPhKQ|GV#Q)lPs9irRxzth>fKAv z3C!~V)wm6}hBmsD(2ii<_z-)D`<+nc+Joz2ta9jw0@Ab18bGYRqj(9&e1zDV50as- z(sXV={OI*>L%Z72{_94Tz-o&I7VTzYYjk|s=}8-&9)bI`ul8rMupKM0c7QBs^zJ`_ zx2Qhd{o58ade?(h3P~$>R@P?Ey5-!Dszt+Dm6gp{IGBz@v7mV)7L0l7MJ?i3WGpxq zd|lyiB&{dI(kGVAWqRc7Xi{x#*YAwmY0wY)2IpDk1~{0jUomKpqd2qS6FZRK7DaJG(QpC5250?;C%=NOI?vbIa z|4$M8@4n!#@^3N+WDdw2kU1c8K<0qV0ht3b2V@S&9FRF6b3o>R%mJALG6!T1$Q+P4 zAag+G!2b#ddO%0+<~q}$xsv(io_-32t`7Wi*XMKU^}gBogGt=yNe}b-gR?ygTD2ST z;+tIh!XtdT^7a2-o<6)4#*sk zIUsXD=77urnFBHhWDdw2kU1c8K<0qV0ht3b2V@S&9FRF6b3o>R%mJALG6!T1$Q+P4 zAag+GfXo4z12P9>4#*skIUwYKL7}Mj1^ldKerD$RGILFYg(B=3{d}Z(0O7@*G)ZRU z=5S?@yA>b1J?WZs4^BC04W8}L_;7Duucn^|&(5Yjnisi$`y|k$+k^XP3O&B>-XV?m zG+8!a^01`c-6sEu+;RmN$vae=-$3t zpH8XC?fJTx463pIZfGfo*XJ!@{_k-RIX;Km6^ph+6^3bWim<`%88~J#chAXEh>E4< zWz#i3EmfZr1mrWthP3OPGG5q3506vzMTXCp?QNmedTCFtgQUIu*g_L58+ZnIwcMbq ztr~-xaJV!B9NA;Jq@J|L3oKF%fluRHw6CAr(>KkLMZ0r+)f9?n&}q52(?P*(5K;t< zBZ_Kc2;4_zbSFKIY#&mDXfxbdv^ERI*WuE7=xn#vo9%J9($%EXokOWfx69|jNuSn> zXJtESuh#3sT@>zgyJ*Pm^-*rpt7SR_`5m;&=O?+J23k>|Pru>PZ7*(eSF5BUO`n@w z|HisqhxdP=Uvq!85t+EBgTqN9mn(<>EkCdPEaX=Uw5veJzTz9x@7eE*m(9$$QeSnZ z{m$al@kWIcP6S-XE1rUa)xuI{Wj!BR2P1yZfa^g~PuxtBN=(|3s>d z_OgS=5_q_R2<)dohd%n>W~1IRZn^pG)d8)H8DGt02k)!+Y6xsxn_(C0SQ~y+%+Jg` zEIT8+-y8kSLueFqr1T}<_hVs+RRM7p!GVIF7_@mxHf`#s7|rc@k9 zm}1=mQ4Z!8+?h=Ka9A67lAFYt z6mPuSWp||KcxVr5P9O2=W$&LW{ys6S-N~E3^oj}DkK|_tyXT2hd?jE-W^R_o=XN{E z3>>I-xO}t+NYo_Ic09-FOXI%?_~QxL;HLl|w@?R9yy&lDLB~#$9t?J#9Vd-a3eCj5-@kw6jlPk$3}ilu`72XAvcK?zJzf8LPEI8W4oKbMBBK8enyor(fJ1MMQ+6rAF! zVLj41sI5~1>HU4Qi@7-@I6Pj(BtF@WJDjPm_8yPhgX9MiVP{nav%p`eJX53ZvANTRRLw2j~fG!X#D=)>|g|a8Ekz z3rVj&ie%b=%o$C$DMhy{O%}%9u)GeR+mok-dEmcm1r9PTbCB^DFy?nPT(>;XEpA$DMyKwc(za{&PN`{;vZ=+{G;rflq28qnUex7uer5OTowjzc&C|&4usg#;3M<-nT0M)vtZ_OOM4X|E&0)cs&Na zj_->>N9oNpiQ%-}Oj&g{BWa>Bilp_F&7_0g;8wy+5=JacU)Xv?y=nb>%Bh|GuxY8^ zzP9=F@m4LBg(~r)EAO~)BN(88`!l%Pt6i|`d-*O|Om-`US*%uyz;t#qX|h^K3$C}( zHlv*|V@4}!&>JyhaCpL3C+gXkLz8X}OC6|cXd0h!0r_XS@=T1z3FHLg*#>V*itmZd zU@{OoOmElgNQ2Ho>U0LoYBymzn~tI}f+CDC>+Ci%z!+w_G8KquU-aF@Hme&AK=OZj zqG(qAiEk>4D}r{mBmM<~o9(pTYA_qkHr#9@40gNOtTR|h17@UPbV#$Aw(H^V0NqSs z5zR*yjMvV}KKIC*KV=XbPOq)6{Iw!z#$7HqcU25b9-{>_;${<0T4^h#H<@vmFE%S> z(%C5!MNrTu%xcjQ)&S{(Iz&BKKGUq)edFd0@6^WTZR1>D#&l)d-JUGm7odR|b}mT` zyBR-wXbWxA8LSjdn@BxQ5qg@SbQb7>*+%PVz21u9q=_)=B2**lO%39!j0Q;4!LQmn zy?Cf->qg~G@mu#6j?>bd1f@DgcS)wmEu8Q^cNRQHOG6o#vvjA_$ujfIFaCiGM^-MW zHEZ;6=SVj4w+${?%_nmw%1eqf*Z$hOJ~#00;>%$PZncz7-H%PrWfk3q32wx)Xu&lhWywkpiTPL^ej#c}Y zeo4V)eKG5$(z<*720z>9D} zcuV*9g{&w>s0-AYNPmPIjQO|6~Ei&5K+I7!_EBiLr8A>rq$AcJ(u z4jX%Aj%A^aXno`J-O0a?gPlY&C(3%8>*sb;UZ1Fz3n#A%HI0`&9THy&r;TT5fYLHqI&BeK1}ZPSNTss+?^e=ULj4g zR@bacJNxcuCzM@VS)429)<=}ZQP*lXQG4QY{0m9+Wq#iO_HX*E2{v}(tS zm%g)O%5&vylkT4lx+6vm71D6{AJ$d(dUbX615>FV3-B(*%H!p2ojpYP3k-j+ zVP6A$BDZL6KKSssf%_77e|Y_eySJJzuTX9-^NeKHb{-DbW3LPEOS8W*i_&@0 zZ!+mECbNz(5tJD>V+M5|Gkp^gAq7+-DF?dr`7A2d5&pG5IN913hsO)N=HVZBz*BgHder`UIOa|}wsg(#Yt$9}_vjbLi{AOJ9FJRuxg~ak zyD|BDV1hRmr8B`3-JrAL1{($cH{&`u0_;|T)RB4%VIfR*aR=C$A)>ug<{S6-K3`;+ zdZgyVx!Bk(%F`7y1hg~2dknXdcG&FUZ4NRY(r7eM7OUQB#^HTSS`0K{u^4O?11Tn* zc8Zy9%ind9uDAG!`kR&ycDr}aSDuNwh9aKuAjrxBwORPn-TzT~vL`l=Yt!iP#@~Ky z@Y(w*L+lHbN6O4JGDGu*+pB?7gaFx@*8eXkoGu1w~+UvB#pO^;IX>?l3V6j{EcB{=|r7^PwBbbr3VirAygUH1I(hLwI z;S?z;4jThgoTGZi+J73MUlnh>US#`z>gw(9DW%WTlFv|vYL2eV9H)>-oyMZYjaIwS zh|@T3#Z44N8jKd5&Vt#jIA+yb3^=K`69i=?w8FALA(Z6^yz=&2BXpO$JYUoN?a@xJ z=Z!A^F_}p^L(UFJlN=g{n?4=)(&KL){O>|{_vSm^RVfdYc^D&2I_@RL&Nz_A+A%B0 z%xt*LhGDqHi0O1RZnx+SR?-N&ik$#)pw1qgag69mINel(7p&^-h*Kjkt#0>pvqjsL zQq4hG296y*|22mhH6sXNEPAVv#%+|zWVT}l5R?%nlCarGoPsH5f_VpWK5d|&aL9_y zKNoCh*>&yEOi!z|j~)L|dAQ6hEMX-umt6lM(A#OV&Wh0>x})GCW+Ba18xAsWn~?(k z8EqtHCX7ac@Gk-=DVqPYU)3(V_{!p?_g~+a__sYbU0G!`FzBK#oqcO-<_-8`Xg~Fz zy}Ayrdioc1$-V}*z10dvUud{#v*wRuc~wXIg4zrzXZr8F&}HDTMO2?AtzNuCbuXx` z4r$6=Jh?~fjVn$cS@xf)cd+IKZMx}tZqvsa_dYzm$K!i*rzZZ7=v~l1mp?vt`{u>} zoPFTzxx?qHFS}#3F6bpq{gEGJ+_R{#Z{n;z#}-wu@;Vo^F!9v`Pjy}T$#HkEohI6yRI)w>-U0ZELPW6zutt~t!+W) zWi4pk#p~{4?>%kCx9tZ_l3r$SL1q;LT?@K*K-_(^3$das^^s+TLvEajF4BiPkYCgg zH1-JUJW8o)LB|(mpvP@B-dKNTs%({cQPyb;*cVzXny4Mx$sC#EWjf4aW@arNLQva6a-1>Ip?kbmFF z^*6>Kt$(i5Zsa3(kVXZ4?4Lj8ESa|Nm+zJ%pI&+)%~I}@t~B}-G^zifHxhVgCWW@I^&E6K^zp=T6k3pnsiMw_)~5 z*Mr3^-v6B3xzbzqr>a0S7g-e)dmRd@OxSpKd-a!3yr{hQR2|idW_N}L10e6bbi-wJ%2Y_eRQY3=XBjC zxu4wux)b!!{KK`j6r6we=c4`9dm}@<(#K|51n@%b2S~PKpgBQ5*JS24o$!K@d}7&O zsh6j8D)(_%8odd6%Fyk^xs8uBR2;mdQPn!Du98|4^j+2N@o!RZ{yb>vkEe?d{P|Q> z(V3tR>@S!%X47)t+c#GCd1WVXr-9R`^zv^Z{WL)XR|IgjQfjXBL9tZp<&a; zf-Mku_jG5SYP_{JiIqt)@IUr?NbqI`UuMR)hjF>k(*0T2WzZSnE^XWFY^Q^B`vjF_ zF0MioI^8u{XVs_tXH)(AcNBeh3|UZOA;~Mh;;Bvo(gl=v=N!lV9oX69;-TI7$HzZ# zu8&GFZ{H$hMMwvtl$QtvD!wn^`2dCu@vOJFzX#i^eK)uN$B%759z4C|Qj^~nAqzu# z5K^kr$AF`tg9p!{;xlNnZ+Ecb2a7#!67{p2h&J~;y3x3PONY7Z>--&N45F0ZUD>NZ zK#PAab)(OxW|f#6Z#EdI z(Ecv!JZ}oX=^NIn;s?zmGP)XJ3m1tYI z+FnH%ya^`>I0n_K5*qM2^ErX<2hF@T_CcZ{{Rd z41uYj7~wz06+@kH7$Oq{$DxKTqCndvzx9&&?m9!-zTDB#*nQ)<)rU?2tjDptklB(& zz@MM~a;kG}e%YMeZOD$X7n1HB-T&$pw%q)Niec>-wHw&%bE_j$LkftWiFvh<8R89#+k*XtvU^V7 zm2hd_@ao53Pn==cjZTBzy^;xbrYilF3BnA8{&EHP`xUC7De{ru|oK{@VwsGy6 zuh@3>*9s}-pUVDXwPqY$+~efZ0gLmR{{8yGeuW%)|EZ-?pw>qhJpWpg5lfyq(4YL` zf~hYu(?3i+ItM%dc(Q9B{cTFkD>e3?pZe(^zh&0fb7S^db*QLKpH&Y`)jTtM!se0Q zlh5yO2uV}UZ%7;a>$U~@Udf)x4!WLs^kzfj&PU&D zZC;c*HZf(xXIrW*<}a}6w2Nl3mAHFrYK{*uCW1?$Fy{Lyw-f@+YPlPaF<0FBuq4yBxHU$CshQ9BLn!gC$& z96)4YU}3l&2OJHNEfvIJUsg8rMqnUl5}Ee`-#&PW1PEXqvNho1szB?mYpH0qZ&j;( z|J)!ucblGc{Rp$ejQ$E?FmXDffQh4;0Y4L%pAs=~6g3s=8TlJ0S_puuz)K$xVOWSS z|5FQA9`{^|f~J7nLS0f|jT+NE@R(!JHyY_RB!D1vXD}mt0RM$d5`1A!1?CN?8Z<+g z>hN@>Jy{Ocyx*&sBm9)Zy}f8}cX%lJ==8jrivT~0Sxy!D33|N8e?R!W;ggBQEj0I?PDI8_vLOGh1iH|VpFB12NlVvvXTLms zMDIy8=b}eWZJo65ysgE_;g|1!u$FH&GERIWP@IlAS=v)(312oURQj@s_?8y4NLb0i+dX=c zWzRikRH*a~7EyW_w*1j5)+;y&8M%&s!AT#A$m$5&hoo=9TB=$Pg>PCFDt*(Iwui!6 zBpSBLTzQdS*(y}}$_^uCj9mO`rCbWjaf?<}n&>J-q#!Z#iTOCE!y6_yk5z!7tJW0e z6(65vnEUiUyLPr5bFgwQ=^^)SwD)dr+VqCIdp&&O-t@PBI&}gW4JgGRKVk7}f3Cnu z0=IF=1sI*DeeKiECqLYEZNY$7YE0^9J)%^4q|r_`1Zm z0r!q4a$J-XUZa|J@UBk8JyD+pF{o7fpl?wC@T8u+c#vtpi;D5PuenO{@RktzvLm~_ zq{zsG_8pSirnOHP;l%T34^71>wwAU3NnA+@u&4BCG|Arpcy|XL$bc~`&33VxA7nO- z=?iB}Zx0IzEa{wpibjH0g_x>SxxKG!UqdLB3T2X_MxS&~AIjCor+6d@8uNo(!`9=_ zCeRETGr=geTP7*)W-_|_fwU0vJ|oP_L!B}J9X?u{%xFPViA)ftx9smxB*v}_W12tY zdh77Nhbk2csJQbjRNUF+bF;kiGORJ(ocNfbZ9N~$kh`Hf{%-*Doy5xO0kqwzO#%dT z;6rUMl;{9RJD@4>DIOJMu;;i~JZ5bN|1T~3X9H01y-XDvrV344j|b0V>ghjd-=ovF z;j>i?{%w2lP8cbpjQD^j*0fb+uqyc?!fXXI9A zhijF`I+HXVHE*=`smSe557#~erz>eYV!mkY_K)1|LSegnf7K!sKM4h;C=rd8*O0l) z`iP9=3vm1_w67S+cQ_#b00u80*N6ECFa|t8ZD5x>r}qIU=oAe>ThyE z_^;7heL3=~oFrV8u-P*p=8|O?E=#m^ml3(OnPFN3@EQi&O44YQoYC5jM<#{Y?Z^6? zwK^6+8eVLY=?|>xHUoW(DA`vS>VG_0fryMm#cAyv6WXm1Fr|*cmpAMaLAUMXR<2GKE=LAqbeG zVAJ4$EQhf`mchTH)s`7~{ALNpFA!G2kIW?*&uCerwf+J!F%)nT_T6w8l*8cU(C8z4 zjMhl>JpA#m%6y((3_fI_N>OUGO1p%ubb`OqAj)H)=Fm^ks&5mv zdVU=;Cv%`;VPdo@n;|2aiO7I7jtamv4uMe;{1xS9-V2$=6b}PPI5j-3;s`&cV1&=n zNKJ{@)&x;o3?KMrLcc_7Au(bL<3%mdPQHF=dbHX*Nw%wrg6#_S7zSG~xK)Mu7_IK- zkOF2LGAK_5h>+Z1T$PpIiSl&f|6uMrfMzL5i&kGtu0F6u1949tBcSr;CvkuDVE%x0 ztkW1oNztl%9vLS_lp7CQ5Cdn(!x#?daN(rM(dz8PZF>Hx=ikyeu)%TgmjG-KI?td5 zN>ZcMZA3;f>|~+g@`a9VY`-m{q-ga--?hLiEwEnsT?^8pRoFtx$ov2!nY%j2MNwL` z+BAZ0jtb!5aeWN_9j%7ekq2QEHwYjt_VYiO5U6o>(DaNwbBR=ZP7FN$e8E48kBL zmftopKfoZTgAg+Zaz$efe2y`5FxI?LXtOBpHT%6}=3o%*Ok%qzu!{_tJ5z)M5M<0q zo-qQWNGK~|iHN`$Fhn$pA?y&15A!t~GsKxfSn>bTb~QNuSd{T+z6BP>$mI5EZJC`T zIR5N+@sbFRKl|~P7esLUnfj!AMQ~{SU!#vdlPSvhOZSMN?XqBh2(Te&!yK|N2*`@T z5)h142m=IT5o!7hvxIbh0vD8yF=a1XgvMbITG(t<)(jem>SP1a(BQ_UHgT00Gx?2V zc$+BMK-4Q6h?X{>cB$uFI1@^Nai?q`>SCfYg73L(AbP7o-pe>ACA%SLWn}|Vu|EJe zF(rKJ&LIr2hP1MQC`3_ZY^Pil?sU6oEhz0HozILupNZKEQCPvGp&SOHRU7D3h1!>F z7`9`;&4Ha%ZEGHFzI~ta4#h)Pq32&5?D(u!%XcTYPO<;~y?Jj;BUVO;s#|ffXut9O zGim9Hq%S;qWAXc68(#N+Cl+n3Ppcw8kWleUyUTn<<$goMk1G)cG|ylK}> z{)cswAG-}~~qV8Ak&={aEefeR>kFOs; z^4gQrULSw;>W*?eDk7NNh{IsAZwx+)X^dikZaciTSMRf@x}_G@-u+?gYk%D_F+iI= zH2$|s3tAUV`Go8`c>Q8qWyS!Fo4C7pXU|40cb|N@=!K^fbxMgAzz>C_C7IZ?AiZJj z%)M$%%P0!rUkIHmwe8UgZF>N0nT=FyhJc4A6Q(yogjxz>?BcXlN0JaZ+d@E?Y|KJh zDVxq{!bF9c>cKDw@CZGCN3y=--)YSojIXx-{OaCEpZld8fg>48g;qmaq16xz3vJL^ z%r;U-STT~ojF=w6eVWV$2pwtTf@<1~dL5482Ff5R3xtBj5l82fb9;|VIdT)-b^7YU z;z##2ui8;n4>c$@rPMyU;Daxw^#9!QhW*Zns=Df+=_%XruRF%oeRx8{W{uLTTvSza z{_fwJeY^9CLyz>@{d++lviuhhu(=9(CPJFznYgdn)y7@h{%ow)uowa%Jkypkom^JXFD+3$feWO_wimH0SHtc}w(4-~*o_Fw_ z<^xkVROP6urj;M=_;n`n>r&hIrlB(rrzo4q_z9p^h#7W+SX~ih%?dB9=PqObILbN2aeqo3|Cmb{_&I7VCcBlwELJN;U^=^*G(ik(3$C}(Hlv+@ zSmsvJ0CzE?zJ%%o9%yoCR@@5~ap1HEmp^t0#Of3Fo#W>|Zni^|Z-d!rw&7+Q#E*vn z@;ZYBg322y7#Y%RrtNz8JHUOWu#nesXx8v+Am}|AU|leYaj4|yKW%|~yunJ*w29Q? z6ai7#DV>Efn9Vj?N9*-g3@1&5Sr?%i;aEsRvqq0>858BhZ4NaWy@xSTJjk&-+ji~V zDK*Wns8TZlT+{*oc`;N0^VpPQcgnFlNy=)q8I4AYvTH?NpYTF7f%t@(CU<1)&O1oa zAcw}p*tZuTk^{IDBM^+FY7csuh6pu+pG2|^IW#6LU^z4w ze?bTcqIjJ;8PkUP2CD-f*#k!!8ncQj70}b`PaIh||C=m&X!F7GZIic2OnOVH{HS1+ z0=nt$#gN+5=`h)P#H2HI*f<9gf- zmkUy7G!PVK*Hbuw>q&zZ3(AJM@-X;Djh?$|$bm+kfO4Z|{gqjbl0}Oft#+dkr*Yhh zn<$Dj7%e(Zn}k{Q76VS|?F2zt39ZnV8}>U0QpzqSInXG0;xnQU!8DTtjcRmSy`47e ztQZYqBnr3dETq|L!>u;bW~4}+-Do2*Ghs9m1hZZNaR8j%VOB9<1MIX42{bAN1zyNV z!KH|Q0T8|pjQ+QoG{9?Ci5EfUO)Gle`jM#Aj6J0Ii5n@KTAYpPjS6kOWLlQ{%X@0I zK9<(#wdc3*RPGgHuxoCCH2w)*8v6LWVTpWk({GpdQlqHTADLcw?+Q6sxjlA7GPr)F zA&|)zmbed0Yj5nj+|slD*x1y6QXkx;tlDZ0+2^7Z>H$U$D*If-NZA2#1!SL#Q0z%o z$H6P0VyW;@p|Z~fyn3sQ(j$z|#Z7UnfLl0ZOLKIEJNGBPJblAz@3F&PdeSpjX4m;5 z#1!Zj&V3G7t2C7P5xBw;Xz4bk`oz!P_RJaH{K+M4KgcSr>)z)UoPCEgA;>hyuO4ekdO*dW7ZTeW_-iN36czkc})WkxSHp87o z1BM+ZU4%#ml#`C;8y&tcveOP2E9i6v%xX7bI-8E7F@hqDgxPMl1>Ij5-6i30Q9`$i zOPcy4KghUeQDNW2S$&Qzs$MM7pO<$;Dolrk%1%4s*FexiCxW+4B{=QeZtWF1FKa>T zE?##Zd+%v8zHL8f(k{t#zP-9Dbnk$;`(_tnMOo@2%L<3wI1}9kC?=XK*~zIql4_AE zDw>>HlrfBy8jTy)pk2MUlc$@83?6-GX5%?u-};Q?Eux~*w`Y5jAZb|W8=y|DaiSE`{xlll)@ z{!qrOoPisUUeEmHV)x?m?g|7G&M#z7U{l3A!ZXK)wDJ!6VM6{7$%oNVKcnZ$+hWkw zDx}%qCvn@WZtOK(|8&pIHplCaKB$?v{&;!YW^dYjSXN&B$0Ul|dzCDF_4Sk2YN{K3 z{Y~fL?&F&!=TONPeYlRWkps1X$brm_QcGHFcB93hHvtHh$*dzx1ZBp}n89MEX@k{7 z8?Abs$!M?yi!tvH)?!-r!eUq0+VXeoom zZq?hZHj9+#jr8~Y zEWVP(3=EA8b_3X-nGnK`3*Q0~Jp>s7|NpHro8-guAjlYKn*ZyM+d%@%0^Efl1p+$Q zBsoA|qyRu+ClNn}Ebp|^P)oEY*Fn-T3eYDJ^;YcS5cdnTJ+u=+rb;IZ7y9fw@x!Ll z3Dd?q9kk2Gvw6mVrke^Mn5eG)`6E3qKizOGvM4;+qGA&F{>twI8$K>RgC_fS7X;{1 zp@oOGt}+(v9^NE#evNKK%ge||5qcB8f*)@8*oed8$&mx;{&-e4Xk3}?SB@OWc(_#l zT9a(k-Q>uD!OMtnVoLZV+?XUVBb7OZ{;;?4ZkOGWp5wuN4!4Wn`)eQlZA#56HTIvM z`sp9PW!Bdt%R_d{$i=T#&^=5H#aoWZfl@U6isLr=W<%r7N8fC1UX(gEF=fMNTTWLB zPeR~{(Icm}PTF_g*5c&w%lAK6%Qsv6QotHlZBr;!h%FTIsb2^$21G1LnR$oe9;-rt zkCFMjdo}ORug;|US_OtNe~ND^rGW%;XK6xxx%v77i!}NB&jx?0hY)geo?Y59v zd@uR-1pTV=MqTi*NPP9cQ(c#S`A=Sh>P5$Q-h)iz`@^cTKurR8+l=`C*NPY;+~sn^ zI|q(#FF#C13&>Z^CY-d=Rtlo5;DF|Bvr;CVoib4bKpYz}s|Dhk1QxcS4gu>`=(z43 z4Cb2S?L9{=udXUa2P1R&o`o+F%blmvV@OI-oRI~5XPIfqk;4E;3pi8>Hc+Y%BPe91 z{{Rf*>t7_kWJvT$(T%b~)W1-_NDr$*6UVGOnEUh}_H##8Ppf-f(GHmwBt?`pI%A^f zwb=L~VW9OyAu$qHu!b}{PGj<}@UgcoF|?D-I0T`b4|E=8gRcA!tkkBj4X zypMDoX?nET!YRo6f&~__T+uC_ay)Rg7{MBLCqS^)l4jb3(N?3KwwY`+1W&+>2EYNJ zNehJ;OJNxXVIW&i)o<*OKgL^-u@#H|VlOg{Z;%5P3?OCiFLOT_D-#j~ycu|oSHssD zgeZs!w!z7ChkjzJqWGul>mOGSej*#01aJc!c0v#W;SMs?Qib4UGY_1;xW|WUf|m?G zULnj+X6rBaDOb9{ol;}2z$qs+`>Jp&FBK{^^Fn6uI~QXpCOUH~(E>~r0>mBIQ6t!l zRj`Se3YFT3A=3kUsl=SD3RsV+LO{Hc2?5JA=6=b{@+;-qe@cYJhFhK2P4=aIT0Z0^ zX)_ZvVWrKK2{!}YF9l&4F|$o)!{HG@VmSOm*-R8JwrmR2BQ$VQp?{rNw_)~5*Mr3^ z-v6B3xzdX)^uuA%Sp-cnz@A*|!ct{_yD~d%i9KbXvV13F6jxN4u<`8n>Mx&oQF-sF zI;s`TkU666u@63h!Pn`E8AI9`7(5KOl6Jtwfrq)-ZXp4+nX*{*)-su;sZgn18Zt}N zEwL3_r5UZMLaf%1`GOk=2&5S-a`CN2qJAue@QayC8I&i(;q|$}t|&_sb(DEh!=*@j z>mf^}@Z!icVQ5r#(Zl5n*1bd_P|6-uFz&c2#N-W`Dh!wk^!tOJR$)ML6)Hs}M`i{> zTZX`wpS+c|>xYTbRIHtx3Y8klAv4$(1F+*TEeg&5HxQ-zj#?1W-5&&z$= zD_ykIQ-*FQ&TV|8q2k~rjjGmJb>Oxq4Xj%Bbr}h19}L`inEhLiqAEo{N2Ud)v=}E{ z3eQ~@8%oxalDUM#eh5(XS|dbDv*@ix8n;m|s(At4Fiv{_l-v(>e>m35kE8z9&Gb~L6fGT@%q==G zsCpIGtc57n?obU`h=MGZLTDLeK#mM5gA9a;Wf~OC#9HeVqI8Podah)p5-QaxMc0c& z*Ux0-lHpV|kSr1dh3JdQeSdFGGy_~CIa5uqC?FT3 zW2j&WeTaa*3Jc;x#CMUoJ``HbQJ|$;~s+H!+Z?H#`^M}nmacchu`eU1x)vksp z6uaIrC=~Th!_P71XJ#Ijosr$|js9jLgLK)QIG*F7GPCKv1B?ppzq=I6nS+mO2kbQ* z8XxZM>(vlBF3Jf(bTlx6eG+K6T;o2PLXYpecSz$sO_mLqJS=HRyK6m3kLEvS4Ai1Wk+^p3O>3VpH4Aq+ z?7%wkmh(Zy@fo z${`(ull_+Jp=ghCdJx1xL*ib#JMHp1d@wDfyLhLK8Dljc{LYH7-5GQs7VOPH==V&d{U2u_A>>wFWGYdA)TGlj4sIR2P~5yA1t!muGY58$hq34#_i)Gf0>Fjh<# zBg_LVQuhVJr3vZ$umO&2vr(xEo+mPj35zTqvy-4?*bN!Q1ONrRjK#K#!kumx4KDTE zVJSR8wM34?Noh-Fr;K89dr%2v6caEIl~GJ?10IGLqs5yI=BWYDqASk0EyY6%mi@iH zbFO;N$py%&5JUwQ9f%t_Ke$3ST3E?Ju}xGZo(z6~6$y?74;IlV!#ywXo%nReBU1SW8vwp%8xr z0@=?vy12*5r2`h{HU0bbh5ZUk+e2Y368TSM&dkU#Br5cO6U9U&vB0l5Zik?lNSusf z-f}uTvU2lSWI=S*n!>!|fppD~ZSo<}4`@p-`zIgV=_}<&TVdY)BJ229&dguNR DE~=`- literal 0 HcmV?d00001 diff --git a/samples/standalone/restdocs/http-client/.gradle/8.3/executionHistory/executionHistory.lock b/samples/standalone/restdocs/http-client/.gradle/8.3/executionHistory/executionHistory.lock new file mode 100644 index 0000000000000000000000000000000000000000..a45987619fba8d33c786244bb3b0ac8ad5784892 GIT binary patch literal 17 UcmZRsihQr-xz~Fl0|amb059wV-2eap literal 0 HcmV?d00001 diff --git a/samples/standalone/restdocs/http-client/.gradle/8.3/fileChanges/last-build.bin b/samples/standalone/restdocs/http-client/.gradle/8.3/fileChanges/last-build.bin new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/samples/standalone/restdocs/http-client/.gradle/8.3/fileHashes/fileHashes.bin b/samples/standalone/restdocs/http-client/.gradle/8.3/fileHashes/fileHashes.bin new file mode 100644 index 0000000000000000000000000000000000000000..9e65a64d68e26c2fe488fc8466d068b5b85493c4 GIT binary patch literal 21097 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 literal 0 HcmV?d00001 diff --git a/samples/standalone/restdocs/http-client/.gradle/8.3/gc.properties b/samples/standalone/restdocs/http-client/.gradle/8.3/gc.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/standalone/restdocs/http-client/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/samples/standalone/restdocs/http-client/.gradle/buildOutputCleanup/buildOutputCleanup.lock new file mode 100644 index 0000000000000000000000000000000000000000..fcdacb6f87f4855088b98b32328443a8d7b6cadc GIT binary patch literal 17 VcmZR+->0~XJ-=uZ0~j!I0st|h1MvU= literal 0 HcmV?d00001 diff --git a/samples/standalone/restdocs/http-client/.gradle/buildOutputCleanup/cache.properties b/samples/standalone/restdocs/http-client/.gradle/buildOutputCleanup/cache.properties new file mode 100644 index 0000000000..98805496db --- /dev/null +++ b/samples/standalone/restdocs/http-client/.gradle/buildOutputCleanup/cache.properties @@ -0,0 +1,2 @@ +#Wed Sep 06 14:27:18 CEST 2023 +gradle.version=8.3 diff --git a/samples/standalone/restdocs/http-client/.gradle/buildOutputCleanup/outputFiles.bin b/samples/standalone/restdocs/http-client/.gradle/buildOutputCleanup/outputFiles.bin new file mode 100644 index 0000000000000000000000000000000000000000..f15dd28feb9e88181d451e89cef55829bd408522 GIT binary patch literal 19145 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

Sw9 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 A=l}o! literal 0 HcmV?d00001 diff --git a/samples/standalone/restdocs/http-client/.gradle/file-system.probe b/samples/standalone/restdocs/http-client/.gradle/file-system.probe new file mode 100644 index 0000000000000000000000000000000000000000..de7642b0578610fef4d2543a6cbd15bf4b95ed8b GIT binary patch literal 8 PcmZQzVC>4OR0sk924w-^ literal 0 HcmV?d00001 diff --git a/samples/standalone/restdocs/http-client/.gradle/vcs-1/gc.properties b/samples/standalone/restdocs/http-client/.gradle/vcs-1/gc.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/standalone/restdocs/http-client/.idea/.gitignore b/samples/standalone/restdocs/http-client/.idea/.gitignore new file mode 100644 index 0000000000..13566b81b0 --- /dev/null +++ b/samples/standalone/restdocs/http-client/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/samples/standalone/restdocs/http-client/.idea/compiler.xml b/samples/standalone/restdocs/http-client/.idea/compiler.xml new file mode 100644 index 0000000000..f8cdb994b0 --- /dev/null +++ b/samples/standalone/restdocs/http-client/.idea/compiler.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/restdocs/http-client/.idea/encodings.xml b/samples/standalone/restdocs/http-client/.idea/encodings.xml new file mode 100644 index 0000000000..63e9001932 --- /dev/null +++ b/samples/standalone/restdocs/http-client/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/samples/standalone/restdocs/http-client/.idea/jarRepositories.xml b/samples/standalone/restdocs/http-client/.idea/jarRepositories.xml new file mode 100644 index 0000000000..77e3c28260 --- /dev/null +++ b/samples/standalone/restdocs/http-client/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/restdocs/http-client/.idea/misc.xml b/samples/standalone/restdocs/http-client/.idea/misc.xml new file mode 100644 index 0000000000..9cc7e822b0 --- /dev/null +++ b/samples/standalone/restdocs/http-client/.idea/misc.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/0/f/0f0eab2c174d28b70b02de758125b58bdbb2cb13 b/samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/0/f/0f0eab2c174d28b70b02de758125b58bdbb2cb13 new file mode 100644 index 0000000000..cb29944c7a --- /dev/null +++ b/samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/0/f/0f0eab2c174d28b70b02de758125b58bdbb2cb13 @@ -0,0 +1,7 @@ + +4 +java:S57867"Remove this 'public' modifier.(Ų÷÷ +9 +java:S5786G"Remove this 'public' modifier.(ª—ò¿úÿÿÿÿ +9 +java:S5786+"Remove this 'public' modifier.(­Ù…Ñúÿÿÿÿ \ No newline at end of file diff --git a/samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/4/1/418b368109de47f2deab6ae6f859bba79503b690 b/samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/4/1/418b368109de47f2deab6ae6f859bba79503b690 new file mode 100644 index 0000000000..ec34676217 --- /dev/null +++ b/samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/4/1/418b368109de47f2deab6ae6f859bba79503b690 @@ -0,0 +1,7 @@ + +4 +java:S5786+"Remove this 'public' modifier.(Ų÷÷ +9 +java:S57867"Remove this 'public' modifier.(ª—ò¿úÿÿÿÿ +4 +java:S5786%"Remove this 'public' modifier.(аƒï \ No newline at end of file diff --git a/samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/4/4/442292b8a7efeabbe4cc176709b833b1792140ec b/samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/4/4/442292b8a7efeabbe4cc176709b833b1792140ec new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/8/4/8485b3d5dbc2b6f87bd101a3a996a5faab5574ea b/samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/8/4/8485b3d5dbc2b6f87bd101a3a996a5faab5574ea new file mode 100644 index 0000000000..46fd249f9f --- /dev/null +++ b/samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/8/4/8485b3d5dbc2b6f87bd101a3a996a5faab5574ea @@ -0,0 +1,7 @@ + +9 +java:S5786:"Remove this 'public' modifier.(ºØÚáýÿÿÿÿ +4 +java:S5786I"Remove this 'public' modifier.(äÔß‹ +9 +java:S5786+"Remove this 'public' modifier.(ØÁÜÿûÿÿÿÿ \ No newline at end of file diff --git a/samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/d/4/d4407a9ef49dcf7dd4b936e7fb4249f7579e0fbb b/samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/d/4/d4407a9ef49dcf7dd4b936e7fb4249f7579e0fbb new file mode 100644 index 0000000000..37c66846d9 --- /dev/null +++ b/samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/d/4/d4407a9ef49dcf7dd4b936e7fb4249f7579e0fbb @@ -0,0 +1,7 @@ + +9 +java:S57864"Remove this 'public' modifier.(ºØÚáýÿÿÿÿ +4 +java:S5786A"Remove this 'public' modifier.(äÔß‹ +4 +java:S5786&"Remove this 'public' modifier.(ßùÍ \ No newline at end of file diff --git a/samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/f/0/f07866736216be0ee2aba49e392191aeae700a35 b/samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/f/0/f07866736216be0ee2aba49e392191aeae700a35 new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/index.pb b/samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/index.pb new file mode 100644 index 0000000000..bf91518239 --- /dev/null +++ b/samples/standalone/restdocs/http-client/.idea/sonarlint/issuestore/index.pb @@ -0,0 +1,13 @@ + +c +3src/test/java/com/example/loan/XmlServiceTests.java,0/f/0f0eab2c174d28b70b02de758125b58bdbb2cb13 +~ +Nsrc/test/java/com/example/loan/LoanApplicationServiceusingStubRunnerTests.java,d/4/d4407a9ef49dcf7dd4b936e7fb4249f7579e0fbb +o +?src/test/java/com/example/loan/LoanApplicationServiceTests.java,8/4/8485b3d5dbc2b6f87bd101a3a996a5faab5574ea +r +Bsrc/test/java/com/example/loan/XmlServiceUsingStubRunnerTests.java,4/1/418b368109de47f2deab6ae6f859bba79503b690 +< + build.gradle,f/0/f07866736216be0ee2aba49e392191aeae700a35 +7 +pom.xml,4/4/442292b8a7efeabbe4cc176709b833b1792140ec \ No newline at end of file diff --git a/samples/standalone/restdocs/http-client/.idea/vcs.xml b/samples/standalone/restdocs/http-client/.idea/vcs.xml new file mode 100644 index 0000000000..4fce1d86b4 --- /dev/null +++ b/samples/standalone/restdocs/http-client/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/samples/standalone/restdocs/http-client/.mvn/jvm.config b/samples/standalone/restdocs/http-client/.mvn/jvm.config deleted file mode 100644 index 0e7dabeff6..0000000000 --- a/samples/standalone/restdocs/http-client/.mvn/jvm.config +++ /dev/null @@ -1 +0,0 @@ --Xmx1024m -XX:CICompilerCount=1 -XX:TieredStopAtLevel=1 -Djava.security.egd=file:/dev/./urandom \ No newline at end of file diff --git a/samples/standalone/restdocs/http-client/.mvn/maven.config b/samples/standalone/restdocs/http-client/.mvn/maven.config deleted file mode 100644 index a682990566..0000000000 --- a/samples/standalone/restdocs/http-client/.mvn/maven.config +++ /dev/null @@ -1 +0,0 @@ --P spring diff --git a/samples/standalone/restdocs/http-client/.mvn/wrapper/MavenWrapperDownloader.java b/samples/standalone/restdocs/http-client/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index b901097f2d..0000000000 --- a/samples/standalone/restdocs/http-client/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2007-present 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. - */ -import java.net.*; -import java.io.*; -import java.nio.channels.*; -import java.util.Properties; - -public class MavenWrapperDownloader { - - private static final String WRAPPER_VERSION = "0.5.6"; - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" - + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if(mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if(mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if(!outputFile.getParentFile().exists()) { - if(!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { - String username = System.getenv("MVNW_USERNAME"); - char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); - Authenticator.setDefault(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(username, password); - } - }); - } - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/samples/standalone/restdocs/http-client/.mvn/wrapper/maven-wrapper.jar b/samples/standalone/restdocs/http-client/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index c1dd12f17644411d6e840bd5a10c6ecda0175f18..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58727 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%0ANsA|A3-jj|r`KAo%oTajX3>^E` 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 YM{}PByk10KD_nuQ4E7Du?}+~TKh4V)`~Uy| diff --git a/samples/standalone/restdocs/http-client/.mvn/wrapper/maven-wrapper.properties b/samples/standalone/restdocs/http-client/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index 015dfe6821..0000000000 --- a/samples/standalone/restdocs/http-client/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,18 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.3/apache-maven-3.8.3-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar diff --git a/samples/standalone/restdocs/http-client/README.adoc b/samples/standalone/restdocs/http-client/README.adoc deleted file mode 100644 index cdcb0e4a56..0000000000 --- a/samples/standalone/restdocs/http-client/README.adoc +++ /dev/null @@ -1,26 +0,0 @@ -= Http Client - -== Prerequisites - -First you have to publish to Maven Local the stubs of the *http-server* module - -== How to run it? - -Run - -[source=groovy] --------- -./gradlew clean build --------- - -or - --------- -./mvnw clean package --------- - -To - -- build the app -- use spring-cloud-contract-stub-runner-spring[Stub Runner Spring] to download the stub of `Http Server` -- run the tests against stubbed server \ No newline at end of file diff --git a/samples/standalone/restdocs/http-client/build.gradle b/samples/standalone/restdocs/http-client/build.gradle deleted file mode 100644 index e64f69d857..0000000000 --- a/samples/standalone/restdocs/http-client/build.gradle +++ /dev/null @@ -1,77 +0,0 @@ -buildscript { - repositories { - mavenCentral() - mavenLocal() - maven { url "https://repo.spring.io/snapshot" } - maven { url "https://repo.spring.io/milestone" } - maven { url "https://repo.spring.io/release" } - } - dependencies { - classpath "org.springframework.boot:spring-boot-gradle-plugin:${findProperty('bootVersion') ?: bootVersion}" - } -} - -group = 'com.example' -version = '0.0.1' - -repositories { - mavenCentral() - mavenLocal() - maven { url "https://repo.spring.io/snapshot" } - maven { url "https://repo.spring.io/milestone" } - maven { url "https://repo.spring.io/release" } -} - -apply plugin: 'groovy' -apply plugin: 'org.springframework.boot' -apply plugin: 'io.spring.dependency-management' -apply plugin: 'maven-publish' - -dependencyManagement { - imports { - mavenBom "org.springframework.cloud:spring-cloud-dependencies:$BOM_VERSION" - mavenBom "org.springframework.cloud:spring-cloud-contract-dependencies:${project.findProperty('verifierVersion') ?: verifierVersion}" - } -} - -dependencies { - implementation("org.springframework.boot:spring-boot-starter-web") - implementation("org.springframework.boot:spring-boot-starter-actuator") - implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") - - testImplementation 'org.springframework.cloud:spring-cloud-contract-wiremock' - testImplementation 'org.springframework.cloud:spring-cloud-starter-contract-stub-runner' - testImplementation('org.springframework.boot:spring-boot-starter-test') { - exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' - } - testImplementation "com.example:http-server-restdocs:0.0.1:stubs" -} - -test { - useJUnitPlatform() - systemProperty 'spring.profiles.active', 'gradle' - testLogging { - exceptionFormat = 'full' - } - afterSuite { desc, result -> - if (!desc.parent) { - println "Results: (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)" - if (result.testCount == 0) { - throw new IllegalStateException("No tests were found. Failing the build") - } - } - } -} - -task resolveDependencies { - doLast { - project.rootProject.allprojects.each { subProject -> - subProject.buildscript.configurations.each { configuration -> - configuration.resolve() - } - subProject.configurations.each { configuration -> - configuration.resolve() - } - } - } -} diff --git a/samples/standalone/restdocs/http-client/gradle.properties b/samples/standalone/restdocs/http-client/gradle.properties deleted file mode 100644 index 23a8e509b5..0000000000 --- a/samples/standalone/restdocs/http-client/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -org.gradle.daemon=false -verifierVersion=4.1.0-SNAPSHOT -BOM_VERSION=2023.0.0-SNAPSHOT -bootVersion=3.2.0-SNAPSHOT diff --git a/samples/standalone/restdocs/http-client/gradle/wrapper/gradle-wrapper.jar b/samples/standalone/restdocs/http-client/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 7f93135c49b765f8051ef9d0a6055ff8e46073d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63721 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鯊%1Et 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⁢ zv5o9#E7!G0XmdzfsS{efPNi`1b44~SZ4Z8fuX!I}#8g+(wxzQwUT#Xb2(tbY1+EUhGKoT@KEU9Ktl>_0 z%bjDJg;#*gtJZv!-Zs`?^}v5eKmnbjqlvnSzE@_SP|LG_PJ6CYU+6zY6>92%E+ z=j@TZf-iW4(%U{lnYxQA;7Q!b;^brF8n0D>)`q5>|WDDXLrqYU_tKN2>=#@~OE7grMnNh?UOz-O~6 z6%rHy{#h9K0AT+lDC7q4{hw^|q6*Ry;;L%Q@)Ga}$60_q%D)rv(CtS$CQbpq9|y1e zRSrN4;$Jyl{m5bZw`$8TGvb}(LpY{-cQ)fcyJv7l3S52TLXVDsphtv&aPuDk1OzCA z4A^QtC(!11`IsNx_HnSy?>EKpHJWT^wmS~hc^p^zIIh@9f6U@I2 zC=Mve{j2^)mS#U$e{@Q?SO6%LDsXz@SY+=cK_QMmXBIU)j!$ajc-zLx3V60EXJ!qC zi<%2x8Q24YN+&8U@CIlN zrZkcT9yh%LrlGS9`G)KdP(@9Eo-AQz@8GEFWcb7U=a0H^ZVbLmz{+&M7W(nXJ4sN8 zJLR7eeK(K8`2-}j(T7JsO`L!+CvbueT%izanm-^A1Dn{`1Nw`9P?cq;7no+XfC`K(GO9?O^5zNIt4M+M8LM0=7Gz8UA@Z0N+lg+cX)NfazRu z5D)~HA^(u%w^cz+@2@_#S|u>GpB+j4KzQ^&Wcl9f z&hG#bCA(Yk0D&t&aJE^xME^&E-&xGHhXn%}psEIj641H+Nl-}boj;)Zt*t(4wZ5DN z@GXF$bL=&pBq-#vkTkh>7hl%K5|3 z{`Vn9b$iR-SoGENp}bn4;fR3>9sA%X2@1L3aE9yTra;Wb#_`xWwLSLdfu+PAu+o3| zGVnpzPr=ch{uuoHjtw7+_!L_2;knQ!DuDl0R`|%jr+}jFzXtrHIKc323?JO{l&;VF z*L1+}JU7%QJOg|5|Tc|D8fN zJORAg=_vsy{ak|o);@)Yh8Lkcg@$FG3k@ep36BRa^>~UmnRPziS>Z=`Jb2x*Q#`%A zU*i3&Vg?TluO@X0O;r2Jl6LKLUOVhSqg1*qOt^|8*c7 zo(298@+r$k_wQNGHv{|$tW(T8L+4_`FQ{kEW5Jgg{yf7ey4ss_(SNKfz(N9lx&a;< je(UuV8hP?p&}TPdm1I$XmG#(RzlD&B2izSj9sl%y5~4qc diff --git a/samples/standalone/restdocs/http-client/gradle/wrapper/gradle-wrapper.properties b/samples/standalone/restdocs/http-client/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index ac72c34e8a..0000000000 --- a/samples/standalone/restdocs/http-client/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/samples/standalone/restdocs/http-client/gradlew b/samples/standalone/restdocs/http-client/gradlew deleted file mode 100755 index 0adc8e1a53..0000000000 --- a/samples/standalone/restdocs/http-client/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/samples/standalone/restdocs/http-client/gradlew.bat b/samples/standalone/restdocs/http-client/gradlew.bat deleted file mode 100644 index 6689b85bee..0000000000 --- a/samples/standalone/restdocs/http-client/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/samples/standalone/restdocs/http-client/mvnw b/samples/standalone/restdocs/http-client/mvnw deleted file mode 100755 index 5643201c7d..0000000000 --- a/samples/standalone/restdocs/http-client/mvnw +++ /dev/null @@ -1,316 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Maven Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /usr/local/etc/mavenrc ] ; then - . /usr/local/etc/mavenrc - fi - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`\\unset -f command; \\command -v java`" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` - fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" - fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi -else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - if [ -n "$MVNW_REPOURL" ]; then - jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - else - jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - fi - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - if $cygwin; then - wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` - fi - - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - else - wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - fi - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl -o "$wrapperJarPath" "$jarUrl" -f - else - curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f - fi - - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - # For Cygwin, switch paths to Windows format before running javac - if $cygwin; then - javaClass=`cygpath --path --windows "$javaClass"` - fi - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` -fi - -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" -export MAVEN_CMD_LINE_ARGS - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -exec "$JAVACMD" \ - $MAVEN_OPTS \ - $MAVEN_DEBUG_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" \ - "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/samples/standalone/restdocs/http-client/mvnw.cmd b/samples/standalone/restdocs/http-client/mvnw.cmd deleted file mode 100644 index 23b7079a3d..0000000000 --- a/samples/standalone/restdocs/http-client/mvnw.cmd +++ /dev/null @@ -1,188 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* -if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% ^ - %JVM_CONFIG_MAVEN_PROPS% ^ - %MAVEN_OPTS% ^ - %MAVEN_DEBUG_OPTS% ^ - -classpath %WRAPPER_JAR% ^ - "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ - %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" -if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%"=="on" pause - -if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% - -cmd /C exit /B %ERROR_CODE% diff --git a/samples/standalone/restdocs/http-client/pom.xml b/samples/standalone/restdocs/http-client/pom.xml deleted file mode 100644 index 5d53bee02b..0000000000 --- a/samples/standalone/restdocs/http-client/pom.xml +++ /dev/null @@ -1,275 +0,0 @@ - - - - - 4.0.0 - - com.example - http-client-restdocs - 0.0.1 - - Spring Cloud Contract RestDocs Http Client Sample - Spring Cloud Contract RestDocs Http Client Sample - - - org.springframework.boot - spring-boot-starter-parent - 3.2.0-SNAPSHOT - - - - - UTF-8 - 17 - 4.1.0-SNAPSHOT - - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-actuator - - - com.fasterxml.jackson.dataformat - jackson-dataformat-xml - - - - - org.springframework.boot - spring-boot-starter-test - test - - - org.junit.vintage - junit-vintage-engine - - - - - org.springframework.cloud - spring-cloud-contract-wiremock - test - - - org.springframework.cloud - spring-cloud-contract-stub-runner - test - - - - org.apache.httpcomponents.client5 - httpclient5 - - - org.slf4j - slf4j-api - - - compile - - - - com.example - http-server-restdocs - stubs - 0.0.1 - test - - - * - * - - - - - - - org.springframework.boot - spring-boot-configuration-processor - true - - - - - - - org.springframework.cloud - spring-cloud-contract-dependencies - ${spring-cloud-contract.version} - pom - import - - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - maven-deploy-plugin - - true - - - - maven-surefire-plugin - - true - - - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - - - - integration - - - - org.codehaus.mojo - exec-maven-plugin - 1.6.0 - - - gradle - test - - ./gradlew - - clean - build - publishToMavenLocal - - -x - test - - -PverifierVersion=${spring-cloud-contract.version} - - - - - exec - - - - - - - - - windows - - - - org.codehaus.mojo - exec-maven-plugin - 1.6.0 - - - gradle - test - - ./gradlew - - clean - build - publishToMavenLocal - - -x - test - - -PverifierVersion=${spring-cloud-contract.version} - - - - - exec - - - - - - - - - - diff --git a/samples/standalone/restdocs/http-client/settings.gradle b/samples/standalone/restdocs/http-client/settings.gradle deleted file mode 100644 index 877b12b9ab..0000000000 --- a/samples/standalone/restdocs/http-client/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'http-client-restdocs-gradle' diff --git a/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/Application.java b/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/Application.java deleted file mode 100644 index 63645c66f5..0000000000 --- a/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/Application.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.properties.EnableConfigurationProperties; - -@SpringBootApplication -@EnableConfigurationProperties(ServiceConfiguration.class) -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } - -} diff --git a/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/LoanApplicationService.java b/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/LoanApplicationService.java deleted file mode 100644 index 0e29422963..0000000000 --- a/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/LoanApplicationService.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan; - -import com.example.loan.model.FraudCheckStatus; -import com.example.loan.model.FraudServiceRequest; -import com.example.loan.model.FraudServiceResponse; -import com.example.loan.model.LoanApplication; -import com.example.loan.model.LoanApplicationResult; -import com.example.loan.model.LoanApplicationStatus; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; -import org.springframework.stereotype.Service; -import org.springframework.web.client.RestTemplate; - -@Service -public class LoanApplicationService { - - private static final String FRAUD_SERVICE_JSON_VERSION_1 = "application/vnd.fraud.v1+json"; - - private final RestTemplate restTemplate; - - private final ServiceConfiguration serviceConfiguration; - - public LoanApplicationService(ServiceConfiguration serviceConfiguration) { - this.restTemplate = new RestTemplate(); - // tag::custom_request_factory[] - this.restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory()); - // end::custom_request_factory[] - this.serviceConfiguration = serviceConfiguration; - } - - public LoanApplicationResult loanApplication(LoanApplication loanApplication) { - FraudServiceRequest request = new FraudServiceRequest(loanApplication); - - FraudServiceResponse response = sendRequestToFraudDetectionService(request); - - return buildResponseFromFraudResult(response); - } - - private FraudServiceResponse sendRequestToFraudDetectionService( - FraudServiceRequest request) { - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.add(HttpHeaders.CONTENT_TYPE, FRAUD_SERVICE_JSON_VERSION_1); - - // tag::client_call_server[] - ResponseEntity response = restTemplate.exchange( - "http://localhost:" + getPort() + "/fraudcheck", HttpMethod.PUT, - new HttpEntity<>(request, httpHeaders), FraudServiceResponse.class); - // end::client_call_server[] - - return response.getBody(); - } - - private LoanApplicationResult buildResponseFromFraudResult( - FraudServiceResponse response) { - LoanApplicationStatus applicationStatus = null; - if (FraudCheckStatus.OK == response.getFraudCheckStatus()) { - applicationStatus = LoanApplicationStatus.LOAN_APPLIED; - } - else if (FraudCheckStatus.FRAUD == response.getFraudCheckStatus()) { - applicationStatus = LoanApplicationStatus.LOAN_APPLICATION_REJECTED; - } - - return new LoanApplicationResult(applicationStatus, - response.getRejectionReason()); - } - - public int getPort() { - return this.serviceConfiguration.getPort(); - } - - public void setPort(int port) { - this.serviceConfiguration.setPort(port); - } - -} - -@ConfigurationProperties("service") -class ServiceConfiguration { - - private int port = 8080; - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } -} diff --git a/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/Client.java b/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/Client.java deleted file mode 100644 index 8fac47b2fd..0000000000 --- a/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/Client.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -public class Client { - - private String pesel; - - public Client() { - } - - public Client(String pesel) { - this.pesel = pesel; - } - - public String getPesel() { - return pesel; - } - - public void setPesel(String pesel) { - this.pesel = pesel; - } - -} diff --git a/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/FraudCheckStatus.java b/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/FraudCheckStatus.java deleted file mode 100644 index 01f2969113..0000000000 --- a/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/FraudCheckStatus.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -public enum FraudCheckStatus { - - OK, FRAUD - -} diff --git a/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/FraudServiceRequest.java b/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/FraudServiceRequest.java deleted file mode 100644 index 379d32e340..0000000000 --- a/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/FraudServiceRequest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -import java.math.BigDecimal; - -public class FraudServiceRequest { - - private String clientId; - - private BigDecimal loanAmount; - - public FraudServiceRequest() { - } - - public FraudServiceRequest(LoanApplication loanApplication) { - this.clientId = loanApplication.getClient().getPesel(); - this.loanAmount = loanApplication.getAmount(); - } - - public String getClientId() { - return clientId; - } - - public void setClientId(String clientId) { - this.clientId = clientId; - } - - public BigDecimal getLoanAmount() { - return loanAmount; - } - - public void setLoanAmount(BigDecimal loanAmount) { - this.loanAmount = loanAmount; - } - -} diff --git a/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/FraudServiceResponse.java b/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/FraudServiceResponse.java deleted file mode 100644 index c7d3aca9fb..0000000000 --- a/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/FraudServiceResponse.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -public class FraudServiceResponse { - - private FraudCheckStatus fraudCheckStatus; - - private String rejectionReason; - - public FraudServiceResponse() { - } - - public FraudCheckStatus getFraudCheckStatus() { - return fraudCheckStatus; - } - - public void setFraudCheckStatus(FraudCheckStatus fraudCheckStatus) { - this.fraudCheckStatus = fraudCheckStatus; - } - - public String getRejectionReason() { - return rejectionReason; - } - - public void setRejectionReason(String rejectionReason) { - this.rejectionReason = rejectionReason; - } - -} diff --git a/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/LoanApplication.java b/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/LoanApplication.java deleted file mode 100644 index e2f4aa2513..0000000000 --- a/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/LoanApplication.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -import java.math.BigDecimal; - -public class LoanApplication { - - private Client client; - - private BigDecimal amount; - - private String loanApplicationId; - - public LoanApplication() { - } - - public LoanApplication(Client client, double amount) { - this.client = client; - this.amount = BigDecimal.valueOf(amount); - } - - public Client getClient() { - return client; - } - - public void setClient(Client client) { - this.client = client; - } - - public BigDecimal getAmount() { - return amount; - } - - public void setAmount(BigDecimal amount) { - this.amount = amount; - } - - public String getLoanApplicationId() { - return loanApplicationId; - } - - public void setLoanApplicationId(String loanApplicationId) { - this.loanApplicationId = loanApplicationId; - } - -} diff --git a/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/LoanApplicationResult.java b/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/LoanApplicationResult.java deleted file mode 100644 index 73501084bb..0000000000 --- a/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/LoanApplicationResult.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -public class LoanApplicationResult { - - private LoanApplicationStatus loanApplicationStatus; - - private String rejectionReason; - - public LoanApplicationResult() { - } - - public LoanApplicationResult(LoanApplicationStatus loanApplicationStatus, - String rejectionReason) { - this.loanApplicationStatus = loanApplicationStatus; - this.rejectionReason = rejectionReason; - } - - public LoanApplicationStatus getLoanApplicationStatus() { - return loanApplicationStatus; - } - - public void setLoanApplicationStatus(LoanApplicationStatus loanApplicationStatus) { - this.loanApplicationStatus = loanApplicationStatus; - } - - public String getRejectionReason() { - return rejectionReason; - } - - public void setRejectionReason(String rejectionReason) { - this.rejectionReason = rejectionReason; - } - -} diff --git a/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/LoanApplicationStatus.java b/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/LoanApplicationStatus.java deleted file mode 100644 index 5afde21afc..0000000000 --- a/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/model/LoanApplicationStatus.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -public enum LoanApplicationStatus { - - LOAN_APPLIED, LOAN_APPLICATION_REJECTED - -} diff --git a/samples/standalone/restdocs/http-client/src/main/resources/application.yml b/samples/standalone/restdocs/http-client/src/main/resources/application.yml deleted file mode 100644 index 456f83e828..0000000000 --- a/samples/standalone/restdocs/http-client/src/main/resources/application.yml +++ /dev/null @@ -1,6 +0,0 @@ -server.port: 8097 -logging: - level: - org.springframework.cloud.contract.wiremock: debug - org.springframework.web.client: debug - com.github.tomakehurst.wiremock: trace \ No newline at end of file diff --git a/samples/standalone/restdocs/http-client/src/test/java/com/example/loan/LoanApplicationServiceTests.java b/samples/standalone/restdocs/http-client/src/test/java/com/example/loan/LoanApplicationServiceTests.java deleted file mode 100644 index bc2cdc6777..0000000000 --- a/samples/standalone/restdocs/http-client/src/test/java/com/example/loan/LoanApplicationServiceTests.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan; - -import java.nio.charset.Charset; - -import com.example.loan.model.Client; -import com.example.loan.model.LoanApplication; -import com.example.loan.model.LoanApplicationResult; -import com.example.loan.model.LoanApplicationStatus; -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.stubbing.StubMapping; -import org.junit.jupiter.api.Test; - - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock; -import org.springframework.core.io.Resource; - -import org.springframework.util.StreamUtils; - -import static org.assertj.core.api.Assertions.assertThat; - - -@SpringBootTest(properties = "service.port=${wiremock.server.port}") -@AutoConfigureWireMock(port = 0) -class LoanApplicationServiceTests { - - @Autowired - private LoanApplicationService service; - - @Value("classpath:META-INF/com.example/http-server-restdocs/0.0.1/mappings/standalone/shouldMarkClientAsFraud.json") - private Resource markClientAsFraud; - - @Value("classpath:META-INF/com.example/http-server-restdocs/0.0.1/mappings/webapp/shouldMarkClientAsNotFraud.json") - private Resource markClientAsNotFraud; - - @Autowired - private WireMockServer server; - - @Test - void shouldSuccessfullyApplyForLoan() throws Exception { - server.addStubMapping(StubMapping.buildFrom(StreamUtils.copyToString( - markClientAsNotFraud.getInputStream(), Charset.forName("UTF-8")))); - // given: - LoanApplication application = new LoanApplication(new Client("1234567890"), - 123.123); - // when: - LoanApplicationResult loanApplication = service.loanApplication(application); - // then: - assertThat(loanApplication.getLoanApplicationStatus()) - .isEqualTo(LoanApplicationStatus.LOAN_APPLIED); - assertThat(loanApplication.getRejectionReason()).isNull(); - } - - @Test - void shouldBeRejectedDueToAbnormalLoanAmount() throws Exception { - server.addStubMapping(StubMapping.buildFrom(StreamUtils.copyToString( - markClientAsFraud.getInputStream(), Charset.forName("UTF-8")))); - // given: - LoanApplication application = new LoanApplication(new Client("1234567890"), - 99999); - // when: - LoanApplicationResult loanApplication = service.loanApplication(application); - // then: - assertThat(loanApplication.getLoanApplicationStatus()) - .isEqualTo(LoanApplicationStatus.LOAN_APPLICATION_REJECTED); - assertThat(loanApplication.getRejectionReason()).isEqualTo("Amount too high"); - } - -} diff --git a/samples/standalone/restdocs/http-client/src/test/java/com/example/loan/LoanApplicationServiceusingStubRunnerTests.java b/samples/standalone/restdocs/http-client/src/test/java/com/example/loan/LoanApplicationServiceusingStubRunnerTests.java deleted file mode 100644 index 7398319c0f..0000000000 --- a/samples/standalone/restdocs/http-client/src/test/java/com/example/loan/LoanApplicationServiceusingStubRunnerTests.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan; - -import com.example.loan.model.Client; -import com.example.loan.model.LoanApplication; -import com.example.loan.model.LoanApplicationResult; -import com.example.loan.model.LoanApplicationStatus; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner; - - -import static org.assertj.core.api.Assertions.assertThat; - - -@SpringBootTest -@AutoConfigureStubRunner(ids = "com.example:http-server-restdocs") -class LoanApplicationServiceusingStubRunnerTests { - - @Autowired - LoanApplicationService service; - - @Value("${stubrunner.runningstubs.http-server-restdocs.port}") - int port; - - @BeforeEach - public void setup() { - this.service.setPort(this.port); - } - - @Test - void shouldSuccessfullyApplyForLoan() throws Exception { - // given - LoanApplication application = new LoanApplication(new Client("1234567890"), - 123.123); - // when: - LoanApplicationResult loanApplication = service.loanApplication(application); - // then: - assertThat(loanApplication.getLoanApplicationStatus()) - .isEqualTo(LoanApplicationStatus.LOAN_APPLIED); - assertThat(loanApplication.getRejectionReason()).isNull(); - } - - @Test - void shouldBeRejectedDueToAbnormalLoanAmount() throws Exception { - // given: - LoanApplication application = new LoanApplication(new Client("1234567890"), - 99999); - // when: - LoanApplicationResult loanApplication = service.loanApplication(application); - // then: - assertThat(loanApplication.getLoanApplicationStatus()) - .isEqualTo(LoanApplicationStatus.LOAN_APPLICATION_REJECTED); - assertThat(loanApplication.getRejectionReason()).isEqualTo("Amount too high"); - } - -} diff --git a/samples/standalone/restdocs/http-client/src/test/java/com/example/loan/XmlServiceTests.java b/samples/standalone/restdocs/http-client/src/test/java/com/example/loan/XmlServiceTests.java deleted file mode 100644 index cf57d978f7..0000000000 --- a/samples/standalone/restdocs/http-client/src/test/java/com/example/loan/XmlServiceTests.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan; - -import java.net.URI; -import java.nio.charset.Charset; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.stubbing.StubMapping; -import org.assertj.core.api.BDDAssertions; -import org.junit.jupiter.api.Test; - - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock; -import org.springframework.core.io.Resource; -import org.springframework.http.MediaType; -import org.springframework.http.RequestEntity; -import org.springframework.http.ResponseEntity; - -import org.springframework.util.StreamUtils; -import org.springframework.web.client.RestTemplate; - - -@SpringBootTest(properties = "service.port=${wiremock.server.port}") -@AutoConfigureWireMock(port = 0) -class XmlServiceTests { - - @Value("classpath:META-INF/com.example/http-server-restdocs/0.0.1/mappings/should_return_empty_content.json") - private Resource empty; - - @Value("classpath:META-INF/com.example/http-server-restdocs/0.0.1/mappings/should_return_full_content.json") - private Resource full; - - @Autowired - private WireMockServer server; - - @Test - void shouldSuccessfullyReturnFullResponse() throws Exception { - server.addStubMapping(StubMapping.buildFrom(StreamUtils - .copyToString(full.getInputStream(), Charset.forName("UTF-8")))); - - ResponseEntity responseEntity = new RestTemplate() - .exchange(RequestEntity - .post(URI.create( - "http://localhost:" + server.port() + "/xmlfraud")) - .contentType(MediaType.valueOf("application/xml;charset=UTF-8")) - .body(new XmlRequestBody("foo")), XmlResponseBody.class); - - BDDAssertions.then(responseEntity.getStatusCodeValue()).isEqualTo(200); - BDDAssertions.then(responseEntity.getBody().status).isEqualTo("FULL"); - } - - @Test - void shouldSuccessfullyReturnEmptyResponse() throws Exception { - server.addStubMapping(StubMapping.buildFrom(StreamUtils - .copyToString(empty.getInputStream(), Charset.forName("UTF-8")))); - - ResponseEntity responseEntity = new RestTemplate() - .exchange(RequestEntity - .post(URI.create( - "http://localhost:" + server.port() + "/xmlfraud")) - .contentType(MediaType.valueOf("application/xml;charset=UTF-8")) - .body(new XmlRequestBody("")), XmlResponseBody.class); - - BDDAssertions.then(responseEntity.getStatusCodeValue()).isEqualTo(200); - BDDAssertions.then(responseEntity.getBody().status).isEqualTo("EMPTY"); - } - -} - -class XmlRequestBody { - - public String name; - - public XmlRequestBody(String name) { - this.name = name; - } - -} - -class XmlResponseBody { - - public String status; - - public XmlResponseBody(String status) { - this.status = status; - } - - public XmlResponseBody() { - } - -} diff --git a/samples/standalone/restdocs/http-client/src/test/java/com/example/loan/XmlServiceUsingStubRunnerTests.java b/samples/standalone/restdocs/http-client/src/test/java/com/example/loan/XmlServiceUsingStubRunnerTests.java deleted file mode 100644 index 68212120c7..0000000000 --- a/samples/standalone/restdocs/http-client/src/test/java/com/example/loan/XmlServiceUsingStubRunnerTests.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan; - -import java.net.URI; - -import org.assertj.core.api.BDDAssertions; -import org.junit.jupiter.api.Test; - - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner; -import org.springframework.http.MediaType; -import org.springframework.http.RequestEntity; -import org.springframework.http.ResponseEntity; - -import org.springframework.web.client.RestTemplate; - - -@SpringBootTest -@AutoConfigureStubRunner(ids = "com.example:http-server-restdocs") -class XmlServiceUsingStubRunnerTests { - - @Value("${stubrunner.runningstubs.http-server-restdocs.port}") - int port; - - @Test - void shouldSuccessfullyReturnFullResponse() throws Exception { - ResponseEntity responseEntity = new RestTemplate() - .exchange(RequestEntity - .post(URI.create("http://localhost:" + this.port + "/xmlfraud")) - .contentType(MediaType.valueOf("application/xml;charset=UTF-8")) - .body(new XmlRequestBody("foo")), XmlResponseBody.class); - - BDDAssertions.then(responseEntity.getStatusCodeValue()).isEqualTo(200); - BDDAssertions.then(responseEntity.getBody().status).isEqualTo("FULL"); - } - - @Test - void shouldSuccessfullyReturnEmptyResponse() throws Exception { - ResponseEntity responseEntity = new RestTemplate() - .exchange(RequestEntity - .post(URI.create("http://localhost:" + this.port + "/xmlfraud")) - .contentType(MediaType.valueOf("application/xml;charset=UTF-8")) - .body(new XmlRequestBody("")), XmlResponseBody.class); - - BDDAssertions.then(responseEntity.getStatusCodeValue()).isEqualTo(200); - BDDAssertions.then(responseEntity.getBody().status).isEqualTo("EMPTY"); - } - -} diff --git a/samples/standalone/restdocs/http-client/src/test/resources/application-gradle.yaml b/samples/standalone/restdocs/http-client/src/test/resources/application-gradle.yaml deleted file mode 100644 index b1818d9164..0000000000 --- a/samples/standalone/restdocs/http-client/src/test/resources/application-gradle.yaml +++ /dev/null @@ -1,2 +0,0 @@ -stubrunner: - stubs.ids: 'com.example:http-server-restdocs-gradle' diff --git a/samples/standalone/restdocs/http-server/.gitignore b/samples/standalone/restdocs/http-server/.gitignore deleted file mode 100644 index b05ba7bd6d..0000000000 --- a/samples/standalone/restdocs/http-server/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ - -target/ - -.gradle -build/ - diff --git a/samples/standalone/restdocs/http-server/.gradle/8.3/checksums/checksums.lock b/samples/standalone/restdocs/http-server/.gradle/8.3/checksums/checksums.lock new file mode 100644 index 0000000000000000000000000000000000000000..13c999bfb63f9fdf494ae26b5ad83a3ca713233c GIT binary patch literal 17 VcmZRU;QDf^fA^=a3}C>>1^_zB1snhX literal 0 HcmV?d00001 diff --git a/samples/standalone/restdocs/http-server/.gradle/8.3/checksums/md5-checksums.bin b/samples/standalone/restdocs/http-server/.gradle/8.3/checksums/md5-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..d054b75afab25df617d5b2769086cefbcce6296b GIT binary patch literal 24947 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 D;A@P1 literal 0 HcmV?d00001 diff --git a/samples/standalone/restdocs/http-server/.gradle/8.3/checksums/sha1-checksums.bin b/samples/standalone/restdocs/http-server/.gradle/8.3/checksums/sha1-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..caca36d04229f61d01fadd5746798fb8f04a952c GIT binary patch literal 25463 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 MV$ObsPu)x42kwG)00000 literal 0 HcmV?d00001 diff --git a/samples/standalone/restdocs/http-server/.gradle/8.3/fileHashes/fileHashes.lock b/samples/standalone/restdocs/http-server/.gradle/8.3/fileHashes/fileHashes.lock new file mode 100644 index 0000000000000000000000000000000000000000..d80b5310e67ab7bd2da2ddcd007e08aa6f841cc1 GIT binary patch literal 17 UcmZR+@T2MZ^1Y2G86bcQ07|0wrh=$Cu zun%x3ffD)`VVm^#luvbGD83X z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~f&U`l&^A)7Z^qnJR+!ZJ6{WkTFj+9XWdh6b zJ^l7@O#VMuIdM6zLKmlcw_0QmxBBvPTho`Kcgnt>PNcn_qjK>czw8Hh(eYf1^H}th z><@-WpvOMeA$p(e`3l#p8b}U__gBgO{u**7-Sh2Y{hI8mJM8Emd1?|p^4+roC)<^6 zHql3AH)VqptHDi==q}kUOR=+;hVw?fTbpIKPu^@8r>=L!`bF72Ht$a2Iesg8PIlkp zVJezgH;R5QySyrjI-}oXL;wK<5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 y009ILKmY**5I_I{1Q0*~0R#|0pfrJA?Jd literal 0 HcmV?d00001 diff --git a/samples/standalone/restdocs/http-server/.gradle/checksums/md5-checksums.bin b/samples/standalone/restdocs/http-server/.gradle/checksums/md5-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..ebf19d0532b3ece1493738446af055e796d8f178 GIT binary patch literal 25247 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 literal 0 HcmV?d00001 diff --git a/samples/standalone/restdocs/http-server/.gradle/checksums/sha1-checksums.bin b/samples/standalone/restdocs/http-server/.gradle/checksums/sha1-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..bd9083966118a2a4f94c49891eebd7cf0f93e46a GIT binary patch literal 28271 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 QwFqt@1BgX+{xEF)AEd96?*IS* literal 0 HcmV?d00001 diff --git a/samples/standalone/restdocs/http-server/.gradle/file-system.probe b/samples/standalone/restdocs/http-server/.gradle/file-system.probe new file mode 100644 index 0000000000000000000000000000000000000000..ecb64ae21624b152b55d943feb5d1a3b1519325b GIT binary patch literal 8 PcmZQzVC>2&b7len22ugB literal 0 HcmV?d00001 diff --git a/samples/standalone/restdocs/http-server/.gradle/vcs-1/gc.properties b/samples/standalone/restdocs/http-server/.gradle/vcs-1/gc.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/standalone/restdocs/http-server/.idea/.gitignore b/samples/standalone/restdocs/http-server/.idea/.gitignore new file mode 100644 index 0000000000..13566b81b0 --- /dev/null +++ b/samples/standalone/restdocs/http-server/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/samples/standalone/restdocs/http-server/.idea/compiler.xml b/samples/standalone/restdocs/http-server/.idea/compiler.xml new file mode 100644 index 0000000000..e668509168 --- /dev/null +++ b/samples/standalone/restdocs/http-server/.idea/compiler.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/restdocs/http-server/.idea/encodings.xml b/samples/standalone/restdocs/http-server/.idea/encodings.xml new file mode 100644 index 0000000000..63e9001932 --- /dev/null +++ b/samples/standalone/restdocs/http-server/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/samples/standalone/restdocs/http-server/.idea/jarRepositories.xml b/samples/standalone/restdocs/http-server/.idea/jarRepositories.xml new file mode 100644 index 0000000000..77e3c28260 --- /dev/null +++ b/samples/standalone/restdocs/http-server/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/restdocs/http-server/.idea/misc.xml b/samples/standalone/restdocs/http-server/.idea/misc.xml new file mode 100644 index 0000000000..9cc7e822b0 --- /dev/null +++ b/samples/standalone/restdocs/http-server/.idea/misc.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/restdocs/http-server/.idea/sonarlint/issuestore/4/4/442292b8a7efeabbe4cc176709b833b1792140ec b/samples/standalone/restdocs/http-server/.idea/sonarlint/issuestore/4/4/442292b8a7efeabbe4cc176709b833b1792140ec new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/standalone/restdocs/http-server/.idea/sonarlint/issuestore/4/7/47243719dc78f8a57d390d73624d6c31feb69d10 b/samples/standalone/restdocs/http-server/.idea/sonarlint/issuestore/4/7/47243719dc78f8a57d390d73624d6c31feb69d10 new file mode 100644 index 0000000000..373ef0b576 --- /dev/null +++ b/samples/standalone/restdocs/http-server/.idea/sonarlint/issuestore/4/7/47243719dc78f8a57d390d73624d6c31feb69d10 @@ -0,0 +1,7 @@ + +9 +java:S5786+"Remove this 'public' modifier.(쌠‘üÿÿÿÿ +4 +java:S57865"Remove this 'public' modifier.(ñËÎ +9 +java:S5786%"Remove this 'public' modifier.(¸£úÛûÿÿÿÿ \ No newline at end of file diff --git a/samples/standalone/restdocs/http-server/.idea/sonarlint/issuestore/c/e/cecf7cde4af07dd004c5c09953f0e7e7dbc86439 b/samples/standalone/restdocs/http-server/.idea/sonarlint/issuestore/c/e/cecf7cde4af07dd004c5c09953f0e7e7dbc86439 new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/standalone/restdocs/http-server/.idea/sonarlint/issuestore/e/a/ea4a50232d6976a3ad6f2619cfb817ba6e474859 b/samples/standalone/restdocs/http-server/.idea/sonarlint/issuestore/e/a/ea4a50232d6976a3ad6f2619cfb817ba6e474859 new file mode 100644 index 0000000000..4692fd9a8e --- /dev/null +++ b/samples/standalone/restdocs/http-server/.idea/sonarlint/issuestore/e/a/ea4a50232d6976a3ad6f2619cfb817ba6e474859 @@ -0,0 +1,7 @@ + +` +java:S4488"JReplace "@RequestMapping(method = RequestMethod.POST)" with "@PostMapping"(’½Üœ +f +java:S1104,"PMake name a static final constant or non-public and provide accessors if needed.( þ; +h +java:S11042"RMake status a static final constant or non-public and provide accessors if needed.(œ©²ÿ \ No newline at end of file diff --git a/samples/standalone/restdocs/http-server/.idea/sonarlint/issuestore/index.pb b/samples/standalone/restdocs/http-server/.idea/sonarlint/issuestore/index.pb new file mode 100644 index 0000000000..16e7bb97fb --- /dev/null +++ b/samples/standalone/restdocs/http-server/.idea/sonarlint/issuestore/index.pb @@ -0,0 +1,9 @@ + +p +@src/main/java/com/example/fraud/FraudDetectionXmlController.java,e/a/ea4a50232d6976a3ad6f2619cfb817ba6e474859 +E +src/assembly/stub.xml,c/e/cecf7cde4af07dd004c5c09953f0e7e7dbc86439 +j +:src/test/java/com/example/fraud/XmlStubGeneratorTests.java,4/7/47243719dc78f8a57d390d73624d6c31feb69d10 +7 +pom.xml,4/4/442292b8a7efeabbe4cc176709b833b1792140ec \ No newline at end of file diff --git a/samples/standalone/restdocs/http-server/.idea/vcs.xml b/samples/standalone/restdocs/http-server/.idea/vcs.xml new file mode 100644 index 0000000000..4fce1d86b4 --- /dev/null +++ b/samples/standalone/restdocs/http-server/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/samples/standalone/restdocs/http-server/.mvn/jvm.config b/samples/standalone/restdocs/http-server/.mvn/jvm.config deleted file mode 100644 index 0e7dabeff6..0000000000 --- a/samples/standalone/restdocs/http-server/.mvn/jvm.config +++ /dev/null @@ -1 +0,0 @@ --Xmx1024m -XX:CICompilerCount=1 -XX:TieredStopAtLevel=1 -Djava.security.egd=file:/dev/./urandom \ No newline at end of file diff --git a/samples/standalone/restdocs/http-server/.mvn/maven.config b/samples/standalone/restdocs/http-server/.mvn/maven.config deleted file mode 100644 index a682990566..0000000000 --- a/samples/standalone/restdocs/http-server/.mvn/maven.config +++ /dev/null @@ -1 +0,0 @@ --P spring diff --git a/samples/standalone/restdocs/http-server/.mvn/wrapper/MavenWrapperDownloader.java b/samples/standalone/restdocs/http-server/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index b901097f2d..0000000000 --- a/samples/standalone/restdocs/http-server/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2007-present 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. - */ -import java.net.*; -import java.io.*; -import java.nio.channels.*; -import java.util.Properties; - -public class MavenWrapperDownloader { - - private static final String WRAPPER_VERSION = "0.5.6"; - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" - + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if(mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if(mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if(!outputFile.getParentFile().exists()) { - if(!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { - String username = System.getenv("MVNW_USERNAME"); - char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); - Authenticator.setDefault(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(username, password); - } - }); - } - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/samples/standalone/restdocs/http-server/.mvn/wrapper/maven-wrapper.jar b/samples/standalone/restdocs/http-server/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index c1dd12f17644411d6e840bd5a10c6ecda0175f18..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58727 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%0ANsA|A3-jj|r`KAo%oTajX3>^E` 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 YM{}PByk10KD_nuQ4E7Du?}+~TKh4V)`~Uy| diff --git a/samples/standalone/restdocs/http-server/.mvn/wrapper/maven-wrapper.properties b/samples/standalone/restdocs/http-server/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index 015dfe6821..0000000000 --- a/samples/standalone/restdocs/http-server/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,18 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.3/apache-maven-3.8.3-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar diff --git a/samples/standalone/restdocs/http-server/README.adoc b/samples/standalone/restdocs/http-server/README.adoc deleted file mode 100644 index 2fd3fbc40d..0000000000 --- a/samples/standalone/restdocs/http-server/README.adoc +++ /dev/null @@ -1,20 +0,0 @@ -= Http Server - -Run - -[source=groovy] --------- -./gradlew clean build publishToMavenLocal --------- - -or - --------- -./mvnw clean install --------- - -To - -- build the app -- generate and run Spring Cloud Contract Verifier tests -- publish the fatJar and the stubs to Maven Local \ No newline at end of file diff --git a/samples/standalone/restdocs/http-server/build.gradle b/samples/standalone/restdocs/http-server/build.gradle deleted file mode 100644 index 6bb63c49d9..0000000000 --- a/samples/standalone/restdocs/http-server/build.gradle +++ /dev/null @@ -1,130 +0,0 @@ -plugins { - id "groovy" - id "org.springframework.boot" - id "io.spring.dependency-management" - id "org.springframework.cloud.contract" - id "maven-publish" -} - -group = 'com.example' -version = '0.0.1' - -repositories { - mavenCentral() - mavenLocal() - maven { url "https://repo.spring.io/snapshot" } - maven { url "https://repo.spring.io/milestone" } - maven { url "https://repo.spring.io/release" } -} - -dependencyManagement { - imports { - mavenBom "org.springframework.cloud:spring-cloud-dependencies:${BOM_VERSION}" - mavenBom "org.springframework.cloud:spring-cloud-contract-dependencies:${verifierVersion}" - } -} - -dependencies { - implementation("org.springframework.boot:spring-boot-starter-web") - implementation("org.springframework.boot:spring-boot-starter-actuator") - implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") - - testImplementation('org.springframework.boot:spring-boot-starter-test') - testImplementation 'org.springframework.cloud:spring-cloud-starter-contract-stub-runner' - // tag::dependencies[] - testImplementation 'org.springframework.cloud:spring-cloud-starter-contract-verifier' - testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc' - // end::dependencies[] -} - -contracts { - baseClassMappings { - baseClassMapping('.*standalone.*', 'com.example.fraud.FraudBaseWithStandaloneSetup') - baseClassMapping('.*webapp.*', 'com.example.fraud.FraudBaseWithWebAppSetup') - } -} - -generateClientStubs.enabled = false - -test { - useJUnitPlatform() - systemProperty 'spring.profiles.active', 'gradle' - testLogging { - exceptionFormat = 'full' - } - afterSuite { desc, result -> - if (!desc.parent) { - println "Results: (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)" - if (result.testCount == 0) { - throw new IllegalStateException("No tests were found. Failing the build") - } - } - } -} - -task stubsJar(type: Jar, dependsOn: ['copySnippets', 'copySources', 'copyClasses']) { - archiveBaseName = project.name - archiveClassifier = 'stubs' - from project.file("${project.buildDir}/stubs") -} - -task copySnippets(type: Copy, dependsOn: test) { - from "target/snippets/stubs" - into "${project.buildDir}/stubs/META-INF/${project.group}/${project.name}/${project.version}/mappings" -} - -task copySources(type: Copy) { - from "src/main/java" - include '**/model/Fraud*.*' - into "${project.buildDir}/stubs/" -} - -task copyClasses(type: Copy) { - from "${project.buildDir}/classes/main/" - include '**/model/Fraud*.*' - into "${project.buildDir}/stubs/" -} - - -project.tasks.named("verifierStubsJar").get().dependsOn('copySnippets', 'copySources', 'stubsJar') // TODO: We need to fix this -project.tasks.named("copyContracts").get().dependsOn('stubsJar') // TODO: We need to fix this -afterEvaluate { - project.tasks.matching { it.name.contains("publish") }.each { it.dependsOn('verifierStubsJar') } // TODO: We need to fix this -} - -publishing { - publications { - maven(MavenPublication) { - artifact bootJar - artifact stubsJar - - // https://github.com/spring-gradle-plugins/dependency-management-plugin/issues/273 - versionMapping { - usage("java-api") { - fromResolutionOf("runtimeClasspath") - } - usage("java-runtime") { - fromResolutionResult() - } - } - } - } -} - -clean.doFirst { - delete 'target/snippets/stubs' - delete "~/.m2/repository/com/example/http-server-restdocs-gradle" -} - -task resolveDependencies { - doLast { - project.rootProject.allprojects.each { subProject -> - subProject.buildscript.configurations.each { configuration -> - configuration.resolve() - } - subProject.configurations.each { configuration -> - configuration.resolve() - } - } - } -} diff --git a/samples/standalone/restdocs/http-server/gradle.properties b/samples/standalone/restdocs/http-server/gradle.properties deleted file mode 100644 index 23a8e509b5..0000000000 --- a/samples/standalone/restdocs/http-server/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -org.gradle.daemon=false -verifierVersion=4.1.0-SNAPSHOT -BOM_VERSION=2023.0.0-SNAPSHOT -bootVersion=3.2.0-SNAPSHOT diff --git a/samples/standalone/restdocs/http-server/gradle/wrapper/gradle-wrapper.jar b/samples/standalone/restdocs/http-server/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 7f93135c49b765f8051ef9d0a6055ff8e46073d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63721 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鯊%1Et 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⁢ zv5o9#E7!G0XmdzfsS{efPNi`1b44~SZ4Z8fuX!I}#8g+(wxzQwUT#Xb2(tbY1+EUhGKoT@KEU9Ktl>_0 z%bjDJg;#*gtJZv!-Zs`?^}v5eKmnbjqlvnSzE@_SP|LG_PJ6CYU+6zY6>92%E+ z=j@TZf-iW4(%U{lnYxQA;7Q!b;^brF8n0D>)`q5>|WDDXLrqYU_tKN2>=#@~OE7grMnNh?UOz-O~6 z6%rHy{#h9K0AT+lDC7q4{hw^|q6*Ry;;L%Q@)Ga}$60_q%D)rv(CtS$CQbpq9|y1e zRSrN4;$Jyl{m5bZw`$8TGvb}(LpY{-cQ)fcyJv7l3S52TLXVDsphtv&aPuDk1OzCA z4A^QtC(!11`IsNx_HnSy?>EKpHJWT^wmS~hc^p^zIIh@9f6U@I2 zC=Mve{j2^)mS#U$e{@Q?SO6%LDsXz@SY+=cK_QMmXBIU)j!$ajc-zLx3V60EXJ!qC zi<%2x8Q24YN+&8U@CIlN zrZkcT9yh%LrlGS9`G)KdP(@9Eo-AQz@8GEFWcb7U=a0H^ZVbLmz{+&M7W(nXJ4sN8 zJLR7eeK(K8`2-}j(T7JsO`L!+CvbueT%izanm-^A1Dn{`1Nw`9P?cq;7no+XfC`K(GO9?O^5zNIt4M+M8LM0=7Gz8UA@Z0N+lg+cX)NfazRu z5D)~HA^(u%w^cz+@2@_#S|u>GpB+j4KzQ^&Wcl9f z&hG#bCA(Yk0D&t&aJE^xME^&E-&xGHhXn%}psEIj641H+Nl-}boj;)Zt*t(4wZ5DN z@GXF$bL=&pBq-#vkTkh>7hl%K5|3 z{`Vn9b$iR-SoGENp}bn4;fR3>9sA%X2@1L3aE9yTra;Wb#_`xWwLSLdfu+PAu+o3| zGVnpzPr=ch{uuoHjtw7+_!L_2;knQ!DuDl0R`|%jr+}jFzXtrHIKc323?JO{l&;VF z*L1+}JU7%QJOg|5|Tc|D8fN zJORAg=_vsy{ak|o);@)Yh8Lkcg@$FG3k@ep36BRa^>~UmnRPziS>Z=`Jb2x*Q#`%A zU*i3&Vg?TluO@X0O;r2Jl6LKLUOVhSqg1*qOt^|8*c7 zo(298@+r$k_wQNGHv{|$tW(T8L+4_`FQ{kEW5Jgg{yf7ey4ss_(SNKfz(N9lx&a;< je(UuV8hP?p&}TPdm1I$XmG#(RzlD&B2izSj9sl%y5~4qc diff --git a/samples/standalone/restdocs/http-server/gradle/wrapper/gradle-wrapper.properties b/samples/standalone/restdocs/http-server/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index ac72c34e8a..0000000000 --- a/samples/standalone/restdocs/http-server/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/samples/standalone/restdocs/http-server/gradlew b/samples/standalone/restdocs/http-server/gradlew deleted file mode 100755 index 0adc8e1a53..0000000000 --- a/samples/standalone/restdocs/http-server/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/samples/standalone/restdocs/http-server/gradlew.bat b/samples/standalone/restdocs/http-server/gradlew.bat deleted file mode 100644 index 6689b85bee..0000000000 --- a/samples/standalone/restdocs/http-server/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/samples/standalone/restdocs/http-server/mvnw b/samples/standalone/restdocs/http-server/mvnw deleted file mode 100755 index 5643201c7d..0000000000 --- a/samples/standalone/restdocs/http-server/mvnw +++ /dev/null @@ -1,316 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Maven Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /usr/local/etc/mavenrc ] ; then - . /usr/local/etc/mavenrc - fi - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`\\unset -f command; \\command -v java`" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` - fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" - fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi -else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - if [ -n "$MVNW_REPOURL" ]; then - jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - else - jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - fi - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - if $cygwin; then - wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` - fi - - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - else - wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - fi - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl -o "$wrapperJarPath" "$jarUrl" -f - else - curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f - fi - - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - # For Cygwin, switch paths to Windows format before running javac - if $cygwin; then - javaClass=`cygpath --path --windows "$javaClass"` - fi - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` -fi - -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" -export MAVEN_CMD_LINE_ARGS - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -exec "$JAVACMD" \ - $MAVEN_OPTS \ - $MAVEN_DEBUG_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" \ - "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/samples/standalone/restdocs/http-server/mvnw.cmd b/samples/standalone/restdocs/http-server/mvnw.cmd deleted file mode 100644 index 23b7079a3d..0000000000 --- a/samples/standalone/restdocs/http-server/mvnw.cmd +++ /dev/null @@ -1,188 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* -if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% ^ - %JVM_CONFIG_MAVEN_PROPS% ^ - %MAVEN_OPTS% ^ - %MAVEN_DEBUG_OPTS% ^ - -classpath %WRAPPER_JAR% ^ - "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ - %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" -if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%"=="on" pause - -if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% - -cmd /C exit /B %ERROR_CODE% diff --git a/samples/standalone/restdocs/http-server/pom.xml b/samples/standalone/restdocs/http-server/pom.xml deleted file mode 100644 index 61839ad9f0..0000000000 --- a/samples/standalone/restdocs/http-server/pom.xml +++ /dev/null @@ -1,290 +0,0 @@ - - - 4.0.0 - - com.example - http-server-restdocs - 0.0.1 - - Spring Cloud Contract RestDocs Http Server Sample - Spring Cloud RestDocs Verifier Http Server Sample - - - org.springframework.boot - spring-boot-starter-parent - 3.2.0-SNAPSHOT - - - - - UTF-8 - 17 - 4.1.0-SNAPSHOT - true - - - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-actuator - - - com.fasterxml.jackson.dataformat - jackson-dataformat-xml - - - - org.springframework.boot - spring-boot-starter-test - test - - - - org.springframework.cloud - spring-cloud-starter-contract-stub-runner - test - - - - org.springframework.cloud - spring-cloud-starter-contract-verifier - test - - - org.springframework.restdocs - spring-restdocs-mockmvc - true - - - - - - - - org.springframework.cloud - spring-cloud-contract-dependencies - ${spring-cloud-contract.version} - pom - import - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - maven-deploy-plugin - - true - - - - org.apache.maven.plugins - maven-clean-plugin - - - - build - - - target - - - - - - org.apache.maven.plugins - maven-assembly-plugin - - - stub - prepare-package - - single - - false - - true - - ${basedir}/src/assembly/stub.xml - - - - - - - maven-surefire-plugin - - true - - - - - org.springframework.cloud - spring-cloud-contract-maven-plugin - ${spring-cloud-contract.version} - true - - - - .*standalone.* - com.example.fraud.FraudBaseWithStandaloneSetup - - - - .*webapp.* - com.example.fraud.FraudBaseWithWebAppSetup - - - - - - - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - - - - - - windows - - - - org.codehaus.mojo - exec-maven-plugin - 1.6.0 - - - gradle - test - - gradlew.bat - - clean - build - - install - - -x - test - - -x - contractTest - - -PverifierVersion=${spring-cloud-contract.version} - - - - - exec - - - - - - - - - diff --git a/samples/standalone/restdocs/http-server/settings.gradle b/samples/standalone/restdocs/http-server/settings.gradle deleted file mode 100644 index 8d6570b7b8..0000000000 --- a/samples/standalone/restdocs/http-server/settings.gradle +++ /dev/null @@ -1,22 +0,0 @@ -pluginManagement { - repositories { - mavenLocal() - maven { url "https://repo.spring.io/snapshot" } - maven { url "https://repo.spring.io/milestone" } - gradlePluginPortal() - } - plugins { - id 'org.springframework.boot' version "${bootVersion}" - id "io.spring.dependency-management" version "1.1.3" - } - resolutionStrategy { - eachPlugin { - // protects us in case the gradle-portal-plugin hasn't yet been published by Maven - if (requested.id.id == 'org.springframework.cloud.contract') { - useModule("org.springframework.cloud:spring-cloud-contract-gradle-plugin:${verifierVersion}") - } - } - } -} - -rootProject.name = 'http-server-restdocs-gradle' diff --git a/samples/standalone/restdocs/http-server/src/assembly/stub.xml b/samples/standalone/restdocs/http-server/src/assembly/stub.xml deleted file mode 100644 index 310a3af245..0000000000 --- a/samples/standalone/restdocs/http-server/src/assembly/stub.xml +++ /dev/null @@ -1,51 +0,0 @@ - - stubs - - jar - - false - - - src/main/java - / - - **/model/Fraud*.* - - - - ${project.build.directory}/classes - / - - **/model/Fraud*.* - - - - ${project.build.directory}/generated-snippets/stubs - - META-INF/${project.groupId}/${project.artifactId}/${project.version}/mappings - - - **/* - - - - ${project.build.directory}/snippets/stubs - - META-INF/${project.groupId}/${project.artifactId}/${project.version}/mappings - - - **/* - - - - ${project.build.directory}/stubs - / - - **/* - - - - diff --git a/samples/standalone/restdocs/http-server/src/main/java/com/example/fraud/Application.java b/samples/standalone/restdocs/http-server/src/main/java/com/example/fraud/Application.java deleted file mode 100644 index c998b507b2..0000000000 --- a/samples/standalone/restdocs/http-server/src/main/java/com/example/fraud/Application.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; - -@Configuration -@EnableAutoConfiguration -@ComponentScan -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } - -} diff --git a/samples/standalone/restdocs/http-server/src/main/java/com/example/fraud/FraudDetectionController.java b/samples/standalone/restdocs/http-server/src/main/java/com/example/fraud/FraudDetectionController.java deleted file mode 100644 index 1d5469e93f..0000000000 --- a/samples/standalone/restdocs/http-server/src/main/java/com/example/fraud/FraudDetectionController.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud; - -import java.math.BigDecimal; - -import com.example.fraud.model.FraudCheck; -import com.example.fraud.model.FraudCheckResult; -import com.example.fraud.model.FraudCheckStatus; - -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import static org.springframework.web.bind.annotation.RequestMethod.PUT; - -@RestController -public class FraudDetectionController { - - private static final String FRAUD_SERVICE_JSON_VERSION_1 = "application/vnd.fraud.v1+json"; - - private static final String NO_REASON = null; - - private static final String AMOUNT_TOO_HIGH = "Amount too high"; - - private static final BigDecimal MAX_AMOUNT = new BigDecimal("5000"); - - // tag::server_api[] - @RequestMapping(value = "/fraudcheck", method = PUT, consumes = FRAUD_SERVICE_JSON_VERSION_1, produces = FRAUD_SERVICE_JSON_VERSION_1) - public FraudCheckResult fraudCheck(@RequestBody FraudCheck fraudCheck) { - // end::server_api[] - // tag::new_impl[] - if (amountGreaterThanThreshold(fraudCheck)) { - return new FraudCheckResult(FraudCheckStatus.FRAUD, AMOUNT_TOO_HIGH); - } - // end::new_impl[] - // tag::initial_impl[] - return new FraudCheckResult(FraudCheckStatus.OK, NO_REASON); - // end::initial_impl[] - } - - private boolean amountGreaterThanThreshold(FraudCheck fraudCheck) { - return MAX_AMOUNT.compareTo(fraudCheck.getLoanAmount()) < 0; - } - -} diff --git a/samples/standalone/restdocs/http-server/src/main/java/com/example/fraud/FraudDetectionXmlController.java b/samples/standalone/restdocs/http-server/src/main/java/com/example/fraud/FraudDetectionXmlController.java deleted file mode 100644 index 7db345a02f..0000000000 --- a/samples/standalone/restdocs/http-server/src/main/java/com/example/fraud/FraudDetectionXmlController.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud; - -import org.springframework.http.MediaType; -import org.springframework.stereotype.Controller; -import org.springframework.util.StringUtils; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; - -import static org.springframework.web.bind.annotation.RequestMethod.POST; - -@Controller -public class FraudDetectionXmlController { - - @RequestMapping(value = "/xmlfraud", method = POST, consumes = MediaType.APPLICATION_XML_VALUE, produces = MediaType.APPLICATION_XML_VALUE) - @ResponseBody - public XmlResponseBody xmlResponseBody(@RequestBody XmlRequestBody xmlRequestBody) { - if (!StringUtils.hasText(xmlRequestBody.name)) { - return new XmlResponseBody("EMPTY"); - } - return new XmlResponseBody("FULL"); - } - -} - -class XmlRequestBody { - - public String name; - -} - -class XmlResponseBody { - - public String status; - - public XmlResponseBody(String status) { - this.status = status; - } - - public XmlResponseBody() { - } - -} diff --git a/samples/standalone/restdocs/http-server/src/main/java/com/example/fraud/model/FraudCheck.java b/samples/standalone/restdocs/http-server/src/main/java/com/example/fraud/model/FraudCheck.java deleted file mode 100644 index 4cf6ae3ea2..0000000000 --- a/samples/standalone/restdocs/http-server/src/main/java/com/example/fraud/model/FraudCheck.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud.model; - -import java.math.BigDecimal; - -public class FraudCheck { - - private String clientId; - - private BigDecimal loanAmount; - - public FraudCheck() { - } - - public String getClientId() { - return clientId; - } - - public void setClientId(String clientId) { - this.clientId = clientId; - } - - public BigDecimal getLoanAmount() { - return loanAmount; - } - - public void setLoanAmount(BigDecimal loanAmount) { - this.loanAmount = loanAmount; - } - -} diff --git a/samples/standalone/restdocs/http-server/src/main/java/com/example/fraud/model/FraudCheckResult.java b/samples/standalone/restdocs/http-server/src/main/java/com/example/fraud/model/FraudCheckResult.java deleted file mode 100644 index 95440c6790..0000000000 --- a/samples/standalone/restdocs/http-server/src/main/java/com/example/fraud/model/FraudCheckResult.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud.model; - -public class FraudCheckResult { - - private FraudCheckStatus fraudCheckStatus; - - private String rejectionReason; - - public FraudCheckResult() { - } - - public FraudCheckResult(FraudCheckStatus fraudCheckStatus, String rejectionReason) { - this.fraudCheckStatus = fraudCheckStatus; - this.rejectionReason = rejectionReason; - } - - public FraudCheckStatus getFraudCheckStatus() { - return fraudCheckStatus; - } - - public void setFraudCheckStatus(FraudCheckStatus fraudCheckStatus) { - this.fraudCheckStatus = fraudCheckStatus; - } - - public String getRejectionReason() { - return rejectionReason; - } - - public void setRejectionReason(String rejectionReason) { - this.rejectionReason = rejectionReason; - } - -} diff --git a/samples/standalone/restdocs/http-server/src/main/java/com/example/fraud/model/FraudCheckStatus.java b/samples/standalone/restdocs/http-server/src/main/java/com/example/fraud/model/FraudCheckStatus.java deleted file mode 100644 index a43b649f5c..0000000000 --- a/samples/standalone/restdocs/http-server/src/main/java/com/example/fraud/model/FraudCheckStatus.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud.model; - -public enum FraudCheckStatus { - - OK, FRAUD - -} diff --git a/samples/standalone/restdocs/http-server/src/test/java/com/example/fraud/FraudBaseWithStandaloneSetup.java b/samples/standalone/restdocs/http-server/src/test/java/com/example/fraud/FraudBaseWithStandaloneSetup.java deleted file mode 100644 index 5af34819b5..0000000000 --- a/samples/standalone/restdocs/http-server/src/test/java/com/example/fraud/FraudBaseWithStandaloneSetup.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// tag::base_class[] -package com.example.fraud; - -import io.restassured.module.mockmvc.RestAssuredMockMvc; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.TestInfo; -import org.junit.jupiter.api.extension.ExtendWith; - -import org.springframework.restdocs.RestDocumentationContextProvider; -import org.springframework.restdocs.RestDocumentationExtension; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; - -@ExtendWith(RestDocumentationExtension.class) -public abstract class FraudBaseWithStandaloneSetup { - - @BeforeEach - public void setup(TestInfo info, RestDocumentationContextProvider restDocumentation) { - RestAssuredMockMvc.standaloneSetup(MockMvcBuilders - .standaloneSetup(new FraudDetectionController()) - .apply(documentationConfiguration(restDocumentation)) - .alwaysDo(document( - getClass().getSimpleName() + "_" + info.getDisplayName()))); - } - -} -// end::base_class[] diff --git a/samples/standalone/restdocs/http-server/src/test/java/com/example/fraud/FraudBaseWithWebAppSetup.java b/samples/standalone/restdocs/http-server/src/test/java/com/example/fraud/FraudBaseWithWebAppSetup.java deleted file mode 100644 index 5a7e68a9ba..0000000000 --- a/samples/standalone/restdocs/http-server/src/test/java/com/example/fraud/FraudBaseWithWebAppSetup.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// tag::base_class[] -package com.example.fraud; - -import io.restassured.module.mockmvc.RestAssuredMockMvc; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.TestInfo; -import org.junit.jupiter.api.extension.ExtendWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.restdocs.RestDocumentationContextProvider; -import org.springframework.restdocs.RestDocumentationExtension; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; - -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; - -@ExtendWith(RestDocumentationExtension.class) -@SpringBootTest(classes = Application.class) -public abstract class FraudBaseWithWebAppSetup { - - @Autowired - private WebApplicationContext context; - - @BeforeEach - public void setup(TestInfo info, RestDocumentationContextProvider restDocumentation) { - RestAssuredMockMvc.mockMvc(MockMvcBuilders.webAppContextSetup(this.context) - .apply(documentationConfiguration(restDocumentation)) - .alwaysDo(document( - getClass().getSimpleName() + "_" + info.getDisplayName())) - .build()); - } - - protected void assertThatRejectionReasonIsNull(Object rejectionReason) { - assert rejectionReason == null; - } - -} -// end::base_class[] diff --git a/samples/standalone/restdocs/http-server/src/test/java/com/example/fraud/StubGeneratorTests.java b/samples/standalone/restdocs/http-server/src/test/java/com/example/fraud/StubGeneratorTests.java deleted file mode 100644 index e159ec787a..0000000000 --- a/samples/standalone/restdocs/http-server/src/test/java/com/example/fraud/StubGeneratorTests.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud; - -import java.math.BigDecimal; - -import com.example.fraud.model.FraudCheck; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters; -import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.json.JacksonTester; -import org.springframework.http.MediaType; - -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; - -import static org.springframework.cloud.contract.wiremock.restdocs.WireMockRestDocs.verify; -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; - -@SpringBootTest(classes = Application.class) -@AutoConfigureRestDocs(outputDir = "target/snippets") -@AutoConfigureMockMvc -@AutoConfigureJsonTesters -public class StubGeneratorTests { - - @Autowired - private MockMvc mockMvc; - - private JacksonTester json; - - @BeforeEach - public void setup() { - ObjectMapper objectMappper = new ObjectMapper(); - // Possibly configure the mapper - JacksonTester.initFields(this, objectMappper); - } - - @Test - public void shouldMarkClientAsFraud() throws Exception { - FraudCheck fraudCheck = new FraudCheck(); - fraudCheck.setClientId("1234567890"); - fraudCheck.setLoanAmount(BigDecimal.valueOf(99999.0)); - mockMvc.perform(MockMvcRequestBuilders.put("/fraudcheck") - .contentType(MediaType.valueOf("application/vnd.fraud.v1+json")) - .content(json.write(fraudCheck).getJson())) - .andExpect(jsonPath("$.fraudCheckStatus").value("FRAUD")) - .andExpect(jsonPath("$.rejectionReason").value("Amount too high")) - .andDo(verify().jsonPath("$.clientId") - .jsonPath("$[?(@.loanAmount > 1000)]") - .contentType(MediaType.valueOf("application/vnd.fraud.v1+json"))) - .andDo(document("markClientAsFraud")); - } - - @Test - public void shouldMarkClientAsNotFraud() throws Exception { - FraudCheck fraudCheck = new FraudCheck(); - fraudCheck.setClientId("1234567890"); - fraudCheck.setLoanAmount(BigDecimal.valueOf(123.123)); - mockMvc.perform(MockMvcRequestBuilders.put("/fraudcheck") - .contentType(MediaType.valueOf("application/vnd.fraud.v1+json")) - .content(json.write(fraudCheck).getJson())) - .andExpect(jsonPath("$.fraudCheckStatus").value("OK")) - .andExpect(jsonPath("$.rejectionReason").doesNotExist()) - .andDo(verify().jsonPath("$.clientId") - .jsonPath("$[?(@.loanAmount <= 1000)]") - .contentType(MediaType.valueOf("application/vnd.fraud.v1+json"))) - .andDo(document("markClientAsNotFraud")); - } - -} diff --git a/samples/standalone/restdocs/http-server/src/test/java/com/example/fraud/XmlStubGeneratorTests.java b/samples/standalone/restdocs/http-server/src/test/java/com/example/fraud/XmlStubGeneratorTests.java deleted file mode 100644 index 610573ee41..0000000000 --- a/samples/standalone/restdocs/http-server/src/test/java/com/example/fraud/XmlStubGeneratorTests.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud; - -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.MediaType; -import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation; - -import org.springframework.test.web.servlet.MockMvc; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@SpringBootTest(classes = Application.class) -@AutoConfigureRestDocs(outputDir = "target/snippets") -@AutoConfigureMockMvc -class XmlStubGeneratorTests { - - @Autowired - private MockMvc mockMvc; - - @Test - void should_return_full_content() throws Exception { - mockMvc.perform(post("/xmlfraud").contentType(MediaType.APPLICATION_XML) - .content("foo")) - .andExpect(status().is2xxSuccessful()) - .andExpect(content().string( - "FULL")) - .andDo(MockMvcRestDocumentation.document("{methodName}")); - } - - @Test - void should_return_empty_content() throws Exception { - mockMvc.perform(post("/xmlfraud").contentType(MediaType.APPLICATION_XML) - .content("")) - .andExpect(status().is2xxSuccessful()) - .andExpect(content().string( - "EMPTY")) - .andDo(MockMvcRestDocumentation.document("{methodName}")); - } - -} diff --git a/samples/standalone/restdocs/http-server/src/test/resources/contracts/standalone/shouldMarkClientAsFraud.groovy b/samples/standalone/restdocs/http-server/src/test/resources/contracts/standalone/shouldMarkClientAsFraud.groovy deleted file mode 100644 index ca4e321816..0000000000 --- a/samples/standalone/restdocs/http-server/src/test/resources/contracts/standalone/shouldMarkClientAsFraud.groovy +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.standalone - -org.springframework.cloud.contract.spec.Contract.make { - request { // (1) - method 'PUT' // (2) - url '/fraudcheck' // (3) - body([ // (4) - clientId : $(c(regex('[0-9]{10}')), p("8532032713")), - loanAmount: 99999 - ]) - headers { // (5) - contentType('application/vnd.fraud.v1+json') - } - } - response { // (6) - status OK() // (7) - body([ // (8) - fraudCheckStatus: "FRAUD", - rejectionReason : "Amount too high" - ]) - headers { // (9) - contentType('application/vnd.fraud.v1+json') - } - } -} - -/* -Since we don't want to force on the user to hardcode values of fields that are dynamic -(timestamps, database ids etc.), one can parametrize those entries. If you wrap your field's - value in a `$(...)` or `value(...)` and provide a dynamic value of a field then - the concrete value will be generated for you. If you want to be really explicit about - which side gets which value you can do that by using the `value(consumer(...), producer(...))` notation. - That way what's present in the `consumer` section will end up in the produced stub. What's - there in the `producer` will end up in the autogenerated test. If you provide only the - regular expression side without the concrete value then Spring Cloud Contract will generate one for you. - -From the Consumer perspective, when shooting a request in the integration test: - -(1) - If the consumer sends a request -(2) - With the "PUT" method -(3) - to the URL "/fraudcheck" -(4) - with the JSON body that - * has a field `clientId` that matches a regular expression `[0-9]{10}` - * has a field `loanAmount` that is equal to `99999` -(5) - with header `Content-Type` equal to `application/vnd.fraud.v1+json` -(6) - then the response will be sent with -(7) - status equal `200` -(8) - and JSON body equal to - { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" } -(9) - with header `Content-Type` equal to `application/vnd.fraud.v1+json` - -From the Producer perspective, in the autogenerated producer-side test: - -(1) - A request will be sent to the producer -(2) - With the "PUT" method -(3) - to the URL "/fraudcheck" -(4) - with the JSON body that - * has a field `clientId` that will have a generated value that matches a regular expression `[0-9]{10}` - * has a field `loanAmount` that is equal to `99999` -(5) - with header `Content-Type` equal to `application/vnd.fraud.v1+json` -(6) - then the test will assert if the response has been sent with -(7) - status equal `200` -(8) - and JSON body equal to - { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" } -(9) - with header `Content-Type` matching `application/vnd.fraud.v1+json.*` - */ diff --git a/samples/standalone/restdocs/http-server/src/test/resources/contracts/webapp/shouldMarkClientAsNotFraud.groovy b/samples/standalone/restdocs/http-server/src/test/resources/contracts/webapp/shouldMarkClientAsNotFraud.groovy deleted file mode 100644 index ec4dc73cc5..0000000000 --- a/samples/standalone/restdocs/http-server/src/test/resources/contracts/webapp/shouldMarkClientAsNotFraud.groovy +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.webapp - -org.springframework.cloud.contract.spec.Contract.make { - request { - method 'PUT' - url '/fraudcheck' - body(""" - { - "clientId":"${value(consumer(regex('[0-9]{10}')), producer('1234567890'))}", - "loanAmount":123.123 - } - """ - ) - headers { - contentType("application/vnd.fraud.v1+json") - } - - } - response { - status OK() - body( - fraudCheckStatus: "OK", - rejectionReason: $(consumer(null), - producer(execute('assertThatRejectionReasonIsNull($it)'))) - ) - headers { - contentType("application/vnd.fraud.v1+json") - } - } -} diff --git a/samples/standalone/restdocs/pom.xml b/samples/standalone/restdocs/pom.xml deleted file mode 100644 index 0b93129b0d..0000000000 --- a/samples/standalone/restdocs/pom.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - 4.0.0 - - - org.springframework.cloud - spring-cloud-contract-samples-standalone - 4.1.0-SNAPSHOT - .. - - - spring-cloud-contract-samples-restdocs - pom - - Spring Cloud Contract Standalone Restdocs Test Samples - Spring Cloud Contract Standalone Test Samples used for end to end tests - - - - 4.1.0-SNAPSHOT - - - - http-server - http-client - - - - - - maven-deploy-plugin - 2.8.2 - - true - - - - - - diff --git a/samples/standalone/webclient/build.log b/samples/standalone/webclient/build.log new file mode 100644 index 0000000000..a25a02cf4c --- /dev/null +++ b/samples/standalone/webclient/build.log @@ -0,0 +1,477 @@ +[INFO] Scanning for projects... +[INFO] ------------------------------------------------------------------------ +[INFO] Reactor Build Order: +[INFO] +[INFO] Spring Cloud Contract RestDocs Http Server Sample [jar] +[INFO] Spring Cloud Contract RestDocs Http WebClient Sample [jar] +[INFO] Spring Cloud Contract Standalone Restdocs Test Samples [pom] +[INFO] +[INFO] -----------------< com.example:http-server-webclient >------------------ +[INFO] Building Spring Cloud Contract RestDocs Http Server Sample 0.0.1 [1/3] +[INFO] --------------------------------[ jar ]--------------------------------- +[INFO] +[INFO] --- maven-clean-plugin:3.3.1:clean (default-clean) @ http-server-webclient --- +[INFO] Deleting /home/marcin/repo/spring-cloud-contract/samples/standalone/webclient/http-server/target +[INFO] +[INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ http-server-webclient --- +[INFO] Copying 1 resource from src/main/resources to target/classes +[INFO] Copying 0 resource from src/main/resources to target/classes +[INFO] +[INFO] --- maven-compiler-plugin:3.11.0:compile (default-compile) @ http-server-webclient --- +[INFO] Changes detected - recompiling the module! :source +[INFO] Compiling 5 source files with javac [debug release 17] to target/classes +[INFO] +[INFO] --- maven-resources-plugin:3.3.1:testResources (default-testResources) @ http-server-webclient --- +[INFO] skip non existing resourceDirectory /home/marcin/repo/spring-cloud-contract/samples/standalone/webclient/http-server/src/test/resources +[INFO] +[INFO] --- maven-compiler-plugin:3.11.0:testCompile (default-testCompile) @ http-server-webclient --- +[INFO] Changes detected - recompiling the module! :dependency +[INFO] Compiling 1 source file with javac [debug release 17] to target/test-classes +[INFO] /home/marcin/repo/spring-cloud-contract/samples/standalone/webclient/http-server/src/test/java/com/example/fraud/StubGeneratorTests.java: /home/marcin/repo/spring-cloud-contract/samples/standalone/webclient/http-server/src/test/java/com/example/fraud/StubGeneratorTests.java uses or overrides a deprecated API. +[INFO] /home/marcin/repo/spring-cloud-contract/samples/standalone/webclient/http-server/src/test/java/com/example/fraud/StubGeneratorTests.java: Recompile with -Xlint:deprecation for details. +[INFO] +[INFO] --- maven-surefire-plugin:3.1.2:test (default-test) @ http-server-webclient --- +[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider +[INFO] +[INFO] ------------------------------------------------------- +[INFO] T E S T S +[INFO] ------------------------------------------------------- +[INFO] Running com.example.fraud.StubGeneratorTests + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v3.2.0-SNAPSHOT) + +2023-09-06T14:30:05.020+02:00 INFO 208298 --- [ main] com.example.fraud.StubGeneratorTests : Starting StubGeneratorTests using Java 17.0.1 with PID 208298 (started by marcin in /home/marcin/repo/spring-cloud-contract/samples/standalone/webclient/http-server) +2023-09-06T14:30:05.024+02:00 INFO 208298 --- [ main] com.example.fraud.StubGeneratorTests : No active profile set, falling back to 1 default profile: "default" +2023-09-06T14:30:05.979+02:00 INFO 208298 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 1 endpoint(s) beneath base path '/actuator' +2023-09-06T14:30:06.317+02:00 INFO 208298 --- [ main] com.example.fraud.StubGeneratorTests : Started StubGeneratorTests in 1.495 seconds (process running for 2.22) +OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended +[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.718 s -- in com.example.fraud.StubGeneratorTests +[INFO] +[INFO] Results: +[INFO] +[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 +[INFO] +[INFO] +[INFO] --- maven-assembly-plugin:3.6.0:single (stub) @ http-server-webclient --- +[INFO] Reading assembly descriptor: /home/marcin/repo/spring-cloud-contract/samples/standalone/webclient/http-server/src/assembly/stub.xml +[INFO] Building jar: /home/marcin/repo/spring-cloud-contract/samples/standalone/webclient/http-server/target/http-server-webclient-0.0.1-stubs.jar +[INFO] +[INFO] --- maven-jar-plugin:3.3.0:jar (default-jar) @ http-server-webclient --- +[INFO] Building jar: /home/marcin/repo/spring-cloud-contract/samples/standalone/webclient/http-server/target/http-server-webclient-0.0.1.jar +[INFO] +[INFO] --- spring-boot-maven-plugin:3.2.0-SNAPSHOT:repackage (repackage) @ http-server-webclient --- +[INFO] Replacing main artifact /home/marcin/repo/spring-cloud-contract/samples/standalone/webclient/http-server/target/http-server-webclient-0.0.1.jar with repackaged archive, adding nested dependencies in BOOT-INF/. +[INFO] The original artifact has been renamed to /home/marcin/repo/spring-cloud-contract/samples/standalone/webclient/http-server/target/http-server-webclient-0.0.1.jar.original +[INFO] +[INFO] --- maven-install-plugin:3.1.1:install (default-install) @ http-server-webclient --- +[INFO] Installing /home/marcin/repo/spring-cloud-contract/samples/standalone/webclient/http-server/pom.xml to /home/marcin/.m2/repository/com/example/http-server-webclient/0.0.1/http-server-webclient-0.0.1.pom +[INFO] Installing /home/marcin/repo/spring-cloud-contract/samples/standalone/webclient/http-server/target/http-server-webclient-0.0.1.jar to /home/marcin/.m2/repository/com/example/http-server-webclient/0.0.1/http-server-webclient-0.0.1.jar +[INFO] Installing /home/marcin/repo/spring-cloud-contract/samples/standalone/webclient/http-server/target/http-server-webclient-0.0.1-stubs.jar to /home/marcin/.m2/repository/com/example/http-server-webclient/0.0.1/http-server-webclient-0.0.1-stubs.jar +[INFO] +[INFO] -----------------< com.example:http-client-webclient >------------------ +[INFO] Building Spring Cloud Contract RestDocs Http WebClient Sample 0.0.1 [2/3] +[INFO] --------------------------------[ jar ]--------------------------------- +[INFO] Downloading from local.central: file:///home/marcin/.m2/repository/org/springframework/boot/spring-boot-configuration-processor/3.2.0-SNAPSHOT/maven-metadata.xml +[INFO] +[INFO] --- maven-clean-plugin:3.3.1:clean (default-clean) @ http-client-webclient --- +[INFO] Deleting /home/marcin/repo/spring-cloud-contract/samples/standalone/webclient/http-client/target +[INFO] +[INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ http-client-webclient --- +[INFO] Copying 1 resource from src/main/resources to target/classes +[INFO] Copying 0 resource from src/main/resources to target/classes +[INFO] +[INFO] --- maven-compiler-plugin:3.11.0:compile (default-compile) @ http-client-webclient --- +[INFO] Changes detected - recompiling the module! :source +[INFO] Compiling 9 source files with javac [debug release 17] to target/classes +[INFO] +[INFO] --- maven-resources-plugin:3.3.1:testResources (default-testResources) @ http-client-webclient --- +[INFO] Copying 1 resource from src/test/resources to target/test-classes +[INFO] +[INFO] --- maven-compiler-plugin:3.11.0:testCompile (default-testCompile) @ http-client-webclient --- +[INFO] Changes detected - recompiling the module! :dependency +[INFO] Compiling 3 source files with javac [debug release 17] to target/test-classes +[INFO] +[INFO] --- maven-surefire-plugin:3.1.2:test (default-test) @ http-client-webclient --- +[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider +[INFO] +[INFO] ------------------------------------------------------- +[INFO] T E S T S +[INFO] ------------------------------------------------------- +[INFO] Running com.example.loan.LoanApplicationServiceusingStubRunnerTests +14:30:08.651 [main] INFO org.springframework.test.context.support.AnnotationConfigContextLoaderUtils -- Could not detect default configuration classes for test class [com.example.loan.LoanApplicationServiceusingStubRunnerTests]: LoanApplicationServiceusingStubRunnerTests does not declare any static, non-private, non-final, nested classes annotated with @Configuration. +14:30:08.719 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper -- Found @SpringBootConfiguration com.example.loan.Application for test class com.example.loan.LoanApplicationServiceusingStubRunnerTests + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v3.2.0-SNAPSHOT) + +2023-09-06T14:30:08.951+02:00 INFO 208420 --- [ main] anApplicationServiceusingStubRunnerTests : Starting LoanApplicationServiceusingStubRunnerTests using Java 17.0.1 with PID 208420 (started by marcin in /home/marcin/repo/spring-cloud-contract/samples/standalone/webclient/http-client) +2023-09-06T14:30:08.952+02:00 INFO 208420 --- [ main] anApplicationServiceusingStubRunnerTests : No active profile set, falling back to 1 default profile: "default" +2023-09-06T14:30:09.603+02:00 WARN 208420 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration' of type [org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). The currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor] is declared through a non-static factory method on that class; consider declaring it as static instead. +2023-09-06T14:30:09.616+02:00 WARN 208420 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'stubrunner-org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties' of type [org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:30:09.620+02:00 INFO 208420 --- [ main] o.s.c.c.s.ClasspathStubProvider : Will download stubs from classpath +2023-09-06T14:30:09.657+02:00 INFO 208420 --- [ main] .s.c.c.s.ResourceResolvingStubDownloader : Unpacked files for [com.example:http-server-webclient:+] to folder [/tmp/classpath-stubs-1694003409651-0] +2023-09-06T14:30:10.235+02:00 INFO 208420 --- [tp1178861747-39] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [225] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "580c4bd5-4ae9-4395-acdb-45689c43c5cc", + "request" : { + "url" : "/ping", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "OK" + }, + "uuid" : "580c4bd5-4ae9-4395-acdb-45689c43c5cc" +} + +2023-09-06T14:30:10.248+02:00 INFO 208420 --- [tp1178861747-32] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [227] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "7f923a77-9c09-4507-b0af-2dfc09e68c60", + "request" : { + "url" : "/health", + "method" : "GET" + }, + "response" : { + "status" : 200, + "body" : "OK" + }, + "uuid" : "7f923a77-9c09-4507-b0af-2dfc09e68c60" +} + +2023-09-06T14:30:10.255+02:00 INFO 208420 --- [tp1178861747-38] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [622] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "2dfb487b-c23b-447d-892c-e89e66f21547", + "request" : { + "urlPath" : "/fraudcheck", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "matches" : "\\Qapplication/vnd.fraud.v1+json\\E.*" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$.clientId" + }, { + "matchesJsonPath" : "$[?(@.loanAmount <= 1000)]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"OK\",\"rejectionReason\":null}", + "headers" : { + "Content-Type" : "application/vnd.fraud.v1+json" + } + }, + "uuid" : "2dfb487b-c23b-447d-892c-e89e66f21547" +} + +2023-09-06T14:30:10.260+02:00 INFO 208420 --- [tp1178861747-39] WireMock : Admin request received: +127.0.0.1 - POST /mappings + +Host: [] +Content-Length: [639] +Content-Type: [text/plain; charset=UTF-8] +Connection: [keep-alive] +User-Agent: [Apache-HttpClient/5.1.3 (Java/17.0.1)] +{ + "id" : "9fa5dc20-a0d2-40fb-badb-4dc89ff73236", + "request" : { + "urlPath" : "/fraudcheck", + "method" : "PUT", + "headers" : { + "Content-Type" : { + "matches" : "\\Qapplication/vnd.fraud.v1+json\\E.*" + } + }, + "bodyPatterns" : [ { + "matchesJsonPath" : "$.clientId" + }, { + "matchesJsonPath" : "$[?(@.loanAmount > 1000)]" + } ] + }, + "response" : { + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"FRAUD\",\"rejectionReason\":\"Amount too high\"}", + "headers" : { + "Content-Type" : "application/vnd.fraud.v1+json" + } + }, + "uuid" : "9fa5dc20-a0d2-40fb-badb-4dc89ff73236" +} + +2023-09-06T14:30:10.264+02:00 INFO 208420 --- [ main] o.s.c.contract.stubrunner.StubServer : Started stub server for project [com.example:http-server-webclient:+:stubs] on port 13186 with [2] mappings +2023-09-06T14:30:10.264+02:00 INFO 208420 --- [ main] o.s.c.c.stubrunner.StubRunnerExecutor : All stubs are now running RunningStubs [namesAndPorts={com.example:http-server-webclient:+:stubs=13186}] +2023-09-06T14:30:10.265+02:00 WARN 208420 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'batchStubRunner' of type [org.springframework.cloud.contract.stubrunner.BatchStubRunner] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [batchStubRunnerBeanPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies. +2023-09-06T14:30:10.736+02:00 INFO 208420 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 1 endpoint(s) beneath base path '/actuator' +2023-09-06T14:30:10.761+02:00 INFO 208420 --- [ main] o.s.c.c.v.m.i.ContractVerifierMessaging : The message verifier sender implementation is of type [class org.springframework.cloud.contract.verifier.messaging.noop.NoOpStubMessages] +2023-09-06T14:30:10.762+02:00 INFO 208420 --- [ main] o.s.c.c.v.m.i.ContractVerifierMessaging : The message verifier receiver implementation is of type [class org.springframework.cloud.contract.verifier.messaging.noop.NoOpStubMessages] +2023-09-06T14:30:10.803+02:00 INFO 208420 --- [ main] anApplicationServiceusingStubRunnerTests : Started LoanApplicationServiceusingStubRunnerTests in 2.015 seconds (process running for 2.579) +OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended +2023-09-06T14:30:11.413+02:00 DEBUG 208420 --- [ main] o.s.web.client.RestTemplate : HTTP PUT http://localhost:13186/fraudcheck +2023-09-06T14:30:11.437+02:00 DEBUG 208420 --- [ main] o.s.web.client.RestTemplate : Accept=[application/json, application/*+json] +2023-09-06T14:30:11.444+02:00 DEBUG 208420 --- [ main] o.s.web.client.RestTemplate : Writing [com.example.loan.model.FraudServiceRequest@18cb4ed1] as "application/vnd.fraud.v1+json" +2023-09-06T14:30:11.472+02:00 INFO 208420 --- [tp1178861747-37] WireMock : Request received: +127.0.0.1 - PUT /fraudcheck + +Accept: [application/json, application/*+json] +Content-Type: [application/vnd.fraud.v1+json] +User-Agent: [Java/17.0.1] +Host: [localhost:13186] +Connection: [keep-alive] +Transfer-Encoding: [chunked] +{"clientId":"1234567890","loanAmount":123.123} + + +Matched response definition: +{ + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"OK\",\"rejectionReason\":null}", + "headers" : { + "Content-Type" : "application/vnd.fraud.v1+json" + } +} + +Response: +HTTP/1.1 200 +Content-Type: [application/vnd.fraud.v1+json] +Matched-Stub-Id: [2dfb487b-c23b-447d-892c-e89e66f21547] + +2023-09-06T14:30:11.474+02:00 DEBUG 208420 --- [ main] o.s.web.client.RestTemplate : Response 200 OK +2023-09-06T14:30:11.475+02:00 DEBUG 208420 --- [ main] o.s.web.client.RestTemplate : Reading to [com.example.loan.model.FraudServiceResponse] +2023-09-06T14:30:11.516+02:00 DEBUG 208420 --- [ main] o.s.web.client.RestTemplate : HTTP PUT http://localhost:13186/fraudcheck +2023-09-06T14:30:11.517+02:00 DEBUG 208420 --- [ main] o.s.web.client.RestTemplate : Accept=[application/json, application/*+json] +2023-09-06T14:30:11.517+02:00 DEBUG 208420 --- [ main] o.s.web.client.RestTemplate : Writing [com.example.loan.model.FraudServiceRequest@1f27f354] as "application/vnd.fraud.v1+json" +2023-09-06T14:30:11.518+02:00 INFO 208420 --- [tp1178861747-38] WireMock : Request received: +127.0.0.1 - PUT /fraudcheck + +Accept: [application/json, application/*+json] +Content-Type: [application/vnd.fraud.v1+json] +User-Agent: [Java/17.0.1] +Host: [localhost:13186] +Connection: [keep-alive] +Transfer-Encoding: [chunked] +{"clientId":"1234567890","loanAmount":99999.0} + + +Matched response definition: +{ + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"FRAUD\",\"rejectionReason\":\"Amount too high\"}", + "headers" : { + "Content-Type" : "application/vnd.fraud.v1+json" + } +} + +Response: +HTTP/1.1 200 +Content-Type: [application/vnd.fraud.v1+json] +Matched-Stub-Id: [9fa5dc20-a0d2-40fb-badb-4dc89ff73236] + +2023-09-06T14:30:11.519+02:00 DEBUG 208420 --- [ main] o.s.web.client.RestTemplate : Response 200 OK +2023-09-06T14:30:11.519+02:00 DEBUG 208420 --- [ main] o.s.web.client.RestTemplate : Reading to [com.example.loan.model.FraudServiceResponse] +[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.963 s -- in com.example.loan.LoanApplicationServiceusingStubRunnerTests +[INFO] Running com.example.loan.LoanApplicationServiceTests +2023-09-06T14:30:11.528+02:00 INFO 208420 --- [ main] t.c.s.AnnotationConfigContextLoaderUtils : Could not detect default configuration classes for test class [com.example.loan.LoanApplicationServiceTests]: LoanApplicationServiceTests does not declare any static, non-private, non-final, nested classes annotated with @Configuration. +2023-09-06T14:30:11.529+02:00 INFO 208420 --- [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.example.loan.Application for test class com.example.loan.LoanApplicationServiceTests + + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v3.2.0-SNAPSHOT) + +2023-09-06T14:30:11.548+02:00 INFO 208420 --- [ main] c.e.loan.LoanApplicationServiceTests : Starting LoanApplicationServiceTests using Java 17.0.1 with PID 208420 (started by marcin in /home/marcin/repo/spring-cloud-contract/samples/standalone/webclient/http-client) +2023-09-06T14:30:11.548+02:00 INFO 208420 --- [ main] c.e.loan.LoanApplicationServiceTests : No active profile set, falling back to 1 default profile: "default" +2023-09-06T14:30:11.885+02:00 INFO 208420 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 1 endpoint(s) beneath base path '/actuator' +2023-09-06T14:30:11.911+02:00 INFO 208420 --- [ main] c.e.loan.LoanApplicationServiceTests : Started LoanApplicationServiceTests in 0.38 seconds (process running for 3.688) +2023-09-06T14:30:11.922+02:00 DEBUG 208420 --- [ main] o.s.web.client.RestTemplate : HTTP PUT http://localhost:11915/fraudcheck +2023-09-06T14:30:11.923+02:00 DEBUG 208420 --- [ main] o.s.web.client.RestTemplate : Accept=[application/json, application/*+json] +2023-09-06T14:30:11.924+02:00 DEBUG 208420 --- [ main] o.s.web.client.RestTemplate : Writing [com.example.loan.model.FraudServiceRequest@823f978] as "application/vnd.fraud.v1+json" +2023-09-06T14:30:11.929+02:00 INFO 208420 --- [tp1254252690-46] WireMock : Request received: +127.0.0.1 - PUT /fraudcheck + +Accept: [application/json, application/*+json] +Content-Type: [application/vnd.fraud.v1+json] +User-Agent: [Java/17.0.1] +Host: [localhost:11915] +Connection: [keep-alive] +Transfer-Encoding: [chunked] +{"clientId":"1234567890","loanAmount":123.123} + + +Matched response definition: +{ + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"OK\",\"rejectionReason\":null}", + "headers" : { + "Content-Type" : "application/vnd.fraud.v1+json" + } +} + +Response: +HTTP/1.1 200 +Content-Type: [application/vnd.fraud.v1+json] +Matched-Stub-Id: [2dfb487b-c23b-447d-892c-e89e66f21547] + +2023-09-06T14:30:11.930+02:00 DEBUG 208420 --- [ main] o.s.web.client.RestTemplate : Response 200 OK +2023-09-06T14:30:11.930+02:00 DEBUG 208420 --- [ main] o.s.web.client.RestTemplate : Reading to [com.example.loan.model.FraudServiceResponse] +2023-09-06T14:30:11.938+02:00 DEBUG 208420 --- [ main] o.s.web.client.RestTemplate : HTTP PUT http://localhost:11915/fraudcheck +2023-09-06T14:30:11.938+02:00 DEBUG 208420 --- [ main] o.s.web.client.RestTemplate : Accept=[application/json, application/*+json] +2023-09-06T14:30:11.938+02:00 DEBUG 208420 --- [ main] o.s.web.client.RestTemplate : Writing [com.example.loan.model.FraudServiceRequest@7894a250] as "application/vnd.fraud.v1+json" +2023-09-06T14:30:11.940+02:00 INFO 208420 --- [tp1254252690-55] WireMock : Request received: +127.0.0.1 - PUT /fraudcheck + +Accept: [application/json, application/*+json] +Content-Type: [application/vnd.fraud.v1+json] +User-Agent: [Java/17.0.1] +Host: [localhost:11915] +Connection: [keep-alive] +Transfer-Encoding: [chunked] +{"clientId":"1234567890","loanAmount":99999.0} + + +Matched response definition: +{ + "status" : 200, + "body" : "{\"fraudCheckStatus\":\"FRAUD\",\"rejectionReason\":\"Amount too high\"}", + "headers" : { + "Content-Type" : "application/vnd.fraud.v1+json" + } +} + +Response: +HTTP/1.1 200 +Content-Type: [application/vnd.fraud.v1+json] +Matched-Stub-Id: [9fa5dc20-a0d2-40fb-badb-4dc89ff73236] + +2023-09-06T14:30:11.941+02:00 DEBUG 208420 --- [ main] o.s.web.client.RestTemplate : Response 200 OK +2023-09-06T14:30:11.941+02:00 DEBUG 208420 --- [ main] o.s.web.client.RestTemplate : Reading to [com.example.loan.model.FraudServiceResponse] +[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.428 s -- in com.example.loan.LoanApplicationServiceTests +[INFO] +[INFO] Results: +[INFO] +[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0 +[INFO] +[INFO] +[INFO] --- exec-maven-plugin:1.6.0:exec (gradle) @ http-client-webclient --- +To honour the JVM settings for this build a single-use Daemon process will be forked. For more on this, please refer to https://docs.gradle.org/8.3/userguide/gradle_daemon.html#sec:disabling_the_daemon in the Gradle documentation. +Daemon will be stopped at the end of the build +> Task :clean +> Task :compileJava +> Task :compileGroovy NO-SOURCE +> Task :processResources +> Task :classes +> Task :resolveMainClassName +> Task :bootJar +> Task :jar +> Task :assemble +> Task :check +> Task :build +> Task :publishToMavenLocal UP-TO-DATE + +BUILD SUCCESSFUL in 6s +6 actionable tasks: 6 executed +[INFO] +[INFO] --- maven-jar-plugin:3.3.0:jar (default-jar) @ http-client-webclient --- +[INFO] Building jar: /home/marcin/repo/spring-cloud-contract/samples/standalone/webclient/http-client/target/http-client-webclient-0.0.1.jar +[INFO] +[INFO] --- spring-boot-maven-plugin:3.2.0-SNAPSHOT:repackage (repackage) @ http-client-webclient --- +[INFO] Replacing main artifact /home/marcin/repo/spring-cloud-contract/samples/standalone/webclient/http-client/target/http-client-webclient-0.0.1.jar with repackaged archive, adding nested dependencies in BOOT-INF/. +[INFO] The original artifact has been renamed to /home/marcin/repo/spring-cloud-contract/samples/standalone/webclient/http-client/target/http-client-webclient-0.0.1.jar.original +[INFO] +[INFO] --- maven-install-plugin:3.1.1:install (default-install) @ http-client-webclient --- +[INFO] Installing /home/marcin/repo/spring-cloud-contract/samples/standalone/webclient/http-client/pom.xml to /home/marcin/.m2/repository/com/example/http-client-webclient/0.0.1/http-client-webclient-0.0.1.pom +[INFO] Installing /home/marcin/repo/spring-cloud-contract/samples/standalone/webclient/http-client/target/http-client-webclient-0.0.1.jar to /home/marcin/.m2/repository/com/example/http-client-webclient/0.0.1/http-client-webclient-0.0.1.jar +[INFO] +[INFO] --< org.springframework.cloud:spring-cloud-contract-samples-webclient >-- +[INFO] Building Spring Cloud Contract Standalone Restdocs Test Samples 4.1.0-SNAPSHOT [3/3] +[INFO] --------------------------------[ pom ]--------------------------------- +[INFO] Downloading from maven-default-http-blocker: http://0.0.0.0/org/slf4j/slf4j-api/maven-metadata.xml +[WARNING] Could not transfer metadata org.slf4j:slf4j-api/maven-metadata.xml from/to maven-default-http-blocker (http://0.0.0.0/): transfer failed for http://0.0.0.0/org/slf4j/slf4j-api/maven-metadata.xml +[INFO] +[INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ spring-cloud-contract-samples-webclient --- +[INFO] Deleting /home/marcin/repo/spring-cloud-contract/samples/standalone/webclient/target +[INFO] +[INFO] --- spring-javaformat-maven-plugin:0.0.35:apply (default) @ spring-cloud-contract-samples-webclient --- +[INFO] +[INFO] --- spring-javaformat-maven-plugin:0.0.35:validate (default) @ spring-cloud-contract-samples-webclient --- +[INFO] +[INFO] --- maven-checkstyle-plugin:3.1.2:check (checkstyle-validation) @ spring-cloud-contract-samples-webclient --- +[INFO] Starting audit... +Audit done. +[INFO] You have 0 Checkstyle violations. +[INFO] +[INFO] --- maven-checkstyle-plugin:3.1.2:check (no-http-checkstyle-validation) @ spring-cloud-contract-samples-webclient --- +[INFO] +[INFO] --- maven-javadoc-plugin:3.3.1:jar (javadoc) @ spring-cloud-contract-samples-webclient --- +[INFO] Not executing Javadoc as the project is not a Java classpath-capable package +[INFO] +[INFO] >>> maven-source-plugin:3.2.1:jar (attach-sources) > generate-sources @ spring-cloud-contract-samples-webclient >>> +[INFO] +[INFO] --- spring-javaformat-maven-plugin:0.0.35:apply (default) @ spring-cloud-contract-samples-webclient --- +[INFO] +[INFO] --- spring-javaformat-maven-plugin:0.0.35:validate (default) @ spring-cloud-contract-samples-webclient --- +[INFO] +[INFO] --- maven-checkstyle-plugin:3.1.2:check (checkstyle-validation) @ spring-cloud-contract-samples-webclient --- +[INFO] Starting audit... +Audit done. +[INFO] You have 0 Checkstyle violations. +[INFO] +[INFO] --- maven-checkstyle-plugin:3.1.2:check (no-http-checkstyle-validation) @ spring-cloud-contract-samples-webclient --- +[INFO] +[INFO] <<< maven-source-plugin:3.2.1:jar (attach-sources) < generate-sources @ spring-cloud-contract-samples-webclient <<< +[INFO] +[INFO] +[INFO] --- maven-source-plugin:3.2.1:jar (attach-sources) @ spring-cloud-contract-samples-webclient --- +[INFO] +[INFO] --- maven-invoker-plugin:3.2.1:run (integration) @ spring-cloud-contract-samples-webclient --- +[INFO] No projects were selected for execution. +[INFO] +[INFO] --- maven-install-plugin:2.4:install (default-install) @ spring-cloud-contract-samples-webclient --- +[INFO] Installing /home/marcin/repo/spring-cloud-contract/samples/standalone/webclient/interpolated-pom.xml to /home/marcin/.m2/repository/org/springframework/cloud/spring-cloud-contract-samples-webclient/4.1.0-SNAPSHOT/spring-cloud-contract-samples-webclient-4.1.0-SNAPSHOT.pom +[INFO] ------------------------------------------------------------------------ +[INFO] Reactor Summary: +[INFO] +[INFO] Spring Cloud Contract RestDocs Http Server Sample 0.0.1 SUCCESS [ 4.793 s] +[INFO] Spring Cloud Contract RestDocs Http WebClient Sample 0.0.1 SUCCESS [ 11.313 s] +[INFO] Spring Cloud Contract Standalone Restdocs Test Samples 4.1.0-SNAPSHOT SUCCESS [ 1.157 s] +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ +[INFO] Total time: 17.421 s +[INFO] Finished at: 2023-09-06T14:30:20+02:00 +[INFO] ------------------------------------------------------------------------ diff --git a/samples/standalone/webclient/http-client/.gitignore b/samples/standalone/webclient/http-client/.gitignore deleted file mode 100644 index a275b7b864..0000000000 --- a/samples/standalone/webclient/http-client/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ - -target/ - -.gradle -build/ - -/.apt_generated/ diff --git a/samples/standalone/webclient/http-client/.gradle/8.3/checksums/checksums.lock b/samples/standalone/webclient/http-client/.gradle/8.3/checksums/checksums.lock new file mode 100644 index 0000000000000000000000000000000000000000..b2908ba0ad737a3aaff046a838d85b67669ced57 GIT binary patch literal 17 UcmZQ}m~!8)>!?yV0|Z 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 literal 0 HcmV?d00001 diff --git a/samples/standalone/webclient/http-client/.gradle/8.3/checksums/sha1-checksums.bin b/samples/standalone/webclient/http-client/.gradle/8.3/checksums/sha1-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..7197a9cd7fae2939823cf23cd4c4ada6cf35fc37 GIT binary patch literal 25139 zcmeI3c{Ekg--j=i;hKjGnL;uog^)3nG7p(&qD1D536&5kQzfBHQIV*q&{af+GL<2b zWR{c+CDD7%-RJnN_g=rX-oM{<_F5g*V?X!1&*$v3_pv$-;BZ{b|B#0JPuu*TZ?W&N z1h53K1h53K1h53K1h53K1h53K1h53K1h53K1h53K1h53K1h53K1h54Dza(G|od_PB z43{J&{0&nu4!4^g`X(&efO$G7J#HEN*s>7)|AW}#s>Ww^fenB=?pxy(zTS6+*|Y)I ziAMRwj4cvN_Z^&ct zIcDJ~&y^6MG;@8Z2Dp*e8ZRk2Wfmjo3%C^<$_s}!Nyu3Q&I7L7gz`J5@YXXLb{>G6 z|3Z23%$C8Ft@_CM8qA^megKWpv4QulpueRb%1aoWKFHb~;s@OHHpgyUWdP+D$D;Wd0gEYz?dB$$(xJ~#8xJ5e3D>fdp*ZnCV3AnE48dr7hr2c(-8gR>j zHNG;ky`+DCGV(b)QU2^_c%OUSPJ}yTp}dkU4zJlb7XbR3v7r3L2$TK^E{|crb&OE{ zGL+9OZTUe2;P%2OuctonuYlt|a=k3tP~Ldy^vE0Pc1_UVi4)~bo?Vlb_KbOe8^o^h zQyvFq<%_rh*Xu!fvt`O{7bg1-QT|5Cb%pQ4`&7UWzg^>2 z5*vT~9XgNjv^CzY{glQpEf8>K3$pGbpxvvd>Xa^Hl4IIw;(i+ddUPmwfr51dSvk1yR_gYXi8`h}8swkhL^*8PG?r{VCZBL^7Tg&;o z8=2|^0N1HP`45I(Z+yaUTEHCxQ9j%ML&dk%RuFLGag;9_y1jgS3x5-E=VX-sF5K=V z{9~pU`Fw7aFL?)tQ@H&2<7y@jVm7gQZ)qJ?kvg~=;;}B<1VNIZeW6PW@bmeqn>kL0k>XS4sn<*dJidc{W_koD8S4dt5yyeqeRUT#9_>Y8$64?LZtxuCTR)t9*D~?U1#r8~ zYy4kFr`Wz%(tw*yqFk`fw?@araTnkw3nHXSGz&n_{O5^rn-+BOeDBKK10oM;jx#Yg8*aVSjWPPy7SmRohHgg)TF)FBpfRe2=8qq==6?59se$gmMM97hW9%Iwimz-l1Iak^lXsyZO7y1uSt|!KGaj(4bFVJ7_1j-Fn@DFlW1d(;dxD4foJ*g{d?30jn#`Gh~ z&HT=#Ut~Wz2tG#_#s3^$iJF>!r0fFRz8?L7YjJ__f{#Na;1(_@KUx;Qy)pjBTfof@ zq1;WdHa(h68d(puHP-l*w%|hcsDGfp-8YmUpApe6`{~01xOOng-Dm4FuY2_(>z<(_ z$~_e+&V(@XiGlv+=4-sp_Lbs!A!Hs}3$F2Zt@@)%daad%7d%oIYk~*5dgPOM0wa-t)Fj>rnRvBzLw+`8#@D8@$My()lhG!(KJH`66-v38R3s{ zK*0rq$REd#z7J2DkH!H@LZ2w%=&zAmmg(%t8|`i=}WqT?YecC?qN2-Gq^LT<^~ z-S0hgrQvJV8Qbw-@$EDfvlpQEZ7Jdeg|wh605_Tz=s=R;W?5Q+&bv+_g(9;anr=yK zp#q<5AuF8SKoS}$+~}yF1Bo@odF9+=*P6!WCdG#CF`0@x!_p@pE6Uu!@f}gZ86}Wg za_3Tf7u1)=V(Uv4c4m8Mc`UnUz}D=gBOSo9gWn`1sU^0rQvL8y?qd!~`c|c&Ln?8% z@lPQu#)6u=9#}z?)h5x+NuPXbGUf!qqX<$krS+j@(}>HHP$x6k`3hkW2PV9N_w_$TDn zps=u7-t(;ctFP~dZKm7mO;DJu=h()c=s_R5^1D>?x|2^J zuy`&3ixIj9NYCq}=~s27a;l_l-y5D}QpI!d^9a6#El0`>Q(!S2C$~o5zUowt>B-#h z!?D^)V=87ClXw)e!fEl_=zzt2m)tt|v@p5?FX~2X8^hwPY-Jg7?R^u`qA}3~7AyQ0 z5G2>@QtI3JUV{j}arr@~P_2eR>fJd^pqAAzu$T$t7QyK^Zw2?Y1^=@;zHYrq&A(@+ zCt!=+K;9TwEPKc;#yMu~37NxcdtB7DtTHX?$5geC0ZZBmSd44)$lOZm=itmM^o3aYOTuBHqLIunkfR z{`(-3G)j10Tf8`=ZMShl^=W#AnUzS_PWXDoyWg)Z1r|#dxwW%DQ@m#BQsmpwD=YFW zL!O^cI8`9EpcM{oyTYIYNv({Bv<8B84sxUH_A;(z3Of9DULJ^5NtAF~hR7}d7RJpd zMl$p&3_Zn$wD*-*>odTsD0E(?jKE@+Be!mhmupPv&wPwnr+~%h zPj0n~SeT_o8J&^kR{FcDP46k{;9!7QDZnyjQ)e93n`t^E z*ikPT$C1DSEHik0hnfd`caqc^UCE>tPz@+hS>5+D%3Qcbo+o%8VwDgjoP7?tHK*+9 zNoUWIJl3Da?%{G^V)?~JnS0Y-tgL>pv^FP8fLaK2HzDqqgZeHFs z$w?FX8!R|^^TWX6hOais2&EkAQxfxY#w>IvHk0>vR zT}%piO{fgYm^B!bg=QHXv3ru;{y>uOu1%muFG?M$S#-cM{`O$)9e7}2O2{N`9punyyfW-Ud$Q|WVYV6l8B zwU#LCHIdv~qd2~wIWLxrb7qo}K$y=WT7Tq0k%UWHkXySHdRbQA4Z4n)3qN2w{ zDq^()OZEe~^^1TZI54!qeo*5$8Igu?*g@KG=W72-8rOb zbcJwyQnGG2obcRA{qkSItN$FfK>IL!UN*VF;(_KRsb!}9ZEwZS>XaQzU4K|-TJiL` z3-iFT#RE%vohOG=Q9-)bzPax5m+yPUlcl#OilBt78@3j};)L&MlDQ%AxvFMA^QXaY zM@C%;tobgexpj(a z>sMX<{0;1Hj@}AX5*^j;mxZ5FptqF>3Qj6nz=1+Ut-HKElt4X`A?J&A$ z%_t0N*&(%<*O?nR2Gu6l>jX2rgEYk{ZyogFJ(j;6SoVy>QaJoNt7zE3@39(&avhFE z&XY9lg`8a*c*GFP23Xu1$w!#w_}trS`Np24yr;8~lmZ;{y0yr9XbdGi-p`8bw^G;Ks7Ji)- zd#Cm3W~qhnL~$*J@@VRSSC!+NLP4!&B#q7V{WxrI^Pp8U!7u7$PY^oI}@ z;@az;%?xVcSZ|P9JURIbah;DM3u~la1~ViZjL)aBfm*BzpcWhSBtd#!(KVg7TeMbw zEEryI?Zd@YN2Ykf8OG85J8c3id=0r(Zylh2R?TLqPBr-yegBeleL){|o#45l36BhF zT1S2fFk)3iObQp0nD-4a-=eb85u5q`nv1@SO; z?&M>xJfh#^|A+1Hu1ruXDGpe4>-;8lBD`nr-h;gk78H-gCCgd3r#~H!fopmA8pFRc zK#fNOI*`;lK43{ZyHV1L;(c%ttCbNHZ(69?nx(Ck<$WlQq8b~EcUNdhxru+uO6K%@_>6b1a(hO9wfL2e~ zy3#@{g`;2RcLxra>q=qe69saM&CVBHpER;~_6Pv$VHL3G;FX)CR)HF0bX|qN$Rg*E zi?Z5e=0PQCXuW{<$^kiGF+u5&T8j$Wyw77*bI%CTospxji4;(WR~b0@3}nuW50G23 z^0nt%#2)(&FRHMgp?od!)gvzTfc9{tFzOvJ9)iqJE13&)z=N351gUaS76buvlCS?%h&#$7I59K5Fa@l zTl-MdLT?+e_SYdJ+(JIWwD^Zc2PG1Pc<0PFvN~^UpBI`UT27@OxsegBGv~F2BA&{& zHy&nR&HSL&qM7^SuN$ z!yR=0qK@;5b3;EVo!1P3*OusvMt6Ymv-1MJ;%Hr)cSOmDB&2+kXy?qr753kx^$kd YegDtUflxAd-^dzR?a{!Z-VIy-1HjVr#sB~S literal 0 HcmV?d00001 diff --git a/samples/standalone/webclient/http-client/.gradle/8.3/dependencies-accessors/dependencies-accessors.lock b/samples/standalone/webclient/http-client/.gradle/8.3/dependencies-accessors/dependencies-accessors.lock new file mode 100644 index 0000000000000000000000000000000000000000..1b91527419a2081c7919bb4596bc1861b69bac52 GIT binary patch literal 17 ScmZQJ_qZ|7!?L!D0SW*r!2@vs literal 0 HcmV?d00001 diff --git a/samples/standalone/webclient/http-client/.gradle/8.3/dependencies-accessors/gc.properties b/samples/standalone/webclient/http-client/.gradle/8.3/dependencies-accessors/gc.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/standalone/webclient/http-client/.gradle/8.3/executionHistory/executionHistory.bin b/samples/standalone/webclient/http-client/.gradle/8.3/executionHistory/executionHistory.bin new file mode 100644 index 0000000000000000000000000000000000000000..0acfdadea33d7adb5b17ae6455f734b39b056616 GIT binary patch literal 94765 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 Tv9%X1hf=UVlAsLiVcGuyt))}V literal 0 HcmV?d00001 diff --git a/samples/standalone/webclient/http-client/.gradle/8.3/executionHistory/executionHistory.lock b/samples/standalone/webclient/http-client/.gradle/8.3/executionHistory/executionHistory.lock new file mode 100644 index 0000000000000000000000000000000000000000..6a26a63468ae59621ab33feb5782d9c19785a30d GIT binary patch literal 17 TcmZRU?&;%Imu%`|fBbTeM*dB~ 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 literal 0 HcmV?d00001 diff --git a/samples/standalone/webclient/http-client/.gradle/checksums/checksums.lock b/samples/standalone/webclient/http-client/.gradle/checksums/checksums.lock new file mode 100644 index 0000000000000000000000000000000000000000..9e92316a8b78ab1cc19f195340bdebc4d71e4925 GIT binary patch literal 17 UcmZQx%Hb{}yL{PK1_*ct04U-FSpWb4 literal 0 HcmV?d00001 diff --git a/samples/standalone/webclient/http-client/.gradle/checksums/md5-checksums.bin b/samples/standalone/webclient/http-client/.gradle/checksums/md5-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..628b9629b790bf5f04b05be18ef70dae46863108 GIT binary patch literal 22847 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 x-v`*b>wh_26chje literal 0 HcmV?d00001 diff --git a/samples/standalone/webclient/http-client/.gradle/file-system.probe b/samples/standalone/webclient/http-client/.gradle/file-system.probe new file mode 100644 index 0000000000000000000000000000000000000000..502c0ff72f5a2188ead111e88c2d48b8a2b6b68b GIT binary patch literal 8 PcmZQzVC>4OIQ10(2w4Ly literal 0 HcmV?d00001 diff --git a/samples/standalone/webclient/http-client/.gradle/vcs-1/gc.properties b/samples/standalone/webclient/http-client/.gradle/vcs-1/gc.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/standalone/webclient/http-client/.mvn/jvm.config b/samples/standalone/webclient/http-client/.mvn/jvm.config deleted file mode 100644 index 0e7dabeff6..0000000000 --- a/samples/standalone/webclient/http-client/.mvn/jvm.config +++ /dev/null @@ -1 +0,0 @@ --Xmx1024m -XX:CICompilerCount=1 -XX:TieredStopAtLevel=1 -Djava.security.egd=file:/dev/./urandom \ No newline at end of file diff --git a/samples/standalone/webclient/http-client/.mvn/maven.config b/samples/standalone/webclient/http-client/.mvn/maven.config deleted file mode 100644 index a682990566..0000000000 --- a/samples/standalone/webclient/http-client/.mvn/maven.config +++ /dev/null @@ -1 +0,0 @@ --P spring diff --git a/samples/standalone/webclient/http-client/.mvn/wrapper/MavenWrapperDownloader.java b/samples/standalone/webclient/http-client/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index b901097f2d..0000000000 --- a/samples/standalone/webclient/http-client/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2007-present 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. - */ -import java.net.*; -import java.io.*; -import java.nio.channels.*; -import java.util.Properties; - -public class MavenWrapperDownloader { - - private static final String WRAPPER_VERSION = "0.5.6"; - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" - + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if(mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if(mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if(!outputFile.getParentFile().exists()) { - if(!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { - String username = System.getenv("MVNW_USERNAME"); - char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); - Authenticator.setDefault(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(username, password); - } - }); - } - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/samples/standalone/webclient/http-client/.mvn/wrapper/maven-wrapper.jar b/samples/standalone/webclient/http-client/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index c1dd12f17644411d6e840bd5a10c6ecda0175f18..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58727 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%0ANsA|A3-jj|r`KAo%oTajX3>^E` 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 YM{}PByk10KD_nuQ4E7Du?}+~TKh4V)`~Uy| diff --git a/samples/standalone/webclient/http-client/.mvn/wrapper/maven-wrapper.properties b/samples/standalone/webclient/http-client/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index 015dfe6821..0000000000 --- a/samples/standalone/webclient/http-client/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,18 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.3/apache-maven-3.8.3-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar diff --git a/samples/standalone/webclient/http-client/README.adoc b/samples/standalone/webclient/http-client/README.adoc deleted file mode 100644 index cdcb0e4a56..0000000000 --- a/samples/standalone/webclient/http-client/README.adoc +++ /dev/null @@ -1,26 +0,0 @@ -= Http Client - -== Prerequisites - -First you have to publish to Maven Local the stubs of the *http-server* module - -== How to run it? - -Run - -[source=groovy] --------- -./gradlew clean build --------- - -or - --------- -./mvnw clean package --------- - -To - -- build the app -- use spring-cloud-contract-stub-runner-spring[Stub Runner Spring] to download the stub of `Http Server` -- run the tests against stubbed server \ No newline at end of file diff --git a/samples/standalone/webclient/http-client/build.gradle b/samples/standalone/webclient/http-client/build.gradle deleted file mode 100644 index 16b81fad0b..0000000000 --- a/samples/standalone/webclient/http-client/build.gradle +++ /dev/null @@ -1,66 +0,0 @@ -plugins { - id "groovy" - id "org.springframework.boot" - id "io.spring.dependency-management" - id "maven-publish" -} - -group = 'com.example' -version = '0.0.1' - -repositories { - mavenCentral() - mavenLocal() - maven { url "https://repo.spring.io/snapshot" } - maven { url "https://repo.spring.io/milestone" } - maven { url "https://repo.spring.io/release" } -} - -dependencyManagement { - imports { - mavenBom "org.springframework.cloud:spring-cloud-dependencies:${BOM_VERSION}" - mavenBom "org.springframework.cloud:spring-cloud-contract-dependencies:${verifierVersion}" - } -} - -dependencies { - implementation("org.springframework.boot:spring-boot-starter-web") - implementation("org.springframework.boot:spring-boot-starter-actuator") - - testImplementation 'org.springframework.cloud:spring-cloud-contract-wiremock' - testImplementation 'org.springframework.cloud:spring-cloud-starter-contract-stub-runner' - testImplementation('org.springframework.boot:spring-boot-starter-test') { - exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' - } - testImplementation "com.example:http-server-webclient:0.0.1:stubs" -} - -test { - useJUnitPlatform() - include '**/*GradleTests*' - systemProperty 'spring.profiles.active', 'gradle' - testLogging { - exceptionFormat = 'full' - } - afterSuite { desc, result -> - if (!desc.parent) { - println "Results: (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)" - if (result.testCount == 0) { - throw new IllegalStateException("No tests were found. Failing the build") - } - } - } -} - -task resolveDependencies { - doLast { - project.rootProject.allprojects.each { subProject -> - subProject.buildscript.configurations.each { configuration -> - configuration.resolve() - } - subProject.configurations.each { configuration -> - configuration.resolve() - } - } - } -} diff --git a/samples/standalone/webclient/http-client/gradle.properties b/samples/standalone/webclient/http-client/gradle.properties deleted file mode 100644 index 23a8e509b5..0000000000 --- a/samples/standalone/webclient/http-client/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -org.gradle.daemon=false -verifierVersion=4.1.0-SNAPSHOT -BOM_VERSION=2023.0.0-SNAPSHOT -bootVersion=3.2.0-SNAPSHOT diff --git a/samples/standalone/webclient/http-client/gradle/wrapper/gradle-wrapper.jar b/samples/standalone/webclient/http-client/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 7f93135c49b765f8051ef9d0a6055ff8e46073d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63721 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鯊%1Et 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⁢ zv5o9#E7!G0XmdzfsS{efPNi`1b44~SZ4Z8fuX!I}#8g+(wxzQwUT#Xb2(tbY1+EUhGKoT@KEU9Ktl>_0 z%bjDJg;#*gtJZv!-Zs`?^}v5eKmnbjqlvnSzE@_SP|LG_PJ6CYU+6zY6>92%E+ z=j@TZf-iW4(%U{lnYxQA;7Q!b;^brF8n0D>)`q5>|WDDXLrqYU_tKN2>=#@~OE7grMnNh?UOz-O~6 z6%rHy{#h9K0AT+lDC7q4{hw^|q6*Ry;;L%Q@)Ga}$60_q%D)rv(CtS$CQbpq9|y1e zRSrN4;$Jyl{m5bZw`$8TGvb}(LpY{-cQ)fcyJv7l3S52TLXVDsphtv&aPuDk1OzCA z4A^QtC(!11`IsNx_HnSy?>EKpHJWT^wmS~hc^p^zIIh@9f6U@I2 zC=Mve{j2^)mS#U$e{@Q?SO6%LDsXz@SY+=cK_QMmXBIU)j!$ajc-zLx3V60EXJ!qC zi<%2x8Q24YN+&8U@CIlN zrZkcT9yh%LrlGS9`G)KdP(@9Eo-AQz@8GEFWcb7U=a0H^ZVbLmz{+&M7W(nXJ4sN8 zJLR7eeK(K8`2-}j(T7JsO`L!+CvbueT%izanm-^A1Dn{`1Nw`9P?cq;7no+XfC`K(GO9?O^5zNIt4M+M8LM0=7Gz8UA@Z0N+lg+cX)NfazRu z5D)~HA^(u%w^cz+@2@_#S|u>GpB+j4KzQ^&Wcl9f z&hG#bCA(Yk0D&t&aJE^xME^&E-&xGHhXn%}psEIj641H+Nl-}boj;)Zt*t(4wZ5DN z@GXF$bL=&pBq-#vkTkh>7hl%K5|3 z{`Vn9b$iR-SoGENp}bn4;fR3>9sA%X2@1L3aE9yTra;Wb#_`xWwLSLdfu+PAu+o3| zGVnpzPr=ch{uuoHjtw7+_!L_2;knQ!DuDl0R`|%jr+}jFzXtrHIKc323?JO{l&;VF z*L1+}JU7%QJOg|5|Tc|D8fN zJORAg=_vsy{ak|o);@)Yh8Lkcg@$FG3k@ep36BRa^>~UmnRPziS>Z=`Jb2x*Q#`%A zU*i3&Vg?TluO@X0O;r2Jl6LKLUOVhSqg1*qOt^|8*c7 zo(298@+r$k_wQNGHv{|$tW(T8L+4_`FQ{kEW5Jgg{yf7ey4ss_(SNKfz(N9lx&a;< je(UuV8hP?p&}TPdm1I$XmG#(RzlD&B2izSj9sl%y5~4qc diff --git a/samples/standalone/webclient/http-client/gradle/wrapper/gradle-wrapper.properties b/samples/standalone/webclient/http-client/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index ac72c34e8a..0000000000 --- a/samples/standalone/webclient/http-client/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/samples/standalone/webclient/http-client/gradlew b/samples/standalone/webclient/http-client/gradlew deleted file mode 100755 index 0adc8e1a53..0000000000 --- a/samples/standalone/webclient/http-client/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/samples/standalone/webclient/http-client/gradlew.bat b/samples/standalone/webclient/http-client/gradlew.bat deleted file mode 100644 index 6689b85bee..0000000000 --- a/samples/standalone/webclient/http-client/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/samples/standalone/webclient/http-client/mvnw b/samples/standalone/webclient/http-client/mvnw deleted file mode 100755 index 5643201c7d..0000000000 --- a/samples/standalone/webclient/http-client/mvnw +++ /dev/null @@ -1,316 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Maven Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /usr/local/etc/mavenrc ] ; then - . /usr/local/etc/mavenrc - fi - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`\\unset -f command; \\command -v java`" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` - fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" - fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi -else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - if [ -n "$MVNW_REPOURL" ]; then - jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - else - jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - fi - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - if $cygwin; then - wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` - fi - - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - else - wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - fi - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl -o "$wrapperJarPath" "$jarUrl" -f - else - curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f - fi - - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - # For Cygwin, switch paths to Windows format before running javac - if $cygwin; then - javaClass=`cygpath --path --windows "$javaClass"` - fi - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` -fi - -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" -export MAVEN_CMD_LINE_ARGS - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -exec "$JAVACMD" \ - $MAVEN_OPTS \ - $MAVEN_DEBUG_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" \ - "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/samples/standalone/webclient/http-client/mvnw.cmd b/samples/standalone/webclient/http-client/mvnw.cmd deleted file mode 100644 index 23b7079a3d..0000000000 --- a/samples/standalone/webclient/http-client/mvnw.cmd +++ /dev/null @@ -1,188 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* -if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% ^ - %JVM_CONFIG_MAVEN_PROPS% ^ - %MAVEN_OPTS% ^ - %MAVEN_DEBUG_OPTS% ^ - -classpath %WRAPPER_JAR% ^ - "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ - %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" -if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%"=="on" pause - -if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% - -cmd /C exit /B %ERROR_CODE% diff --git a/samples/standalone/webclient/http-client/pom.xml b/samples/standalone/webclient/http-client/pom.xml deleted file mode 100644 index db96e175b0..0000000000 --- a/samples/standalone/webclient/http-client/pom.xml +++ /dev/null @@ -1,245 +0,0 @@ - - - 4.0.0 - - com.example - http-client-webclient - 0.0.1 - - Spring Cloud Contract RestDocs Http WebClient Sample - Spring Cloud Contract RestDocs Http WebClient Sample - - - org.springframework.boot - spring-boot-starter-parent - 3.2.0-SNAPSHOT - - - - - UTF-8 - 17 - 4.1.0-SNAPSHOT - - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-actuator - - - - - org.springframework.boot - spring-boot-starter-test - test - - - org.junit.vintage - junit-vintage-engine - - - - - org.springframework.cloud - spring-cloud-contract-wiremock - test - - - org.springframework.cloud - spring-cloud-contract-stub-runner - test - - - com.example - http-server-webclient - stubs - 0.0.1 - test - - - * - * - - - - - - - org.springframework.boot - spring-boot-configuration-processor - true - - - - - - - org.springframework.cloud - spring-cloud-contract-dependencies - ${spring-cloud-contract.version} - pom - import - - - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - **/*GradleTests.java - - true - - - - org.springframework.boot - spring-boot-maven-plugin - - - maven-deploy-plugin - - true - - - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - - - - integration - - - - org.codehaus.mojo - exec-maven-plugin - 1.6.0 - - - gradle - test - - ./gradlew - - clean - build - publishToMavenLocal - - -x - test - - -PverifierVersion=${spring-cloud-contract.version} - - - - - exec - - - - - - - - - windows - - - - org.codehaus.mojo - exec-maven-plugin - 1.6.0 - - - gradle - test - - ./gradlew - - clean - build - publishToMavenLocal - - -x - test - - -PverifierVersion=${spring-cloud-contract.version} - - - - - exec - - - - - - - - - - diff --git a/samples/standalone/webclient/http-client/settings.gradle b/samples/standalone/webclient/http-client/settings.gradle deleted file mode 100644 index ff0d4920f8..0000000000 --- a/samples/standalone/webclient/http-client/settings.gradle +++ /dev/null @@ -1,14 +0,0 @@ -pluginManagement { - repositories { - mavenLocal() - maven { url "https://repo.spring.io/snapshot" } - maven { url "https://repo.spring.io/milestone" } - gradlePluginPortal() - } - plugins { - id 'org.springframework.boot' version "${bootVersion}" - id "io.spring.dependency-management" version "1.1.3" - } -} - -rootProject.name = 'http-client-webclient-gradle' diff --git a/samples/standalone/webclient/http-client/src/main/java/com/example/loan/Application.java b/samples/standalone/webclient/http-client/src/main/java/com/example/loan/Application.java deleted file mode 100644 index 63645c66f5..0000000000 --- a/samples/standalone/webclient/http-client/src/main/java/com/example/loan/Application.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.properties.EnableConfigurationProperties; - -@SpringBootApplication -@EnableConfigurationProperties(ServiceConfiguration.class) -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } - -} diff --git a/samples/standalone/webclient/http-client/src/main/java/com/example/loan/LoanApplicationService.java b/samples/standalone/webclient/http-client/src/main/java/com/example/loan/LoanApplicationService.java deleted file mode 100644 index 0db17a8ebe..0000000000 --- a/samples/standalone/webclient/http-client/src/main/java/com/example/loan/LoanApplicationService.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan; - -import com.example.loan.model.FraudCheckStatus; -import com.example.loan.model.FraudServiceRequest; -import com.example.loan.model.FraudServiceResponse; -import com.example.loan.model.LoanApplication; -import com.example.loan.model.LoanApplicationResult; -import com.example.loan.model.LoanApplicationStatus; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Service; -import org.springframework.web.client.RestTemplate; - -@Service -public class LoanApplicationService { - - private static final String FRAUD_SERVICE_JSON_VERSION_1 = "application/vnd.fraud.v1+json"; - - private final RestTemplate restTemplate; - - private final ServiceConfiguration serviceConfiguration; - - public LoanApplicationService(ServiceConfiguration serviceConfiguration) { - this.restTemplate = new RestTemplate(); - this.serviceConfiguration = serviceConfiguration; - } - - public LoanApplicationResult loanApplication(LoanApplication loanApplication) { - FraudServiceRequest request = new FraudServiceRequest(loanApplication); - - FraudServiceResponse response = sendRequestToFraudDetectionService(request); - - return buildResponseFromFraudResult(response); - } - - private FraudServiceResponse sendRequestToFraudDetectionService( - FraudServiceRequest request) { - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.add(HttpHeaders.CONTENT_TYPE, FRAUD_SERVICE_JSON_VERSION_1); - - // tag::client_call_server[] - ResponseEntity response = this.restTemplate.exchange( - "http://localhost:" + getPort() + "/fraudcheck", HttpMethod.PUT, - new HttpEntity<>(request, httpHeaders), FraudServiceResponse.class); - // end::client_call_server[] - - return response.getBody(); - } - - private LoanApplicationResult buildResponseFromFraudResult( - FraudServiceResponse response) { - LoanApplicationStatus applicationStatus = null; - if (FraudCheckStatus.OK == response.getFraudCheckStatus()) { - applicationStatus = LoanApplicationStatus.LOAN_APPLIED; - } - else if (FraudCheckStatus.FRAUD == response.getFraudCheckStatus()) { - applicationStatus = LoanApplicationStatus.LOAN_APPLICATION_REJECTED; - } - - return new LoanApplicationResult(applicationStatus, - response.getRejectionReason()); - } - - public int getPort() { - return this.serviceConfiguration.getPort(); - } - - public void setPort(int port) { - this.serviceConfiguration.setPort(port); - } - -} - -@ConfigurationProperties("service") -class ServiceConfiguration { - - private int port = 8080; - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } -} \ No newline at end of file diff --git a/samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/Client.java b/samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/Client.java deleted file mode 100644 index 2c2c8b8d8a..0000000000 --- a/samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/Client.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -public class Client { - - private String pesel; - - public Client() { - } - - public Client(String pesel) { - this.pesel = pesel; - } - - public String getPesel() { - return this.pesel; - } - - public void setPesel(String pesel) { - this.pesel = pesel; - } - -} diff --git a/samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/FraudCheckStatus.java b/samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/FraudCheckStatus.java deleted file mode 100644 index 01f2969113..0000000000 --- a/samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/FraudCheckStatus.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -public enum FraudCheckStatus { - - OK, FRAUD - -} diff --git a/samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/FraudServiceRequest.java b/samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/FraudServiceRequest.java deleted file mode 100644 index e4e63590bc..0000000000 --- a/samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/FraudServiceRequest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -import java.math.BigDecimal; - -public class FraudServiceRequest { - - private String clientId; - - private BigDecimal loanAmount; - - public FraudServiceRequest() { - } - - public FraudServiceRequest(LoanApplication loanApplication) { - this.clientId = loanApplication.getClient().getPesel(); - this.loanAmount = loanApplication.getAmount(); - } - - public String getClientId() { - return this.clientId; - } - - public void setClientId(String clientId) { - this.clientId = clientId; - } - - public BigDecimal getLoanAmount() { - return this.loanAmount; - } - - public void setLoanAmount(BigDecimal loanAmount) { - this.loanAmount = loanAmount; - } - -} diff --git a/samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/FraudServiceResponse.java b/samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/FraudServiceResponse.java deleted file mode 100644 index 4ca6dfc623..0000000000 --- a/samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/FraudServiceResponse.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -public class FraudServiceResponse { - - private FraudCheckStatus fraudCheckStatus; - - private String rejectionReason; - - public FraudServiceResponse() { - } - - public FraudCheckStatus getFraudCheckStatus() { - return this.fraudCheckStatus; - } - - public void setFraudCheckStatus(FraudCheckStatus fraudCheckStatus) { - this.fraudCheckStatus = fraudCheckStatus; - } - - public String getRejectionReason() { - return this.rejectionReason; - } - - public void setRejectionReason(String rejectionReason) { - this.rejectionReason = rejectionReason; - } - -} diff --git a/samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/LoanApplication.java b/samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/LoanApplication.java deleted file mode 100644 index 54ae63b0fe..0000000000 --- a/samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/LoanApplication.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -import java.math.BigDecimal; - -public class LoanApplication { - - private Client client; - - private BigDecimal amount; - - private String loanApplicationId; - - public LoanApplication() { - } - - public LoanApplication(Client client, double amount) { - this.client = client; - this.amount = BigDecimal.valueOf(amount); - } - - public Client getClient() { - return this.client; - } - - public void setClient(Client client) { - this.client = client; - } - - public BigDecimal getAmount() { - return this.amount; - } - - public void setAmount(BigDecimal amount) { - this.amount = amount; - } - - public String getLoanApplicationId() { - return this.loanApplicationId; - } - - public void setLoanApplicationId(String loanApplicationId) { - this.loanApplicationId = loanApplicationId; - } - -} diff --git a/samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/LoanApplicationResult.java b/samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/LoanApplicationResult.java deleted file mode 100644 index 0850c0af0b..0000000000 --- a/samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/LoanApplicationResult.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -public class LoanApplicationResult { - - private LoanApplicationStatus loanApplicationStatus; - - private String rejectionReason; - - public LoanApplicationResult() { - } - - public LoanApplicationResult(LoanApplicationStatus loanApplicationStatus, - String rejectionReason) { - this.loanApplicationStatus = loanApplicationStatus; - this.rejectionReason = rejectionReason; - } - - public LoanApplicationStatus getLoanApplicationStatus() { - return this.loanApplicationStatus; - } - - public void setLoanApplicationStatus(LoanApplicationStatus loanApplicationStatus) { - this.loanApplicationStatus = loanApplicationStatus; - } - - public String getRejectionReason() { - return this.rejectionReason; - } - - public void setRejectionReason(String rejectionReason) { - this.rejectionReason = rejectionReason; - } - -} diff --git a/samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/LoanApplicationStatus.java b/samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/LoanApplicationStatus.java deleted file mode 100644 index 5afde21afc..0000000000 --- a/samples/standalone/webclient/http-client/src/main/java/com/example/loan/model/LoanApplicationStatus.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -public enum LoanApplicationStatus { - - LOAN_APPLIED, LOAN_APPLICATION_REJECTED - -} diff --git a/samples/standalone/webclient/http-client/src/main/resources/application.yml b/samples/standalone/webclient/http-client/src/main/resources/application.yml deleted file mode 100644 index 056c802c77..0000000000 --- a/samples/standalone/webclient/http-client/src/main/resources/application.yml +++ /dev/null @@ -1,5 +0,0 @@ -server.port: 8097 -logging: - level: - org.springframework.web.client: debug - com.github.tomakehurst.wiremock: trace \ No newline at end of file diff --git a/samples/standalone/webclient/http-client/src/test/java/com/example/loan/LoanApplicationServiceTests.java b/samples/standalone/webclient/http-client/src/test/java/com/example/loan/LoanApplicationServiceTests.java deleted file mode 100644 index ebd91253ad..0000000000 --- a/samples/standalone/webclient/http-client/src/test/java/com/example/loan/LoanApplicationServiceTests.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan; - -import java.nio.charset.Charset; - -import com.example.loan.model.Client; -import com.example.loan.model.LoanApplication; -import com.example.loan.model.LoanApplicationResult; -import com.example.loan.model.LoanApplicationStatus; -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.stubbing.StubMapping; -import org.junit.jupiter.api.Test; - - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock; -import org.springframework.core.io.Resource; - -import org.springframework.util.StreamUtils; - -import static org.assertj.core.api.Assertions.assertThat; - - -@SpringBootTest(properties = "service.port=${wiremock.server.port}") -@AutoConfigureWireMock(port = 0) -public class LoanApplicationServiceTests { - - @Autowired - private LoanApplicationService service; - - @Value("classpath:META-INF/com.example/http-server-webclient/0.0.1/mappings/markClientAsFraud.json") - private Resource markClientAsFraud; - - @Value("classpath:META-INF/com.example/http-server-webclient/0.0.1/mappings/markClientAsNotFraud.json") - private Resource markClientAsNotFraud; - - @Autowired - private WireMockServer server; - - @Test - public void shouldSuccessfullyApplyForLoan() throws Exception { - this.server.addStubMapping(StubMapping.buildFrom(StreamUtils.copyToString( - this.markClientAsNotFraud.getInputStream(), Charset.forName("UTF-8")))); - // given: - LoanApplication application = new LoanApplication(new Client("1234567890"), - 123.123); - // when: - LoanApplicationResult loanApplication = this.service.loanApplication(application); - // then: - assertThat(loanApplication.getLoanApplicationStatus()) - .isEqualTo(LoanApplicationStatus.LOAN_APPLIED); - assertThat(loanApplication.getRejectionReason()).isNull(); - } - - @Test - public void shouldBeRejectedDueToAbnormalLoanAmount() throws Exception { - this.server.addStubMapping(StubMapping.buildFrom(StreamUtils.copyToString( - this.markClientAsFraud.getInputStream(), Charset.forName("UTF-8")))); - // given: - LoanApplication application = new LoanApplication(new Client("1234567890"), - 99999); - // when: - LoanApplicationResult loanApplication = this.service.loanApplication(application); - // then: - assertThat(loanApplication.getLoanApplicationStatus()) - .isEqualTo(LoanApplicationStatus.LOAN_APPLICATION_REJECTED); - assertThat(loanApplication.getRejectionReason()).isEqualTo("Amount too high"); - } - -} diff --git a/samples/standalone/webclient/http-client/src/test/java/com/example/loan/LoanApplicationServiceusingStubRunnerGradleTests.java b/samples/standalone/webclient/http-client/src/test/java/com/example/loan/LoanApplicationServiceusingStubRunnerGradleTests.java deleted file mode 100644 index e75bbbae92..0000000000 --- a/samples/standalone/webclient/http-client/src/test/java/com/example/loan/LoanApplicationServiceusingStubRunnerGradleTests.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan; - -import com.example.loan.model.Client; -import com.example.loan.model.LoanApplication; -import com.example.loan.model.LoanApplicationResult; -import com.example.loan.model.LoanApplicationStatus; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner; - - -import static org.assertj.core.api.Assertions.assertThat; - - -@SpringBootTest -@AutoConfigureStubRunner(ids = "com.example:http-server-webclient") -public class LoanApplicationServiceusingStubRunnerGradleTests { - - @Autowired - LoanApplicationService service; - - @Value("${stubrunner.runningstubs.http-server-webclient.port}") - int port; - - @BeforeEach - public void setup() { - this.service.setPort(this.port); - } - - @Test - public void shouldSuccessfullyApplyForLoan() throws Exception { - // given - LoanApplication application = new LoanApplication(new Client("1234567890"), - 123.123); - // when: - LoanApplicationResult loanApplication = this.service.loanApplication(application); - // then: - assertThat(loanApplication.getLoanApplicationStatus()) - .isEqualTo(LoanApplicationStatus.LOAN_APPLIED); - assertThat(loanApplication.getRejectionReason()).isNull(); - } - - @Test - public void shouldBeRejectedDueToAbnormalLoanAmount() throws Exception { - // given: - LoanApplication application = new LoanApplication(new Client("1234567890"), - 99999); - // when: - LoanApplicationResult loanApplication = this.service.loanApplication(application); - // then: - assertThat(loanApplication.getLoanApplicationStatus()) - .isEqualTo(LoanApplicationStatus.LOAN_APPLICATION_REJECTED); - assertThat(loanApplication.getRejectionReason()).isEqualTo("Amount too high"); - } - -} diff --git a/samples/standalone/webclient/http-client/src/test/java/com/example/loan/LoanApplicationServiceusingStubRunnerTests.java b/samples/standalone/webclient/http-client/src/test/java/com/example/loan/LoanApplicationServiceusingStubRunnerTests.java deleted file mode 100644 index e1c1c13ec7..0000000000 --- a/samples/standalone/webclient/http-client/src/test/java/com/example/loan/LoanApplicationServiceusingStubRunnerTests.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan; - -import com.example.loan.model.Client; -import com.example.loan.model.LoanApplication; -import com.example.loan.model.LoanApplicationResult; -import com.example.loan.model.LoanApplicationStatus; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner; - - -import static org.assertj.core.api.Assertions.assertThat; - - -@SpringBootTest -@AutoConfigureStubRunner(ids = "com.example:http-server-webclient") -public class LoanApplicationServiceusingStubRunnerTests { - - @Autowired - LoanApplicationService service; - - @Value("${stubrunner.runningstubs.http-server-webclient.port}") - int port; - - @BeforeEach - public void setup() { - this.service.setPort(this.port); - } - - @Test - public void shouldSuccessfullyApplyForLoan() throws Exception { - // given - LoanApplication application = new LoanApplication(new Client("1234567890"), - 123.123); - // when: - LoanApplicationResult loanApplication = this.service.loanApplication(application); - // then: - assertThat(loanApplication.getLoanApplicationStatus()) - .isEqualTo(LoanApplicationStatus.LOAN_APPLIED); - assertThat(loanApplication.getRejectionReason()).isNull(); - } - - @Test - public void shouldBeRejectedDueToAbnormalLoanAmount() throws Exception { - // given: - LoanApplication application = new LoanApplication(new Client("1234567890"), - 99999); - // when: - LoanApplicationResult loanApplication = this.service.loanApplication(application); - // then: - assertThat(loanApplication.getLoanApplicationStatus()) - .isEqualTo(LoanApplicationStatus.LOAN_APPLICATION_REJECTED); - assertThat(loanApplication.getRejectionReason()).isEqualTo("Amount too high"); - } - -} diff --git a/samples/standalone/webclient/http-client/src/test/resources/application-gradle.yaml b/samples/standalone/webclient/http-client/src/test/resources/application-gradle.yaml deleted file mode 100644 index 085483afa6..0000000000 --- a/samples/standalone/webclient/http-client/src/test/resources/application-gradle.yaml +++ /dev/null @@ -1,2 +0,0 @@ -stubrunner: - stubs.ids: 'com.example:http-server-webclient' diff --git a/samples/standalone/webclient/http-server/.gitignore b/samples/standalone/webclient/http-server/.gitignore deleted file mode 100644 index b05ba7bd6d..0000000000 --- a/samples/standalone/webclient/http-server/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ - -target/ - -.gradle -build/ - diff --git a/samples/standalone/webclient/http-server/.gradle/8.3/checksums/checksums.lock b/samples/standalone/webclient/http-server/.gradle/8.3/checksums/checksums.lock new file mode 100644 index 0000000000000000000000000000000000000000..47b31c383b6d975a9a7ef95e2f79b66f44bca84a GIT binary patch literal 17 UcmZP;v5Qd2k#dh>00Txg02lBA00000 literal 0 HcmV?d00001 diff --git a/samples/standalone/webclient/http-server/.gradle/8.3/checksums/md5-checksums.bin b/samples/standalone/webclient/http-server/.gradle/8.3/checksums/md5-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..f2750b11685f8149cb9c0833353946c1a328f50d GIT binary patch literal 24947 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 F{U7V4q>cap literal 0 HcmV?d00001 diff --git a/samples/standalone/webclient/http-server/.gradle/8.3/dependencies-accessors/dependencies-accessors.lock b/samples/standalone/webclient/http-server/.gradle/8.3/dependencies-accessors/dependencies-accessors.lock new file mode 100644 index 0000000000000000000000000000000000000000..f5a4ec123c4066293cb68cc793f04a4dc088d741 GIT binary patch literal 17 TcmZRU=J}@fZhaIt0~7!ND4qjJ literal 0 HcmV?d00001 diff --git a/samples/standalone/webclient/http-server/.gradle/8.3/dependencies-accessors/gc.properties b/samples/standalone/webclient/http-server/.gradle/8.3/dependencies-accessors/gc.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/standalone/webclient/http-server/.gradle/8.3/executionHistory/executionHistory.bin b/samples/standalone/webclient/http-server/.gradle/8.3/executionHistory/executionHistory.bin new file mode 100644 index 0000000000000000000000000000000000000000..4541e570dbd7268e8c285b11a34c7fe8fc94a07f GIT binary patch literal 19723 zcmeI%Pe>F|90%|jcZraqg)D^VW~J56Sn3v$2W__u><_M%K_Ig;FXy?lGvk}L4oSzY zq(t*z1Y$=oLR~5-2r0tqVo|4}KSBjXr;sjou$i4*T%m(dM#OhuW*+lq-tYT9Z)PtW z7lg{lLSYjYw+)L;v>*Th2tWV=5P$##AOHafKmY;|fB*y_009U<00I#BUj#b5iIfME zsoYuSH`cj=P`k!!h_&jb&a$-=*MshsrsDqx#j|(4Cg{Tv0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOL}XL7+|$ z!VkRtuD_3I=?2SnP4`SsD#bD}m1_OHF*U93=?$`q~IyIAryW<>aY4 zu5jJIedJJEQ@l0N)salJb+sHjk|>Vl-w+xqOheYF!<`ZT$Y?6dsb&6&T1y7}MZv43 z1(Uk6yCIg$W`re=wV$=g>O0GtbG#(J|5&d1@X;%!B|4Z9y03F?JNsnWA*_$8#3`<= zS0c|)1aRbF(W85%x@d};Qa`naf=ed|b3CF@&g&XB33n})Zl@VyWqDW-wneV>DF)TN zx1ltVS6mdrgDHipdQxT7=HgpX)~yVYGv4}AQ)a}rWXERI?2f92mDQrEWpbvdTy~U< zZ4gIxxMFIGVVOjBNlG;+F}du|DC$p#utH{6^2!L2t-WUL)7k1(jjg$w{i78>-hX=i za$?u5jp2bFg&m{@5$9Gafn0pE3W&w;#VagChEDTAcl-0%$uWJdBJ?@&^`oEb%ePQ? z*k+dZS#e67e7^a=oo}(e5E;Lh9(dS!d*)Qt^u?)I=uHrFUJPG$^6QsR_-dsRxx!dN=d|;jr0|YPw05RDE<^TWy literal 0 HcmV?d00001 diff --git a/samples/standalone/webclient/http-server/.gradle/8.3/fileChanges/last-build.bin b/samples/standalone/webclient/http-server/.gradle/8.3/fileChanges/last-build.bin new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/samples/standalone/webclient/http-server/.gradle/8.3/fileHashes/fileHashes.bin b/samples/standalone/webclient/http-server/.gradle/8.3/fileHashes/fileHashes.bin new file mode 100644 index 0000000000000000000000000000000000000000..3231b5c1b929dc92c005cdd31e9237a590bb7065 GIT binary patch literal 18697 zcmeI%PbkA-9LMp8$-&7Wa9wI;L@+B1l2q1s} z0tg_000IagfB*srAb&$)fBd_%`*FiFd2* z!8!AOFx1u9yu3H*)BStXUwGe~?X9j!>VCiJ+XsCO=ZEzpy1#GwW|jSz+T)7=0tg_0 z00IagfB*srAb<{VtVoTQJqj}$<<$&*qWH%u-os_M>~;E zm*ZtXC!#8mc`Z)to<`Tt#!ha>TQ1j9LB~U3LVOn|R-2xEiMVxs0|amZ04`Gl)c^nh literal 0 HcmV?d00001 diff --git a/samples/standalone/webclient/http-server/.gradle/8.3/gc.properties b/samples/standalone/webclient/http-server/.gradle/8.3/gc.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/standalone/webclient/http-server/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/samples/standalone/webclient/http-server/.gradle/buildOutputCleanup/buildOutputCleanup.lock new file mode 100644 index 0000000000000000000000000000000000000000..7b93e15b84600c713773d8a54e178bce2f9228d7 GIT binary patch literal 17 VcmZRUi4<5gmHXcj1~6cD0{|%I1J(cl literal 0 HcmV?d00001 diff --git a/samples/standalone/webclient/http-server/.gradle/buildOutputCleanup/cache.properties b/samples/standalone/webclient/http-server/.gradle/buildOutputCleanup/cache.properties new file mode 100644 index 0000000000..4435636e9b --- /dev/null +++ b/samples/standalone/webclient/http-server/.gradle/buildOutputCleanup/cache.properties @@ -0,0 +1,2 @@ +#Wed Sep 06 14:27:56 CEST 2023 +gradle.version=8.3 diff --git a/samples/standalone/webclient/http-server/.gradle/buildOutputCleanup/outputFiles.bin b/samples/standalone/webclient/http-server/.gradle/buildOutputCleanup/outputFiles.bin new file mode 100644 index 0000000000000000000000000000000000000000..07bd03a9e95f307658c344d1697931e9dc89e7df GIT binary patch literal 18767 zcmeI%O(=tL9Ki8sD9yYb$c*H~VUkkAL0)n&2N!nP#l=f2gkq6$pfsf%+~nnAk#=yP znU%Dw78eedyzD~BOD$4j^Zb7;xj9MSr=I8e_x=C>PtWtYJ}sJN&izn_mOS#4Lq-T7 zfB*srAbF+PI&STefx#~;O4X!OmbK8BM>OScy+t(gPEa+3uFO;4;m$uOD zHHX#u9_jX)qSC3=UaMMPFTHc%V$C#owxia2qz~WjpZKFICe?4Gk3P+hG-PFqTa$FR zx6u;XC}>yDw@R10rWwZdIj#sGfB*srAbE-z1~6a@0{|>O1RnqZ literal 0 HcmV?d00001 diff --git a/samples/standalone/webclient/http-server/.gradle/checksums/md5-checksums.bin b/samples/standalone/webclient/http-server/.gradle/checksums/md5-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..97daa59cf670ddb0852e443d31dae2594ef640dc GIT binary patch literal 25147 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 literal 0 HcmV?d00001 diff --git a/samples/standalone/webclient/http-server/.gradle/checksums/sha1-checksums.bin b/samples/standalone/webclient/http-server/.gradle/checksums/sha1-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..f397849f68bcb327f02cbe8349609647b8eff116 GIT binary patch literal 28379 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 literal 0 HcmV?d00001 diff --git a/samples/standalone/webclient/http-server/.gradle/file-system.probe b/samples/standalone/webclient/http-server/.gradle/file-system.probe new file mode 100644 index 0000000000000000000000000000000000000000..3addccf3ab846e10b9442e714d678c76dcbed0fc GIT binary patch literal 8 PcmZQzVC>2&+h_>@2W0|Q literal 0 HcmV?d00001 diff --git a/samples/standalone/webclient/http-server/.gradle/vcs-1/gc.properties b/samples/standalone/webclient/http-server/.gradle/vcs-1/gc.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/standalone/webclient/http-server/.idea/.gitignore b/samples/standalone/webclient/http-server/.idea/.gitignore new file mode 100644 index 0000000000..13566b81b0 --- /dev/null +++ b/samples/standalone/webclient/http-server/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/samples/standalone/webclient/http-server/.idea/compiler.xml b/samples/standalone/webclient/http-server/.idea/compiler.xml new file mode 100644 index 0000000000..902be9d7f6 --- /dev/null +++ b/samples/standalone/webclient/http-server/.idea/compiler.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/webclient/http-server/.idea/encodings.xml b/samples/standalone/webclient/http-server/.idea/encodings.xml new file mode 100644 index 0000000000..63e9001932 --- /dev/null +++ b/samples/standalone/webclient/http-server/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/samples/standalone/webclient/http-server/.idea/jarRepositories.xml b/samples/standalone/webclient/http-server/.idea/jarRepositories.xml new file mode 100644 index 0000000000..77e3c28260 --- /dev/null +++ b/samples/standalone/webclient/http-server/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/webclient/http-server/.idea/misc.xml b/samples/standalone/webclient/http-server/.idea/misc.xml new file mode 100644 index 0000000000..9cc7e822b0 --- /dev/null +++ b/samples/standalone/webclient/http-server/.idea/misc.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/samples/standalone/webclient/http-server/.idea/sonarlint/issuestore/4/4/442292b8a7efeabbe4cc176709b833b1792140ec b/samples/standalone/webclient/http-server/.idea/sonarlint/issuestore/4/4/442292b8a7efeabbe4cc176709b833b1792140ec new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/standalone/webclient/http-server/.idea/sonarlint/issuestore/4/9/4933a334253a42a1b13f0397013f3267a154e096 b/samples/standalone/webclient/http-server/.idea/sonarlint/issuestore/4/9/4933a334253a42a1b13f0397013f3267a154e096 new file mode 100644 index 0000000000..eee4209b1a --- /dev/null +++ b/samples/standalone/webclient/http-server/.idea/sonarlint/issuestore/4/9/4933a334253a42a1b13f0397013f3267a154e096 @@ -0,0 +1,7 @@ + +4 +java:S5786;"Remove this 'public' modifier.(˶¯‹ +4 +java:S5786L"Remove this 'public' modifier.(ÌÔ¹ +4 +java:S5786,"Remove this 'public' modifier.(Ì…ï‹ \ No newline at end of file diff --git a/samples/standalone/webclient/http-server/.idea/sonarlint/issuestore/index.pb b/samples/standalone/webclient/http-server/.idea/sonarlint/issuestore/index.pb new file mode 100644 index 0000000000..9fb9830c49 --- /dev/null +++ b/samples/standalone/webclient/http-server/.idea/sonarlint/issuestore/index.pb @@ -0,0 +1,5 @@ + +g +7src/test/java/com/example/fraud/StubGeneratorTests.java,4/9/4933a334253a42a1b13f0397013f3267a154e096 +7 +pom.xml,4/4/442292b8a7efeabbe4cc176709b833b1792140ec \ No newline at end of file diff --git a/samples/standalone/webclient/http-server/.idea/vcs.xml b/samples/standalone/webclient/http-server/.idea/vcs.xml new file mode 100644 index 0000000000..4fce1d86b4 --- /dev/null +++ b/samples/standalone/webclient/http-server/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/samples/standalone/webclient/http-server/.mvn/jvm.config b/samples/standalone/webclient/http-server/.mvn/jvm.config deleted file mode 100644 index 0e7dabeff6..0000000000 --- a/samples/standalone/webclient/http-server/.mvn/jvm.config +++ /dev/null @@ -1 +0,0 @@ --Xmx1024m -XX:CICompilerCount=1 -XX:TieredStopAtLevel=1 -Djava.security.egd=file:/dev/./urandom \ No newline at end of file diff --git a/samples/standalone/webclient/http-server/.mvn/maven.config b/samples/standalone/webclient/http-server/.mvn/maven.config deleted file mode 100644 index a682990566..0000000000 --- a/samples/standalone/webclient/http-server/.mvn/maven.config +++ /dev/null @@ -1 +0,0 @@ --P spring diff --git a/samples/standalone/webclient/http-server/.mvn/wrapper/MavenWrapperDownloader.java b/samples/standalone/webclient/http-server/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index b901097f2d..0000000000 --- a/samples/standalone/webclient/http-server/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2007-present 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. - */ -import java.net.*; -import java.io.*; -import java.nio.channels.*; -import java.util.Properties; - -public class MavenWrapperDownloader { - - private static final String WRAPPER_VERSION = "0.5.6"; - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" - + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if(mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if(mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if(!outputFile.getParentFile().exists()) { - if(!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { - String username = System.getenv("MVNW_USERNAME"); - char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); - Authenticator.setDefault(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(username, password); - } - }); - } - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/samples/standalone/webclient/http-server/.mvn/wrapper/maven-wrapper.jar b/samples/standalone/webclient/http-server/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index c1dd12f17644411d6e840bd5a10c6ecda0175f18..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58727 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%0ANsA|A3-jj|r`KAo%oTajX3>^E` zq{Nq+*dAH{EQyjZw_d4E!54gka%phEHEm}XI5o%$)&Z+*4qj<_EChj#X+kA1t|O3V@_RzoBA(&rgxwAF+zhjMY6+Xi>tw<6k+vgz=?DPJS^! zei4z1%+2HDqt}Ow+|2v^3IZQkTR<&IRxc0IZ_-Di>CErQ+oFQ~G{;lJSzvh9rKkAiSGHlAB$1}ZRdR^v zs2OS)Pca>Ap(RaSs7lM2GfJ#%F`}$!)K4#RaGJ_tY}6PMzY{5uHi}HjU>Qb~wlXQ) zdd(`#gdDgN_cat+Q#1q&iH{`26k}U3UR5(?FXM>Jm{W%IKpM4Jo{`3aEHN)XI&Bwx zs}a_P|M)fwG1Tybl)Rkw#D__n_uM+eDn*}}uN4z)3dq)U)n>pIk&pbWpPt@TXlB?b z8AAgq!2_g-!QL>xdU4~4f6CB06j6@M?60$f;#gpb)X1N0YO*%fw2W`m=M@%ZGWPx; z)r*>C$WLCDX)-_~S%jEx%dBpzU6HNHNQ%gLO~*egm7li)zfi|oMBt1pwzMA$x@ zu{Ht#H}ZBZwaf0Ylus3KCZ*qfyfbTUYGuOQI9>??gLrBPf-0XB84}sCqt5Q(O$M& zoJ+1hx4Wp#z?uex+Q1crm2ai?kci;AE!yriBr}c@tQdCnhs$P-CE8jdP&uriF`WFt>D9wO9fCS0WzaqUKjV_uRWg>^hIC!n-~q=1K87NAECZb^W?R zjbI&9pJ)4SSxiq06Zasv*@ATm7ghLgGw3coL-dn6@_D-UhvwPXC3tLC)q3xA2`^D{ z&=G&aeSCN)6{2W6l@cg&2`cCja~D2N{_>ZQ)(5oSf!ns1i9szOif~I8@;2b)f2yQ5 zCqr{lGy5(^+d!<0g??wFzH^wuv=~0)g55&^7m8Ptk3y$OU|eI7 zIovLvNCoY%N(aW#=_C%GDqEO|hH3O9&iCp+LU=&CJ(=JYDGI;&ag&NKq}d;B`TonC zK+-t8V5KjcmDyMR@jvDs|7lkga4>TQej$5B+>A`@{zE&?j-QbQWk4J*eP2@%RzQ{J z?h`1~zwArwi^D7k9~%xtyf(2&$=GsP*n-fTKneej-y6y(3nNfC7|0{drDx{zz~cSs z<_+d2#ZDst@+`w{mwzmn?dM2aB;E;bS-Opq$%w@WnDwa$hUGL90u9c=as)+_6aO10 zLR|CR8nr<2DQTvkaH0QDsyn@TYCs7Nk3lN}Ix$)JM0*zf=0Ad$w9j723W#%{r8V&`{wx-8kSv#)mZ{FU%UZDIi zvbgLHyJ>z0BZe`GNM$Q;D6D48#zc9s(4^SGr>u-arE}okN62N{zuwX)@FL5>$ib=b z5Wtm~!ojD3X|g59lw%^hE?dL;c^bgVtBOkJxQR{Eb*nR1wVM&fJQ{<))bn9e3bSlu z3E-qpLbAE(S^I4mVn`?lycoV!yO!Qj_4qYgsg7tXR)Gu2%1)5FZu&lY7x>bU`eE}x zSZ5c`z~^&$9V?eEH!^Rp-Fz3WiCvEgf`Tq}CnWRZY+@jZ{2NewmyGUM6|xa3Sh7)v zj6d&NWUVqu9f-&W)tQ>Y%Ea!e76@y!Vm*aQp|wU5u<%knNvHZ!U}`fp*_)mIWba=j z*w9~{f5pD;zCmEWePjM#ERNiNjv!SnM-&rGpB9Nmiv}J+hwB&0f_+x?%*lgJFRHsqfFDPwyvh8<*xLT0u_BeEHw{q+UGj=$4udEx)Vq#sV zKB3+_C!RUKy?ac3-`+}dL2!D_2(5=8&@hBf`-AbU`-<_3>Ilqkg6qSI>9G(@Kx?g<0h0K&31$AR>R%d}{%DyXPss$&c^ja7NR z$0AN7Fl$>VpGxqHW15CjxAa6DUVmCpQNbOwBv8D^Y{bXg28> zEQE9xl?CWh0gS6%Y=G4Cy($Vb>jBb2f_dm#0_B<_Ce`|~Obt_Xp^nkR zK%o_`{h1XkWn}i|5Dp#q8D(;k;2|+{DAG{2gJgPNQ=KZ=FKY@d>QEu6W;oLsE(1}< zpnwSEj(K{Bu^#CXdi7L_$!X`QOx^tA1c{&-XTHo3G?3(H*&VM~*Aud?8%FU=dE&kV zJ$SqZoj^g@(q9x;7B30J$(-qUml{?3e+I^Cf?X0PpLr}m zS}W9`QaCwINRU&D5>j9O*j6S}R1`7{5+{d-xUlI~)U!^4+*b5tkuon-Msz03Z{{Kp zH!GAXoyr#1K;t5o#h#a%Lzj3XQGqM0TRnfu$(fsQe^wb_?W!m!+7r55q>svWN`k~T zS(gk9bi|@+8wg;dR<&0f;MpwQbY27$N{{laPQk3@3uCz$w1&jq)`uW*yn!Pe-V^%Q zR9)cW;UB~ODlwolWFAX?ik#_|v)AtHNwoq72E9Jg#v2e5SErf+7nTleI8&}%tn6hf zuz#5YtRs94Ui&E_1PakHfo+^t-{#ewhO*j5ls-zhm^C{kCARNEB1aORsxE!1SXBRz z6Oc-^#|0W6=7AJ;I|}pH#qby@i^C+Vsu9?zdtkE{0`oO_Hw|N=Lz9Is8j}R zI+8thGK?(KSZ5ZW4nQG1`v(=0Jd*0gIlavVihzo#fPaa=}(Rqdxl3^6O8K+{MqU`;1iTJ$<^k)Nms(A$j?A-wHJKvh9 zUHW3}JkE;x?FETPV8DFTxFLY8eSAd%C8vp?P_EuaMakmyFN_e?Hf|LBctnncUb}zF zIGP4WqtKCydoov~Bi<_I%y%$l+})!;SQVcP?>)9wM3q-GE6t9*LfoePBlo{gx~~e{g_XM5PQ8Y5dsuG%3Xq}I&qcY6 zTCo?<6E%)O$A2torq3-g8j3?GGd){+VHg@gM6Kw|E($M9}3HVIyL1D9321C zu#6~~h<<*=V7*ria%j^d5A;S^E;n!mOnFppfi+4)!BQ@#O2<|WH$RS~)&2Qol|@ff zFR#zmU(|jaqCXPA@q?UhrgbMO7zNXQYA@8$E+;4Bz7g=&zV-)=&08J_noLAz#ngz$ zA)8L8MrbXIDZuFsR_M(DsdX)s$}yH!*bLr{s$YWl5J?alLci=I#p`&MbL4`5bC}=2 z^8-(u4v2hs9*us}hjB!uiiY6vvv&QWJcVLTJ=SFG=lpR+S4Cd91l}oZ+B-*ehY2Ic_85)SRSa% zMEL~a3xrvH8ZnMIC!{9@pfOT7lrhxMf^8N20{CJXg}M35=`50S;6g-JYwjwj!K{^) z5Bohf6_G6z=+0V8&>F8xLbJ4mkCVu^g66#h&?tL z9odv&iW21IAh~y9D-DupKP-NcernF2(*RsFkAsM<$<>@-Cl1?&XAi4+Mh2Zm@2x#u zWH&J^1=8G|`|H2%94bnjUZyI>QACu9FS}^$lbtzzCz4AMspqGYEwFFM<%G!Oc$+;7 z3r_L!H~PR}5n8+3-&4v*fFr$uK{y_VamM0*TKn^))nQsn5U?7Iv?`4|Oy&m6himAG z%=a;2ji3f_RtDPqkwR>ISxhnS0f)E`ITo}TR!zIxPwECZy#jzo%q{BNYtd!<IP_S+=*yDOk1GgwLqe!d9esV@3$iVAm1!8RoE| zqnTz;5a)B(~~KcP)c>?+ysFAlAGF4EBor6)K{K*Kn>B(&QtMAkR^ynG%k%UbJpKM zI$}qQXXP3PISHe_vTFssbcL`irhG2zN7J((3ZFmh*bnPuiK~=#YG=820hXqOON#HI<0bvIT{z&SaqRvqaMG-d5<06zdP?-kIH{%UMR$Xn@S}Hx3 zFjg}6no}vN_512D+RIn-mo9^_Li-)WI5%VigYt{Jd!RyI%d|-LqJU$y3aJ*a$y6$1 zjyTuIF2&t>1rPlw&k5OVLhrYBvk5Vl8T(*Gd?Alqi}> z<@-`X_o@9EOB8Ik&?|;lvKHFU@#O+?T!kEf&oJUaLzN;>!}!!e1WIs(T}V#Irf$AK z42`x`z-9ogxd@%CS;D5S z2M^b;Pu)q)c&_KBO!va-4xnI57L7V@*_I_r4vU)z>xk5z6PDVqg92R7_iZH|VlO_B z#8R`5HZVn?ou>czd>gZ~s;w4ZkzVXJNP8FiezlB5JXe6Z-OLsDw%N7!(135!Vl2Lb zLYI79?U{h#W-_#W6hf`<$BQHJCu5ehv?IF+-uxUqt~j!ZW1cxfiEJal^q7~RMWQ0a z2CEaPa1_p|P6qRmmeKgas*N}@(2tH%U37-<5i(DSnVOFFxg-Sv%7&{hPeRh{U`&ufGz=V|JdYQ2sG5 zk%3JimSwQFP=Yr?u_beSG^B$nnh$4hrxb4lpTTiUFRQEZ3ulr+L3m;>;Io?D;jG6Wjj!b)nsZds<6 zX@cD%+aVr!ra~F7HYr`TB!|y-t)HSb^FQt zbo+_XP44IWJGGxg73JyhBjKMSv`77ngDOw}6Eve6ZIol$Q5s65d(1-sP{BU{1_y)7 zF8sh5A~jxRHk=wq3c5i3*e&otCd9>cstT?IQ&D4slC-&^q!ut1;WAQ}fE}Y+jU}r{ zmpSI%sW?})RAm8}$WUU+V$PmQOF5gSKOGQ2;LF-E(gd<67rYu2K| zom8mOppa%XJ6C(@I7-*opqLn73e9BMFStaBER?suJ{jte1$vA%z?$_`Em=a=(?T-q z*A=VZOQ`P{co!*UUKyV@Rd-c#*wmb7v<%rN=TGFmWmqhbj#&+?X|3bZYAjbNGTv~O zs7SIYi3VgW6@?=PGnbNNZIWaY^*+ChW&a)A$uqH8xxehwx2`<1w6mag?zuHbsVJiO$a)tQ zuBBoR>rLfhpA@)Qf`8BwRMx886%9HP5rOR%YCy9pQ|^Xw!=Mcnwx8j=(ZE)P-tJ&s zON&Nsr%14jS@K+IvrJj720NkCR*C(j&aI$EFCV)w$9M<#LdihyRKdzTjJPI|t9_S} z--#oF#;F?Y1KN%_yE);Bxv}9PWZphz_g5mReOKR`y%9UZ=n}GXWw?E$T1%NAfK1Ad z|0$Lp^;sntA>}=ybW)mkxNv1?hkZ`<8hCemcT5 zYl6$I^bhXDzPlz<>6zOy3Fu*3?>#q$;1fJ>nuxyx#&<&x6Y}j zCU&VmtCJ`;aYN+qP}nwr%s2ZQC|Z**axS^?iGu+x^{{>FIv!k0#HaXtEG=*C7kPe!mMnknbn}TKpp6Xv9 zVvq&%A3nmY^N*XTg&+=wO>(|{uTwm;ZP9@+M)6%T zwXPh-&{+aAfv^ZCzOEb;yj>A=f5Pbu)7T{9PT3u>#w*%?K8jqEF%I>A?q;E%CXn)f z|0ohNa5DMv@HVk^vT(L=HBtH*Vzo81L?)M=g7)>@j*vUx?S zxqZo23n3vn@K-Q@bx3lLT+5=fB_oz8+p?P;@*UU<-u)jb5WFEXzoc+8*EC5P6(HWr zY$mfFr=L&G>(jvl8US2fLQqTzHtAGizfR*;W4-kN2^I>L3KkXgx=e*}+i*N($}{?c zi=Q67G)oEMW{|Gdsm{)|V)5Evo}KLj%}gIe>98FFoNTLrJX z-ACRdewnT1w#Egct%wpGg~q%?!$}>$_UJPC4SP0^)G_$d4jN0jBEx}+rcd*^aDtnx zewG{`m!oSbQ?A~FZ6L{&V0hUE+b$DxjO_;oskFha>@gzy(jDnzGO>z3Tzz|i&Dakg zFid5$;SFxINis^4JzK5XIVabKoP`=ZWp|p|t{hTi8n|#XE=-rINwJ*blo?=%Se(qw zkW7x5Qs(LV5RVGxu2e&4);c73lY#0(iZo1x=MY;7mW`uUQIY+$_PqH`4a`6O#urwU zE6(FrvyExmB{c5z*YAj_P&t??F1t6TN2N!$N#~02u(t(PDVyD)$mL3hqKQ4E91N#GOIngPr&pUb-f_Z4*XV8`p1pq+mzrUlUY=4~i|3RDo;Lo36U}uwm zaOah}mO8c@%J*~~{Up7_7->8|3x<}WemgaMA}h>xD17Fey@V9;LgjQFSBS(A<+2kCP9( zlkD%;oXzWtZ_hgu0IxeTjH`6=vi|t_04Btl32=g8swD1oZguWr4|lx0RuXoDHbh27 z+ks?gkVWYnr~_{h+PzQjQ(#8kaJai4We{F!JuqCzU0t*+H{n6i3;K<>_6XUn1n)}) zJ?}JCUPYhT9S1Hi-M+$(Z**%fz7Z%IiMN6%kD>wh%r4#C?Ge4{>w9o??Vbehy9!3@ zffZs8?LGxyWQr@yB(|%~Aa>fVj3$O=i{K*f;?h-a@-ce{(cY8qByOCA1r0;NC}}gr zcC^fCa$Ot`42n>`ehclOAqBo7L&D6Mi=;M5!pd@jj$H z?U7LQWX_u7bHpBzF7L-s4*`C)`dUrbEIgKy5=QHsi7%#&WYozvQOXrNcG{~HIIM%x zV^eEHrB=(%$-FXVCvH@A@|nvmh`|agsu9s1UhmdPdKflZa7m&1G`3*tdUI5$9Z>*F zYy|l8`o!QqR9?pP4D7|Lqz&~*Rl-kIL8%z?mi`BQh9Pk9a$Z}_#nRe4NIwqEYR(W0 z1lAKVtT#ZTXK2pwfcCP%Apfo#EVU|strP=o4bbt3j zP?k0Bn$A&Xv$GTun3!izxU#IXsK1GQt;F0k`Tglr{z>v2>gCINX!vfs`aqag!S*AG5Z`y-# zUv_u&J4r;|EA`r!-gsoYGn<^nSZLH-nj1SRGc0MRG%LWVL)PckFn9z!ebIJ}eg+ix zIJo7GN;j1s$D6!({bYW)auypcB~eAWN;vhF%(l=|RR})$TOn;ldq^@8ZPi<%Xz~{Z zQQ|KAJ@JHaX!Ka2nhP%Cb^I}V6_C|e1SjOQpcPMMwfNz#U@Az|+rmH*Zn=cYJu-KR z{>f++Z~P=jm)4-7^yc#52U4qeNcBRYb!hhT3Q7Ngu5t@CvY*ygxu^Eh?2l6= zhdqN{QEaP(!p>1p1*toD!TllHH6EH~S%l9`mG62dyAd+?}1(vf@N*x^6vhEFU<-RqS7#12*q-xtU z5d|F^n%WSAQHnm-vL)4L-VvoUVvO0kvhpIg57Wf@9p;lYS5YfrG9jtrr?E<_JL{q% z7uPQ52{)aP{7<_v^&=J)?_|}Ep*`{dH-=cDt*65^%LodzPSH@+Z~;7sAL}ZECxQv+;z*f;(?k)>-Lp@jBh9%J`XotGJO(HcJc!21iZ98g zS-O!L9vpE(xMx1mf9DIcy8J5)hGpT!o|C8H4)o-_$BR!bDb^zNiWIT6UA{5}dYySM zHQT8>e*04zk1)?F99$dp5F^2Htt*jJ=( zH(#XwfEZ`EErdI~k(THhgbwNK9a(()+Ha1EBDWVRLSB?0Q;=5Y(M0?PRJ>2M#uzuD zmf5hDxfxr%P1;dy0k|ogO(?oahcJqGgVJmb=m16RKxNU3!xpt19>sEsWYvwP{J!u& zhdu+RFZ4v8PVYnwc{fM7MuBs+CsdV}`PdHl)2nn0;J!OA&)^P23|uK)87pmdZ@8~F$W)lLA}u#meb zcl7EI?ng$CAA;AN+8y~9?aon#I*BgYxWleUO+W3YsQxAUF@2;Lu-m#U?F(tFRNIYA zvXuKXpMuxLjHEn&4;#P|=^k+?^~TbcB2pzqPMEz1N%;UDcf{z2lSiwvJs(KhoK+3^2 zfrmK%Z-ShDHo^OUl@cfy#(cE=fZvfHxbQ!Chs#(vIsL%hf55_zyx>0|h2JT=|7JWo z+Uth3y@G;48O|plybV_jER4KV{y{$yL5wc#-5H&w(6~)&1NfQe9WP99*Kc+Z^!6u7 zj`vK@fV-8(sZW=(Si)_WUKp0uKT$p8mKTgi$@k}(Ng z#xPo-5i8eZl6VB8Bk%2=&`o=v+G7g|dW47~gh}b3hDtjW%w)47v#X!VYM}Z7hG1GI zj16;ufr@1^yZ*w3R&6pB8PMbuz%kQ%r=|F4+a!Gw2RBX6RD5c!3fU@+QCq#X7W@Q5 zuVQ}Uu0dzN+2mSX5)KV%CsU;2FL%B6YT`10$8JR^#;jOO1x?t()Q_gI zxpQr2HI0_^@ge0hNt&MQAI`yJ1Zhd-fpR{rdNmRkEEDu7SpB)QOP4ajV;UBZZZK<6 zWds;!f+|}iP-kqWAH#1@QisJpjcg`+s80!LhAG@(eMad|zcln~oE8}9l5!K{^zf~( zd=HArZ5+Mryc$uNa`@|GSdOX=y}8GZc-%p8W@OM)uk2DfmhQXCU1E#y3XJ>|+XdW2 z)FQLeK38}u_D(5E{GV|YT^rI4qds2{-r<@@@@SG@u&4LbC z5o|KKqVM{?wk$5>2?t*I?IHdh~gljn_2m2zqZNJEEz4Mb$o&I3_UAg#$B{0u$uF4-q}{ zzs5+k@qOe08!CGLGmy3eRrcuqsgB*B>i8c3>3=T^Hv>nL{{u)jtNc6tLbL7KxfUr; z=Pp14Nz+ggjuwd~*oRJ)xWwGwdge+~b!E%c3Gzw6`vT>CCxE0t6v5Z`tw1oKCcm68A~Dbc zgbhP6bkWwSQ=#5EsX*O9Sm^}EwmQQzt2V2phrqqe2y)w8;|&t6W?lUSOTjeU%PKXC z3Kw$|>1YrfgUf6^)h(|d9SRFO_0&Cvpk<+i83DLS_}jgt~^YFwg0XWQSKW?cnBUVU}$R9F3Uo;N#%+js-gOY@`B4+9DH zYuN|s&@2{9&>eH?p1WVQcdDx&V(%-kz&oSSnvqzcXC3VsggWet1#~bRj5lBJDo#zF zSz))FHQd8>3iSw{63m`Pgy_jkkj9LTmJ&!J(V0E~&}HJ4@nXp<(miz$sb;(I<8s!7 zZyezu!-+X81r03486gAlx@n#aKx_93DREBtNcYln*8oliQ zbh0~SkAgHXX%C6}HwN(TRwaK2k_$Y}PxKId;jYt=S1Bf<8s@(IL?k3u1(f^V%TYO1 zA_jPf*V)SLEZFWS#y>M&p$LoSk+%ubs`)H%WEZf=F)RKh&x;i)uLIGJ94~A4m$(;S z;1rQC{m>--`WHFcaFA&5#7~vz|5S;{fB(7pPnG;@$D~C0pZYNEG?B8X*GB2e4{Qk; za1oop8OvHqs1Lk6B`AuYOv4`y`IgM315iTr{VUVc9WeOG;xE z%eDQgE4rb_B%vuT>N?^K zRvPnQwG%7RjO26+DY!OXWjgBu4^!)W-+ob_G&nX++))pD->QdRCo0spZN?Y*J#@-q z)fk-fJvZYz8)GSxYc^oXYIM;Pw}ftHW+a3dis#dXx^OS^m-~FlwcVr6MXv78fNI!i z51K-2t&!&IZ4(GF=mT@;qIp!&R(I@UiWPPz)%Us&(FdAAGxZ-+6^UZ7em`J-F#_3r zLkHym@VAnZFM$J~?0b@&O`l4YXyvOQ+OqalbZ0{g{qD{neY_xno1ZpXlSJWM=Mv(~ zvK{?O>AcXpbd}+hn{~*>weZwDTURX*M^9RkOO#DUfRW1;comKg1bn+mlsrNY8XDyW zgWg9~AWb_1^D8zsD4bL(1J4oinVy0Fimrh&AC}Itl;IH*p4eU_I;SWkOI!9tAbi3B zO@0=q#LHAc>z?ve8Q&hsF(sR9lgf_99_5Kvuug<^&0}Y&m)YjI?bITGIuh}AJO|>z zc*`Mly$>TA={AIT#d%JuMpXHDt($qkc*3UTf-wS$8^awqDD^|EAeA{FoeyJfWM@QX zk>vJ4L|8DU7jg_fB^3Qvz*V$QmDl*AXdw6@KSckh#qxjLCM8Nba!dTkJgr(S@~Z0a zt8%|W!a~3zG4Y&X6xbLtt^JK5;JT($B`_9bv(BjRTfG_Y`tg3k-}%sQoY@F|=}}${ zwmW%Ub6jPd)$;NA0=b7w!^2dE-qvI4)AVr`yvkabJcGwvuQ2rAoRlTjvCC^-$2BG} ziy0<6nt8;J67rymwm&wVZ8E7Krouv2Ir@-GQ%ui6PR42KHKms3MK&Z$zp{_XAVvrd znK4cbg)Ggh5k(4SlFOM9yyRUlVH1oo%|6Lu9%ZxZW28!c9Z%H5#E?B?7H7ulcUtirB<{s@jnS(-R@we z^R#{Mn$#JXd~5sw9rU&~e3fYTx!T&hY{S<~7hviG-T$<4OPcG6eA0KOHJbTz^(`i~ z_WON4ILDLdi}Ra@cWXKLqyd0nPi06vnrU-)-{)Xp&|2gV>E{Uc>Td`@f@=WYJYZ^- zw&+fjnmyeRoK-unBVvX>g>wO3!ey<+X#z@8GNc9MD}khMO>TV{4`z zx4%!9|H6k|Ue;`M{G6d!p#LL+_@6WMpWgF7jk*%$D_JB3c%D`~YmHRJD1UNDLh;Tf zYbbKcv9R(81c4yK+g+1Ril{5w#?E}+NVz>d@n48C-T-(L?9a9W`JV*{dan-sH*P3_Hnt~iRv)}ye;7$b}^4l%ixphDK`G#b!4R4qoouT@*A zZ)kQa)e94??k7N>tqoRl>h(9DFq&92=z|F!LJrh-97EoFL|Wt2v}>(zG1*#aiYA_^ zM_&%_G^g*O8x650e>m!#MDmwRub!irY>^^|L=!4^%lBr;?}mvgP3y~^mSdKSm^R~WAt7T0_ck0mA`GS)J^SYTo6^vQ|vuM7!92&@$BhtcQ^Z4h2)aN zh~EQthyjn1(eI~$FtuHH!|x(iHU{9k40k5nPBwB)X@8Lo$P6u81EeoNOGRct%a-LM_4y3Ts z7ki0PWAO^Es6c%M*SSRn)2|NAoUsKyL%))uVx7?5lkrk`njxs4q@M~x+8%jr7xV;- z|KC=g3aTZO|y|g~oHXB6b42(|J_&fP2Y`*;L07H2d>{~JP zFNGl$MYUG(Qy3dR?9Bfdg8#peGRiVP8VYn@)6T1bj*v)s6q*7<6P(ZVm4ZnTA;rOHSd>P`_5uT0+azWdV`gIvLaJ1o*DB}&W6LCgX|BycgF5qd z!)}dT#A~4*6{1=Bd5VV(Qa2h4x9m#2X711z(ZN>i&cn`BopG*5P`CD*HfYiQmXNGk zhgqcHPBrJP$Z@PLZ4}d-8^}%X^LtUDHq&;~3}lUyrxxl@|IS={GP&6-qq&Iy5gKW- zC@$}`EEZd}DOSeSD+v_x5r_tpBWfN0gDa21p(@TAIrgWQFo7NO@slI6XOAML_lN;3 zEv~}LlMbGWKu}0s$tO-vR)wD!=olGcA?}vU;lRu4+Zf z?nCD7hBmA5`U9P#W8-*0V1=OT-NI0k&_`UZ87DbpYq_=DBdyNDchZ<|V1f%dbaa7i zf~R+6Xt%G)VXlM@8REfP3u#7UPadWYOBMsQ56fHRv!0p9R6q>Rbx!n|IY0goLb%{+ zzy|5WXk+(d@ChzOWatIV1lc1F!(uEOfEmMd;v`|$Kt3X2Uws;%@OV!E86PN?CeHV& z=4#TX{J8RWaH`)!J<8AUs#Ar{6Am^8M{S( zc%K7y2YbcLUz+*eDTXdthNE)Lm^P&*e^eV zilOS9)TVKgr9_^_M!TJ^44v<YF2NO=h(oOr5jYxVTxWk0XJ8n0{F_SOH%49WMk*Sg7`g6B(=^< z*rLAW;8I5;1?;Fh{N=f;kxjLpj}u^mD|k8lih|G4#}wEG1j`HIG( z8y;BMR3cE01e?(+k8NLR|Z+)#>qR^iMZc=BkcixWSKYmkaHpIFN?s%*74kc&wxwB zrtbYBGz9%pvV6E(uli6j)5ir%#lQkjb3dvlX*rw5tLv#Z>OZm@`Bf2t{r>u^&lRCg z11*w4A;Lyb@q~I(UQMdvrmi=)$OCVYnk+t;^r>c#G8`h!o`YcqH8gU}9po>S=du9c*l_g~>doGE0IcWrED`rvE=z~Ywv@;O-##+DMmBR>lb!~_7 zR`BUxf?+5fruGkiwwu|HbWP^Jzui=9t^Pmg#NmGvp(?!d)5EY<%rIhD=9w5u)G z%IE9*4yz9o$1)VZJQuppnkY)lK!TBiW`sGyfH16#{EV>_Im$y783ui)a;-}3CPRt- zmxO@Yt$vIOrD}k_^|B2lDb2%nl2OWg6Y)59a?)gy#YtpS+gXx?_I|RZ&XPO`M!yl7 z;2IS@aT4!^l`Tped5UGWStOw5PrH#`=se%(ox%gmJUBk18PsN$*-J8S%r51Y$i!4N zQ!rW%cgj44jA~_x%%smSTU2WG_W0c&PB$A5*kl8{$|865+lSIX~uyDT`uI7qnS!BPAg1Wwrc0e)8Usf zv9^E38H&hWSp5!@K8Qinl|)9 zEB?NMaxZK^GB!PUf1TBw+`H&jFSNI=Q@v5$Ryf-y^#IuXO#vsM5R+9@qz#z0fD0GP z9|Hj#E>?<=HTcsF$`xn`je~D&3kF1Qi%dfH{sKh!~(IpgjkDGQn zQx2F9rv{*x2$(@P9v?|JZY)^b9cd+SO6_1#63n-HAY3fE&s(G031g2@Q^a@63@o?I zE_^r%aUvMhsOi=tkW;}Shom;+Nc%cdktxtkh|>BIneNRGIK{m_1`lDB*U=m|M^HGl zWF#z8NRBduQcF-G43k2-5YrD}6~rn2DKdpV0gD%Kl{02J{G3<4zSJ1GFFSXFehumq zyPvyjMp2SLpdE5dG#@%A>+R3%AhLAwyqxjvGd{I7J`Iw{?=KKPRzyrdFeU}Qj{rm{351DoP_;vx zMo*s+!Gwgn;${(LXXO(xyI@$ULPZI|uzYR%`>MmW6Hcr1y2aM5b$grFwW_(9Fzz$Q z$&8dKNdWvBkK=iYWA|0}s1B7>8J$g*Ij_+S9vC1#jy~uA8nr)yY)a+ zoJ=e>Lp`7v3^tQN<&6UpDi{c1b}F~fJ$9r=p=@U^J_7bOck$5}ncVjYB0yEjbWrhe@E`j64yN3X?=k_F3BalH$aN zV=94?wDNv=BKLB<1*xU|65Zl!%51r5sHQ?qCggCw;$2QfCZ$lN40WPL=n^{Prf^QS zjbZ&1MRGgiZ2T)}DpiluFr#q*!AZJ$1v#d10YQ{>wQ5px!y28-1hCZ7lwvQnQYN*U zOg9BpvB0A$WUzFs+KWk1qLiGTrDT-0>DUpFl??l(FqWVz_3_Xzqg9vTpagp- zZcJ!5W?|0G%W|AJVVHJ7`u6@<4yyqMGHj@kpv`P+LV<)%PM__Rz&oq~t-*vV12@NR zoEVPz<2D>O==MlNI`;l8Gmv49&|1`FR!}2`NLRCqA{@`imLz6zrjS4ui0)O;!Pu&?KPAcX)?tDPS26uKvR(ry(p{6kiXPoZbnQ!vx6dLu zZCaj~Ocr$h##KqsD;9;ZiUwhmUd%5lrwczWr1Yn6V>+IK=>51;N7JDkrm1NY-ZBes z;FxeOTb^HAyA+~P2}WvSSu_fzt_K=(m4wUp%c*^hF zEJ+1dP0{0B8bryXR+qApLz43iu?ga<5QQxTa$1gMCBq0W=4|DTv4nY4T*-^Im%>U~ z)98;hc(d7vk0zAML$WnPWsqK>=O-FZSLI3_WQKr*PCK=(i6LelZ$$}XXrD5cb~VXz zT%egX>8e;KZs@jcD>cL9VP(Q}b0r~ST$Mc%mr1cC8mqRUQc|N^9@Weu$Z|KeczK7HhSFeFV0i)MQmwrn7CBL=p`_9n?nh320m}6-MSv3L7I*<*56GR zZ`zI^1zyC7F#*zVL@M)F2+oqxydaiQz?|ODmqs|Ub8%&KXk9P3P7<4tM?X{~!;Ygw zt=h7)AYGDO9F&wV=BhCyD9exr#YM_-<;Fo~iE>IBEXK$%;JCUAEr;lR&3S_DUy_E) z#!oCYdENVE9OaaeaIrPk-odMtvdFG;ocA#`L6AifMu0og^?Oy9F|Et9q6 z8;3_|9+Io@hqYoN;58x1K&OP!9Vd#dzhTRjB2kI?%31ceHb#Q~WqJV5lw;@b>4@Rd z={z1S`d05YdWC*RLc7sR0bVGSytn-a3`JZL3|d8KC?vj_70Vi4ohP9QbU&Q4?Zjd0 zSZA?KbqLBsJg(qj>fycto3`zN-)lDe4{Ij-QfoBn@rT_tTszA+CnM~xWmE(4zfpCQ z;zPJfl3=ctrggYM!KQg;V{J;utMMF9&BfOe!<{wU0ph?-VQ%cv3B%fFiW?6xBPdf0 zD-HhEU?0C`G@7e+b-=8fj=TP3mdz&SIQ}Nd`*G#DTz9Y@b zaoDF}Gx7ZhPzpDhi^fA7WZ)EAEFv;N2*bKp0T za0t<^1|Zc#`A+?s$!$8eO4CK~PUFECC3BwNR4f)!V&-Y>$xg(%T{MtrH|CPcO(Lf> zE_meE1?6S-qlV^p2fh! zT11Ub)hHw!_mpFDMIAFB`%Yal+`1IXV>b?%!q^Ps%8nh8wtjVGlF-!5x*D29WJ4=M zZ7X(QvKe$YZNgM(HibD7+VO5Q29?@HzS?k$c|3B@JI6dlLgu5S&LbU4=4p-Yn||z@ z4p05vq*k*pbOV9QjVTMp8`c$?t@~!$8&5AP_sz@tk%a$nWHMh-Gm{WS5+q)5W6pU# za@YZXJCLTpZ}zb=$HCYbIm->?Hu6XIBz_d7)n1+3eSLzGVoNQCTHcu9qS2@({0sxc zu<-mhx@Xz_*(S1DEL|d0`YV7uNevL*Y6|DAQmvSp{4DzPL@>hqJ?`FjvIU;<&}YEKDmFUGSBYjRmK{Km-1m%-t=fFfI9kV|POH|SxvO=P+><+1JK_lt5F6fTPf8PXU+lYEJz__** z&>`4F2F8EWE+k7ZsZx9%!?A56{lsk1juYw5zN)V+g$d^Q^Gm}fnHKA6L^36=`e;p% zp{;JD$X3%}O7qINR*2<>a422}_hmc=)-A7B-1#2v85jN5K31t0DtmqON-Dim`XIR; zOo`KRv)gtn?stp*`^f>}UDnGYGnJAbl(4srd>(5fo2#oqi>#bus86EHfeItFIu$+% z;lE|3gjQA`BXHEE5JdcjCoethN`@NEc~zm6CYf@LJ|hT^1>l}gRl7oDHMnw!*5*IC z@@Mi=gO=lZSnWln`dX^4Bd{9zYG{HNIX-87A#5OM%xu*%V?7K3j3CHcN*t!zNK4N4 z!U2?a>0`8m8}UQshILC0g6-k>8~;SRIJ?vQKDj z@U{DrstWIT7ufyRYox^&*IyHYb$3wtB}V^0sS|1OyK#sDc%sh+(gy&NT9j4Aa7J0C zPe$02TylMjad&|{_oe3`zx)Cqns?6qThYue6U=~j5+l0Po4`bX*&9V@a<-O;;vCzm z(af&;e<^}?5$7&MRW$eb*P< zX|33QmDvFSDFK-qMz|RF|Eedum@~W zt~8C1@i8@LammTr)rAgKm8X_SczCg@+@LeWpcmx;VL;iLQJ;t%Z*|XbNWUnHX|o=Q z%bsXc%bw=pk~8%3aV-w(7E$co9_cHQ$!}Ep6YcoCb7~GQBWl#4D!T8A5!P*tSl4FK zK2CX0mjmosg6TSK@-E-He{dm0?9h{&v~}OX15xgF<1-w4DCypYo22%@;uRq`ZFld- z{Uqof@a@P5dW@kfF-`1B1(!R>(DHb&$UXY%Gd+6r?w8klhP&ldzG*6#l#VuM&`)ki z)f$+Rp?YYog9u==<#MC%1daG#%3EOX9A{7$`_(s#_4mV`xZaB+6YlX`H4{}vq;)TF zo~fR@do6EZIR?413A$V6o^fq&QV7P(bB(9m1969szOosyhZRYciAWXe4@u-}s(LeJpuIkSx)XvjXmvVEseG zJvWN4s|$6r;s(3F+cgeh4DMEq??h!$eb^5h#`whT5d03qfYpol8dCim)A^NG1-H}} z!b)V8DTL2Q8@R2p`y4@CeSVj9;8B5#O?jfl-j<$Quv?Ztwp*)GvQ~|W8i6?-ZV@Lf z8$04U_1m{2|AIu+rd8KW`Qk|P1w(}d%}cjG6cxsTJ3Y&*J^_@bQgXwILWY7w zx+z)v81rZv-|mi>y#p$4S7AA760X?)P&0e{iKcWq4xvv@KA@EWjPGdt8CKvh4}p}~ zdUVzuzkBlU2Z+*hTK214><61~h~9zQ3k+-{Pv~w`#4|YdjTFKc{===9Ml7EMFmE!f zH}U3O{Z`DuJrBZbz~OjSVlD6uZSEeNK8epja_LanEh8v;_$Eg9?g*9ihMoat$#qd^ z?;x?a*y3-pW#6|kF^<$w;2^~s!fc;3D~#&#WYZfK@3;bO{MvmN?>qy%_%v`BVCgfC zdwL~(H14Gr6w(1CX|R;zhZh%?*Q{hxJH`MV2)@Jg$pbqjZeL+LO7^vwgi!@3yn@NT zU91-{;BWIi8bV-j-YR|A9Qs?M?e7Ru&Onl1(Sz(kxAw?LEbd+Le%Z43rZgb2h2m|e z^rblc;4r+}?@tC(YIBB_qpQL?_kg{;zO#6JD9{;HSUgf@zIZ)}Bh4wFZIs>meSd}f z4iF~nD$KAV6CVEw+{YOPrW~~y~Y=?snG4dE3edN$~SXh`!c_F zUsQ1M;ARz&v0mIbfP}aLWZ&cBPU+DU{l+0}_>9DZGL{@}lF6QCtgAg;EWUu`D$Evm znblG}kC!}Mw)bR~U;+S}T9TVc6lXWR!LNMm)nmxr*ORkv#&UO$_WQpt0WdX{A=bjC zV^lB~(r;y!C4$Rk0fWUR|09O?KBos@aFQjUx{ODABcj}h5~ObwM_cS>5;iI^I- zPVEP9qrox2CFbG`T5r_GwQQpoI0>mVc_|$o>zdY5vbE~B%oK26jZ)m=1nu_uLEvZ< z8QI_G?ejz`;^ap+REYQzBo}7CnlSHE_DI5qrR!yVx3J1Jl;`UaLnKp2G$R__fAe;R(9%n zC)#)tvvo-9WUBL~r_=XlhpWhM=WS6B0DItw{1160xd;M(JxX_-a&i%PXO@}rnu73_ zObHBZrH%R!#~pjEp~P?qIj4MdAx@sv;E96Doi$eO-~)oUz%Z0Tr4K`-jl06Il!9{s zdjF*1r{XU?)C(%XKPm;UnpnDGD%QL3pgo0ust~+sB0pa|v37>E1dp*Odn)n=DY;5j zDzSAkU9B6F$;|##_mrDe#%hd7pC1u`{9ZKeDdtkyl&4>H=e)Fq@}$UffPt1#cjYZg zd%O%xpg4~brEr>AnKT)kF@`cdX4tMlZ#Vk!l1Xz!G970p`Gkv^lk-|>jmt0W5Wu6woGf?hNA zXO2?BG)<{`NsYAY#3|L^x*=rS7uWU~s<*UhTC8AYc#lGP-=Aw1I)@y(<` znQb^nL~$rlDbsdAc4nc#{+$_;Z4iY;Pi0i9Q;>ZB3+IjWLg_r40-Fso^xF<*_s7Tj zujFrMH{vW3PmCndjQIscnQE%`Qj|E2kidi#c&PcWIMyH+e#7!l`<$_)*pDP$!49pY6w!bN)j8~A1wV%gIakf+vA04 zV)_Q=QMPSj6$M2Ar#KhhxsbZUOq3nZHh8m0?Fr}I6N(Fk zkhXM(f57yOa8vn^97J+g9ISPa=-**6^8ZX&g=z+m&6~x<1>)MyM&tpbWhSf8#+Pcd4rVK#)NSw>1eLKHTO z44A@sc_}Ypi#ggFRbDRFV(IhOnRU&XPrQYh9`mVMo-^U$&AwsXooSRUFqJ7)XUXCK zFpt;gJ}9QTN9xy9$=3OnRkjgUuQZ`X)!}LBm~WUIEKuK-Z%}f?2?+MKucWU<3)>9G zxsz~2pHut1AmH<@66;LdCB9+dSpojE4ggrYS?%icv*Rpi?G0Q($^`(g<1&Z){O_5B$@f#;I2-+Qa1P$a@=u-vOY5vqo z|6G67X;*A|V86ZET9OpFB&02twZtc2K}~ASoQpM_p{vJ{-XvA8UmQa4Ed%fS{D@g( zr_aY0gKw*=2SIGznXXKFo$r0x3)@bq8@4od^U(L0-jvTsK@qYOWX?2G_>N+?;r{TU2{M>V0zid zB_Zu?WSnRl@k?oE*gsgv;jH@+ z-}BDGyR-ls7$dz{e( ztv7lI2|OxNkLD4zc3xGA`!d7LiSdOys4H!8aA(_c0Nm*uLjS4TW%Z3v>am1nwQ_lI zIs85Uufd;cv-(4wi(Js;QsL#|qdv)n;r_?puaK*1>zTC@d=#sK+q1YF_Q(5B%%3TtI8&bNs_e8vIb;oc|Rk`F~u?|A?jj{c={?{Env{mW#q@8 z)#WEgt4B6b&X2?o3=b`ilz;)-h$t4;hsxPDo-%5C(7m#c9tZF-U`vcx0HnVtf_X(}4Tg}4wx(=y!@T7{)4;I_p95mBhikg-|U9z35q`|!1+Zz@97 z(PFE5jCv|=t;^=(CLqYp)k90rV4ZSiFDAhD8YOCzv{}1WDuB?epORibW36);q(Aig ze27@D?lN-ZyjuB4GsebA$;+(KGiOtCe6Bfd%GKRty>dBS1GUe}MXgnu61UdgO=m1& zE(eECPF_%J-lU{;R)eQJot;;}Wch$-8Z|lxN*AAdc;bkpbD`W}F=Z}^Cy(SKyfF#+ zQSalA%JDDAu|77$M3E|kv==3vx~pFPw_<+9xgcE#oigh*>#QsA2}sTYO7uY(h@dhR zHJBi^bb-`1?<1cGFZJa8Akzs{H^$N<)5@hlXeKwt9hD5^5K&`pdHOI92p<7XhS?>| z(5h9KYctN|H+W~Xh2N4W+yjMyBm(AdewjX?PBuRU$^J zS#+U($K6rhFFzf z0q*kJ>B6xI1qAti?H@X@dxtB7_vT+Nj@PNxr?CSK#xqE6jh5S{`nH#zzvjOId=i1X zK(Yjl!7KF(73GXYLVkQA5irn|v-ArCqwi)CM8X&m!#@NQ3bqmQlfurU4qT`zl_m^C zhpk?mfVvy9L|)*+bW8&NY4lG$@0_PKfO9+~(zrbn?wECGi7472W{H&dRPZum^Qf z73C-TR6$#q>XJgYnUgV!WkbmRas;`TY#7CxPXIEGwT6VPBDKbyr#|C2M%q|7l#Ql< zuM}j=2{D+?SxT8?ZJn&Z%cRN8Gu@y(`zV(lfj1T%g44(d#-g&@O0FL5;I9=?bW>!M z%c3J&e}GThdean-<||jUh zlLP`UeKBhhrQ?HHjM3}kfO7Z=EKB%+rs*t+nuBoeuD2yk%n32SA?-s)4+DsTV7U&K zyKQO2b2*tQT}#((=#fkb%hkRkt^%tY&VK$hcs91+hld zJ%lgC!ooILC&|(Z9$zzk=Q0*%&l7wwyf%nv=`C=OcPjb|Q%@9*XkPGFrn+bxp?t^D z!_qO=e-;bnT)^0d|Ex9X&svN9S8M&R>5l*5Df2H@r2l)VfBO@LqeVw`Fz6TSwAt^I z5Wu6A>LNnF7hq4Ow=7D7LEDv3A))d5!M=lT3ConlFN`5eTQMexVVs* zH0tx-*R+-B@&Lp`0V4j6Uy=LJmLQRY_6tH4vnV{_am%kkv|{CYkF}4Wn6U+|9Xre$ zJkO;_=dtw`@aEs|^GlO-zvpp-73H;PYk}V5RrH83G4SVkRJ0YSluQa8pKejcqB4u~ z^9^lDR|?7vEo|jITtaIFI6}1;vTI6n(d0kDGQUJuk>>sqdd7#VBF;?_dM5i<+VMEq zc>habJK}_0eEsOkdwv48d43jKMnqYFMnYDU&c?vi#Fp+S)sxo1-oVJ*g!X^^K! z>z!G8?KfU{qOnLHhaEF4QRHgOpfvoo7@=FG(2ZefYJk- zZuA9ubiTTP9jw9Uzpx8FfJBFt+NNE9dTlM!$g$|lTD za4LMNxWhw8!AV(x;U`IV-(bK@iQ%#QSmq8D$YqLgt?V#|~% z;{ST}6aQbOoewMKYzZT@8|Qq z@9SNBu1UErolMjrhJW-Id&7y<0I<+Z-lr`IHMh1;M)n@g|hx_T-maO`s{Tuhax}EjC zS;1kdL*A3BW5YZXgD|0zm)g3_3vMs>5xgHUhQDl19lfQWMcfLTsw$)amgDs>bW*Oe+$UK^`ioL%F0Ua5vb%II+EGS>*I zw)AmqcWBZpWH&Aswk_FJT=J|^Gn=MfnDTIzMdnoRUB91MeW?e>+C)g3_FDN8rN$(? zL+kH!*L}rq`MK`KDt^v4nUJg3Ce-`IW0Ph0?|}Puq5WIS_a7iEO;~mGQqqo=Ey;ND zhBXA^$ZrCc#&0}dMA&@)&TCq5PMzgJPafZCg-6$R zRqJ2+_t+dGUAY@~xPzU3`od7-(8nnuMfM-4#u`Q~`l-CUGC7u*^5VwH`ot;Ck#R1% zRr%?;!NrB$w^}NW=GGR}m!3a9bh#wXrq?fF7j-IS?E_!GaD3KYzcXhCUHhjEl-6b# zCmIF#4y@HN=^#uIz zRFl8D)Ri1<(Kr~Hoi_MtXWP8^AyTKxi1)ew88bV{*Ok8w8YLXBFW0sRJ<(vU{$ym| zz)feLQbz3k;_}2_{-bW`h~t&2$ObtlbS?k2k|5Kbu?FZLDMTVW_Z6p#A)c)`3DD?a*hxHS2Zj zcIiebfsINfWvwY7Z{YOlIQ61b`j=%6{>MPs+`()Q{wq0z0?|jwRN(1IrMQsj40BHx zvBC_Xfcr;55&}MeoP_@#nz$avCh%FJfE5NNAE~fW@L7~f8Y=?Wno31128EYOK8+O! zc4Vaj-DCsB6CPH$?pQQVbb_(tg^x{$STYM_WKLtrh-_-Hq-M%Ubpt6$mCHY!B{ISD zz}grIo^bNVDw4={SA2*nDNq5`e@ZO5r4TbQpHM)~qfD9!s0h(Jf>vYd;I~j<2fD4)_>ctbwNX6S*8>i^*4 zYKI5<4}d;hM!!N|A$@eg09J|HV;!UUVIau_I~dxZp#?a3u0G)pts6GKdCNk>FKxdh_`Xu!>zO3Kv?u+W6cYJPy!@=PuY868>3|Zg} z$7galV~M`d!q(`I{;CJsq6G9>W0}H6gVY`q7S@9s8ak1r{>}*Q0JyH&f!f8(NZxhC zkn|KS64r^A1fniFel2KkxYByk%erCx9UgFLI)`yuA)X z8SU?6kj!numPNCAj}>1ipax(t{%rxU;6`(Nqt$~Z4~76TQ$9d8l`yJ}rniII%HbH= zlS_7o!qB{55at^>N!Voer%)`KMh9Yd@Z?~nc19*hs)NGN954`O9zA&&vJHbm&|D@E za(&z6A=3NfC;>I)hlI@ulP8E@W-ziGe{iCf_mHvWGldxw8{ng-hI({EtOdALnD9zG ze)fU?I(DNt)Bzdd9Cs^>!|+2!xv1SK=I zJ+y_;=Sq-zqD~GKy@{5(my&aPgFfGY&_mayR_)?dF_^Fwc-n!UAG+fQQGfjWE-1MF YM{}PByk10KD_nuQ4E7Du?}+~TKh4V)`~Uy| diff --git a/samples/standalone/webclient/http-server/.mvn/wrapper/maven-wrapper.properties b/samples/standalone/webclient/http-server/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index 015dfe6821..0000000000 --- a/samples/standalone/webclient/http-server/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,18 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.3/apache-maven-3.8.3-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar diff --git a/samples/standalone/webclient/http-server/README.adoc b/samples/standalone/webclient/http-server/README.adoc deleted file mode 100644 index 2fd3fbc40d..0000000000 --- a/samples/standalone/webclient/http-server/README.adoc +++ /dev/null @@ -1,20 +0,0 @@ -= Http Server - -Run - -[source=groovy] --------- -./gradlew clean build publishToMavenLocal --------- - -or - --------- -./mvnw clean install --------- - -To - -- build the app -- generate and run Spring Cloud Contract Verifier tests -- publish the fatJar and the stubs to Maven Local \ No newline at end of file diff --git a/samples/standalone/webclient/http-server/build.gradle b/samples/standalone/webclient/http-server/build.gradle deleted file mode 100644 index afda75b3b8..0000000000 --- a/samples/standalone/webclient/http-server/build.gradle +++ /dev/null @@ -1,130 +0,0 @@ -plugins { - id "groovy" - id "org.springframework.boot" - id "io.spring.dependency-management" - id "maven-publish" - /** - * While the SCC Gradle plugin is not strictly necessary for this project. - * It is included to ensure that if the contractDslDir does not exist, then - * the plugin reports "NO-SOURCE" for associated tasks, rather than resulting - * in an error for the end user. - */ - id "org.springframework.cloud.contract" -} - -group = 'com.example' -version = '0.0.1' - -repositories { - mavenCentral() - mavenLocal() - maven { url "https://repo.spring.io/snapshot" } - maven { url "https://repo.spring.io/milestone" } -// maven { url "https://repo.spring.io/release" } -} - -dependencyManagement { - imports { - mavenBom "org.springframework.cloud:spring-cloud-dependencies:${BOM_VERSION}" - mavenBom "org.springframework.cloud:spring-cloud-contract-dependencies:${verifierVersion}" - } -} - -dependencies { - implementation("org.springframework.boot:spring-boot-starter-webflux") - implementation("org.springframework.boot:spring-boot-starter-actuator") - - testImplementation('org.springframework.boot:spring-boot-starter-test') { - exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' - } - testImplementation 'org.springframework.restdocs:spring-restdocs-webtestclient' - testImplementation 'org.springframework.cloud:spring-cloud-contract-wiremock' -} - -contracts { - failOnNoContracts = false -} - -generateClientStubs.enabled = false - -test { - useJUnitPlatform() - systemProperty 'spring.profiles.active', 'gradle' - testLogging { - exceptionFormat = 'full' - } - afterSuite { desc, result -> - if (!desc.parent) { - println "Results: (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)" - if (result.testCount == 0) { - throw new IllegalStateException("No tests were found. Failing the build") - } - } - } -} - -task stubsJar(type: Jar, dependsOn: ['copySnippets', 'copySources', 'copyClasses']) { - archiveBaseName = project.name - archiveClassifier = 'stubs' - from project.file("${project.buildDir}/stubs") -} - -task copySnippets(type: Copy, dependsOn: test) { - from "target/snippets/stubs" - into "${project.buildDir}/stubs/META-INF/${project.group}/${project.name}/${project.version}/mappings" -} - -task copySources(type: Copy) { - from "src/main/java" - include '**/model/Fraud*.*' - into "${project.buildDir}/stubs/" -} - -task copyClasses(type: Copy) { - from "${project.buildDir}/classes/main/" - include '**/model/Fraud*.*' - into "${project.buildDir}/stubs/" -} - -project.tasks.named("verifierStubsJar").get().dependsOn('copySnippets', 'copySources', 'stubsJar') // TODO: We need to fix this -project.tasks.named("copyContracts").get().dependsOn('stubsJar') // TODO: We need to fix this -afterEvaluate { - project.tasks.matching { it.name.contains("publish") }.each { it.dependsOn('verifierStubsJar') } // TODO: We need to fix this -} - -publishing { - publications { - maven(MavenPublication) { - artifact bootJar - artifact stubsJar - - // https://github.com/spring-gradle-plugins/dependency-management-plugin/issues/273 - versionMapping { - usage("java-api") { - fromResolutionOf("runtimeClasspath") - } - usage("java-runtime") { - fromResolutionResult() - } - } - } - } -} - -clean.doFirst { - delete 'target/snippets/stubs' - delete "~/.m2/repository/com/example/http-server-webclient-gradle" -} - -task resolveDependencies { - doLast { - project.rootProject.allprojects.each { subProject -> - subProject.buildscript.configurations.each { configuration -> - configuration.resolve() - } - subProject.configurations.each { configuration -> - configuration.resolve() - } - } - } -} diff --git a/samples/standalone/webclient/http-server/gradle.properties b/samples/standalone/webclient/http-server/gradle.properties deleted file mode 100644 index 23a8e509b5..0000000000 --- a/samples/standalone/webclient/http-server/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -org.gradle.daemon=false -verifierVersion=4.1.0-SNAPSHOT -BOM_VERSION=2023.0.0-SNAPSHOT -bootVersion=3.2.0-SNAPSHOT diff --git a/samples/standalone/webclient/http-server/gradle/wrapper/gradle-wrapper.jar b/samples/standalone/webclient/http-server/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 7f93135c49b765f8051ef9d0a6055ff8e46073d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63721 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鯊%1Et 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⁢ zv5o9#E7!G0XmdzfsS{efPNi`1b44~SZ4Z8fuX!I}#8g+(wxzQwUT#Xb2(tbY1+EUhGKoT@KEU9Ktl>_0 z%bjDJg;#*gtJZv!-Zs`?^}v5eKmnbjqlvnSzE@_SP|LG_PJ6CYU+6zY6>92%E+ z=j@TZf-iW4(%U{lnYxQA;7Q!b;^brF8n0D>)`q5>|WDDXLrqYU_tKN2>=#@~OE7grMnNh?UOz-O~6 z6%rHy{#h9K0AT+lDC7q4{hw^|q6*Ry;;L%Q@)Ga}$60_q%D)rv(CtS$CQbpq9|y1e zRSrN4;$Jyl{m5bZw`$8TGvb}(LpY{-cQ)fcyJv7l3S52TLXVDsphtv&aPuDk1OzCA z4A^QtC(!11`IsNx_HnSy?>EKpHJWT^wmS~hc^p^zIIh@9f6U@I2 zC=Mve{j2^)mS#U$e{@Q?SO6%LDsXz@SY+=cK_QMmXBIU)j!$ajc-zLx3V60EXJ!qC zi<%2x8Q24YN+&8U@CIlN zrZkcT9yh%LrlGS9`G)KdP(@9Eo-AQz@8GEFWcb7U=a0H^ZVbLmz{+&M7W(nXJ4sN8 zJLR7eeK(K8`2-}j(T7JsO`L!+CvbueT%izanm-^A1Dn{`1Nw`9P?cq;7no+XfC`K(GO9?O^5zNIt4M+M8LM0=7Gz8UA@Z0N+lg+cX)NfazRu z5D)~HA^(u%w^cz+@2@_#S|u>GpB+j4KzQ^&Wcl9f z&hG#bCA(Yk0D&t&aJE^xME^&E-&xGHhXn%}psEIj641H+Nl-}boj;)Zt*t(4wZ5DN z@GXF$bL=&pBq-#vkTkh>7hl%K5|3 z{`Vn9b$iR-SoGENp}bn4;fR3>9sA%X2@1L3aE9yTra;Wb#_`xWwLSLdfu+PAu+o3| zGVnpzPr=ch{uuoHjtw7+_!L_2;knQ!DuDl0R`|%jr+}jFzXtrHIKc323?JO{l&;VF z*L1+}JU7%QJOg|5|Tc|D8fN zJORAg=_vsy{ak|o);@)Yh8Lkcg@$FG3k@ep36BRa^>~UmnRPziS>Z=`Jb2x*Q#`%A zU*i3&Vg?TluO@X0O;r2Jl6LKLUOVhSqg1*qOt^|8*c7 zo(298@+r$k_wQNGHv{|$tW(T8L+4_`FQ{kEW5Jgg{yf7ey4ss_(SNKfz(N9lx&a;< je(UuV8hP?p&}TPdm1I$XmG#(RzlD&B2izSj9sl%y5~4qc diff --git a/samples/standalone/webclient/http-server/gradle/wrapper/gradle-wrapper.properties b/samples/standalone/webclient/http-server/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index ac72c34e8a..0000000000 --- a/samples/standalone/webclient/http-server/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/samples/standalone/webclient/http-server/gradlew b/samples/standalone/webclient/http-server/gradlew deleted file mode 100755 index 0adc8e1a53..0000000000 --- a/samples/standalone/webclient/http-server/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/samples/standalone/webclient/http-server/gradlew.bat b/samples/standalone/webclient/http-server/gradlew.bat deleted file mode 100644 index 6689b85bee..0000000000 --- a/samples/standalone/webclient/http-server/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/samples/standalone/webclient/http-server/mvnw b/samples/standalone/webclient/http-server/mvnw deleted file mode 100755 index 5643201c7d..0000000000 --- a/samples/standalone/webclient/http-server/mvnw +++ /dev/null @@ -1,316 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Maven Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /usr/local/etc/mavenrc ] ; then - . /usr/local/etc/mavenrc - fi - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`\\unset -f command; \\command -v java`" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` - fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" - fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi -else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - if [ -n "$MVNW_REPOURL" ]; then - jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - else - jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - fi - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - if $cygwin; then - wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` - fi - - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - else - wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - fi - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl -o "$wrapperJarPath" "$jarUrl" -f - else - curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f - fi - - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - # For Cygwin, switch paths to Windows format before running javac - if $cygwin; then - javaClass=`cygpath --path --windows "$javaClass"` - fi - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` -fi - -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" -export MAVEN_CMD_LINE_ARGS - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -exec "$JAVACMD" \ - $MAVEN_OPTS \ - $MAVEN_DEBUG_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" \ - "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/samples/standalone/webclient/http-server/mvnw.cmd b/samples/standalone/webclient/http-server/mvnw.cmd deleted file mode 100644 index 23b7079a3d..0000000000 --- a/samples/standalone/webclient/http-server/mvnw.cmd +++ /dev/null @@ -1,188 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* -if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% ^ - %JVM_CONFIG_MAVEN_PROPS% ^ - %MAVEN_OPTS% ^ - %MAVEN_DEBUG_OPTS% ^ - -classpath %WRAPPER_JAR% ^ - "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ - %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" -if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%"=="on" pause - -if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% - -cmd /C exit /B %ERROR_CODE% diff --git a/samples/standalone/webclient/http-server/pom.xml b/samples/standalone/webclient/http-server/pom.xml deleted file mode 100644 index 31eb4aa913..0000000000 --- a/samples/standalone/webclient/http-server/pom.xml +++ /dev/null @@ -1,257 +0,0 @@ - - - 4.0.0 - - com.example - http-server-webclient - 0.0.1 - - Spring Cloud Contract RestDocs Http Server Sample - Spring Cloud RestDocs Verifier Http Server Sample - - - org.springframework.boot - spring-boot-starter-parent - 3.2.0-SNAPSHOT - - - - - UTF-8 - 17 - 4.1.0-SNAPSHOT - - - - - org.springframework.boot - spring-boot-starter-webflux - - - org.springframework.boot - spring-boot-starter-actuator - - - - org.springframework.boot - spring-boot-starter-test - test - - - org.junit.vintage - junit-vintage-engine - - - - - - org.springframework.restdocs - spring-restdocs-webtestclient - test - - - org.springframework.cloud - spring-cloud-contract-wiremock - test - - - - - - - org.springframework.cloud - spring-cloud-contract-dependencies - ${spring-cloud-contract.version} - pom - import - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - maven-deploy-plugin - - true - - - - org.apache.maven.plugins - maven-clean-plugin - - - - build - - - target - - - - - - org.apache.maven.plugins - maven-assembly-plugin - - - stub - prepare-package - - single - - false - - true - - ${basedir}/src/assembly/stub.xml - - - - - - - maven-surefire-plugin - - true - - - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - - - - - windows - - - - org.codehaus.mojo - exec-maven-plugin - 1.6.0 - - - gradle - test - - gradlew.bat - - clean - build - - install - - -x - test - - -x - contractTest - - -PverifierVersion=${spring-cloud-contract.version} - - - - - exec - - - - - - - - - diff --git a/samples/standalone/webclient/http-server/settings.gradle b/samples/standalone/webclient/http-server/settings.gradle deleted file mode 100644 index e3747344a1..0000000000 --- a/samples/standalone/webclient/http-server/settings.gradle +++ /dev/null @@ -1,22 +0,0 @@ -pluginManagement { - repositories { - mavenLocal() - maven { url "https://repo.spring.io/snapshot" } - maven { url "https://repo.spring.io/milestone" } - gradlePluginPortal() - } - plugins { - id 'org.springframework.boot' version "${bootVersion}" - id "io.spring.dependency-management" version "1.1.3" - } - resolutionStrategy { - eachPlugin { - // protects us in case the gradle-portal-plugin hasn't yet been published by Maven - if (requested.id.id == 'org.springframework.cloud.contract') { - useModule("org.springframework.cloud:spring-cloud-contract-gradle-plugin:${verifierVersion}") - } - } - } -} - -rootProject.name = 'http-server-webclient-gradle' diff --git a/samples/standalone/webclient/http-server/src/assembly/stub.xml b/samples/standalone/webclient/http-server/src/assembly/stub.xml deleted file mode 100644 index 13bdf69cef..0000000000 --- a/samples/standalone/webclient/http-server/src/assembly/stub.xml +++ /dev/null @@ -1,35 +0,0 @@ - - stubs - - jar - - false - - - src/main/java - / - - **/model/Fraud*.* - - - - ${project.build.directory}/classes - / - - **/model/Fraud*.* - - - - ${project.build.directory}/snippets/stubs - - META-INF/${project.groupId}/${project.artifactId}/${project.version}/mappings - - - **/* - - - - diff --git a/samples/standalone/webclient/http-server/src/main/java/com/example/fraud/Application.java b/samples/standalone/webclient/http-server/src/main/java/com/example/fraud/Application.java deleted file mode 100644 index c998b507b2..0000000000 --- a/samples/standalone/webclient/http-server/src/main/java/com/example/fraud/Application.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; - -@Configuration -@EnableAutoConfiguration -@ComponentScan -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } - -} diff --git a/samples/standalone/webclient/http-server/src/main/java/com/example/fraud/FraudDetectionController.java b/samples/standalone/webclient/http-server/src/main/java/com/example/fraud/FraudDetectionController.java deleted file mode 100644 index 1d5469e93f..0000000000 --- a/samples/standalone/webclient/http-server/src/main/java/com/example/fraud/FraudDetectionController.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud; - -import java.math.BigDecimal; - -import com.example.fraud.model.FraudCheck; -import com.example.fraud.model.FraudCheckResult; -import com.example.fraud.model.FraudCheckStatus; - -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import static org.springframework.web.bind.annotation.RequestMethod.PUT; - -@RestController -public class FraudDetectionController { - - private static final String FRAUD_SERVICE_JSON_VERSION_1 = "application/vnd.fraud.v1+json"; - - private static final String NO_REASON = null; - - private static final String AMOUNT_TOO_HIGH = "Amount too high"; - - private static final BigDecimal MAX_AMOUNT = new BigDecimal("5000"); - - // tag::server_api[] - @RequestMapping(value = "/fraudcheck", method = PUT, consumes = FRAUD_SERVICE_JSON_VERSION_1, produces = FRAUD_SERVICE_JSON_VERSION_1) - public FraudCheckResult fraudCheck(@RequestBody FraudCheck fraudCheck) { - // end::server_api[] - // tag::new_impl[] - if (amountGreaterThanThreshold(fraudCheck)) { - return new FraudCheckResult(FraudCheckStatus.FRAUD, AMOUNT_TOO_HIGH); - } - // end::new_impl[] - // tag::initial_impl[] - return new FraudCheckResult(FraudCheckStatus.OK, NO_REASON); - // end::initial_impl[] - } - - private boolean amountGreaterThanThreshold(FraudCheck fraudCheck) { - return MAX_AMOUNT.compareTo(fraudCheck.getLoanAmount()) < 0; - } - -} diff --git a/samples/standalone/webclient/http-server/src/main/java/com/example/fraud/model/FraudCheck.java b/samples/standalone/webclient/http-server/src/main/java/com/example/fraud/model/FraudCheck.java deleted file mode 100644 index 4cf6ae3ea2..0000000000 --- a/samples/standalone/webclient/http-server/src/main/java/com/example/fraud/model/FraudCheck.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud.model; - -import java.math.BigDecimal; - -public class FraudCheck { - - private String clientId; - - private BigDecimal loanAmount; - - public FraudCheck() { - } - - public String getClientId() { - return clientId; - } - - public void setClientId(String clientId) { - this.clientId = clientId; - } - - public BigDecimal getLoanAmount() { - return loanAmount; - } - - public void setLoanAmount(BigDecimal loanAmount) { - this.loanAmount = loanAmount; - } - -} diff --git a/samples/standalone/webclient/http-server/src/main/java/com/example/fraud/model/FraudCheckResult.java b/samples/standalone/webclient/http-server/src/main/java/com/example/fraud/model/FraudCheckResult.java deleted file mode 100644 index 95440c6790..0000000000 --- a/samples/standalone/webclient/http-server/src/main/java/com/example/fraud/model/FraudCheckResult.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud.model; - -public class FraudCheckResult { - - private FraudCheckStatus fraudCheckStatus; - - private String rejectionReason; - - public FraudCheckResult() { - } - - public FraudCheckResult(FraudCheckStatus fraudCheckStatus, String rejectionReason) { - this.fraudCheckStatus = fraudCheckStatus; - this.rejectionReason = rejectionReason; - } - - public FraudCheckStatus getFraudCheckStatus() { - return fraudCheckStatus; - } - - public void setFraudCheckStatus(FraudCheckStatus fraudCheckStatus) { - this.fraudCheckStatus = fraudCheckStatus; - } - - public String getRejectionReason() { - return rejectionReason; - } - - public void setRejectionReason(String rejectionReason) { - this.rejectionReason = rejectionReason; - } - -} diff --git a/samples/standalone/webclient/http-server/src/main/java/com/example/fraud/model/FraudCheckStatus.java b/samples/standalone/webclient/http-server/src/main/java/com/example/fraud/model/FraudCheckStatus.java deleted file mode 100644 index a43b649f5c..0000000000 --- a/samples/standalone/webclient/http-server/src/main/java/com/example/fraud/model/FraudCheckStatus.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud.model; - -public enum FraudCheckStatus { - - OK, FRAUD - -} diff --git a/samples/standalone/webclient/http-server/src/main/resources/application.yml b/samples/standalone/webclient/http-server/src/main/resources/application.yml deleted file mode 100644 index 1c421cf2b7..0000000000 --- a/samples/standalone/webclient/http-server/src/main/resources/application.yml +++ /dev/null @@ -1 +0,0 @@ -server.port=0 \ No newline at end of file diff --git a/samples/standalone/webclient/http-server/src/test/java/com/example/fraud/StubGeneratorTests.java b/samples/standalone/webclient/http-server/src/test/java/com/example/fraud/StubGeneratorTests.java deleted file mode 100644 index 42e8074aa0..0000000000 --- a/samples/standalone/webclient/http-server/src/test/java/com/example/fraud/StubGeneratorTests.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.fraud; - -import java.math.BigDecimal; - -import com.example.fraud.model.FraudCheck; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters; -import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; -import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.json.JacksonTester; -import org.springframework.http.MediaType; -import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation; -import org.springframework.test.web.reactive.server.WebTestClient; -import org.springframework.web.reactive.function.BodyInserters; - -import static org.springframework.cloud.contract.wiremock.restdocs.WireMockWebTestClient.verify; - - -@SpringBootTest(classes = Application.class) -@AutoConfigureRestDocs(outputDir = "target/snippets") -@AutoConfigureWebTestClient -@AutoConfigureJsonTesters -public class StubGeneratorTests { - - @Autowired - private WebTestClient client; - - private JacksonTester json; - - @BeforeEach - public void setup() { - ObjectMapper objectMappper = new ObjectMapper(); - // Possibly configure the mapper - JacksonTester.initFields(this, objectMappper); - } - - @Test - public void shouldMarkClientAsFraud() throws Exception { - FraudCheck fraudCheck = new FraudCheck(); - fraudCheck.setClientId("1234567890"); - fraudCheck.setLoanAmount(BigDecimal.valueOf(99999.0)); - client.put().uri("/fraudcheck") - .contentType(MediaType.valueOf("application/vnd.fraud.v1+json")) - .body(BodyInserters.fromObject(json.write(fraudCheck).getJson())) - .exchange().expectBody().jsonPath("$.fraudCheckStatus").isEqualTo("FRAUD") - .jsonPath("$.rejectionReason").isEqualTo("Amount too high") - .consumeWith(verify().jsonPath("$.clientId") - .jsonPath("$[?(@.loanAmount > 1000)]") - .contentType(MediaType.valueOf("application/vnd.fraud.v1+json"))) - .consumeWith( - WebTestClientRestDocumentation.document("markClientAsFraud")); - } - - @Test - public void shouldMarkClientAsNotFraud() throws Exception { - FraudCheck fraudCheck = new FraudCheck(); - fraudCheck.setClientId("1234567890"); - fraudCheck.setLoanAmount(BigDecimal.valueOf(123.123)); - client.put().uri("/fraudcheck") - .contentType(MediaType.valueOf("application/vnd.fraud.v1+json")) - .body(BodyInserters.fromObject(json.write(fraudCheck).getJson())) - .exchange().expectBody().jsonPath("$.fraudCheckStatus").isEqualTo("OK") - .jsonPath("$.rejectionReason").doesNotExist() - .consumeWith(verify().jsonPath("$.clientId") - .jsonPath("$[?(@.loanAmount <= 1000)]") - .contentType(MediaType.valueOf("application/vnd.fraud.v1+json"))) - .consumeWith( - WebTestClientRestDocumentation.document("markClientAsNotFraud")); - } - -} diff --git a/samples/standalone/webclient/pom.xml b/samples/standalone/webclient/pom.xml deleted file mode 100644 index bc8f44561e..0000000000 --- a/samples/standalone/webclient/pom.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - 4.0.0 - - - org.springframework.cloud - spring-cloud-contract-samples-standalone - 4.1.0-SNAPSHOT - .. - - - spring-cloud-contract-samples-webclient - pom - - Spring Cloud Contract Standalone Restdocs Test Samples - Spring Cloud Contract Standalone Test Samples used for end to end tests - - - - 4.1.0-SNAPSHOT - - - - http-server - http-client - - - - - - maven-deploy-plugin - 2.8.2 - - true - - - - - - diff --git a/scripts/buildWithDocs.sh b/scripts/buildWithDocs.sh deleted file mode 100755 index 7d74a45999..0000000000 --- a/scripts/buildWithDocs.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -source common.sh || source scripts/common.sh || echo "No common.sh script found..." - -FOLDER=`pwd` - -set -e - -./mvnw clean install -Pintegration -${FOLDER}/scripts/generateDocs.sh \ No newline at end of file diff --git a/scripts/ciBuild.sh b/scripts/ciBuild.sh deleted file mode 100755 index 7e91efbaa1..0000000000 --- a/scripts/ciBuild.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -source common.sh || source scripts/common.sh || echo "No common.sh script found..." - -FOLDER=`pwd` - -set -e - -./scripts/noIntegration.sh -Pfast -./scripts/gradleOnly.sh -./scripts/integrationOnly.sh diff --git a/scripts/common.sh b/scripts/common.sh deleted file mode 100755 index a0e7a85a36..0000000000 --- a/scripts/common.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash - -set -e - -ROOT_FOLDER=`pwd` -echo "Current folder is $ROOT_FOLDER" - -if [[ ! -e "${ROOT_FOLDER}/.git" ]]; then - cd .. - ROOT_FOLDER=`pwd` -fi - -echo "Root folder is $ROOT_FOLDER" - -# Code grepping for the 3rd presence of "version" in pom.xml. -# The 3rd one is where we define the SC-Contract version -VERSION_NODE=`awk '/version/{i++}i==3{print; exit}' $ROOT_FOLDER/pom.xml` -# Extract the contents of the version node -VERSION_VALUE=$(sed -ne '/version/{s/.*\(.*\)<\/version>.*/\1/p;q;}' <<< "$VERSION_NODE") - -echo "Extracted version from root pom.xml is [$VERSION_VALUE]" - -export ROOT_FOLDER -export VERSION_VALUE \ No newline at end of file diff --git a/scripts/compileOnly.sh b/scripts/compileOnly.sh deleted file mode 100755 index d335cc8d7b..0000000000 --- a/scripts/compileOnly.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -source common.sh || source scripts/common.sh || echo "No common.sh script found..." - -FOLDER=`pwd` - -set -e - -./mvnw clean install -DskipTests -Pfast -fae diff --git a/scripts/downloadDependencies.sh b/scripts/downloadDependencies.sh deleted file mode 100755 index c3502eaae9..0000000000 --- a/scripts/downloadDependencies.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash - -source common.sh || source scripts/common.sh || echo "No common.sh script found..." - -set -e - -./mvnw -s .settings.xml --fail-never dependency:go-offline || true -cd $ROOT_FOLDER/spring-cloud-contract-tools/spring-cloud-contact-gradle-plugin && ./gradlew resolveDependencies || true -cd $ROOT_FOLDER/samples/standalone/dsl/http-client && ./mvnw --fail-never dependency:go-offline || true -cd $ROOT_FOLDER/samples/standalone/dsl/http-client && ./gradlew resolveDependencies || true -cd $ROOT_FOLDER/samples/standalone/dsl/http-server && ./mvnw --fail-never dependency:go-offline || true -cd $ROOT_FOLDER/samples/standalone/dsl/http-server && ./gradlew resolveDependencies || true -cd $ROOT_FOLDER/samples/standalone/restdocs/http-client && ./mvnw --fail-never dependency:go-offline || true -cd $ROOT_FOLDER/samples/standalone/restdocs/http-client && ./gradlew resolveDependencies || true -cd $ROOT_FOLDER/samples/standalone/restdocs/http-server && ./mvnw --fail-never dependency:go-offline || true -cd $ROOT_FOLDER/samples/standalone/restdocs/http-server && ./gradlew resolveDependencies || true -cd $ROOT_FOLDER/samples/standalone/messaging/stream-sink && ./mvnw --fail-never dependency:go-offline || true -cd $ROOT_FOLDER/samples/standalone/messaging/stream-sink && ./gradlew resolveDependencies || true -cd $ROOT_FOLDER/samples/standalone/messaging/stream-source && ./mvnw --fail-never dependency:go-offline || true -cd $ROOT_FOLDER/samples/standalone/messaging/stream-source && ./gradlew resolveDependencies || true diff --git a/scripts/fastBuild.sh b/scripts/fastBuild.sh deleted file mode 100755 index c01c9b8686..0000000000 --- a/scripts/fastBuild.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -source common.sh || source scripts/common.sh || echo "No common.sh script found..." - -set -e - -[[ -z "${CORES}" ]] && CORES=4 -echo -e "\n\nRUNNING FAST BUILD (NO INTEGRATION TESTS) WITH [${CORES}] CORES\n\n" - -./mvnw clean install -Pdocs,fast -T ${CORES} -Dinvoker.parallelThreads=${CORES} diff --git a/scripts/generateDocs.sh b/scripts/generateDocs.sh deleted file mode 100755 index 75ac6ecfb1..0000000000 --- a/scripts/generateDocs.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash - -source common.sh || source scripts/common.sh || echo "No common.sh script found..." - -set -e - -echo "Generating docs for Spring Cloud Contract" - -echo "Building main docs" -./mvnw clean install -P docs --pl docs ${@} - -echo "Building maven plugin docs" -./mvnw site -DskipTests=true --pl spring-cloud-contract-tools/spring-cloud-contract-maven-plugin ${@} - -echo "Copying generated maven plugin docs to main docs" -cp -r spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/target/site docs/target/generated-docs/spring-cloud-contract-maven-plugin \ No newline at end of file diff --git a/scripts/gradleOnly.sh b/scripts/gradleOnly.sh deleted file mode 100755 index 5d5808c0e5..0000000000 --- a/scripts/gradleOnly.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -source common.sh || source scripts/common.sh || echo "No common.sh script found..." - -FOLDER=`pwd` - -set -e - -cd "${FOLDER}/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin" - ./gradlew clean build publishToMavenLocal -cd "${FOLDER}" diff --git a/scripts/integrationOnly.sh b/scripts/integrationOnly.sh deleted file mode 100755 index c090c8d5a0..0000000000 --- a/scripts/integrationOnly.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -source common.sh || source scripts/common.sh || echo "No common.sh script found..." - -FOLDER=`pwd` - -set -e - -./mvnw clean install ${@} -Pintegration -pl docker -./mvnw clean install ${@} -Pintegration -rf samples \ No newline at end of file diff --git a/scripts/noIntegration.sh b/scripts/noIntegration.sh deleted file mode 100755 index e8dad9c611..0000000000 --- a/scripts/noIntegration.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -source common.sh || source scripts/common.sh || echo "No common.sh script found..." - -FOLDER=`pwd` - -set -e - -./mvnw clean install ${@} -${FOLDER}/scripts/generateDocs.sh ${@} \ No newline at end of file diff --git a/scripts/parallelBuild.sh b/scripts/parallelBuild.sh deleted file mode 100755 index 8ee774cbb2..0000000000 --- a/scripts/parallelBuild.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -source common.sh || source scripts/common.sh || echo "No common.sh script found..." - -set -e - -[[ -z "${CORES}" ]] && CORES=4 -echo -e "\n\nRUNNING PARALLEL BUILD WITH [${CORES}] CORES\n\n" - -./mvnw clean install -Pdocs,integration -T ${CORES} -Dinvoker.parallelThreads=${CORES} \ No newline at end of file diff --git a/scripts/runTests.sh b/scripts/runTests.sh deleted file mode 100755 index 36e0a5dccb..0000000000 --- a/scripts/runTests.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -source common.sh || source scripts/common.sh || echo "No common.sh script found..." - -set -e - -[[ -z "${VERSION_VALUE}" ]] && VERSION_VALUE="4.0.0.BUILD-SNAPSHOT" -[[ -z "${VERIFIER_VERSION}" ]] && VERIFIER_VERSION="$VERSION_VALUE" -export VERIFIER_VERSION - -echo -e "\n\nRUNNING TESTS FOR VERIFIER IN VERSION [${VERIFIER_VERSION}]\n\n" - -cd samples/standalone - -echo "Running tests" -../../mvnw clean install -P integration - -cd $ROOT_FOLDER diff --git a/scripts/updateWrappers.sh b/scripts/updateWrappers.sh deleted file mode 100755 index c341884ddd..0000000000 --- a/scripts/updateWrappers.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -set -o errexit -set -o errtrace -set -o nounset -set -o pipefail - -export WRAPPER_VERSION="${WRAPPER_VERSION:-7.4.1}" - -find . -name 'build.gradle' | while read -r file; do - parentdir="$(dirname "$file")" - ( echo "Updating [${parentdir}]" && cd "$parentdir" && ./gradlew wrapper --gradle-version "${WRAPPER_VERSION}" ) -done \ No newline at end of file diff --git a/specs/README.adoc b/specs/README.adoc deleted file mode 100644 index 4761e48814..0000000000 --- a/specs/README.adoc +++ /dev/null @@ -1,4 +0,0 @@ -=== Spring Cloud Contract Specification - -This module contains the specifications describing contracts. Currently we have only -one way for contract description which is the Groovy DSL. \ No newline at end of file diff --git a/specs/pom.xml b/specs/pom.xml deleted file mode 100644 index e814f8bd0e..0000000000 --- a/specs/pom.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - 4.0.0 - - - org.springframework.cloud - spring-cloud-contract-parent - 4.1.0-SNAPSHOT - .. - - - spring-cloud-contract-specs - pom - 4.1.0-SNAPSHOT - Spring Cloud Contract Specs - Spring Cloud Contract Specs - - - ${basedir}/.. - - - - spring-cloud-contract-spec-java - spring-cloud-contract-spec-groovy - spring-cloud-contract-spec-kotlin - spring-cloud-contract-spec - - - - - - maven-deploy-plugin - 2.8.2 - - true - - - - - - diff --git a/specs/spring-cloud-contract-spec-groovy/README.adoc b/specs/spring-cloud-contract-spec-groovy/README.adoc deleted file mode 100644 index e1aa472960..0000000000 --- a/specs/spring-cloud-contract-spec-groovy/README.adoc +++ /dev/null @@ -1,3 +0,0 @@ -=== Spring Cloud Contract Specification Groovy - -This module contains the Contract specification written in Groovy. It extends the Java spec with Groovy methods. \ No newline at end of file diff --git a/specs/spring-cloud-contract-spec-groovy/pom.xml b/specs/spring-cloud-contract-spec-groovy/pom.xml deleted file mode 100644 index 06c3f529c2..0000000000 --- a/specs/spring-cloud-contract-spec-groovy/pom.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - 4.0.0 - - org.springframework.cloud - spring-cloud-contract-parent - 4.1.0-SNAPSHOT - ../.. - - spring-cloud-contract-spec-groovy - jar - Spring Cloud Contract Spec Groovy - Spring Cloud Contract Spec Groovy - - - org.springframework.cloud - spring-cloud-contract-spec-java - - - org.apache.groovy - groovy - - - org.apache.groovy - groovy-nio - - - org.apache.groovy - groovy-json - - - org.apache.groovy - groovy-xml - - - org.apache.commons - commons-text - - - org.springframework - spring-jcl - - - org.spockframework - spock-core - test - - - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - - - - addSources - addTestSources - generateStubs - compile - generateTestStubs - compileTests - removeStubs - removeTestStubs - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - - - diff --git a/specs/spring-cloud-contract-spec-groovy/src/main/groovy/org/springframework/cloud/contract/spec/internal/GroovyDslPropertyConverter.java b/specs/spring-cloud-contract-spec-groovy/src/main/groovy/org/springframework/cloud/contract/spec/internal/GroovyDslPropertyConverter.java deleted file mode 100644 index bbaad88b86..0000000000 --- a/specs/spring-cloud-contract-spec-groovy/src/main/groovy/org/springframework/cloud/contract/spec/internal/GroovyDslPropertyConverter.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -import groovy.lang.GString; -import org.codehaus.groovy.runtime.GStringImpl; - -/** - * Groovy converter that understand types like {@link GString}. - * - * @author Marcin Grzejszczak - * @since 2.2.0 - */ -public class GroovyDslPropertyConverter implements DslPropertyConverter { - - @Override - public Object testSide(Object object) { - if (object instanceof GString) { - boolean anyPattern = Arrays.stream(((GString) object).getValues()) - .anyMatch(it -> it instanceof RegexProperty); - if (!anyPattern) { - return object; - } - List generatedValues = Arrays.stream(((GString) object).getValues()) - .map(it -> it instanceof RegexProperty ? ((RegexProperty) it).generate() : it) - .collect(Collectors.toList()); - Object[] arrayOfObjects = generatedValues.toArray(); - String[] strings = Arrays.copyOf(((GString) object).getStrings(), ((GString) object).getStrings().length, - String[].class); - String newUrl = new GStringImpl(arrayOfObjects, strings).toString(); - return new Url(newUrl); - } - return object; - } - -} diff --git a/specs/spring-cloud-contract-spec-groovy/src/main/resources/META-INF/spring.factories b/specs/spring-cloud-contract-spec-groovy/src/main/resources/META-INF/spring.factories deleted file mode 100644 index d040f4a478..0000000000 --- a/specs/spring-cloud-contract-spec-groovy/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,2 +0,0 @@ -org.springframework.cloud.contract.spec.internal.DslPropertyConverter=\ -org.springframework.cloud.contract.spec.internal.GroovyDslPropertyConverter diff --git a/specs/spring-cloud-contract-spec-groovy/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy b/specs/spring-cloud-contract-spec-groovy/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy deleted file mode 100644 index 91bd5605a5..0000000000 --- a/specs/spring-cloud-contract-spec-groovy/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal - -import spock.lang.Specification - -import org.springframework.cloud.contract.spec.Contract - -/** - * @author Marcin Grzejszczak - */ -class ContractSpec extends Specification { - - def 'should work for http'() { - when: - Contract.make { - request { - url("/foo/${regex('[0]')}") - method('PUT') - headers { - header([ - foo: 'bar' - ]) - } - body([ - foo: 'bar' - ]) - } - response { - status 200 - headers { - header([ - foo2: 'bar' - ]) - } - body([ - foo2: 'bar' - ]) - } - } - then: - noExceptionThrown() - } -} diff --git a/specs/spring-cloud-contract-spec-java/README.adoc b/specs/spring-cloud-contract-spec-java/README.adoc deleted file mode 100644 index ec24646c4e..0000000000 --- a/specs/spring-cloud-contract-spec-java/README.adoc +++ /dev/null @@ -1,3 +0,0 @@ -=== Spring Cloud Contract Specification Java - -This module contains the Contract specification written in Java. \ No newline at end of file diff --git a/specs/spring-cloud-contract-spec-java/pom.xml b/specs/spring-cloud-contract-spec-java/pom.xml deleted file mode 100644 index 187a5196bd..0000000000 --- a/specs/spring-cloud-contract-spec-java/pom.xml +++ /dev/null @@ -1,95 +0,0 @@ - - - 4.0.0 - - 1.12-4 - - - org.springframework.cloud - spring-cloud-contract-parent - 4.1.0-SNAPSHOT - ../.. - - spring-cloud-contract-spec-java - jar - Spring Cloud Contract Spec Java - Spring Cloud Contract Spec Java - - - - org.apache.groovy - groovy - - - org.springframework - spring-core - - - dk.brics - automaton - ${automaton.version} - - - org.apache.commons - commons-text - - - org.springframework - spring-jcl - - - org.apache.groovy - groovy-nio - test - - - org.apache.groovy - groovy-json - test - - - org.apache.groovy - groovy-xml - test - - - org.spockframework - spock-core - test - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - - - - addTestSources - generateTestStubs - compileTests - removeTestStubs - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - - - diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/Contract.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/Contract.java deleted file mode 100644 index 5c6a47292e..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/Contract.java +++ /dev/null @@ -1,414 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.function.Consumer; - -import groovy.lang.Closure; -import groovy.lang.DelegatesTo; - -import org.springframework.cloud.contract.spec.internal.Input; -import org.springframework.cloud.contract.spec.internal.OutputMessage; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.spec.internal.Response; - -/** - * The definition of a Contract. Contains helper methods in Groovy left for backward - * compatibility reasons. - * - * @since 1.0.0 - */ -public class Contract { - - /** - * You can set the level of priority of this contract. If there are two contracts - * mapped for example to the same endpoint, then the one with greater priority should - * take precedence. A priority of 1 is highest and takes precedence over a priority of - * 2. - */ - private Integer priority; - - /** - * The HTTP request part of the contract. - */ - private Request request; - - /** - * The HTTP response part of the contract. - */ - private Response response; - - /** - * The label by which you'll reference the contract on the message consumer side. - */ - private String label; - - /** - * Description of a contract. May be used in the documentation generation. - */ - private String description; - - /** - * Name of the generated test / stub. If not provided then the file name will be used. - * If you have multiple contracts in a single file and you don't provide this value - * then a prefix will be added to the file with the index number while iterating over - * the collection of contracts. - * - * Remember to have a unique name for every single contract. Otherwise you might - * generate tests that have two identical methods or you will override the stubs. - */ - private String name; - - /** - * The input side of a messaging contract. - */ - private Input input; - - /** - * The output side of a messaging contract. - */ - private OutputMessage outputMessage; - - /** - * Whether the contract should be ignored or not. - */ - private boolean ignored; - - /** - * Whether the contract is in progress. It's not ignored, but the feature is not yet - * finished. Used together with the {@code generateStubs} option. - */ - private boolean inProgress; - - /** - * Mapping of metadata. Can be used for external integrations. - */ - private Map metadata = new HashMap<>(); - - public Contract() { - - } - - /** - * You can set the level of priority of this contract. If there are two contracts - * mapped for example to the same endpoint, then the one with greater priority should - * take precedence. A priority of 1 is highest and takes precedence over a priority of - * 2. - * @param priority the higher the value the lower the priority - */ - public void priority(int priority) { - this.priority = priority; - } - - /** - * Name of the generated test / stub. If not provided then the file name will be used. - * If you have multiple contracts in a single file and you don't provide this value - * then a prefix will be added to the file with the index number while iterating over - * the collection of contracts. - * - * Remember to have a unique name for every single contract. Otherwise you might - * generate tests that have two identical methods or you will override the stubs. - * @param name name of the contract - */ - public void name(String name) { - this.name = name; - } - - /** - * Label used by the messaging contracts to trigger a message on the consumer side. - * @param label - name of the label of a messaging contract to trigger - */ - public void label(String label) { - this.label = label; - } - - /** - * Description text. Might be used to describe the usage scenario. - * @param description - value of the description - */ - public void description(String description) { - this.description = description; - } - - public static void assertContract(Contract dsl) { - if (dsl.getRequest() != null) { - if (dsl.request.getUrl() == null && dsl.request.getUrlPath() == null) { - throw new IllegalStateException("URL is missing for HTTP contract"); - } - if (dsl.request.getMethod() == null) { - throw new IllegalStateException("Method is missing for HTTP contract"); - } - } - if (dsl.response != null) { - if (dsl.response.getStatus() == null) { - throw new IllegalStateException("Status is missing for HTTP contract"); - } - } - } - - /** - * Point of entry to build a contract. - * @param consumer function to manipulate the contract - * @return manipulated contract - */ - public static Contract make(Consumer consumer) { - Contract contract = new Contract(); - consumer.accept(contract); - return contract; - } - - /** - * Groovy point of entry to build a contract. Left for backward compatibility reasons. - * @param closure function to manipulate the contract - * @return manipulated contract - */ - public static Contract make(@DelegatesTo(Contract.class) Closure closure) { - Contract dsl = new Contract(); - closure.setDelegate(dsl); - closure.call(); - Contract.assertContract(dsl); - return dsl; - } - - /** - * The HTTP request part of the contract. - * @param consumer function to manipulate the request - */ - public void request(Consumer consumer) { - this.request = new Request(); - consumer.accept(this.request); - } - - /** - * The HTTP response part of the contract. - * @param consumer function to manipulate the response - */ - public void response(Consumer consumer) { - this.response = new Response(); - consumer.accept(this.response); - } - - /** - * The input part of the contract. - * @param consumer function to manipulate the input - */ - public void input(Consumer consumer) { - this.input = new Input(); - consumer.accept(this.input); - } - - /** - * The output part of the contract. - * @param consumer function to manipulate the output message - */ - public void outputMessage(Consumer consumer) { - this.outputMessage = new OutputMessage(); - consumer.accept(this.outputMessage); - } - - /** - * The HTTP request part of the contract. - * @param consumer function to manipulate the request - */ - public void request(@DelegatesTo(Request.class) Closure consumer) { - this.request = new Request(); - consumer.setDelegate(this.request); - consumer.call(); - } - - /** - * The HTTP response part of the contract. - * @param consumer function to manipulate the response - */ - public void response(@DelegatesTo(Response.class) Closure consumer) { - this.response = new Response(); - consumer.setDelegate(this.response); - consumer.call(); - } - - /** - * The input part of the contract. - * @param consumer function to manipulate the input - */ - public void input(@DelegatesTo(Input.class) Closure consumer) { - this.input = new Input(); - consumer.setDelegate(this.input); - consumer.call(); - } - - /** - * The output part of the contract. - * @param consumer function to manipulate the output message - */ - public void outputMessage(@DelegatesTo(OutputMessage.class) Closure consumer) { - this.outputMessage = new OutputMessage(); - consumer.setDelegate(this.outputMessage); - consumer.call(); - } - - /** - * Appends all entries to the existing metadata mapping. - * @param map metadata to set - */ - public void metadata(Map map) { - this.metadata.putAll(map); - } - - /** - * Whether the contract should be ignored or not. - */ - public void ignored() { - this.ignored = true; - } - - /** - * Whether the contract is in progress or not. - */ - public void inProgress() { - this.inProgress = true; - } - - public boolean isInProgress() { - return this.inProgress; - } - - public Integer getPriority() { - return priority; - } - - public void setPriority(Integer priority) { - this.priority = priority; - } - - public Request getRequest() { - return request; - } - - public void setRequest(Request request) { - this.request = request; - } - - public Response getResponse() { - return response; - } - - public void setResponse(Response response) { - this.response = response; - } - - public String getLabel() { - return label; - } - - public void setLabel(String label) { - this.label = label; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Input getInput() { - return input; - } - - public void setInput(Input input) { - this.input = input; - } - - public OutputMessage getOutputMessage() { - return outputMessage; - } - - public void setOutputMessage(OutputMessage outputMessage) { - this.outputMessage = outputMessage; - } - - public boolean getIgnored() { - return ignored; - } - - public boolean isIgnored() { - return ignored; - } - - public void setIgnored(boolean ignored) { - this.ignored = ignored; - } - - public boolean getInProgress() { - return this.inProgress; - } - - public void setInProgress(boolean inProgress) { - this.inProgress = inProgress; - } - - public void setMetadata(Map metadata) { - this.metadata = metadata; - } - - public Map getMetadata() { - return metadata; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Contract contract = (Contract) o; - return ignored == contract.ignored && Objects.equals(priority, contract.priority) - && Objects.equals(request, contract.request) && Objects.equals(response, contract.response) - && Objects.equals(label, contract.label) && Objects.equals(description, contract.description) - && Objects.equals(name, contract.name) && Objects.equals(input, contract.input) - && Objects.equals(metadata, contract.metadata) && Objects.equals(outputMessage, contract.outputMessage); - } - - @Override - public int hashCode() { - return Objects.hash(priority, request, response, label, description, name, input, outputMessage, metadata, - ignored); - } - - @Override - public String toString() { - return "Contract{" + "\npriority=" + priority + ", \n\trequest=" + request + ", \n\tresponse=" + response - + ", \n\tlabel='" + label + '\'' + ", \n\tdescription='" + description + '\'' + ", \n\tname='" + name - + '\'' + ", \n\tinput=" + input + ", \n\toutputMessage=" + outputMessage + ", \n\tignored=" + ignored - + '}'; - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/ContractConverter.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/ContractConverter.java deleted file mode 100644 index 93a1754f9e..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/ContractConverter.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec; - -import java.io.File; -import java.util.Collection; - -/** - * Converter to be used to convert FROM {@link File} TO {@link Contract} and from - * {@link Contract} to {@code T}. - * - * @param - type to which we want to convert the contract - * @author Marcin Grzejszczak - * @since 1.1.0 - */ -public interface ContractConverter extends ContractStorer, ContractReader { - - /** - * Should this file be accepted by the converter. Can use the file extension to check - * if the conversion is possible. - * @param file - file to be considered for conversion - * @return - {@code true} if the given implementation can convert the file - */ - boolean isAccepted(File file); - - /** - * Converts the given {@link File} to its {@link Contract} representation. - * @param file - file to convert - * @return - {@link Contract} representation of the file - */ - Collection convertFrom(File file); - - /** - * Converts the given {@link Contract} to a {@link T} representation. - * @param contract - the parsed contract - * @return - {@link T} the type to which we do the conversion - */ - T convertTo(Collection contract); - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/ContractReader.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/ContractReader.java deleted file mode 100644 index e645d9cd97..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/ContractReader.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec; - -/** - * Defines how to read converted contracts from a byte array representation back to - * contracts. - * - * @param contracts type - * @author Marcin Grzejszczak - * @since 3.0.0 - */ -public interface ContractReader { - - /** - * Reads contracts from bytes. - * @param bytes - byte representation of contracts - * @return contracts - */ - default T read(byte[] bytes) { - throw new UnsupportedOperationException("Can't read contract from bytes"); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/ContractStorer.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/ContractStorer.java deleted file mode 100644 index c9d5bb7315..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/ContractStorer.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec; - -import java.util.HashMap; -import java.util.Map; - -/** - * Defines how to store converted contracts to a byte array representation that can be - * stored to drive. - * - * @param contracts type - * @author Marcin Grzejszczak - * @since 2.1.0 - */ -public interface ContractStorer { - - /** - * Stores the contracts as a map of filename and String. - * @param contracts - to convert - * @return mapping of filename to converted byte array representation of the contract - */ - default Map store(T contracts) { - Map map = new HashMap<>(); - map.put(String.valueOf(Math.abs(hashCode())), contracts.toString().getBytes()); - return map; - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/ContractTemplate.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/ContractTemplate.java deleted file mode 100644 index 20adc247a0..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/ContractTemplate.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec; - -/** - * Contract for defining templated responses. - *

- * If no implementation is provided then Handlebars will be picked as a default - * implementation. - * - * @author Marcin Grzejszczak - * @since 1.1.0 - */ -public interface ContractTemplate { - - /** - * @param text text to assert - * @return asserts whether the given text starts with proper opening template. - */ - default boolean startsWithTemplate(String text) { - return text.startsWith(openingTemplate()); - } - - /** - * @param text text to assert - * @return asserts whether the given text starts with proper opening template for - * escaped value. - */ - default boolean startsWithEscapedTemplate(String text) { - return text.startsWith(escapedOpeningTemplate()); - } - - /** - * Handlebars is using the Mustache template thus it looks like this {{ Mustache }}. - * In this case the opening template would return {{ - * @return opening template for a variable - */ - String openingTemplate(); - - /** - * Handlebars is using the Mustache template thus it looks like this {{ Mustache }}. - * In this case the closing template would return }} - * @return closing template for a variable - */ - String closingTemplate(); - - /** - * Handlebars is using the Mustache template thus it looks like this {{{ Mustache }}}. - * In this case the opening template would return {{{ - * @return escaped opening template for a variable - */ - default String escapedOpeningTemplate() { - return openingTemplate(); - } - - /** - * Handlebars is using the Mustache template thus it looks like this {{{ Mustache }}}. - * In this case the closing template would return }}} - * @return escaped closing template for a variable - */ - default String escapedClosingTemplate() { - return closingTemplate(); - } - - /** - * @return returns the template for retrieving a URL path and query from request - */ - String url(); - - /** - * @param key query parameter key - * @return the template for retrieving first value of a query parameter e.g. {{ - * request.query.search }} - */ - String query(String key); - - /** - * @param key query parameter key - * @param index query parameter index - * @return the template for retrieving nth value of a query parameter (zero indexed) - * e.g. {{ request.query.search.[5] }} - */ - String query(String key, int index); - - /** - * @return the template for retrieving a URL path - */ - String path(); - - /** - * @param index request path index - * @return the template for retrieving nth value of a URL path (zero indexed) e.g. {{ - * request.path.[2] }} - */ - String path(int index); - - /** - * @param key headers key - * @return the template for retrieving the first value of a request header e.g. {{ - * request.headers.X-Request-Id }} - */ - String header(String key); - - /** - * @param key headers key - * @param index headers index - * @return the template for retrieving the nth value of a request header (zero - * indexed) e.g. {{ request.headers.X-Request-Id.[5] }} - */ - String header(String key, int index); - - /** - * @param key cookie key - * @return the template for retrieving the first value of a cookie with certain key - */ - String cookie(String key); - - /** - * @return request body text (avoid for non-text bodies) e.g. {{ request.body }} . The - * body will not be escaped so you won't be able to directly embed it in a JSON for - * example. - */ - String body(); - - /** - * @param jsonPath json path value - * @return request body text for the given JsonPath. e.g. {{ jsonPath request.body - * '$.a.b.c' }} - */ - String body(String jsonPath); - - /** - * @return the template for retrieving a escaped URL path and query from request - */ - default String escapedUrl() { - return url(); - } - - /** - * @param key query parameter key - * @return the template for retrieving escaped first value of a query parameter e.g. - * {{{ request.query.search }}} - */ - default String escapedQuery(String key) { - return query(key); - } - - /** - * @param key query parameter key - * @param index query parameter index - * @return the template for retrieving esacped nth value of a query parameter (zero - * indexed) e.g. {{{ request.query.search.[5] }}} - */ - default String escapedQuery(String key, int index) { - return query(key, index); - } - - /** - * @return the template for retrieving a escaped URL path - */ - default String escapedPath() { - return path(); - } - - /** - * @param index path index - * @return the template for retrieving escaped nth value of a URL path (zero indexed) - * e.g. {{{ request.path.[2] }}} - */ - default String escapedPath(int index) { - return path(index); - } - - /** - * @param key headers key - * @return the template for retrieving the escaped first value of a request header - * e.g. {{{ request.headers.X-Request-Id }}} - */ - default String escapedHeader(String key) { - return header(key); - } - - /** - * @param key headers key - * @param index headers index - * @return the template for retrieving the esacaped nth value of a request header - * (zero indexed) e.g. {{{ request.headers.X-Request-Id.[5] }}} - */ - default String escapedHeader(String key, int index) { - return header(key, index); - } - - /** - * @param key cookie key - * @return the template for retrieving the escaped first value of a cookie with - * certain key - */ - default String escapedCookie(String key) { - return cookie(key); - } - - /** - * @return request body text (avoid for non-text bodies) e.g. {{{ request.body }}} . - * The body will not be escaped so you won't be able to directly embed it in a JSON - * for example. - */ - default String escapedBody() { - return body(); - } - - /** - * @param jsonPath json path value - * @return request body text for the given JsonPath. e.g. {{{ jsonPath request.body - * '$.a.b.c' }}} - */ - default String escapedBody(String jsonPath) { - return body(jsonPath); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/ContractVerifierException.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/ContractVerifierException.java deleted file mode 100644 index e491406dfb..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/ContractVerifierException.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec; - -/** - * @author Jakub Kubrynski, codearte.io - */ -public class ContractVerifierException extends RuntimeException { - - public ContractVerifierException(String message) { - super(message); - } - - public ContractVerifierException(String message, Throwable cause) { - super(message, cause); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Body.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Body.java deleted file mode 100644 index 5f81f86143..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Body.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.io.Serializable; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; - -/** - * Represents a body of a request / response or a message. - * - * @since 1.0.0 - */ -public class Body extends DslProperty { - - public Body(Map body) { - super(extractValue(body, ContractUtils.CLIENT_VALUE), extractValue(body, ContractUtils.SERVER_VALUE)); - } - - public Body(List bodyAsList) { - super(bodyAsList.stream().map(DslProperty::getClientValue).collect(Collectors.toList()), - bodyAsList.stream().map(DslProperty::getServerValue).collect(Collectors.toList())); - } - - public Body(Object value) { - super(ContractUtils.CLIENT_VALUE.apply(value), ContractUtils.SERVER_VALUE.apply(value)); - } - - public Body(Byte[] bodyAsValue) { - super(bodyAsValue); - } - - public Body(Number bodyAsValue) { - super(bodyAsValue); - } - - public Body(String bodyAsValue) { - super(bodyAsValue, bodyAsValue); - } - - public Body(DslProperty bodyAsValue) { - super(bodyAsValue.getClientValue(), bodyAsValue.getServerValue()); - } - - public Body(Serializable serializable) { - super(serializable, serializable); - } - - public Body(MatchingStrategy matchingStrategy) { - super(matchingStrategy, matchingStrategy); - } - - private static Map extractValue(Map body, final Function valueProvider) { - final Map map = new LinkedHashMap(); - body.forEach((key, value) -> map.put(key, valueProvider.apply(value))); - return map; - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/BodyMatcher.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/BodyMatcher.java deleted file mode 100644 index 1a19bf776d..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/BodyMatcher.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -/** - * Matchers for the given path. - * - * @author Marcin Grzejszczak - * @since 1.0.3 - */ -public interface BodyMatcher { - - /** - * @return What kind of matching are we dealing with. - */ - MatchingType matchingType(); - - /** - * @return Path to the path. Example for JSON it will be JSON Path. - */ - String path(); - - /** - * @return Optional value that the given path should be checked against. If there is - * no value then presence will be checked only together with type check. Example if we - * expect a JSON Path path {@code $.a} to be matched. by type, the defined response - * body contained an integer but the actual one contained a string then the assertion - * should fail. - */ - Object value(); - - /** - * @return Min no of occurrence when matching by type. In all other cases it will be - * ignored. - */ - Integer minTypeOccurrence(); - - /** - * @return Max no of occurrence when matching by type. In all other cases it will be - * ignored. - */ - Integer maxTypeOccurrence(); - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/BodyMatchers.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/BodyMatchers.java deleted file mode 100644 index a8afb2f9cc..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/BodyMatchers.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.util.LinkedList; -import java.util.List; -import java.util.Objects; -import java.util.function.Consumer; -import java.util.regex.Pattern; - -import groovy.lang.Closure; -import groovy.lang.DelegatesTo; - -/** - * Matching strategy of dynamic parts of the body. - * - * @author Marcin Grzejszczak - * @author Olga Maciaszek-Sharma - * @author Tim Ysewyn - * @since 1.0.3 - */ -public class BodyMatchers { - - protected final List matchers = new LinkedList<>(); - - public void jsonPath(String path, MatchingTypeValue matchingType) { - this.matchers.add(new PathBodyMatcher(path, matchingType)); - } - - /** - * Adds xPath matcher; even though same implementation as in - * {@link BodyMatchers#jsonPath(java.lang.String, org.springframework.cloud.contract.spec.internal.MatchingTypeValue)}, - * added for logical coherence in xml. - * @param xPath the xPath used to find the element to match - * @param matchingTypeValue to match the element found by the xPath against - */ - public void xPath(String xPath, MatchingTypeValue matchingTypeValue) { - this.matchers.add(new PathBodyMatcher(xPath, matchingTypeValue)); - } - - public boolean hasMatchers() { - return !this.matchers.isEmpty(); - } - - public List matchers() { - return this.matchers; - } - - public MatchingTypeValue byDate() { - return new MatchingTypeValue(MatchingType.DATE, RegexPatterns.isoDate()); - } - - public MatchingTypeValue byTime() { - return new MatchingTypeValue(MatchingType.TIME, RegexPatterns.isoTime()); - } - - public MatchingTypeValue byTimestamp() { - return new MatchingTypeValue(MatchingType.TIMESTAMP, RegexPatterns.isoDateTime()); - } - - public RegexMatchingTypeValue byRegex(String regex) { - return byRegex(Pattern.compile(regex)); - } - - public RegexMatchingTypeValue byRegex(RegexProperty regex) { - assertNotNull(regex); - return new RegexMatchingTypeValue(MatchingType.REGEX, regex); - } - - public RegexMatchingTypeValue byRegex(Pattern regex) { - assertNotNull(regex); - return new RegexMatchingTypeValue(MatchingType.REGEX, new RegexProperty(regex)); - } - - public MatchingTypeValue byEquality() { - return new MatchingTypeValue(MatchingType.EQUALITY); - } - - private void assertNotNull(Object object) { - if (object == null) { - throw new IllegalStateException("Object can't be null!"); - } - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - BodyMatchers that = (BodyMatchers) o; - return Objects.equals(matchers, that.matchers); - } - - @Override - public int hashCode() { - return Objects.hash(matchers); - } - - @Override - public String toString() { - return "BodyMatchers{" + "\nmatchers=" + matchers + '}'; - } - - /** - * The output part of the contract. - * @param consumer function to manipulate the output message - * @return matching type - */ - public MatchingTypeValue byType(Consumer consumer) { - MatchingTypeValueHolder matchingTypeValue = new MatchingTypeValueHolder(); - consumer.accept(matchingTypeValue); - return matchingTypeValue.matchingTypeValue; - } - - /** - * The output part of the contract. - * @param consumer function to manipulate the output message - * @return matching type - */ - public MatchingTypeValue byType(@DelegatesTo(MatchingTypeValueHolder.class) Closure consumer) { - MatchingTypeValueHolder matchingTypeValue = new MatchingTypeValueHolder(); - consumer.setDelegate(matchingTypeValue); - consumer.call(); - return matchingTypeValue.matchingTypeValue; - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/CanBeDynamic.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/CanBeDynamic.java deleted file mode 100644 index 501b83c242..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/CanBeDynamic.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -/** - * Some properties can contain dynamic values. If that's the case we need to know how to - * generate a concrete value for them. - * - * @author Marcin Grzejszczak - * @since 2.1.0 - */ -public interface CanBeDynamic { - - /** - * @return a generated, concrete value. - */ - Object generateConcreteValue(); - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ClientDslProperty.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ClientDslProperty.java deleted file mode 100644 index 2366df6fff..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ClientDslProperty.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -/** - * Represents a client side {@link DslProperty}. - * - * @since 1.0.0 - */ -public class ClientDslProperty extends DslProperty { - - public ClientDslProperty(Object singleValue) { - super(singleValue); - } - - public ClientDslProperty(Object client, Object server) { - super(client, server); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ClientOutputMessage.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ClientOutputMessage.java deleted file mode 100644 index 44ff58b0d9..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ClientOutputMessage.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -class ClientOutputMessage extends OutputMessage { - - ClientOutputMessage(OutputMessage request) { - super(request); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Common.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Common.java deleted file mode 100644 index 4103f3d6d8..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Common.java +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.io.File; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.charset.Charset; -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.function.BinaryOperator; -import java.util.function.Function; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -/** - * Contains useful common methods for the DSL. - * - * @author Marcin Grzejszczak - * @author Olga Maciaszek-Sharma - * @author Tim Ysewyn - * @since 1.0.0 - */ -public class Common { - - public Map convertObjectsToDslProperties(Map body) { - return body.entrySet().stream() - .collect(Collectors.toMap((Function) t -> t.getKey().toString(), - (Function) t -> toDslProperty(t.getValue()), throwingMerger(), - LinkedHashMap::new)); - } - - private static BinaryOperator throwingMerger() { - return (u, v) -> { - throw new IllegalStateException(String.format("Duplicate key %s", u)); - }; - } - - public Collection convertObjectsToDslProperties(List body) { - return body.stream().map(this::toDslProperty).collect(Collectors.toList()); - } - - public DslProperty toDslProperty(Object property) { - return new DslProperty(property); - } - - public DslProperty toDslProperty(Map property) { - return new DslProperty(convertObjectsToDslProperties(property)); - } - - public DslProperty toDslProperty(List property) { - return new DslProperty(convertObjectsToDslProperties(property)); - } - - public DslProperty toDslProperty(DslProperty property) { - return property; - } - - public NamedProperty named(DslProperty name, DslProperty value) { - return new NamedProperty(name, value); - } - - public NamedProperty named(DslProperty name, DslProperty value, DslProperty contentType) { - return new NamedProperty(name, value, contentType); - } - - public NamedProperty named(Map namedMap) { - return new NamedProperty(namedMap); - } - - public DslProperty value(DslProperty value) { - return value; - } - - public DslProperty $(DslProperty value) { - return value; - } - - public DslProperty value(Object value) { - return new DslProperty(value); - } - - public DslProperty $(Object value) { - return new DslProperty(value); - } - - public DslProperty value(ClientDslProperty client, ServerDslProperty server) { - assertThatSidesMatch(client.getClientValue(), server.getServerValue()); - return new DslProperty(client.getClientValue(), server.getServerValue()); - } - - public DslProperty $(ClientDslProperty client, ServerDslProperty server) { - return value(client, server); - } - - public DslProperty value(ServerDslProperty server, ClientDslProperty client) { - assertThatSidesMatch(client.getClientValue(), server.getServerValue()); - return new DslProperty(client.getClientValue(), server.getServerValue()); - } - - public DslProperty $(ServerDslProperty server, ClientDslProperty client) { - return value(server, client); - } - - public RegexProperty regex(String regex) { - return regexProperty(Pattern.compile(regex)); - } - - public RegexProperty regex(RegexProperty regex) { - return regex; - } - - public RegexProperty regex(Pattern regex) { - return regexProperty(regex); - } - - public OptionalProperty optional(Object object) { - return new OptionalProperty(object); - } - - public RegexProperty regexProperty(Object object) { - return new RegexProperty(object); - } - - public ExecutionProperty execute(String commandToExecute) { - return new ExecutionProperty(commandToExecute); - } - - /** - * Helper method to provide a better name for the consumer side. - * @param clientValue client value - * @return client dsl property - */ - public ClientDslProperty client(Object clientValue) { - return new ClientDslProperty(clientValue); - } - - /** - * Helper method to provide a better name for the consumer side. - * @param clientValue client value - * @return client dsl property - */ - public ClientDslProperty stub(Object clientValue) { - return new ClientDslProperty(clientValue); - } - - /** - * Helper method to provide a better name for the consumer side. - * @param clientValue client value - * @return client dsl property - */ - public ClientDslProperty consumer(Object clientValue) { - return new ClientDslProperty(clientValue); - } - - /** - * Helper method to provide a better name for the server side. - * @param serverValue server value - * @return server dsl property - */ - public ServerDslProperty server(Object serverValue) { - return new ServerDslProperty(serverValue); - } - - /** - * Helper method to provide a better name for the consumer side. - * @param clientValue client value - * @return client dsl property - */ - public ClientDslProperty c(Object clientValue) { - return new ClientDslProperty(clientValue); - } - - /** - * Helper method to provide a better name for the server side. - * @param serverValue server value - * @return server dsl property - */ - public ServerDslProperty p(Object serverValue) { - return new ServerDslProperty(serverValue); - } - - /** - * Helper method to provide a better name for the server side. - * @param serverValue server value - * @return server dsl property - */ - public ServerDslProperty test(Object serverValue) { - return new ServerDslProperty(serverValue); - } - - /** - * Read file contents as String. - * @param relativePath of the file to read - * @return String file contents - */ - public FromFileProperty file(String relativePath) { - return file(relativePath, Charset.defaultCharset()); - } - - /** - * Read file contents as bytes[]. - * @param relativePath of the file to read - * @return String file contents - */ - public FromFileProperty fileAsBytes(String relativePath) { - return new FromFileProperty(fileLocation(relativePath), byte[].class); - } - - /** - * Read file contents as String with the given Charset. - * @param relativePath of the file to read - * @param charset to use for converting the bytes to String - * @return String file contents - */ - public FromFileProperty file(String relativePath, Charset charset) { - return new FromFileProperty(fileLocation(relativePath), String.class, charset); - } - - /** - * Read file contents as array of bytes. - * @param relativePath of the file to read - * @return file contents as an array of bytes - */ - private File fileLocation(String relativePath) { - URL resource = Thread.currentThread().getContextClassLoader().getResource(relativePath); - if (resource == null) { - throw new IllegalStateException("File [" + relativePath + "] is not present"); - } - try { - return new File(resource.toURI()); - } - catch (URISyntaxException ex) { - throw new IllegalStateException(ex); - } - } - - /** - * Helper method to provide a better name for the server side. - * @param serverValue server value - * @return server dsl property - */ - public ServerDslProperty producer(Object serverValue) { - return new ServerDslProperty(serverValue); - } - - private void throwAbsentError() { - throw new IllegalStateException("Absent cannot only be used only on one side"); - } - - private void assertThat(boolean condition, String msg) { - if (!condition) { - throw new IllegalStateException(msg); - } - } - - public void assertThatSidesMatch(Object firstSide, Object secondSide) { - if (firstSide instanceof OptionalProperty) { - if (secondSide == null) { - return; - } - assertThat(secondSide.toString().matches(((OptionalProperty) firstSide).optionalPattern()), - "Pattern [" + ((OptionalProperty) firstSide).optionalPattern() + "] is not matched by [" - + secondSide.toString() + "]"); - } - else if ((firstSide instanceof Pattern || firstSide instanceof RegexProperty) && secondSide instanceof String) { - Pattern pattern = firstSide instanceof Pattern ? (Pattern) firstSide - : ((RegexProperty) firstSide).getPattern(); - assertThat(((String) secondSide).toString().matches(pattern.pattern()), - "Pattern [" + pattern.pattern() + "] is not matched by [" + secondSide.toString() + "]"); - } - else if ((secondSide instanceof Pattern || secondSide instanceof RegexProperty) - && firstSide instanceof String) { - Pattern pattern = secondSide instanceof Pattern ? (Pattern) secondSide - : ((RegexProperty) secondSide).getPattern(); - assertThat(((String) firstSide).matches(pattern.pattern()), - "Pattern [" + pattern.pattern() + "] is not matched by [" + firstSide.toString() + "]"); - } - else if (firstSide instanceof MatchingStrategy && secondSide instanceof MatchingStrategy) { - if (((MatchingStrategy) firstSide).getType().equals(MatchingStrategy.Type.ABSENT) - && !((MatchingStrategy) secondSide).getType().equals(MatchingStrategy.Type.ABSENT)) { - throwAbsentError(); - } - - } - else if (firstSide instanceof MatchingStrategy) { - if (((MatchingStrategy) firstSide).getType().equals(MatchingStrategy.Type.ABSENT)) { - throwAbsentError(); - } - - } - else if (secondSide instanceof MatchingStrategy) { - if (((MatchingStrategy) secondSide).getType().equals(MatchingStrategy.Type.ABSENT)) { - throwAbsentError(); - } - - } - - } - - public RegexProperty onlyAlphaUnicode() { - return RegexPatterns.onlyAlphaUnicode(); - } - - public RegexProperty alphaNumeric() { - return RegexPatterns.alphaNumeric(); - } - - public RegexProperty number() { - return RegexPatterns.number(); - } - - public RegexProperty positiveInt() { - return RegexPatterns.positiveInt(); - } - - public RegexProperty anyBoolean() { - return RegexPatterns.anyBoolean(); - } - - public RegexProperty anInteger() { - return RegexPatterns.anInteger(); - } - - public RegexProperty aDouble() { - return RegexPatterns.aDouble(); - } - - public RegexProperty ipAddress() { - return RegexPatterns.ipAddress(); - } - - public RegexProperty hostname() { - return RegexPatterns.hostname(); - } - - public RegexProperty email() { - return RegexPatterns.email(); - } - - public RegexProperty url() { - return RegexPatterns.url(); - } - - public RegexProperty httpsUrl() { - return RegexPatterns.httpsUrl(); - } - - public RegexProperty uuid() { - return RegexPatterns.uuid(); - } - - public RegexProperty isoDate() { - return RegexPatterns.isoDate(); - } - - public RegexProperty isoDateTime() { - return RegexPatterns.isoDateTime(); - } - - public RegexProperty isoTime() { - return RegexPatterns.isoTime(); - } - - public RegexProperty iso8601WithOffset() { - return RegexPatterns.iso8601WithOffset(); - } - - public RegexProperty nonEmpty() { - return RegexPatterns.nonEmpty(); - } - - public RegexProperty nonBlank() { - return RegexPatterns.nonBlank(); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/CompositeContractTemplate.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/CompositeContractTemplate.java deleted file mode 100644 index 27cd59ccd4..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/CompositeContractTemplate.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import org.springframework.cloud.contract.spec.ContractTemplate; - -/** - * For backward compatibility when assertions take place, first checks the custom setup. - * Writes in a new format, can read the old format. - * - * @author Marcin Grzejszczak - * @since 2.1.0 - */ -public class CompositeContractTemplate implements ContractTemplate { - - private final HandlebarsContractTemplate template = new HandlebarsContractTemplate(); - - @Override - public boolean startsWithTemplate(String text) { - return template.startsWithTemplate(text); - } - - @Override - public boolean startsWithEscapedTemplate(String text) { - return this.template.startsWithEscapedTemplate(text); - } - - @Override - public String openingTemplate() { - return this.template.openingTemplate(); - } - - @Override - public String closingTemplate() { - return this.template.closingTemplate(); - } - - @Override - public String escapedOpeningTemplate() { - return this.template.escapedOpeningTemplate(); - } - - @Override - public String escapedClosingTemplate() { - return this.template.escapedClosingTemplate(); - } - - @Override - public String url() { - return this.template.url(); - } - - @Override - public String query(String key) { - return this.template.query(key); - } - - @Override - public String query(String key, int index) { - return this.template.query(key, index); - } - - @Override - public String path() { - return this.template.path(); - } - - @Override - public String path(int index) { - return this.template.path(index); - } - - @Override - public String header(String key) { - return this.template.header(key); - } - - @Override - public String header(String key, int index) { - return this.template.header(key, index); - } - - @Override - public String cookie(String key) { - return this.template.cookie(key); - } - - @Override - public String body() { - return this.template.body(); - } - - @Override - public String escapedBody() { - // WireMock doesn't support proper escaping of JSON body - // that's why we need to use our custom handlebars extension - return this.template.escapedBody(); - } - - @Override - public String escapedBody(String jsonPath) { - return this.template.escapedBody(jsonPath); - } - - @Override - public String body(String jsonPath) { - return this.template.body(jsonPath); - } - - @Override - public String escapedUrl() { - return this.template.escapedUrl(); - } - - @Override - public String escapedQuery(String key) { - return this.template.escapedQuery(key); - } - - @Override - public String escapedQuery(String key, int index) { - return this.template.escapedQuery(key, index); - } - - @Override - public String escapedPath() { - return this.template.escapedPath(); - } - - @Override - public String escapedPath(int index) { - return this.template.escapedPath(index); - } - - @Override - public String escapedHeader(String key) { - return this.template.escapedHeader(key); - } - - @Override - public String escapedHeader(String key, int index) { - return this.template.escapedHeader(key, index); - } - - @Override - public String escapedCookie(String key) { - return this.template.escapedCookie(key); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ContractUtils.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ContractUtils.java deleted file mode 100644 index bf038b2f6e..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ContractUtils.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.util.function.Function; - -final class ContractUtils { - - static final Function CLIENT_VALUE = o -> o instanceof DslProperty ? ((DslProperty) o).getClientValue() : o; - static final Function SERVER_VALUE = o -> o instanceof DslProperty ? ((DslProperty) o).getServerValue() : o; - - private ContractUtils() { - throw new IllegalStateException("Can't instantiate an utility class"); - } - - static Object convertStubSideRecursively(Object object) { - return convertRecursively(object, CLIENT_VALUE); - } - - static Object convertTestSideRecursively(Object object) { - return convertRecursively(object, SERVER_VALUE); - } - - private static Object convertRecursively(Object object, Function function) { - if (object instanceof DslProperty) { - return convertRecursively(function.apply(object), function); - } - return object; - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Cookie.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Cookie.java deleted file mode 100644 index 1a73edf9cb..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Cookie.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.util.Objects; - -/** - * Represents a http cookie. - * - * @author Alex Xandra Albert Sim - * @since 1.2.5 - */ -public class Cookie extends DslProperty { - - private String key; - - public Cookie(String key, DslProperty dslProperty) { - super(dslProperty.getClientValue(), dslProperty.getServerValue()); - this.key = key; - } - - public Cookie(String key, MatchingStrategy value) { - super(value); - this.key = key; - } - - public Cookie(String key, Object value) { - super(ContractUtils.CLIENT_VALUE.apply(value), ContractUtils.SERVER_VALUE.apply(value)); - this.key = key; - } - - public static Cookie build(String key, Object value) { - if (value instanceof MatchingStrategy) { - return new Cookie(key, (MatchingStrategy) value); - } - return new Cookie(key, value); - } - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - if (!super.equals(o)) { - return false; - } - Cookie cookie = (Cookie) o; - return Objects.equals(key, cookie.key); - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), key); - } - - @Override - public String toString() { - return "Cookie{" + "key='" + key + '\'' + "}, value=" + super.toString(); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Cookies.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Cookies.java deleted file mode 100644 index 287c120e59..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Cookies.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.function.Consumer; - -/** - * Represents a set of http cookies. - * - * @author Alex Xandra Albert Sim - * @since 1.2.5 - */ -public class Cookies { - - private Set entries = new HashSet<>(); - - public void cookie(Map singleCookie) { - Iterator> iterator = singleCookie.entrySet().iterator(); - if (iterator.hasNext()) { - Map.Entry first = iterator.next(); - if (first != null) { - entries.add(Cookie.build(first.getKey(), first.getValue())); - } - } - } - - public void cookie(String cookieKey, Object cookieValue) { - entries.add(Cookie.build(cookieKey, cookieValue)); - } - - public void executeForEachCookie(final Consumer consumer) { - entries.forEach(consumer::accept); - } - - public DslProperty matching(String value) { - return new DslProperty(value); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Cookies cookies = (Cookies) o; - return Objects.equals(entries, cookies.entries); - } - - @Override - public int hashCode() { - return Objects.hash(entries); - } - - @Override - public String toString() { - return "Cookies{" + "entries=" + entries + '}'; - } - - /** - * Converts the headers into their stub side representations and returns as a map of - * String key => Object value. - * @return converted map - */ - public Map asStubSideMap() { - final Map map = new LinkedHashMap<>(); - entries.forEach(cookie -> map.put(cookie.getKey(), ContractUtils.convertStubSideRecursively(cookie))); - return map; - } - - /** - * Converts the headers into their stub side representations and returns as a map of - * String key => Object value. - * @return converted map - */ - public Map asTestSideMap() { - final Map map = new HashMap(); - entries.forEach(cookie -> map.put(cookie.getKey(), ContractUtils.convertTestSideRecursively(cookie))); - return map; - } - - public Set getEntries() { - return entries; - } - - public void setEntries(Set entries) { - this.entries = entries; - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/DslProperty.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/DslProperty.java deleted file mode 100644 index 7b8be7a539..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/DslProperty.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.io.Serializable; -import java.util.Objects; -import java.util.regex.Pattern; - -/** - * Represents an element of a DSL that can contain client or sever side values. - * - * @since 1.0.0 - */ -public class DslProperty implements Serializable { - - private final T clientValue; - - private final T serverValue; - - public DslProperty(T clientValue, T serverValue) { - this.clientValue = clientValue; - this.serverValue = serverValue; - } - - public DslProperty(T singleValue) { - this.clientValue = singleValue; - this.serverValue = singleValue; - } - - public boolean isSingleValue() { - return this.clientValue.equals(this.serverValue) || (this.clientValue != null && this.serverValue == null) - || (this.serverValue != null && this.clientValue == null); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - DslProperty that = (DslProperty) o; - Object thisClientValue = stringPatternIfPattern(clientValue); - Object thatClientValue = stringPatternIfPattern(that.clientValue); - Object thisServerValue = stringPatternIfPattern(serverValue); - Object thatServerValue = stringPatternIfPattern(that.serverValue); - return Objects.equals(thisClientValue, thatClientValue) && Objects.equals(thisServerValue, thatServerValue); - } - - private Object stringPatternIfPattern(Object value) { - return value instanceof Pattern ? ((Pattern) value).pattern() : value; - } - - @Override - public int hashCode() { - return Objects.hash(stringPatternIfPattern(clientValue), stringPatternIfPattern(serverValue)); - } - - @Override - public String toString() { - return getClass().getSimpleName() + "{" + "\nclientValue=" + clientValue + ", \n\tserverValue=" + serverValue - + '}'; - } - - public final T getClientValue() { - return clientValue; - } - - public final T getServerValue() { - return serverValue; - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/DslPropertyConverter.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/DslPropertyConverter.java deleted file mode 100644 index 8d585ec91f..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/DslPropertyConverter.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.util.List; - -import org.springframework.core.io.support.SpringFactoriesLoader; - -/** - * A hook mechanism to allow external languages and frameworks to convert types that are - * not in Java for Spring Cloud Contract to understand. - * - * @author Marcin Grzejszczak - * @since 2.2.0 - */ -public interface DslPropertyConverter { - - /** - * Default no op implementation. - */ - DslPropertyConverter DEFAULT = new DslPropertyConverter() { - }; - - /** - * A composite over available instances or default if none is present. - */ - DslPropertyConverter INSTANCE = instance(); - - /** - * @return a composite {@link DslPropertyConverter} around a list of - * {@link DslPropertyConverter} or a default no op instance - */ - static DslPropertyConverter instance() { - if (INSTANCE != null) { - return INSTANCE; - } - List converters = SpringFactoriesLoader.loadFactories(DslPropertyConverter.class, null); - if (converters.isEmpty()) { - return DEFAULT; - } - return new DslPropertyConverter() { - @Override - public Object testSide(Object object) { - Object convertedObject = object; - for (DslPropertyConverter converter : converters) { - convertedObject = converter.testSide(convertedObject); - } - return convertedObject; - } - - @Override - public Object stubSide(Object object) { - Object convertedObject = object; - for (DslPropertyConverter converter : converters) { - convertedObject = converter.stubSide(convertedObject); - } - return convertedObject; - } - }; - } - - /** - * Conversion mechanism for the test side manipulation. - * @param object object to manipulate - * @return converted object for the test side - */ - default Object testSide(Object object) { - return object; - } - - /** - * Conversion mechanism for the stub side manipulation. - * @param object object to manipulate - * @return converted object for the stub side - */ - default Object stubSide(Object object) { - return object; - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ExecutionProperty.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ExecutionProperty.java deleted file mode 100644 index 3483852d00..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ExecutionProperty.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.io.Serializable; -import java.util.Objects; - -/** - * Represents a property that will become an executable method in the generated tests. - * - * @since 1.0.0 - */ -public class ExecutionProperty implements Serializable { - - private static final String PLACEHOLDER_VALUE = "$it"; - - private final String executionCommand; - - public ExecutionProperty(String executionCommand) { - this.executionCommand = executionCommand; - } - - /** - * Inserts the provided code as a parameter to the method and returns the code that - * represents that method execution. - * @param valueToInsert value to insert into the string - * @return string with inserted value - */ - public String insertValue(String valueToInsert) { - return executionCommand.replace(PLACEHOLDER_VALUE, valueToInsert); - } - - @Override - public String toString() { - return executionCommand; - } - - public final String getExecutionCommand() { - return executionCommand; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ExecutionProperty that = (ExecutionProperty) o; - return Objects.equals(executionCommand, that.executionCommand); - } - - @Override - public int hashCode() { - return Objects.hash(executionCommand); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/FromFileProperty.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/FromFileProperty.java deleted file mode 100644 index dfc0d482cc..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/FromFileProperty.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.io.File; -import java.io.IOException; -import java.io.Serializable; -import java.io.UnsupportedEncodingException; -import java.nio.charset.Charset; -import java.nio.file.Files; - -/** - * Represents a property that will become a File content. - * - * @since 2.1.0 - */ -public class FromFileProperty implements Serializable { - - private final File file; - - private final String charset; - - private final Class type; - - public FromFileProperty(File file, Class type) { - this(file, type, Charset.defaultCharset()); - } - - public FromFileProperty(File file, Class type, Charset charset) { - this.file = file; - this.type = type; - this.charset = charset.toString(); - } - - public boolean isString() { - return String.class.equals(this.type); - } - - public boolean isByte() { - return byte[].class.equals(this.type) || Byte[].class.equals(this.type); - } - - public boolean isJson() { - return this.fileName().endsWith(".json"); - } - - public boolean isXml() { - return this.fileName().endsWith(".xml"); - } - - public String asString() { - try { - return new String(asBytes(), this.charset); - } - catch (UnsupportedEncodingException ex) { - throw new IllegalStateException(ex); - } - } - - public String fileName() { - return this.file.getName(); - } - - public byte[] asBytes() { - try { - return Files.readAllBytes(this.file.toPath()); - } - catch (IOException ex) { - throw new IllegalStateException(ex); - } - } - - @Override - public String toString() { - return asString(); - } - - public final File getFile() { - return file; - } - - public final String getCharset() { - return charset; - } - - public final Class getType() { - return type; - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/FromRequest.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/FromRequest.java deleted file mode 100644 index 38ca93b4f4..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/FromRequest.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import org.springframework.cloud.contract.spec.ContractTemplate; - -/** - * Helper class to reference the request body parameters. - * - * @author Marcin Grzejszczak - * @since 1.1.0 - */ -public class FromRequest { - - private final ContractTemplate template; - - public FromRequest() { - this.template = template(); - } - - private ContractTemplate template() { - return new CompositeContractTemplate(); - } - - /** - * @return URL path and query. - */ - public DslProperty url() { - return new DslProperty(template.escapedUrl()); - } - - /** - * First value of a query parameter e.g. request.query.search. - * @param key key for the query param - * @return dsl property - */ - public DslProperty query(String key) { - return new DslProperty(template.escapedQuery(key)); - } - - /** - * nth value of a query parameter (zero indexed) e.g. request.query.search.[5]. - * @param key key for the query param - * @param index index of the query param - * @return dsl property - */ - public DslProperty query(String key, int index) { - return new DslProperty(template.escapedQuery(key, index)); - } - - /** - * URL path. - * @return dsl property - */ - public DslProperty path() { - return new DslProperty(template.escapedPath()); - } - - /** - * nth value of a URL path (zero indexed) e.g. {{{ request.path.[2] }}}* @param index. - * @param index path index - * @return dsl property - */ - public DslProperty path(int index) { - return new DslProperty(template.escapedPath(index)); - } - - /** - * First value of a request header e.g. request.headers.X-Request-Id. - * @param key header key - * @return dsl property - */ - public DslProperty header(String key) { - return new DslProperty(template.escapedHeader(key)); - } - - /** - * nth value of a request header (zero indexed) e.g. request.headers.X-Request-Id. - * @param key header key - * @param index header index - * @return dsl property - */ - public DslProperty header(String key, int index) { - return new DslProperty(template.escapedHeader(key, index)); - } - - /** - * Retruns the tempalte for retrieving the first value of a cookie with certain key. - * @param key cookie key - * @return dsl property - */ - public DslProperty cookie(String key) { - return new DslProperty(template.escapedCookie(key)); - } - - /** - * Request body text (avoid for non-text bodies). - * @return dsl property - */ - public DslProperty body() { - return new DslProperty(template.escapedBody()); - } - - /** - * Request body text for the given JsonPath. - * @param jsonPath json path body - * @return dsl property - */ - public DslProperty body(String jsonPath) { - return new DslProperty(template.escapedBody(jsonPath)); - } - - /** - * Unescaped URL path and query. - * @return dsl property - */ - public DslProperty rawUrl() { - return new DslProperty(template.url()); - } - - /** - * Unescaped First value of a query parameter e.g. request.query.search. - * @param key query key - * @return dsl property - */ - public DslProperty rawQuery(String key) { - return new DslProperty(template.query(key)); - } - - /** - * Unescaped nth value of a query parameter (zero indexed) e.g. - * request.query.search.[5]. - * @param key query key - * @param index query index - * @return dsl property - */ - public DslProperty rawQuery(String key, int index) { - return new DslProperty(template.query(key, index)); - } - - /** - * Unescaped URL path. - * @return dsl property - */ - public DslProperty rawPath() { - return new DslProperty(template.path()); - } - - /** - * Unescaped nth value of a URL path (zero indexed) e.g. {{{ request.path.[2]. }}}* - * @param index path index - * @return dsl property - */ - public DslProperty rawPath(int index) { - return new DslProperty(template.path(index)); - } - - /** - * Unescaped First value of a request header e.g. request.headers.X-Request-Id. - * @param key header key - * @return dsl property - */ - public DslProperty rawHeader(String key) { - return new DslProperty(template.header(key)); - } - - /** - * Unescaped nth value of a request header (zero indexed) e.g. - * request.headers.X-Request-Id. - * @param key header key - * @param index header index - * @return dsl property - */ - public DslProperty rawHeader(String key, int index) { - return new DslProperty(template.header(key, index)); - } - - /** - * Unescaped Returns the template for retrieving the first value of a cookie with - * certain key. - * @param key cookie key - * @return dsl property - */ - public DslProperty rawCookie(String key) { - return new DslProperty(template.cookie(key)); - } - - /** - * Unescaped Request body text (avoid for non-text bodies). - * @return dsl property - */ - public DslProperty rawBody() { - return new DslProperty(template.body()); - } - - /** - * Unescaped Request body text for the given JsonPath. - * @param jsonPath json path body - * @return dsl property - */ - public DslProperty rawBody(String jsonPath) { - return new DslProperty(template.body(jsonPath)); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/HandlebarsContractTemplate.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/HandlebarsContractTemplate.java deleted file mode 100644 index b7a6c5901c..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/HandlebarsContractTemplate.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import org.springframework.cloud.contract.spec.ContractTemplate; - -/** - * Represents the structure of templates using Handlebars compatible with WireMock - * template model requirements. - * - * @author Marcin Grzejszczak - * @since 1.1.0 - */ -public class HandlebarsContractTemplate implements ContractTemplate { - - @Override - public String openingTemplate() { - return "{{"; - } - - @Override - public String closingTemplate() { - return "}}"; - } - - @Override - public String escapedOpeningTemplate() { - return "{{{"; - } - - @Override - public String escapedClosingTemplate() { - return "}}}"; - } - - @Override - public String url() { - return wrapped("request.url"); - } - - @Override - public String query(String key) { - return query(key, 0); - } - - @Override - public String query(String key, int index) { - return wrapped("request.query." + key + ".[" + index + "]"); - } - - @Override - public String path() { - return wrapped("request.path"); - } - - @Override - public String path(int index) { - return wrapped("request.path.[" + index + "]"); - } - - @Override - public String header(String key) { - return header(key, 0); - } - - @Override - public String header(String key, int index) { - return wrapped("request.headers." + key + ".[" + index + "]"); - } - - @Override - public String cookie(String key) { - return wrapped("request.cookies." + key); - } - - @Override - public String body() { - return wrapped("request.body"); - } - - @Override - public String escapedBody() { - return escapedWrapped("escapejsonbody"); - } - - @Override - public String escapedBody(String jsonPath) { - return escapedWrapped("jsonPath request.body \'" + jsonPath + "\'"); - } - - @Override - public String body(String jsonPath) { - return wrapped("jsonPath request.body \'" + jsonPath + "\'"); - } - - @Override - public String escapedUrl() { - return escapedWrapped("request.url"); - } - - @Override - public String escapedQuery(String key) { - return escapedQuery(key, 0); - } - - @Override - public String escapedQuery(String key, int index) { - return escapedWrapped("request.query." + key + ".[" + index + "]"); - } - - @Override - public String escapedPath() { - return escapedWrapped("request.path"); - } - - @Override - public String escapedPath(int index) { - return escapedWrapped("request.path.[" + index + "]"); - } - - @Override - public String escapedHeader(String key) { - return escapedHeader(key, 0); - } - - @Override - public String escapedHeader(String key, int index) { - return escapedWrapped("request.headers." + key + ".[" + index + "]"); - } - - @Override - public String escapedCookie(String key) { - return escapedWrapped("request.cookies." + key); - } - - private String wrapped(String text) { - return openingTemplate() + text + closingTemplate(); - } - - private String escapedWrapped(String text) { - return escapedOpeningTemplate() + text + escapedClosingTemplate(); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Header.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Header.java deleted file mode 100644 index 39d38501f7..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Header.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.util.Objects; - -/** - * Represents a header of a request / response or a message. - * - * @since 1.0.0 - */ -public class Header extends DslProperty { - - private String name; - - public Header(String name, DslProperty dslProperty) { - super(dslProperty.getClientValue(), dslProperty.getServerValue()); - this.name = name; - } - - public Header(String name, MatchingStrategy value) { - super(value); - this.name = name; - } - - public Header(String name, Object value) { - super(ContractUtils.CLIENT_VALUE.apply(value), ContractUtils.SERVER_VALUE.apply(value)); - this.name = name; - } - - public static Header build(String key, Object value) { - if (value instanceof MatchingStrategy) { - return new Header(key, (MatchingStrategy) value); - } - return new Header(key, value); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - if (!super.equals(o)) { - return false; - } - Header header = (Header) o; - return Objects.equals(name, header.name); - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), name); - } - - @Override - public String toString() { - return "Header{" + "\nname='" + name + '\'' + "} \n" + super.toString(); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Headers.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Headers.java deleted file mode 100644 index a188e355a7..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Headers.java +++ /dev/null @@ -1,462 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.function.BiFunction; -import java.util.function.Consumer; -import java.util.regex.Pattern; - -/** - * Represents a set of headers of a request / response or a message. - * - * @author Marcin Grzejszczak - * @author Olga Maciaszek-Sharma - * @author Tim Ysewyn - * @since 1.0.0 - */ -public class Headers { - - private static final BiFunction CLIENT_SIDE = (s, header) -> ContractUtils - .convertStubSideRecursively(header); - - private static final BiFunction SERVER_SIDE = (s, header) -> ContractUtils - .convertTestSideRecursively(header); - - private Set
entries = new LinkedHashSet<>(); - - public void header(Map singleHeader) { - Iterator> iterator = singleHeader.entrySet().iterator(); - if (iterator.hasNext()) { - Map.Entry first = iterator.next(); - if (first != null) { - entries.add(Header.build(first.getKey(), first.getValue())); - } - } - } - - public void header(String headerKey, Object headerValue) { - entries.add(Header.build(headerKey, headerValue)); - } - - public void executeForEachHeader(final Consumer
consumer) { - entries.forEach(consumer); - } - - public void headers(Set
headers) { - entries.addAll(headers); - } - - public void accept(String contentType) { - header(accept(), matching(contentType)); - } - - public void contentType(String contentType) { - header(HttpHeaders.CONTENT_TYPE, matching(contentType)); - } - - public void messagingContentType(String contentType) { - header(MessagingHeaders.MESSAGING_CONTENT_TYPE, matching(contentType)); - } - - /** - * If for the consumer / producer you want to match exactly only the root of content - * type. I.e. {@code application/json;charset=UTF8} you care only about - * {@code application/json} then you should use this method - * @param value regex as String - * @return dsl property - */ - public DslProperty matching(String value) { - return new DslProperty(value); - } - - protected NotToEscapePattern notEscaped(Pattern pattern) { - return new NotToEscapePattern(pattern); - } - - public Map asMap(final BiFunction consumer) { - final Map map = new LinkedHashMap<>(); - entries.forEach(header -> map.put(header.getName(), consumer.apply(header.getName(), header))); - return map; - } - - /** - * Converts the headers into their stub side representations and returns as a map of - * String key => Object value. - * @return converted map - */ - public Map asStubSideMap() { - return asMap(CLIENT_SIDE); - } - - /** - * Converts the headers into their stub side representations and returns as a map of - * String key => Object value. - * @return converted map - */ - public Map asTestSideMap() { - return asMap(SERVER_SIDE); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Headers headers = (Headers) o; - return Objects.equals(entries, headers.entries); - } - - @Override - public int hashCode() { - return Objects.hash(entries); - } - - @Override - public String toString() { - return "Headers{" + "\nentries=" + entries + '}'; - } - - public Set
getEntries() { - return entries; - } - - public void setEntries(Set
entries) { - this.entries = entries; - } - - public String messagingContentType() { - return MessagingHeaders.MESSAGING_CONTENT_TYPE; - } - - public String accept() { - return HttpHeaders.ACCEPT; - } - - public String acceptCharset() { - return HttpHeaders.ACCEPT_CHARSET; - } - - public String acceptEncoding() { - return HttpHeaders.ACCEPT_ENCODING; - } - - public String acceptLanguage() { - return HttpHeaders.ACCEPT_LANGUAGE; - } - - public String acceptRanges() { - return HttpHeaders.ACCEPT_RANGES; - } - - public String accessControlAllowCredentials() { - return HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS; - } - - public String accessControlAllowHeaders() { - return HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS; - } - - public String accessControlAllowMethods() { - return HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS; - } - - public String accessControlAllowOrigin() { - return HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN; - } - - public String accessControlExposeHeaders() { - return HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS; - } - - public String accessControlMaxAge() { - return HttpHeaders.ACCESS_CONTROL_MAX_AGE; - } - - public String accessControlRequestHeaders() { - return HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS; - } - - public String accessControlRequestMethod() { - return HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD; - } - - public String age() { - return HttpHeaders.AGE; - } - - public String allow() { - return HttpHeaders.ALLOW; - } - - public String authorization() { - return HttpHeaders.AUTHORIZATION; - } - - public String cacheControl() { - return HttpHeaders.CACHE_CONTROL; - } - - public String connection() { - return HttpHeaders.CONNECTION; - } - - public String contentEncoding() { - return HttpHeaders.CONTENT_ENCODING; - } - - public String contentDisposition() { - return HttpHeaders.CONTENT_DISPOSITION; - } - - public String contentLanguage() { - return HttpHeaders.CONTENT_LANGUAGE; - } - - public String contentLength() { - return HttpHeaders.CONTENT_LENGTH; - } - - public String contentLocation() { - return HttpHeaders.CONTENT_LOCATION; - } - - public String contentRange() { - return HttpHeaders.CONTENT_RANGE; - } - - public String contentType() { - return HttpHeaders.CONTENT_TYPE; - } - - public String cookie() { - return HttpHeaders.COOKIE; - } - - public String date() { - return HttpHeaders.DATE; - } - - public String etag() { - return HttpHeaders.ETAG; - } - - public String expect() { - return HttpHeaders.EXPECT; - } - - public String expires() { - return HttpHeaders.EXPIRES; - } - - public String from() { - return HttpHeaders.FROM; - } - - public String host() { - return HttpHeaders.HOST; - } - - public String ifMatch() { - return HttpHeaders.IF_MATCH; - } - - public String ifModifiedSince() { - return HttpHeaders.IF_MODIFIED_SINCE; - } - - public String ifNoneMatch() { - return HttpHeaders.IF_NONE_MATCH; - } - - public String ifRange() { - return HttpHeaders.IF_RANGE; - } - - public String ifUnmodifiedSince() { - return HttpHeaders.IF_UNMODIFIED_SINCE; - } - - public String lastModified() { - return HttpHeaders.LAST_MODIFIED; - } - - public String link() { - return HttpHeaders.LINK; - } - - public String location() { - return HttpHeaders.LOCATION; - } - - public String max_forwards() { - return HttpHeaders.MAX_FORWARDS; - } - - public String origin() { - return HttpHeaders.ORIGIN; - } - - public String pragma() { - return HttpHeaders.PRAGMA; - } - - public String proxyAuthenticate() { - return HttpHeaders.PROXY_AUTHENTICATE; - } - - public String proxyAuthorization() { - return HttpHeaders.PROXY_AUTHORIZATION; - } - - public String range() { - return HttpHeaders.RANGE; - } - - public String referer() { - return HttpHeaders.REFERER; - } - - public String retryAfter() { - return HttpHeaders.RETRY_AFTER; - } - - public String server() { - return HttpHeaders.SERVER; - } - - public String setCookie() { - return HttpHeaders.SET_COOKIE; - } - - public String setCookie2() { - return HttpHeaders.SET_COOKIE_2; - } - - public String te() { - return HttpHeaders.TE; - } - - public String trailer() { - return HttpHeaders.TRAILER; - } - - public String transferEncoding() { - return HttpHeaders.TRANSFER_ENCODING; - } - - public String upgrade() { - return HttpHeaders.UPGRADE; - } - - public String user_agent() { - return HttpHeaders.USER_AGENT; - } - - public String vary() { - return HttpHeaders.VARY; - } - - public String via() { - return HttpHeaders.VIA; - } - - public String warning() { - return HttpHeaders.WARNING; - } - - public String wwwAuthenticate() { - return HttpHeaders.WWW_AUTHENTICATE; - } - - public String allValue() { - return MediaTypes.ALL_VALUE; - } - - public String applicationAtomXml() { - return MediaTypes.APPLICATION_ATOM_XML; - } - - public String applicationFormUrlencoded() { - return MediaTypes.APPLICATION_FORM_URLENCODED; - } - - public String applicationJson() { - return MediaTypes.APPLICATION_JSON; - } - - public String applicationJsonUtf8() { - return MediaTypes.APPLICATION_JSON_UTF8; - } - - public String applicationOctetStream() { - return MediaTypes.APPLICATION_OCTET_STREAM; - } - - public String applicationPdf() { - return MediaTypes.APPLICATION_PDF; - } - - public String applicationXhtmlXml() { - return MediaTypes.APPLICATION_XHTML_XML; - } - - public String applicationXml() { - return MediaTypes.APPLICATION_XML; - } - - public String imageGif() { - return MediaTypes.IMAGE_GIF; - } - - public String imageJpeg() { - return MediaTypes.IMAGE_JPEG; - } - - public String imagePng() { - return MediaTypes.IMAGE_PNG; - } - - public String multipartFormData() { - return MediaTypes.MULTIPART_FORM_DATA; - } - - public String textHtml() { - return MediaTypes.TEXT_HTML; - } - - public String textMarkdown() { - return MediaTypes.TEXT_MARKDOWN; - } - - public String textPlain() { - return MediaTypes.TEXT_PLAIN; - } - - public String textXml() { - return MediaTypes.TEXT_XML; - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/HttpHeaders.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/HttpHeaders.java deleted file mode 100644 index 1f2eeb8c3e..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/HttpHeaders.java +++ /dev/null @@ -1,436 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -/** - * Contains most commonly used http headers. - * - * @author Marcin Grzejszczak - * @author Tim Ysewyn - * @since 1.0.2 - */ -public final class HttpHeaders { - - /** - * The HTTP {@code Accept} header field name. - * @see Section 5.3.2 of - * RFC 7231 - */ - public static final String ACCEPT = "Accept"; - - /** - * The HTTP {@code Accept-Charset} header field name. - * @see Section 5.3.3 of - * RFC 7231 - */ - public static final String ACCEPT_CHARSET = "Accept-Charset"; - - /** - * The HTTP {@code Accept-Encoding} header field name. - * @see Section 5.3.4 of - * RFC 7231 - */ - public static final String ACCEPT_ENCODING = "Accept-Encoding"; - - /** - * The HTTP {@code Accept-Language} header field name. - * @see Section 5.3.5 of - * RFC 7231 - */ - public static final String ACCEPT_LANGUAGE = "Accept-Language"; - - /** - * The HTTP {@code Accept-Ranges} header field name. - * @see Section 5.3.5 of RFC - * 7233 - */ - public static final String ACCEPT_RANGES = "Accept-Ranges"; - - /** - * The CORS {@code Access-Control-Allow-Credentials} response header field name. - * @see CORS W3C recommendation - */ - public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials"; - - /** - * The CORS {@code Access-Control-Allow-Headers} response header field name. - * @see CORS W3C recommendation - */ - public static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers"; - - /** - * The CORS {@code Access-Control-Allow-Methods} response header field name. - * @see CORS W3C recommendation - */ - public static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods"; - - /** - * The CORS {@code Access-Control-Allow-Origin} response header field name. - * @see CORS W3C recommendation - */ - public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin"; - - /** - * The CORS {@code Access-Control-Expose-Headers} response header field name. - * @see CORS W3C recommendation - */ - public static final String ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers"; - - /** - * The CORS {@code Access-Control-Max-Age} response header field name. - * @see CORS W3C recommendation - */ - public static final String ACCESS_CONTROL_MAX_AGE = "Access-Control-Max-Age"; - - /** - * The CORS {@code Access-Control-Request-Headers} request header field name. - * @see CORS W3C recommendation - */ - public static final String ACCESS_CONTROL_REQUEST_HEADERS = "Access-Control-Request-Headers"; - - /** - * The CORS {@code Access-Control-Request-Method} request header field name. - * @see CORS W3C recommendation - */ - public static final String ACCESS_CONTROL_REQUEST_METHOD = "Access-Control-Request-Method"; - - /** - * The HTTP {@code Age} header field name. - * @see Section 5.1 of RFC - * 7234 - */ - public static final String AGE = "Age"; - - /** - * The HTTP {@code Allow} header field name. - * @see Section 7.4.1 of - * RFC 7231 - */ - public static final String ALLOW = "Allow"; - - /** - * The HTTP {@code Authorization} header field name. - * @see Section 4.2 of RFC - * 7235 - */ - public static final String AUTHORIZATION = "Authorization"; - - /** - * The HTTP {@code Cache-Control} header field name. - * @see Section 5.2 of RFC - * 7234 - */ - public static final String CACHE_CONTROL = "Cache-Control"; - - /** - * The HTTP {@code Connection} header field name. - * @see Section 6.1 of RFC - * 7230 - */ - public static final String CONNECTION = "Connection"; - - /** - * The HTTP {@code Content-Encoding} header field name. - * @see Section 3.1.2.2 - * of RFC 7231 - */ - public static final String CONTENT_ENCODING = "Content-Encoding"; - - /** - * The HTTP {@code Content-Disposition} header field name. - * @see RFC 6266 - */ - public static final String CONTENT_DISPOSITION = "Content-Disposition"; - - /** - * The HTTP {@code Content-Language} header field name. - * @see Section 3.1.3.2 - * of RFC 7231 - */ - public static final String CONTENT_LANGUAGE = "Content-Language"; - - /** - * The HTTP {@code Content-Length} header field name. - * @see Section 3.3.2 of - * RFC 7230 - */ - public static final String CONTENT_LENGTH = "Content-Length"; - - /** - * The HTTP {@code Content-Location} header field name. - * @see Section 3.1.4.2 - * of RFC 7231 - */ - public static final String CONTENT_LOCATION = "Content-Location"; - - /** - * The HTTP {@code Content-Range} header field name. - * @see Section 4.2 of RFC - * 7233 - */ - public static final String CONTENT_RANGE = "Content-Range"; - - /** - * The HTTP {@code Content-Type} header field name. - * @see Section 3.1.1.5 - * of RFC 7231 - */ - public static final String CONTENT_TYPE = "Content-Type"; - - /** - * The HTTP {@code Cookie} header field name. - * @see Section 4.3.4 of - * RFC 2109 - */ - public static final String COOKIE = "Cookie"; - - /** - * The HTTP {@code Date} header field name. - * @see Section 7.1.1.2 - * of RFC 7231 - */ - public static final String DATE = "Date"; - - /** - * The HTTP {@code ETag} header field name. - * @see Section 2.3 of RFC - * 7232 - */ - public static final String ETAG = "ETag"; - - /** - * The HTTP {@code Expect} header field name. - * @see Section 5.1.1 of - * RFC 7231 - */ - public static final String EXPECT = "Expect"; - - /** - * The HTTP {@code Expires} header field name. - * @see Section 5.3 of RFC - * 7234 - */ - public static final String EXPIRES = "Expires"; - - /** - * The HTTP {@code From} header field name. - * @see Section 5.5.1 of - * RFC 7231 - */ - public static final String FROM = "From"; - - /** - * The HTTP {@code Host} header field name. - * @see Section 5.4 of RFC - * 7230 - */ - public static final String HOST = "Host"; - - /** - * The HTTP {@code If-Match} header field name. - * @see Section 3.1 of RFC - * 7232 - */ - public static final String IF_MATCH = "If-Match"; - - /** - * The HTTP {@code If-Modified-Since} header field name. - * @see Section 3.3 of RFC - * 7232 - */ - public static final String IF_MODIFIED_SINCE = "If-Modified-Since"; - - /** - * The HTTP {@code If-None-Match} header field name. - * @see Section 3.2 of RFC - * 7232 - */ - public static final String IF_NONE_MATCH = "If-None-Match"; - - /** - * The HTTP {@code If-Range} header field name. - * @see Section 3.2 of RFC - * 7233 - */ - public static final String IF_RANGE = "If-Range"; - - /** - * The HTTP {@code If-Unmodified-Since} header field name. - * @see Section 3.4 of RFC - * 7232 - */ - public static final String IF_UNMODIFIED_SINCE = "If-Unmodified-Since"; - - /** - * The HTTP {@code Last-Modified} header field name. - * @see Section 2.2 of RFC - * 7232 - */ - public static final String LAST_MODIFIED = "Last-Modified"; - - /** - * The HTTP {@code Link} header field name. - * @see RFC 5988 - */ - public static final String LINK = "Link"; - - /** - * The HTTP {@code Location} header field name. - * @see Section 7.1.2 of - * RFC 7231 - */ - public static final String LOCATION = "Location"; - - /** - * The HTTP {@code Max-Forwards} header field name. - * @see Section 5.1.2 of - * RFC 7231 - */ - public static final String MAX_FORWARDS = "Max-Forwards"; - - /** - * The HTTP {@code Origin} header field name. - * @see RFC 6454 - */ - public static final String ORIGIN = "Origin"; - - /** - * The HTTP {@code Pragma} header field name. - * @see Section 5.4 of RFC - * 7234 - */ - public static final String PRAGMA = "Pragma"; - - /** - * The HTTP {@code Proxy-Authenticate} header field name. - * @see Section 4.3 of RFC - * 7235 - */ - public static final String PROXY_AUTHENTICATE = "Proxy-Authenticate"; - - /** - * The HTTP {@code Proxy-Authorization} header field name. - * @see Section 4.4 of RFC - * 7235 - */ - public static final String PROXY_AUTHORIZATION = "Proxy-Authorization"; - - /** - * The HTTP {@code Range} header field name. - * @see Section 3.1 of RFC - * 7233 - */ - public static final String RANGE = "Range"; - - /** - * The HTTP {@code Referer} header field name. - * @see Section 5.5.2 of - * RFC 7231 - */ - public static final String REFERER = "Referer"; - - /** - * The HTTP {@code Retry-After} header field name. - * @see Section 7.1.3 of - * RFC 7231 - */ - public static final String RETRY_AFTER = "Retry-After"; - - /** - * The HTTP {@code Server} header field name. - * @see Section 7.4.2 of - * RFC 7231 - */ - public static final String SERVER = "Server"; - - /** - * The HTTP {@code Set-Cookie} header field name. - * @see Section 4.2.2 of - * RFC 2109 - */ - public static final String SET_COOKIE = "Set-Cookie"; - - /** - * The HTTP {@code Set-Cookie2} header field name. - * @see RFC 2965 - */ - public static final String SET_COOKIE_2 = "Set-Cookie2"; - - /** - * The HTTP {@code TE} header field name. - * @see Section 4.3 of RFC - * 7230 - */ - public static final String TE = "TE"; - - /** - * The HTTP {@code Trailer} header field name. - * @see Section 4.4 of RFC - * 7230 - */ - public static final String TRAILER = "Trailer"; - - /** - * The HTTP {@code Transfer-Encoding} header field name. - * @see Section 3.3.1 of - * RFC 7230 - */ - public static final String TRANSFER_ENCODING = "Transfer-Encoding"; - - /** - * The HTTP {@code Upgrade} header field name. - * @see Section 6.7 of RFC - * 7230 - */ - public static final String UPGRADE = "Upgrade"; - - /** - * The HTTP {@code User-Agent} header field name. - * @see Section 5.5.3 of - * RFC 7231 - */ - public static final String USER_AGENT = "User-Agent"; - - /** - * The HTTP {@code Vary} header field name. - * @see Section 7.1.4 of - * RFC 7231 - */ - public static final String VARY = "Vary"; - - /** - * The HTTP {@code Via} header field name. - * @see Section 5.7.1 of - * RFC 7230 - */ - public static final String VIA = "Via"; - - /** - * The HTTP {@code Warning} header field name. - * @see Section 5.5 of RFC - * 7234 - */ - public static final String WARNING = "Warning"; - - /** - * The HTTP {@code WWW-Authenticate} header field name. - * @see Section 4.1 of RFC - * 7235 - */ - public static final String WWW_AUTHENTICATE = "WWW-Authenticate"; - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/HttpMethods.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/HttpMethods.java deleted file mode 100644 index de0821abca..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/HttpMethods.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Contains Http Methods. - * - * @author Marcin Grzejszczak - * @author Tim Ysewyn - * @since 1.0.2 - */ -public final class HttpMethods { - - private static final Log log = LogFactory.getLog(HttpMethods.class); - - public HttpMethods() { - log.warn("WARNING: HttpMethods shouldn't be instantiated. Use its static methods instead."); - } - - /** - * The HTTP {@code GET} method. - */ - public static String GET = "GET"; - - /** - * The HTTP {@code HEAD} method. - */ - public static String HEAD = "HEAD"; - - /** - * The HTTP {@code POST} method. - */ - public static String POST = "POST"; - - /** - * The HTTP {@code PUT} method. - */ - public static String PUT = "PUT"; - - /** - * The HTTP {@code PATCH} method. - */ - public static String PATCH = "PATCH"; - - /** - * The HTTP {@code DELETE} method. - */ - public static String DELETE = "DELETE"; - - /** - * The HTTP {@code OPTIONS} method. - */ - public static String OPTIONS = "OPTIONS"; - - /** - * The HTTP {@code TRACE} method. - */ - public static String TRACE = "TRACE"; - - public enum HttpMethod { - - GET(HttpMethods.GET), HEAD(HttpMethods.HEAD), POST(HttpMethods.POST), PUT(HttpMethods.PUT), - PATCH(HttpMethods.PATCH), DELETE(HttpMethods.DELETE), OPTIONS(HttpMethods.OPTIONS), TRACE(HttpMethods.TRACE),; - - private final String methodName; - - HttpMethod(String methodName) { - this.methodName = methodName; - } - - public String getMethodName() { - return methodName; - } - - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/HttpStatus.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/HttpStatus.java deleted file mode 100644 index e2763195ea..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/HttpStatus.java +++ /dev/null @@ -1,448 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Helper functions for HTTP statuses. - * - * @author Marcin Grzejszczak - * @author Tim Ysewyn - * @since 2.0.0 - */ -public final class HttpStatus { - - private static final Log log = LogFactory.getLog(HttpStatus.class); - - public HttpStatus() { - log.warn("WARNING: HttpStatus shouldn't be instantiated. Use its static methods instead."); - } - - /** - * The HTTP {@code 100 Continue} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.2.1 - */ - public static final int CONTINUE = 100; - - /** - * The HTTP {@code 101 Switching Protocols} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.2.2 - */ - public static final int SWITCHING_PROTOCOLS = 101; - - /** - * The HTTP {@code 102 Processing} status code. - * @see WebDAV - */ - public static final int PROCESSING = 102; - - /** - * The HTTP {@code 103 Checkpoint} status code. - * @see - * A proposal for supporting resumable POST/PUT HTTP requests in HTTP/1.0 - */ - public static final int CHECKPOINT = 103; - - /** - * The HTTP {@code 200 OK} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.3.1 - */ - public static final int OK = 200; - - /** - * The HTTP {@code 201 Created} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.3.2 - */ - public static final int CREATED = 201; - - /** - * The HTTP {@code 202 Accepted} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.3.3 - */ - public static final int ACCEPTED = 202; - - /** - * The HTTP {@code 203 Non-Authoritative Information} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.3.4 - */ - public static final int NON_AUTHORITATIVE_INFORMATION = 203; - - /** - * The HTTP {@code 204 No Content} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.3.5 - */ - public static final int NO_CONTENT = 204; - - /** - * The HTTP {@code 205 Reset Content} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.3.6 - */ - public static final int RESET_CONTENT = 205; - - /** - * The HTTP {@code 206 Partial Content} status code. - * @see HTTP/1.1: Range - * Requests, section 4.1 - */ - public static final int PARTIAL_CONTENT = 206; - - /** - * The HTTP {@code 207 Multi-Status} status code. - * @see WebDAV - */ - public static final int MULTI_STATUS = 207; - - /** - * The HTTP {@code 208 Already Reported} status code. - * @see WebDAV Binding - * Extensions - */ - public static final int ALREADY_REPORTED = 208; - - /** - * The HTTP {@code 226 IM Used} status code. - * @see Delta encoding in - * HTTP - */ - public static final int IM_USED = 226; - - /** - * The HTTP {@code 300 Multiple Choices} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.4.1 - */ - public static final int MULTIPLE_CHOICES = 300; - - /** - * The HTTP {@code 301 Moved Permanently} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.4.2 - */ - public static final int MOVED_PERMANENTLY = 301; - - /** - * The HTTP {@code 302 Found} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.4.3 - */ - public static final int FOUND = 302; - - /** - * The HTTP {@code 303 See Other} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.4.4 - */ - public static final int SEE_OTHER = 303; - - /** - * The HTTP {@code 304 Not Modified} status code. - * @see HTTP/1.1: - * Conditional Requests, section 4.1 - */ - public static final int NOT_MODIFIED = 304; - - /** - * The HTTP {@code 307 Temporary Redirect} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.4.7 - */ - public static final int TEMPORARY_REDIRECT = 307; - - /** - * The HTTP {@code 308 Permanent Redirect} status code. - * @see RFC 7238 - */ - public static final int PERMANENT_REDIRECT = 308; - - /** - * The HTTP {@code 400 Bad Request} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.5.1 - */ - public static final int BAD_REQUEST = 400; - - /** - * The HTTP {@code 401 Unauthorized} status code. - * @see HTTP/1.1: - * Authentication, section 3.1 - */ - public static final int UNAUTHORIZED = 401; - - /** - * The HTTP {@code 402 Payment Required} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.5.2 - */ - public static final int PAYMENT_REQUIRED = 402; - - /** - * The HTTP {@code 403 Forbidden} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.5.3 - */ - public static final int FORBIDDEN = 403; - - /** - * The HTTP {@code 404 Not Found} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.5.4 - */ - public static final int NOT_FOUND = 404; - - /** - * The HTTP {@code 405 Method Not Allowed} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.5.5 - */ - public static final int METHOD_NOT_ALLOWED = 405; - - /** - * The HTTP {@code 406 Not Acceptable} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.5.6 - */ - public static final int NOT_ACCEPTABLE = 406; - - /** - * The HTTP {@code 407 Proxy Authentication Required} status code. - * @see HTTP/1.1: - * Authentication, section 3.2 - */ - public static final int PROXY_AUTHENTICATION_REQUIRED = 407; - - /** - * The HTTP {@code 408 Request Timeout} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.5.7 - */ - public static final int REQUEST_TIMEOUT = 408; - - /** - * The HTTP {@code 409 Conflict} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.5.8 - */ - public static final int CONFLICT = 409; - - /** - * The HTTP {@code 410 Gone} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.5.9 - */ - public static final int GONE = 410; - - /** - * The HTTP {@code 411 Length Required} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.5.10 - */ - public static final int LENGTH_REQUIRED = 411; - - /** - * The HTTP {@code 412 Precondition failed} status code. - * @see HTTP/1.1: - * Conditional Requests, section 4.2 - */ - public static final int PRECONDITION_FAILED = 412; - - /** - * The HTTP {@code 413 Payload Too Large} status code. - * @since 4.1* @see - * HTTP/1.1: Semantics and Content, section 6.5.11 - */ - public static final int PAYLOAD_TOO_LARGE = 413; - - /** - * The HTTP {@code 414 URI Too Long} status code. - * @since 4.1* @see - * HTTP/1.1: Semantics and Content, section 6.5.12 - */ - public static final int URI_TOO_LONG = 414; - - /** - * The HTTP {@code 415 Unsupported Media Type} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.5.13 - */ - public static final int UNSUPPORTED_MEDIA_TYPE = 415; - - /** - * The HTTP {@code 416 Requested Range Not Satisfiable} status code. - * @see HTTP/1.1: Range - * Requests, section 4.4 - */ - public static final int REQUESTED_RANGE_NOT_SATISFIABLE = 416; - - /** - * The HTTP {@code 417 Expectation Failed} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.5.14 - */ - public static final int EXPECTATION_FAILED = 417; - - /** - * The HTTP {@code 418 I'm a teapot} status code. - * @see HTCPCP/1.0 - */ - public static final int I_AM_A_TEAPOT = 418; - - /** - * The HTTP {@code 422 Unprocessable Entity} status code. - * @see WebDAV - */ - public static final int UNPROCESSABLE_ENTITY = 422; - - /** - * The HTTP {@code 423 Locked} status code. - * @see WebDAV - */ - public static final int LOCKED = 423; - - /** - * The HTTP {@code 424 Failed Dependency} status code. - * @see WebDAV - */ - public static final int FAILED_DEPENDENCY = 424; - - /** - * The HTTP {@code 426 Upgrade Required} status code. - * @see Upgrading to TLS - * Within HTTP/1.1 - */ - public static final int UPGRADE_REQUIRED = 426; - - /** - * The HTTP {@code 428 Precondition Required} status code. - * @see Additional HTTP Status - * Codes - */ - public static final int PRECONDITION_REQUIRED = 428; - - /** - * The HTTP {@code 429 Too Many Requests} status code. - * @see Additional HTTP Status - * Codes - */ - public static final int TOO_MANY_REQUESTS = 429; - - /** - * The HTTP {@code 431 Request Header Fields Too Large} status code. - * @see Additional HTTP Status - * Codes - */ - public static final int REQUEST_HEADER_FIELDS_TOO_LARGE = 431; - - /** - * The HTTP {@code 451 Unavailable For Legal Reasons} status code. - * @see An - * HTTP Status Code to Report Legal Obstacles - */ - public static final int UNAVAILABLE_FOR_LEGAL_REASONS = 451; - - /** - * The HTTP {@code 500 Internal Server Error} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.6.1 - */ - public static final int INTERNAL_SERVER_ERROR = 500; - - /** - * The HTTP {@code 501 Not Implemented} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.6.2 - */ - public static final int NOT_IMPLEMENTED = 501; - - /** - * The HTTP {@code 502 Bad Gateway} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.6.3 - */ - public static final int BAD_GATEWAY = 502; - - /** - * The HTTP {@code 503 Service Unavailable} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.6.4 - */ - public static final int SERVICE_UNAVAILABLE = 503; - - /** - * The HTTP {@code 504 Gateway Timeout} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.6.5 - */ - public static final int GATEWAY_TIMEOUT = 504; - - /** - * The HTTP {@code 505 HTTP Version Not Supported} status code. - * @see HTTP/1.1: - * Semantics and Content, section 6.6.6 - */ - public static final int HTTP_VERSION_NOT_SUPPORTED = 505; - - /** - * The HTTP {@code 506 Variant Also Negotiates} status code. - * @see Transparent Content - * Negotiation - */ - public static final int VARIANT_ALSO_NEGOTIATES = 506; - - /** - * The HTTP {@code 507 Insufficient Storage} status code. - * @see WebDAV - */ - public static final int INSUFFICIENT_STORAGE = 507; - - /** - * The HTTP {@code 508 Loop Detected} status code. - * @see WebDAV Binding - * Extensions - */ - public static final int LOOP_DETECTED = 508; - - /** - * The HTTP {@code 509 Bandwidth Limit Exceeded} status code. - */ - public static final int BANDWIDTH_LIMIT_EXCEEDED = 509; - - /** - * The HTTP {@code 510 Not Extended} status code. - * @see HTTP Extension - * Framework - */ - public static final int NOT_EXTENDED = 510; - - /** - * The HTTP {@code 511 Network Authentication Required} status code. - * @see Additional HTTP Status - * Codes - */ - public static final int NETWORK_AUTHENTICATION_REQUIRED = 511; - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Input.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Input.java deleted file mode 100644 index 7324ddcc39..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Input.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.util.Objects; -import java.util.regex.Pattern; - -/** - * Represents an input for messaging. The input can be a message or some action inside the - * application. - * - * @author Marcin Grzejszczak - * @author Tim Ysewyn - * @since 1.0.0 - */ -public class Input extends Common implements RegexCreatingProperty { - - private ClientPatternValueDslProperty property = new ClientPatternValueDslProperty(); - - private ExecutionProperty triggeredBy; - - private ExecutionProperty assertThat; - - /** - * Function that needs to be executed to trigger action in the system. - * @param triggeredBy method name that triggers the message - */ - public void triggeredBy(String triggeredBy) { - this.triggeredBy = new ExecutionProperty(triggeredBy); - } - - public DslProperty value(ClientDslProperty client) { - Object dynamicValue = client.getClientValue(); - Object concreteValue = client.getServerValue(); - if (dynamicValue instanceof RegexProperty) { - return ((RegexProperty) dynamicValue).dynamicClientConcreteProducer(); - } - return new DslProperty(dynamicValue, concreteValue); - } - - public DslProperty value(RegexProperty prop) { - return value(client(prop)); - } - - public DslProperty $(RegexProperty prop) { - return value(client(prop)); - } - - public DslProperty $(ClientDslProperty client) { - return value(client); - } - - @Override - public RegexProperty regexProperty(Object object) { - return new RegexProperty(object).dynamicClientConcreteProducer(); - } - - public void assertThat(String assertThat) { - this.assertThat = new ExecutionProperty(assertThat); - } - - public ClientPatternValueDslProperty getProperty() { - return property; - } - - public void setProperty(ClientPatternValueDslProperty property) { - this.property = property; - } - - public ExecutionProperty getTriggeredBy() { - return triggeredBy; - } - - public void setTriggeredBy(ExecutionProperty triggeredBy) { - this.triggeredBy = triggeredBy; - } - - public ExecutionProperty getAssertThat() { - return assertThat; - } - - public void setAssertThat(ExecutionProperty assertThat) { - this.assertThat = assertThat; - } - - @Override - public ClientDslProperty anyAlphaUnicode() { - return property.anyAlphaUnicode(); - } - - @Override - public ClientDslProperty anyAlphaNumeric() { - return property.anyAlphaNumeric(); - } - - @Override - public ClientDslProperty anyNumber() { - return property.anyNumber(); - } - - @Override - public ClientDslProperty anyInteger() { - return property.anyInteger(); - } - - @Override - public ClientDslProperty anyPositiveInt() { - return property.anyPositiveInt(); - } - - @Override - public ClientDslProperty anyDouble() { - return property.anyDouble(); - } - - @Override - public ClientDslProperty anyHex() { - return property.anyHex(); - } - - @Override - public ClientDslProperty aBoolean() { - return property.aBoolean(); - } - - @Override - public ClientDslProperty anyIpAddress() { - return property.anyIpAddress(); - } - - @Override - public ClientDslProperty anyHostname() { - return property.anyHostname(); - } - - @Override - public ClientDslProperty anyEmail() { - return property.anyEmail(); - } - - @Override - public ClientDslProperty anyUrl() { - return property.anyUrl(); - } - - @Override - public ClientDslProperty anyHttpsUrl() { - return property.anyHttpsUrl(); - } - - @Override - public ClientDslProperty anyUuid() { - return property.anyUuid(); - } - - @Override - public ClientDslProperty anyDate() { - return property.anyDate(); - } - - @Override - public ClientDslProperty anyDateTime() { - return property.anyDateTime(); - } - - @Override - public ClientDslProperty anyTime() { - return property.anyTime(); - } - - @Override - public ClientDslProperty anyIso8601WithOffset() { - return property.anyIso8601WithOffset(); - } - - @Override - public ClientDslProperty anyNonBlankString() { - return property.anyNonBlankString(); - } - - @Override - public ClientDslProperty anyNonEmptyString() { - return property.anyNonEmptyString(); - } - - @Override - public ClientDslProperty anyOf(String... values) { - return property.anyOf(values); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Input input = (Input) o; - return Objects.equals(triggeredBy, input.triggeredBy) && Objects.equals(assertThat, input.assertThat); - } - - @Override - public int hashCode() { - return Objects.hash(triggeredBy, assertThat); - } - - @Override - public String toString() { - return "Input{\n\t" + ", \n\ttriggeredBy=" + triggeredBy + ", \n\tassertThat=" + assertThat + "} \n\t" - + super.toString(); - } - - private class ClientPatternValueDslProperty extends PatternValueDslProperty { - - @Override - protected ClientDslProperty createProperty(Pattern pattern, Object generatedValue) { - return new ClientDslProperty(pattern, generatedValue); - } - - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/JSONCompareMode.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/JSONCompareMode.java deleted file mode 100644 index 238b0da79f..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/JSONCompareMode.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -/** - * Represents JSON comparison modes. - * - * @since 1.0.0 - */ -public enum JSONCompareMode { - - /** - * Strict checking. Not extensible, and strict array ordering. - */ - STRICT, - /** - * Lenient checking. Extensible, and non-strict array ordering. - */ - LENIENT, - /** - * Non-extensible checking. Not extensible, and non-strict array ordering. - */ - NON_EXTENSIBLE, - /** - * Strict order checking. Extensible, and strict array ordering. - */ - STRICT_ORDER; - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/MatchingStrategy.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/MatchingStrategy.java deleted file mode 100644 index 5e7464b444..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/MatchingStrategy.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.util.Objects; - -/** - * Represents a matching strategy for a JSON. - * - * @since 1.0.0 - */ -public class MatchingStrategy extends DslProperty { - - private Type type; - - private JSONCompareMode jsonCompareMode; - - public MatchingStrategy(Object value, Type type) { - this(value, type, null); - } - - public MatchingStrategy(Object value, Type type, JSONCompareMode jsonCompareMode) { - super(value); - this.type = type; - this.jsonCompareMode = jsonCompareMode; - } - - public MatchingStrategy(DslProperty value, Type type) { - this(value, type, null); - } - - public MatchingStrategy(DslProperty value, Type type, JSONCompareMode jsonCompareMode) { - super(value.getClientValue(), value.getServerValue()); - this.type = type; - this.jsonCompareMode = jsonCompareMode; - } - - public Type getType() { - return type; - } - - public void setType(Type type) { - this.type = type; - } - - public JSONCompareMode getJsonCompareMode() { - return jsonCompareMode; - } - - public void setJsonCompareMode(JSONCompareMode jsonCompareMode) { - this.jsonCompareMode = jsonCompareMode; - } - - @Override - public String toString() { - return "MatchingStrategy{" + "type=" + type + ", jsonCompareMode=" + jsonCompareMode + '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - if (!super.equals(o)) { - return false; - } - MatchingStrategy that = (MatchingStrategy) o; - return type == that.type && jsonCompareMode == that.jsonCompareMode; - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), type, jsonCompareMode); - } - - public enum Type { - - /** - * Equality check. - */ - EQUAL_TO("equalTo"), - - /** - * Contains check. - */ - CONTAINS("containing"), - - /** - * Matching check. - */ - MATCHING("matching"), - - /** - * Not matching check. - */ - NOT_MATCHING("notMatching"), - - /** - * Equal to JSON check. - */ - EQUAL_TO_JSON("equalToJson"), - - /** - * Equal to XML check. - */ - EQUAL_TO_XML("equalToXml"), - - /** - * Absence check. - */ - ABSENT("absent"), - - /** - * Binary equality check. - */ - BINARY_EQUAL_TO("binaryEqualTo"); - - private final String name; - - Type(String name) { - this.name = name; - } - - public final String getName() { - return name; - } - - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/MatchingType.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/MatchingType.java deleted file mode 100644 index c35577059b..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/MatchingType.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -/** - * Represents the type of matching the should be done against the body of the request or - * response. - * - * @author Marcin Grzejszczak - * @author Tim Ysewyn - * @author Olga Maciaszek-Sharma - * @since 1.0.3 - */ -public enum MatchingType { - - /** - * Verification by equality. - */ - EQUALITY, - /** - * Verification by type - is the type received in a body for the given path is of the - * same type. If it's a collection you can verify number of occurrences. - */ - TYPE, - /** - * Special version of regex for date check. - */ - DATE, - /** - * Special version of regex for time check. - */ - TIME, - /** - * Special version of regex for timestamp check. - */ - TIMESTAMP, - /** - * Verification if the value for the given path matches the provided regex. - */ - REGEX, - /** - * The user can provide custom command to execute. - */ - COMMAND, - /** - * Verification if the value for the given path is null. - */ - NULL; - - public static boolean regexRelated(MatchingType type) { - return !type.equals(EQUALITY) && !type.equals(TYPE) && !type.equals(COMMAND) && !type.equals(NULL); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/MatchingTypeValue.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/MatchingTypeValue.java deleted file mode 100644 index 6cc246e95f..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/MatchingTypeValue.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.util.Objects; - -/** - * Matching type with corresponding values. - */ -public class MatchingTypeValue { - - private MatchingType type; - - /** - * Value to check. - */ - private Object value; - - /** - * Min occurrence when matching by type. - */ - private Integer minTypeOccurrence; - - /** - * Max occurrence when matching by type. - */ - private Integer maxTypeOccurrence; - - MatchingTypeValue() { - } - - MatchingTypeValue(MatchingType type) { - this.type = type; - } - - MatchingTypeValue(MatchingType type, Object value) { - this.type = type; - this.value = value; - } - - MatchingTypeValue(MatchingType type, Object value, Integer minTypeOccurrence) { - this.type = type; - this.value = value; - this.minTypeOccurrence = minTypeOccurrence; - } - - MatchingTypeValue(MatchingType type, Object value, Integer minTypeOccurrence, Integer maxTypeOccurrence) { - this.type = type; - this.value = value; - this.minTypeOccurrence = minTypeOccurrence; - this.maxTypeOccurrence = maxTypeOccurrence; - } - - public MatchingType getType() { - return type; - } - - public void setType(MatchingType type) { - this.type = type; - } - - public Object getValue() { - return value; - } - - public void setValue(Object value) { - this.value = value; - } - - public Integer getMinTypeOccurrence() { - return minTypeOccurrence; - } - - public void setMinTypeOccurrence(Integer minTypeOccurrence) { - this.minTypeOccurrence = minTypeOccurrence; - } - - public Integer getMaxTypeOccurrence() { - return maxTypeOccurrence; - } - - public void setMaxTypeOccurrence(Integer maxTypeOccurrence) { - this.maxTypeOccurrence = maxTypeOccurrence; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - MatchingTypeValue value1 = (MatchingTypeValue) o; - return type == value1.type && Objects.equals(value, value1.value) - && Objects.equals(minTypeOccurrence, value1.minTypeOccurrence) - && Objects.equals(maxTypeOccurrence, value1.maxTypeOccurrence); - } - - @Override - public int hashCode() { - return Objects.hash(type, value, minTypeOccurrence, maxTypeOccurrence); - } - - @Override - public String toString() { - return "MatchingTypeValue{" + "type=" + type + ", value=" + value + ", minTypeOccurrence=" + minTypeOccurrence - + ", maxTypeOccurrence=" + maxTypeOccurrence + '}'; - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/MatchingTypeValueHolder.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/MatchingTypeValueHolder.java deleted file mode 100644 index d3cbb1d02d..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/MatchingTypeValueHolder.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -public class MatchingTypeValueHolder { - - MatchingTypeValue matchingTypeValue = new MatchingTypeValue(MatchingType.TYPE); - - public MatchingTypeValue minOccurrence(int number) { - this.matchingTypeValue.setMinTypeOccurrence(number); - return this.matchingTypeValue; - } - - public MatchingTypeValue maxOccurrence(int number) { - this.matchingTypeValue.setMaxTypeOccurrence(number); - return this.matchingTypeValue; - } - - public MatchingTypeValue occurrence(int number) { - this.matchingTypeValue.setMinTypeOccurrence(number); - this.matchingTypeValue.setMaxTypeOccurrence(number); - return this.matchingTypeValue; - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/MediaTypes.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/MediaTypes.java deleted file mode 100644 index 967138672d..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/MediaTypes.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Contains most commonly used media types. - * - * @author Marcin Grzejszczak - * @author Tim Ysewyn - * @since 1.0.2 - */ -public final class MediaTypes { - - private static final Log log = LogFactory.getLog(MediaTypes.class); - - private MediaTypes() { - throw new IllegalStateException("You can't instantiate an utility class"); - } - - /** - * Public constant for that includes all media ranges (i.e. "*/*"). - */ - public static final String ALL_VALUE = "*/*"; - - /** - * Public constant for {@code application/atom+xml}. - */ - public static final String APPLICATION_ATOM_XML = "application/atom+xml"; - - /** - * Public constant for {@code application/x-www-form-urlencoded}. - */ - public static final String APPLICATION_FORM_URLENCODED = "application/x-www-form-urlencoded"; - - /** - * Public constant for {@code application/json}. - */ - public static final String APPLICATION_JSON = "application/json"; - - /** - * Public constant for {@code application/json;charset=UTF-8}. - */ - public static final String APPLICATION_JSON_UTF8 = APPLICATION_JSON + ";charset=UTF-8"; - - /** - * Public constant for {@code application/octet-stream}. - */ - public static final String APPLICATION_OCTET_STREAM = "application/octet-stream"; - - /** - * Public constant for {@code application/pdf}. - */ - public static final String APPLICATION_PDF = "application/pdf"; - - /** - * Public constant for {@code application/xhtml+xml}. - */ - public static final String APPLICATION_XHTML_XML = "application/xhtml+xml"; - - /** - * Public constant for {@code application/xml}. - */ - public static final String APPLICATION_XML = "application/xml"; - - /** - * Public constant for {@code image/gif}. - */ - public static final String IMAGE_GIF = "image/gif"; - - /** - * Public constant for {@code image/jpeg}. - */ - public static final String IMAGE_JPEG = "image/jpeg"; - - /** - * Public constant for {@code image/png}. - */ - public static final String IMAGE_PNG = "image/png"; - - /** - * Public constant for {@code multipart/form-data}. - */ - public static final String MULTIPART_FORM_DATA = "multipart/form-data"; - - /** - * Public constant for {@code text/html}. - */ - public static final String TEXT_HTML = "text/html"; - - /** - * Public constant for {@code text/markdown}. - */ - public static final String TEXT_MARKDOWN = "text/markdown"; - - /** - * Public constant for {@code text/plain}. - */ - public static final String TEXT_PLAIN = "text/plain"; - - /** - * Public constant for {@code text/xml}. - */ - public static final String TEXT_XML = "text/xml"; - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/MessagingHeaders.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/MessagingHeaders.java deleted file mode 100644 index 10bce429f9..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/MessagingHeaders.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -/** - * Contains most commonly used messaging headers. - * - * @author Marcin Grzejszczak - * @author Tim Ysewyn - * @since 1.1.2 - */ -public final class MessagingHeaders { - - private MessagingHeaders() { - throw new IllegalStateException("You can't instantiate an utility class"); - } - - /** - * The Content-Type header name of a message. - */ - public static final String MESSAGING_CONTENT_TYPE = "contentType"; - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Multipart.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Multipart.java deleted file mode 100644 index 0c5cd67bdd..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Multipart.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; - -public class Multipart extends DslProperty { - - public Multipart(Map multipart) { - super(extractValue(multipart, ContractUtils.CLIENT_VALUE), extractValue(multipart, ContractUtils.SERVER_VALUE)); - } - - public Multipart(List multipartAsList) { - super(multipartAsList.stream().map(DslProperty::getClientValue).collect(Collectors.toList()), - multipartAsList.stream().map(DslProperty::getServerValue).collect(Collectors.toList())); - } - - public Multipart(Object value) { - super(ContractUtils.CLIENT_VALUE.apply(value), ContractUtils.SERVER_VALUE.apply(value)); - } - - public Multipart(DslProperty multipartAsValue) { - super(multipartAsValue.getClientValue(), multipartAsValue.getServerValue()); - } - - public Multipart(MatchingStrategy matchingStrategy) { - super(matchingStrategy); - } - - public static Multipart build(Object value) { - if (value instanceof MatchingStrategy) { - return new Multipart((MatchingStrategy) value); - } - return new Multipart(value); - } - - private static Map extractValue(Map multipart, final Function valueProvider) { - final Map map = new LinkedHashMap(); - multipart.forEach((s, dslProperty) -> map.put(s, valueProvider.apply(dslProperty))); - return map; - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/NamedProperty.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/NamedProperty.java deleted file mode 100644 index b509003153..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/NamedProperty.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.util.Map; -import java.util.Objects; - -/** - * Represents a property that has name and content. Used together with multipart requests. - * - * @since 1.0.0 - */ -public class NamedProperty { - - private static final String NAME = "name"; - - private static final String CONTENT = "content"; - - private static final String CONTENT_TYPE = "contentType"; - - private DslProperty name; - - private DslProperty value; - - private DslProperty contentType; - - public NamedProperty(DslProperty name, DslProperty value) { - this.name = name; - this.value = value; - this.contentType = null; - } - - public NamedProperty(DslProperty name, DslProperty value, DslProperty contentType) { - this.name = name; - this.value = value; - this.contentType = contentType; - } - - public NamedProperty(Map namedMap) { - this(asDslProperty(value(namedMap, NAME)), asDslProperty(value(namedMap, CONTENT)), - asDslProperty(value(namedMap, CONTENT_TYPE))); - } - - private static DslProperty value(Map namedMap, String key) { - if (namedMap == null) { - return null; - } - - return namedMap.get(key); - } - - public static DslProperty asDslProperty(Object o) { - if (o == null) { - return null; - } - - if (o instanceof DslProperty) { - return ((DslProperty) (o)); - } - - return new DslProperty(o); - } - - public DslProperty getName() { - return name; - } - - public void setName(DslProperty name) { - this.name = name; - } - - public DslProperty getValue() { - return value; - } - - public void setValue(DslProperty value) { - this.value = value; - } - - public DslProperty getContentType() { - return contentType; - } - - public void setContentType(DslProperty contentType) { - this.contentType = contentType; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - NamedProperty that = (NamedProperty) o; - return Objects.equals(name, that.name) && Objects.equals(value, that.value) - && Objects.equals(contentType, that.contentType); - } - - @Override - public int hashCode() { - return Objects.hash(name, value, contentType); - } - - @Override - public String toString() { - return "NamedProperty{" + "name=" + name + ", value=" + value + ", contentType=" + contentType + '}'; - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/NotToEscapePattern.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/NotToEscapePattern.java deleted file mode 100644 index bc6e8fe65d..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/NotToEscapePattern.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.util.regex.Pattern; - -/** - * Special case of Patterns that we don't want to escape. - * - * @author Marcin Grzejszczak - * @since 1.0.3 - */ -public class NotToEscapePattern extends DslProperty { - - public NotToEscapePattern(Pattern clientValue, Pattern serverValue) { - super(clientValue, serverValue); - } - - public NotToEscapePattern(Pattern singleValue) { - super(singleValue); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/OptionalProperty.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/OptionalProperty.java deleted file mode 100644 index b4f9065184..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/OptionalProperty.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.io.Serializable; -import java.util.regex.Pattern; - -import repackaged.nl.flotsam.xeger.Xeger; - -/** - * Represents a property that may or may not be there. - * - * @since 1.0.0 - */ -public class OptionalProperty implements Serializable, CanBeDynamic { - - private final Object value; - - public OptionalProperty(Object value) { - this.value = value; - } - - /** - * String version of a regular expression that wraps the provided value in an optional - * function. - * @return pattern wrapped in optional regular expresion - */ - public String optionalPattern() { - return "(" + value() + ")?"; - } - - public String value() { - return valueToCheck(this.value).toString(); - } - - private Object valueToCheck(Object value) { - if (value == null) { - return ""; - } - else if (value instanceof ClientDslProperty) { - return valueToCheck(((ClientDslProperty) value).getClientValue()); - } - else if (value instanceof ServerDslProperty) { - return valueToCheck(((ServerDslProperty) value).getServerValue()); - } - else if (value instanceof RegexProperty || value instanceof Pattern) { - return new RegexProperty(value).pattern(); - } - else { - return value.toString(); - } - } - - protected Pattern optionalPatternValue() { - return Pattern.compile(optionalPattern()); - } - - @Override - public String toString() { - return optionalPattern(); - } - - @Override - public Object generateConcreteValue() { - return new Xeger(optionalPattern()).generate(); - } - - public final Object getValue() { - return value; - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/OutputMessage.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/OutputMessage.java deleted file mode 100644 index 2c7dddc7f8..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/OutputMessage.java +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.util.Objects; -import java.util.function.Consumer; -import java.util.regex.Pattern; - -import groovy.lang.Closure; -import groovy.lang.DelegatesTo; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Represents an output for messaging. Used for verifying the body and headers that are - * sent. - * - * @author Marcin Grzejszczak - * @author Tim Ysewyn - * @since 1.0.0 - */ -public class OutputMessage extends Common implements RegexCreatingProperty { - - private static final Log log = LogFactory.getLog(OutputMessage.class); - - private DslProperty sentTo; - - private Headers headers; - - private DslProperty body; - - private ExecutionProperty assertThat; - - private ResponseBodyMatchers bodyMatchers; - - private ServerPatternValueDslProperty property = new ServerPatternValueDslProperty(); - - public OutputMessage() { - } - - public OutputMessage(OutputMessage outputMessage) { - this.sentTo = outputMessage.getSentTo(); - this.headers = outputMessage.getHeaders(); - this.body = outputMessage.getBody(); - } - - public void sentTo(String sentTo) { - this.sentTo = new DslProperty(sentTo); - } - - public void sentTo(DslProperty sentTo) { - this.sentTo = sentTo; - } - - public void body(Object bodyAsValue) { - this.body = new DslProperty(bodyAsValue); - } - - public void body(DslProperty bodyAsValue) { - this.body = bodyAsValue; - } - - public void assertThat(String assertThat) { - this.assertThat = new ExecutionProperty(assertThat); - } - - public DslProperty value(ServerDslProperty serverDslProperty) { - Object concreteValue = serverDslProperty.getClientValue(); - Object dynamicValue = serverDslProperty.getServerValue(); - // for the output messages ran via stub runner, - // entries have to have fixed values - if (dynamicValue instanceof RegexProperty) { - return ((RegexProperty) dynamicValue).concreteClientEscapedDynamicProducer(); - } - - return new DslProperty(concreteValue, dynamicValue); - } - - public DslProperty $(ServerDslProperty property) { - return value(property); - } - - public DslProperty $(Pattern pattern) { - return value(new RegexProperty(pattern)); - } - - public DslProperty $(RegexProperty pattern) { - return value(pattern); - } - - public DslProperty value(RegexProperty pattern) { - return value(producer(pattern)); - } - - public DslProperty $(OptionalProperty property) { - return value(producer(property.optionalPatternValue())); - } - - @Override - public RegexProperty regexProperty(Object object) { - return new RegexProperty(object).concreteClientDynamicProducer(); - } - - public ServerPatternValueDslProperty getProperty() { - return property; - } - - public void setProperty(ServerPatternValueDslProperty property) { - this.property = property; - } - - public DslProperty getSentTo() { - return sentTo; - } - - public void setSentTo(DslProperty sentTo) { - this.sentTo = sentTo; - } - - public Headers getHeaders() { - return headers; - } - - public void setHeaders(Headers headers) { - this.headers = headers; - } - - public DslProperty getBody() { - return body; - } - - public void setBody(DslProperty body) { - this.body = body; - } - - public ExecutionProperty getAssertThat() { - return assertThat; - } - - public void setAssertThat(ExecutionProperty assertThat) { - this.assertThat = assertThat; - } - - public ResponseBodyMatchers getBodyMatchers() { - return bodyMatchers; - } - - public void setBodyMatchers(ResponseBodyMatchers bodyMatchers) { - this.bodyMatchers = bodyMatchers; - } - - @Override - public ServerDslProperty anyAlphaUnicode() { - return property.anyAlphaUnicode(); - } - - @Override - public ServerDslProperty anyAlphaNumeric() { - return property.anyAlphaNumeric(); - } - - @Override - public ServerDslProperty anyNumber() { - return property.anyNumber(); - } - - @Override - public ServerDslProperty anyInteger() { - return property.anyInteger(); - } - - @Override - public ServerDslProperty anyPositiveInt() { - return property.anyPositiveInt(); - } - - @Override - public ServerDslProperty anyDouble() { - return property.anyDouble(); - } - - @Override - public ServerDslProperty anyHex() { - return property.anyHex(); - } - - @Override - public ServerDslProperty aBoolean() { - return property.aBoolean(); - } - - @Override - public ServerDslProperty anyIpAddress() { - return property.anyIpAddress(); - } - - @Override - public ServerDslProperty anyHostname() { - return property.anyHostname(); - } - - @Override - public ServerDslProperty anyEmail() { - return property.anyEmail(); - } - - @Override - public ServerDslProperty anyUrl() { - return property.anyUrl(); - } - - @Override - public ServerDslProperty anyHttpsUrl() { - return property.anyHttpsUrl(); - } - - @Override - public ServerDslProperty anyUuid() { - return property.anyUuid(); - } - - @Override - public ServerDslProperty anyDate() { - return property.anyDate(); - } - - @Override - public ServerDslProperty anyDateTime() { - return property.anyDateTime(); - } - - @Override - public ServerDslProperty anyTime() { - return property.anyTime(); - } - - @Override - public ServerDslProperty anyIso8601WithOffset() { - return property.anyIso8601WithOffset(); - } - - @Override - public ServerDslProperty anyNonBlankString() { - return property.anyNonBlankString(); - } - - @Override - public ServerDslProperty anyNonEmptyString() { - return property.anyNonEmptyString(); - } - - @Override - public ServerDslProperty anyOf(String... values) { - return property.anyOf(values); - } - - /** - * The message headers part of the contract. - * @param consumer function to manipulate the message headers - */ - public void headers(Consumer consumer) { - this.headers = new Headers(); - consumer.accept(this.headers); - } - - /** - * The stub matchers part of the contract. - * @param consumer function to manipulate the body matchers - */ - public void bodyMatchers(Consumer consumer) { - this.bodyMatchers = new ResponseBodyMatchers(); - consumer.accept(this.bodyMatchers); - } - - /** - * The message headers part of the contract. - * @param consumer function to manipulate the message headers - */ - public void headers(@DelegatesTo(Headers.class) Closure consumer) { - this.headers = new Headers(); - consumer.setDelegate(this.headers); - consumer.call(); - } - - /** - * The stub matchers part of the contract. - * @param consumer function to manipulate the body matchers - */ - public void bodyMatchers(@DelegatesTo(ResponseBodyMatchers.class) Closure consumer) { - this.bodyMatchers = new ResponseBodyMatchers(); - consumer.setDelegate(this.bodyMatchers); - consumer.call(); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - OutputMessage that = (OutputMessage) o; - return Objects.equals(sentTo, that.sentTo) && Objects.equals(headers, that.headers) - && Objects.equals(body, that.body) && Objects.equals(assertThat, that.assertThat) - && Objects.equals(bodyMatchers, that.bodyMatchers); - } - - @Override - public int hashCode() { - return Objects.hash(sentTo, headers, body, assertThat, bodyMatchers); - } - - @Override - public String toString() { - return "OutputMessage{" + "\n\tsentTo=" + sentTo + ", \n\theaders=" + headers + ", \n\tbody=" + body - + ", \n\tassertThat=" + assertThat + ", \n\tbodyMatchers=" + bodyMatchers + "} \n\t" + super.toString(); - } - - private class ServerPatternValueDslProperty extends PatternValueDslProperty { - - @Override - protected ServerDslProperty createProperty(Pattern pattern, Object generatedValue) { - return new ServerDslProperty(pattern, generatedValue); - } - - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/PathBodyMatcher.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/PathBodyMatcher.java deleted file mode 100644 index 2e02b13c14..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/PathBodyMatcher.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.util.Objects; - -/** - * @author Marcin Grzejszczak - */ -public class PathBodyMatcher implements BodyMatcher { - - private String path; - - private MatchingTypeValue matchingTypeValue; - - PathBodyMatcher(String path, MatchingTypeValue matchingTypeValue) { - this.path = path; - this.matchingTypeValue = matchingTypeValue; - } - - @Override - public MatchingType matchingType() { - return this.matchingTypeValue.getType(); - } - - @Override - public String path() { - return this.path; - } - - @Override - public Object value() { - return this.matchingTypeValue.getValue(); - } - - @Override - public Integer minTypeOccurrence() { - return this.matchingTypeValue.getMinTypeOccurrence(); - } - - @Override - public Integer maxTypeOccurrence() { - return this.matchingTypeValue.getMaxTypeOccurrence(); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - PathBodyMatcher that = (PathBodyMatcher) o; - return Objects.equals(path, that.path) && Objects.equals(matchingTypeValue, that.matchingTypeValue); - } - - @Override - public int hashCode() { - return Objects.hash(path, matchingTypeValue); - } - - @Override - public String toString() { - return "PathBodyMatcher{" + "path='" + path + '\'' + ", matchingTypeValue=" + matchingTypeValue + '}'; - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/PatternValueDslProperty.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/PatternValueDslProperty.java deleted file mode 100644 index 6fe1cf561d..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/PatternValueDslProperty.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.util.Random; -import java.util.UUID; -import java.util.regex.Pattern; - -import org.apache.commons.lang3.RandomStringUtils; - -/** - * @author Marcin Grzejszczak - * @author Tim Ysewyn - */ -abstract class PatternValueDslProperty implements RegexCreatingProperty { - - private final Random random = new Random(); - - protected T createAndValidateProperty(Pattern pattern, Object object) { - if (object != null) { - String generatedValue = object.toString(); - boolean matches = pattern.matcher(generatedValue).matches(); - if (!matches) { - throw new IllegalStateException("The generated value [" + generatedValue - + "] doesn't match the pattern [" + pattern.pattern() + "]"); - } - - return createProperty(pattern, object); - } - - return createProperty(pattern, object); - } - - protected T createAndValidateProperty(Pattern pattern) { - return createAndValidateProperty(pattern, null); - } - - /** - * Method to generate the PatternValue. The resulting implementation will create - * either a Client or a Server side impl. - * @param pattern - pattern for which the value will be generated or reused - * @param generatedValue - Nullable - potential generated value to be reused - * @return {@link DslProperty} wrapping a pattern and generated value - */ - protected abstract T createProperty(Pattern pattern, Object generatedValue); - - @Override - public T anyAlphaUnicode() { - return createAndValidateProperty(RegexPatterns.ONLY_ALPHA_UNICODE, RandomStringGenerator.randomString(20)); - } - - @Override - public T anyAlphaNumeric() { - return createAndValidateProperty(RegexPatterns.ALPHA_NUMERIC, RandomStringUtils.randomAlphanumeric(20)); - } - - @Override - public T anyNumber() { - return createAndValidateProperty(RegexPatterns.NUMBER, this.random.nextInt()); - } - - @Override - public T anyInteger() { - return createAndValidateProperty(RegexPatterns.INTEGER, this.random.nextInt()); - } - - @Override - public T anyPositiveInt() { - return createAndValidateProperty(RegexPatterns.POSITIVE_INT, Math.abs(this.random.nextInt() + 1)); - } - - @Override - public T anyDouble() { - return createAndValidateProperty(RegexPatterns.DOUBLE, this.random.nextInt(100) + this.random.nextDouble()); - } - - @Override - public T anyHex() { - return createAndValidateProperty(RegexPatterns.HEX, RandomStringUtils.random(10, "0123456789abcdef")); - } - - @Override - public T aBoolean() { - return createAndValidateProperty(RegexPatterns.TRUE_OR_FALSE, this.random.nextBoolean()); - } - - @Override - public T anyIpAddress() { - return createAndValidateProperty(RegexPatterns.IP_ADDRESS, "192.168.0." + this.random.nextInt(10)); - } - - @Override - public T anyHostname() { - return createAndValidateProperty(RegexPatterns.HOSTNAME_PATTERN, - "https://foo" + this.random.nextInt() + ".com"); - } - - @Override - public T anyEmail() { - return createAndValidateProperty(RegexPatterns.EMAIL, "foo@bar" + this.random.nextInt() + ".com"); - } - - @Override - public T anyUrl() { - return createAndValidateProperty(RegexPatterns.URL, "https://foo" + this.random.nextInt() + ".com"); - } - - @Override - public T anyHttpsUrl() { - return createAndValidateProperty(RegexPatterns.HTTPS_URL, "https://baz" + this.random.nextInt() + ".com"); - } - - @Override - public T anyUuid() { - return createAndValidateProperty(RegexPatterns.UUID, UUID.randomUUID().toString()); - } - - @Override - public T anyDate() { - int d = this.random.nextInt(8) + 1; - return createAndValidateProperty(RegexPatterns.ANY_DATE, - "201" + String.valueOf(d) + "-0" + String.valueOf(d) + "-1" + String.valueOf(d)); - } - - @Override - public T anyDateTime() { - final int d = this.random.nextInt(8) + 1; - return createAndValidateProperty(RegexPatterns.ANY_DATE_TIME, - "201" + String.valueOf(d) + "-0" + String.valueOf(d) + "-1" + String.valueOf(d) + "T12:23:34"); - } - - @Override - public T anyTime() { - int d = this.random.nextInt(9); - return createAndValidateProperty(RegexPatterns.ANY_TIME, "12:2" + String.valueOf(d) + ":3" + String.valueOf(d)); - } - - @Override - public T anyIso8601WithOffset() { - final int d = this.random.nextInt(8) + 1; - return createAndValidateProperty(RegexPatterns.ISO8601_WITH_OFFSET, - "201" + String.valueOf(d) + "-0" + String.valueOf(d) + "-1" + String.valueOf(d) + "T12:23:34.123Z"); - } - - @Override - public T anyNonBlankString() { - return createAndValidateProperty(RegexPatterns.NON_BLANK, RandomStringGenerator.randomString(20)); - } - - @Override - public T anyNonEmptyString() { - return createAndValidateProperty(RegexPatterns.NON_EMPTY, RandomStringGenerator.randomString(20)); - } - - @Override - public T anyOf(String... values) { - return createAndValidateProperty(RegexPatterns.anyOf(values), values[this.random.nextInt(values.length)]); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/QueryParameter.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/QueryParameter.java deleted file mode 100644 index 12d99b2555..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/QueryParameter.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.util.Objects; - -import org.springframework.cloud.contract.spec.util.ValidateUtils; - -/** - * Represents a single HTTP query parameter. - * - * @since 1.0.0 - */ -public class QueryParameter extends DslProperty { - - private String name; - - public QueryParameter(String name, DslProperty dslProperty) { - super(dslProperty.getClientValue(), dslProperty.getServerValue()); - ValidateUtils.validateServerValueIsAvailable(dslProperty.getServerValue(), "Query parameter \'" + name + "\'"); - this.name = name; - } - - public QueryParameter(String name, MatchingStrategy matchingStrategy) { - super(matchingStrategy); - ValidateUtils.validateServerValueIsAvailable(matchingStrategy, "Query parameter \'" + name + "\'"); - this.name = name; - } - - public QueryParameter(String name, Object value) { - super(ContractUtils.CLIENT_VALUE.apply(value), ContractUtils.SERVER_VALUE.apply(value)); - ValidateUtils.validateServerValueIsAvailable(value, "Query parameter \'" + name + "\'"); - this.name = name; - } - - public static QueryParameter build(String key, Object value) { - if (value instanceof MatchingStrategy) { - return new QueryParameter(key, (MatchingStrategy) value); - } - else if (value instanceof RegexProperty) { - return new QueryParameter(key, ((RegexProperty) value).dynamicClientEscapedConcreteProducer()); - } - return new QueryParameter(key, value); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - if (!super.equals(o)) { - return false; - } - QueryParameter that = (QueryParameter) o; - return Objects.equals(name, that.name); - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), name); - } - - @Override - public String toString() { - return "QueryParameter{" + "name='" + name + '\'' + ", value=" + super.toString() + '}'; - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/QueryParameters.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/QueryParameters.java deleted file mode 100644 index 9d26aa466a..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/QueryParameters.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -public class QueryParameters { - - private List parameters = new LinkedList(); - - public void parameter(Map singleParameter) { - Iterator> iterator = singleParameter.entrySet().iterator(); - if (iterator.hasNext()) { - Map.Entry first = iterator.next(); - if (first != null) { - parameters.add(QueryParameter.build(first.getKey(), first.getValue())); - } - } - } - - public void parameter(String parameterName, Object parameterValue) { - parameters.add(QueryParameter.build(parameterName, parameterValue)); - } - - public List getParameters() { - return parameters; - } - - public void setParameters(List parameters) { - this.parameters = parameters; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - QueryParameters that = (QueryParameters) o; - return Objects.equals(parameters, that.parameters); - } - - @Override - public int hashCode() { - return Objects.hash(parameters); - } - - @Override - public String toString() { - return "QueryParameters{" + "\nparameters=" + parameters + '}'; - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/RandomStringGenerator.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/RandomStringGenerator.java deleted file mode 100644 index 77aaadb1d0..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/RandomStringGenerator.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.util.Random; - -final class RandomStringGenerator { - - private RandomStringGenerator() { - throw new IllegalStateException("Can't instantiate a utility class"); - } - - static String randomString(int length) { - char[] characterSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); - Random random = new Random(); - char[] result = new char[length]; - for (int i = 0; i < result.length; i++) { - // picks a random index out of character set > random character - int randomCharIndex = random.nextInt(characterSet.length); - result[i] = characterSet[randomCharIndex]; - } - return new String(result); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/RegexCreatingProperty.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/RegexCreatingProperty.java deleted file mode 100644 index 2f072cd251..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/RegexCreatingProperty.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -/** - * @author Marcin Grzejszczak - */ -interface RegexCreatingProperty { - - // tag::regex_creating_props[] - T anyAlphaUnicode(); - - T anyAlphaNumeric(); - - T anyNumber(); - - T anyInteger(); - - T anyPositiveInt(); - - T anyDouble(); - - T anyHex(); - - T aBoolean(); - - T anyIpAddress(); - - T anyHostname(); - - T anyEmail(); - - T anyUrl(); - - T anyHttpsUrl(); - - T anyUuid(); - - T anyDate(); - - T anyDateTime(); - - T anyTime(); - - T anyIso8601WithOffset(); - - T anyNonBlankString(); - - T anyNonEmptyString(); - - T anyOf(String... values); - // end::regex_creating_props[] - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/RegexMatchingTypeValue.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/RegexMatchingTypeValue.java deleted file mode 100644 index 6d96441369..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/RegexMatchingTypeValue.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -/** - * Matching type with corresponding values. - */ -public class RegexMatchingTypeValue extends MatchingTypeValue { - - RegexMatchingTypeValue(MatchingType type, Object value, Integer minTypeOccurrence, Integer maxTypeOccurrence) { - super(type, value, minTypeOccurrence, maxTypeOccurrence); - } - - RegexMatchingTypeValue(MatchingType type, Object value) { - super(type, value); - } - - public RegexMatchingTypeValue asInteger() { - return typed(Integer.class); - } - - private RegexMatchingTypeValue typed(Class clazz) { - if (!(this.getValue() instanceof RegexProperty)) { - throw new IllegalStateException("Value has to be a regex"); - } - RegexProperty regexProperty = (RegexProperty) this.getValue(); - return new RegexMatchingTypeValue(this.getType(), - new RegexProperty(regexProperty.getClientValue(), regexProperty.getServerValue(), clazz), - this.getMinTypeOccurrence(), this.getMaxTypeOccurrence()); - } - - public RegexMatchingTypeValue asDouble() { - return typed(Double.class); - } - - public RegexMatchingTypeValue asFloat() { - return typed(Float.class); - } - - public RegexMatchingTypeValue asLong() { - return typed(Long.class); - } - - public RegexMatchingTypeValue asShort() { - return typed(Short.class); - } - - public RegexMatchingTypeValue asString() { - return typed(String.class); - } - - public RegexMatchingTypeValue asBooleanType() { - return typed(Boolean.class); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/RegexPatterns.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/RegexPatterns.java deleted file mode 100644 index 939c8ebe92..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/RegexPatterns.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.util.Arrays; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.spec.util.RegexpUtils; - -/** - * Contains most common regular expression patterns. - * - * @author Marcin Grzejszczak - * @author Tim Ysewyn - * @since 1.0.0 - */ -public final class RegexPatterns { - - private static final Log log = LogFactory.getLog(RegexPatterns.class); - - public RegexPatterns() { - log.warn("WARNING: RegexPatterns shouldn't be instantiated. Use its static methods instead."); - } - - protected static final Pattern TRUE_OR_FALSE = Pattern.compile("(true|false)"); - - protected static final Pattern ALPHA_NUMERIC = Pattern.compile("[a-zA-Z0-9]+"); - - protected static final Pattern ONLY_ALPHA_UNICODE = Pattern.compile("[\\p{L}]*"); - - protected static final Pattern NUMBER = Pattern.compile("-?(\\d*\\.\\d+|\\d+)"); - - protected static final Pattern INTEGER = Pattern.compile("-?(\\d+)"); - - protected static final Pattern POSITIVE_INT = Pattern.compile("([1-9]\\d*)"); - - protected static final Pattern DOUBLE = Pattern.compile("-?(\\d*\\.\\d+)"); - - protected static final Pattern HEX = Pattern.compile("[a-fA-F0-9]+"); - - protected static final Pattern IP_ADDRESS = Pattern.compile( - "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])"); - - protected static final Pattern HOSTNAME_PATTERN = Pattern.compile("((http[s]?|ftp):/)/?([^:/\\s]+)(:[0-9]{1,5})?"); - - protected static final Pattern EMAIL = Pattern.compile("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}"); - - protected static final Pattern URL = UrlHelper.URL; - - protected static final Pattern HTTPS_URL = UrlHelper.HTTPS_URL; - - protected static final Pattern UUID = Pattern - .compile("[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}", Pattern.CASE_INSENSITIVE); - - protected static final Pattern UUID4 = Pattern - .compile("[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}", Pattern.CASE_INSENSITIVE); - - protected static final Pattern ANY_DATE = Pattern - .compile("(\\d\\d\\d\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])"); - - protected static final Pattern ANY_DATE_TIME = Pattern.compile( - "([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])"); - - protected static final Pattern ANY_TIME = Pattern.compile("(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])"); - - protected static final Pattern NON_EMPTY = Pattern.compile("[\\S\\s]+"); - - protected static final Pattern NON_BLANK = Pattern.compile("^\\s*\\S[\\S\\s]*"); - - protected static final Pattern ISO8601_WITH_OFFSET = Pattern.compile( - "([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\\.\\d+)?(Z|[+-][01]\\d:[0-5]\\d)"); - - protected static Pattern anyOf(String... values) { - return Pattern - .compile(Arrays.stream(values).map(it -> '^' + RegexpUtils.escapeSpecialRegexWithSingleEscape(it) + '$') - .collect(Collectors.joining("|"))); - } - - public static String multipartParam(Object name, Object value) { - return ".*--(.*)\r?\nContent-Disposition: form-data; name=\"" + name - + "\"\r?\n(Content-Type: .*\r?\n)?(Content-Transfer-Encoding: .*\r?\n)?(Content-Length: \\d+\r?\n)?\r?\n" - + value + "\r?\n--.*"; - } - - public static String multipartFile(Object name, Object filename, Object content, Object contentType) { - return ".*--(.*)\r?\nContent-Disposition: form-data; name=\"" + name + "\"; filename=\"" + filename - + "\"\r?\n(Content-Type: " + toContentType(contentType) - + "\r?\n)?(Content-Transfer-Encoding: .*\r?\n)?(Content-Length: \\d+\r?\n)?\r?\n" + content - + "\r?\n--.*"; - } - - private static String toContentType(Object contentType) { - if (contentType == null) { - return ".*"; - } - if (contentType instanceof RegexProperty) { - return ((RegexProperty) contentType).pattern(); - } - return contentType.toString(); - } - - // tag::regexps[] - - public static RegexProperty onlyAlphaUnicode() { - return new RegexProperty(ONLY_ALPHA_UNICODE).asString(); - } - - public static RegexProperty alphaNumeric() { - return new RegexProperty(ALPHA_NUMERIC).asString(); - } - - public static RegexProperty number() { - return new RegexProperty(NUMBER).asDouble(); - } - - public static RegexProperty positiveInt() { - return new RegexProperty(POSITIVE_INT).asInteger(); - } - - public static RegexProperty anyBoolean() { - return new RegexProperty(TRUE_OR_FALSE).asBooleanType(); - } - - public static RegexProperty anInteger() { - return new RegexProperty(INTEGER).asInteger(); - } - - public static RegexProperty aDouble() { - return new RegexProperty(DOUBLE).asDouble(); - } - - public static RegexProperty ipAddress() { - return new RegexProperty(IP_ADDRESS).asString(); - } - - public static RegexProperty hostname() { - return new RegexProperty(HOSTNAME_PATTERN).asString(); - } - - public static RegexProperty email() { - return new RegexProperty(EMAIL).asString(); - } - - public static RegexProperty url() { - return new RegexProperty(URL).asString(); - } - - public static RegexProperty httpsUrl() { - return new RegexProperty(HTTPS_URL).asString(); - } - - public static RegexProperty uuid() { - return new RegexProperty(UUID).asString(); - } - - public static RegexProperty uuid4() { - return new RegexProperty(UUID4).asString(); - } - - public static RegexProperty isoDate() { - return new RegexProperty(ANY_DATE).asString(); - } - - public static RegexProperty isoDateTime() { - return new RegexProperty(ANY_DATE_TIME).asString(); - } - - public static RegexProperty isoTime() { - return new RegexProperty(ANY_TIME).asString(); - } - - public static RegexProperty iso8601WithOffset() { - return new RegexProperty(ISO8601_WITH_OFFSET).asString(); - } - - public static RegexProperty nonEmpty() { - return new RegexProperty(NON_EMPTY).asString(); - } - - public static RegexProperty nonBlank() { - return new RegexProperty(NON_BLANK).asString(); - } - - // end::regexps[] - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/RegexProperty.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/RegexProperty.java deleted file mode 100644 index 69f3490e1a..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/RegexProperty.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.io.UnsupportedEncodingException; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.Objects; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.commons.text.StringEscapeUtils; -import repackaged.nl.flotsam.xeger.Xeger; - -/** - * Represents a regular expression property. - * - * @since 2.1.0 - */ -public class RegexProperty extends DslProperty implements CanBeDynamic { - - final Pattern pattern; - - String charset = StandardCharsets.UTF_8.name(); - - private final Class clazz; - - public RegexProperty(Object value) { - this(value, value, null); - } - - public RegexProperty(Object client, Object server) { - this(client, server, null); - } - - public RegexProperty(Object client, Object server, Class clazz) { - super(client, server); - boolean clientDynamic = client instanceof Pattern || client instanceof RegexProperty; - boolean serverDynamic = server instanceof Pattern || server instanceof RegexProperty; - if (!clientDynamic && !serverDynamic) { - throw new IllegalStateException("Neither client not server side is dynamic"); - } - Object dynamicValue = clientDynamic ? client : server; - if (dynamicValue instanceof Pattern) { - this.pattern = (Pattern) dynamicValue; - this.clazz = clazz != null ? clazz : String.class; - } - else if (dynamicValue instanceof RegexProperty) { - RegexProperty regexProperty = ((RegexProperty) dynamicValue); - this.pattern = regexProperty.pattern; - this.clazz = clazz != null ? clazz : regexProperty.clazz; - } - else { - this.clazz = clazz; - this.pattern = null; - } - } - - public Matcher matcher(CharSequence input) { - return this.pattern.matcher(input); - } - - public String pattern() { - return this.pattern.pattern(); - } - - public Class clazz() { - return this.getClass(); - } - - public RegexProperty asInteger() { - return new RegexProperty(this.getClientValue(), this.getServerValue(), Integer.class); - } - - public RegexProperty asDouble() { - return new RegexProperty(this.getClientValue(), this.getServerValue(), Double.class); - } - - public RegexProperty asFloat() { - return new RegexProperty(this.getClientValue(), this.getServerValue(), Float.class); - } - - public RegexProperty asLong() { - return new RegexProperty(this.getClientValue(), this.getServerValue(), Long.class); - } - - public RegexProperty asShort() { - return new RegexProperty(this.getClientValue(), this.getServerValue(), Short.class); - } - - public RegexProperty asString() { - return new RegexProperty(this.getClientValue(), this.getServerValue(), String.class); - } - - public RegexProperty asString(Charset charset) { - RegexProperty regexProperty = asString(); - regexProperty.charset = charset.name(); - return regexProperty; - } - - public RegexProperty asString(String charset) { - RegexProperty regexProperty = asString(); - regexProperty.charset = charset; - return regexProperty; - } - - public RegexProperty asBooleanType() { - return new RegexProperty(this.getClientValue(), this.getServerValue(), Boolean.class); - } - - public Object generate() { - return doGenerate(3); - } - - private Object doGenerate(int retries) { - try { - String generatedValue = new Xeger(this.pattern.pattern()).generate(); - if (Integer.class.equals(this.clazz)) { - return Integer.parseInt(generatedValue); - } - else if (Double.class.equals(this.clazz)) { - return Double.parseDouble(generatedValue); - } - else if (Float.class.equals(this.clazz)) { - return Float.parseFloat(generatedValue); - } - else if (Long.class.equals(this.clazz)) { - return Long.parseLong(generatedValue); - } - else if (Short.class.equals(this.clazz)) { - return Short.parseShort(generatedValue); - } - else if (Boolean.class.equals(this.clazz)) { - return Boolean.parseBoolean(generatedValue); - } - return new String(generatedValue.getBytes(Charset.forName(this.charset)), this.charset); - } - catch (NumberFormatException ex) { - if (retries > 0) { - retries = retries - 1; - return doGenerate(retries); - } - throw ex; - } - catch (UnsupportedEncodingException e) { - throw new IllegalStateException(e); - } - } - - public Object generateAndEscapeJavaStringIfNeeded() { - Object generated = generate(); - if (isNumber()) { - return generated; - } - return StringEscapeUtils.escapeJava(String.valueOf(generated)); - } - - private boolean isNumber() { - return Number.class.isAssignableFrom(this.clazz); - } - - public RegexProperty dynamicClientConcreteProducer() { - return new RegexProperty(this.pattern, generate(), this.clazz); - } - - public RegexProperty concreteClientDynamicProducer() { - return new RegexProperty(generate(), this.pattern, this.clazz); - } - - public RegexProperty concreteClientEscapedDynamicProducer() { - return new RegexProperty(generateAndEscapeJavaStringIfNeeded(), this.pattern, this.clazz); - } - - public RegexProperty dynamicClientEscapedConcreteProducer() { - return new RegexProperty(this.pattern, generateAndEscapeJavaStringIfNeeded(), this.clazz); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - RegexProperty that = (RegexProperty) o; - return Objects.equals(stringPatternIfPresent(pattern), stringPatternIfPresent(that.pattern)) - && Objects.equals(clazz, that.clazz); - } - - private Object stringPatternIfPresent(Pattern value) { - return value != null ? value.pattern() : null; - } - - @Override - public int hashCode() { - return Objects.hash(stringPatternIfPresent(pattern), clazz); - } - - @Override - public String toString() { - return this.pattern(); - } - - @Override - public Object generateConcreteValue() { - return generate(); - } - - public Pattern getPattern() { - return pattern; - } - - public Class getClazz() { - return clazz; - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Request.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Request.java deleted file mode 100644 index 15ec6f87a6..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Request.java +++ /dev/null @@ -1,798 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.function.Consumer; -import java.util.regex.Pattern; - -import groovy.lang.Closure; -import groovy.lang.DelegatesTo; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.spec.util.RegexpUtils; - -/** - * Represents the request side of the HTTP communication. - * - * @author Marcin Grzejszczak - * @author Tim Ysewyn - * @since 1.0.0 - */ -public class Request extends Common implements RegexCreatingProperty { - - private static final Log log = LogFactory.getLog(Request.class); - - private ClientPatternValueDslProperty property = new ClientPatternValueDslProperty(); - - private DslProperty method; - - private Url url; - - private UrlPath urlPath; - - private Headers headers; - - private Cookies cookies; - - private Body body; - - private Multipart multipart; - - private BodyMatchers bodyMatchers; - - public Request() { - } - - public Request(Request request) { - this.method = request.getMethod(); - this.url = request.getUrl(); - this.urlPath = request.getUrlPath(); - this.headers = request.getHeaders(); - this.cookies = request.getCookies(); - this.body = request.getBody(); - this.multipart = request.getMultipart(); - } - - /** - * Name of the HTTP method. - * @param method HTTP method name - */ - public void method(String method) { - this.method = toDslProperty(method); - } - - /** - * Name of the HTTP method. - * @param method HTTP method name - */ - public void method(DslProperty method) { - this.method = toDslProperty(method); - } - - /** - * @param url URL to which the request will be sent - */ - public void url(Object url) { - this.url = new Url(url); - } - - /** - * @param url URL to which the request will be sent - */ - public void url(DslProperty url) { - this.url = new Url(url); - } - - /** - * @param path URL to which the request will be sent - */ - public void urlPath(String path) { - this.urlPath = new UrlPath(path); - } - - /** - * @param path URL to which the request will be sent - */ - public void urlPath(Object path) { - this.urlPath = new UrlPath(path); - } - - /** - * @param path URL to which the request will be sent - */ - public void urlPath(DslProperty path) { - this.urlPath = new UrlPath(path); - } - - /** - * Allows set an HTTP body. - * @param body body to set - */ - public void body(Map body) { - this.body = new Body(convertObjectsToDslProperties(body)); - } - - /** - * Allows set an HTTP body. - * @param body body to set - */ - public void body(List body) { - this.body = new Body(convertObjectsToDslProperties(body)); - } - - /** - * Allows set an HTTP body. - * @param matchingStrategy body to set - */ - public void body(MatchingStrategy matchingStrategy) { - this.body = new Body(matchingStrategy); - } - - /** - * Allows set an HTTP body. - * @param dslProperty body to set - */ - public void body(DslProperty dslProperty) { - this.body = new Body(dslProperty); - } - - /** - * Allows set an HTTP body. - * @param bodyAsValue body to set - */ - public void body(Object bodyAsValue) { - this.body = new Body(bodyAsValue); - } - - public Body getBody() { - return body; - } - - public void setBody(Body body) { - this.body = body; - } - - /** - * Allows to set multipart via the map notation. - * @param body multipart in a map notation - */ - public void multipart(Map body) { - this.multipart = new Multipart(convertObjectsToDslProperties(body)); - } - - /** - * Allows to set multipart via lists. - * @param multipartAsList multipart in a list notation - */ - public void multipart(List multipartAsList) { - this.multipart = Multipart.build(convertObjectsToDslProperties(multipartAsList)); - } - - /** - * Allows to set multipart value. - * @param dslProperty multipart - */ - public void multipart(DslProperty dslProperty) { - this.multipart = new Multipart(dslProperty); - } - - /** - * Allows to set multipart value. - * @param multipartAsValue multipart - */ - public void multipart(Object multipartAsValue) { - this.multipart = Multipart.build(multipartAsValue); - } - - /** - * Sets the equality check to the given query parameter. - * @param value value to check against - * @return matching strategy - */ - public MatchingStrategy equalTo(Object value) { - return new MatchingStrategy(value, MatchingStrategy.Type.EQUAL_TO); - } - - /** - * Sets the containing check to the given query parameter. - * @param value value to check against - * @return matching strategy - */ - public MatchingStrategy containing(Object value) { - return new MatchingStrategy(value, MatchingStrategy.Type.CONTAINS); - } - - /** - * Sets the matching check to the given query parameter. - * @param value value to check against - * @return matching strategy - */ - public MatchingStrategy matching(Object value) { - return new MatchingStrategy(value, MatchingStrategy.Type.MATCHING); - } - - /** - * Sets the not matching check to the given query parameter. - * @param value value to check against - * @return matching strategy - */ - public MatchingStrategy notMatching(Object value) { - return new MatchingStrategy(value, MatchingStrategy.Type.NOT_MATCHING); - } - - /** - * Sets the XML equality check to the body. - * @param value value to check against - * @return matching strategy - */ - public MatchingStrategy equalToXml(Object value) { - return new MatchingStrategy(value, MatchingStrategy.Type.EQUAL_TO_XML); - } - - /** - * Sets the JSON equality check to the body. - * @param value value to check against - * @return matching strategy - */ - public MatchingStrategy equalToJson(Object value) { - return new MatchingStrategy(value, MatchingStrategy.Type.EQUAL_TO_JSON); - } - - /** - * Sets absence check to the given query parameter. - * @return matching strategy - */ - public MatchingStrategy absent() { - return new MatchingStrategy(true, MatchingStrategy.Type.ABSENT); - } - - @Override - public void assertThatSidesMatch(Object stubSide, Object testSide) { - if (testSide instanceof OptionalProperty) { - throw new IllegalStateException("Optional can be used only for the stub side of the request!"); - } - super.assertThatSidesMatch(stubSide, testSide); - } - - /** - * Allows to set a dynamic value for the given element. - * @param client client value - * @return dsl property - */ - public DslProperty value(ClientDslProperty client) { - Object concreteValue = client.getServerValue(); - Object dynamicValue = client.getClientValue(); - if (dynamicValue instanceof RegexProperty && client.isSingleValue()) { - return ((RegexProperty) dynamicValue).dynamicClientEscapedConcreteProducer(); - } - else if (concreteValue instanceof RegexProperty && !client.isSingleValue()) { - concreteValue = dynamicValue; - } - - return new DslProperty(dynamicValue, concreteValue); - } - - /** - * Allows to set a dynamic value for the given regular expression element. - * @param property property to set - * @return dsl property - */ - public DslProperty $(RegexProperty property) { - return value(property); - } - - /** - * Allows to set a dynamic value for the given regular expression element. - * @param property property to set - * @return dsl property - */ - public DslProperty value(RegexProperty property) { - return value(client(property)); - } - - /** - * Allows to set a dynamic value for the given element. - * @param client property to set - * @return dsl property - */ - public DslProperty $(ClientDslProperty client) { - return value(client); - } - - /** - * Allows to set a dynamic value for the Pattern element. - * @param client property to set - * @return dsl property - */ - public DslProperty value(Pattern client) { - return value(new RegexProperty(client)); - } - - /** - * Allows to set a dynamic value for the given Pattern element. - * @param client property to set - * @return dsl property - */ - public DslProperty $(Pattern client) { - return value(client); - } - - @Override - public RegexProperty regexProperty(Object object) { - return new RegexProperty(object).dynamicClientConcreteProducer(); - } - - /** - * Allows to set a dynamic value for client and server side. - * @param client client value - * @param server server value - * @return dsl property - */ - @Override - public DslProperty value(ClientDslProperty client, ServerDslProperty server) { - if (server.getClientValue() instanceof RegexProperty) { - throw new IllegalStateException("You can't have a regular expression for the request on the server side"); - } - return super.value(client, server); - } - - /** - * Allows to set a dynamic value for client and server side. - * @param client client value - * @param server server value - * @return dsl property - */ - @Override - public DslProperty value(ServerDslProperty server, ClientDslProperty client) { - if (server.getClientValue() instanceof RegexProperty) { - throw new IllegalStateException("You can't have a regular expression for the request on the server side"); - } - - return super.value(server, client); - } - - public ClientPatternValueDslProperty getProperty() { - return property; - } - - public void setProperty(ClientPatternValueDslProperty property) { - this.property = property; - } - - public DslProperty getMethod() { - return method; - } - - public void setMethod(DslProperty method) { - this.method = method; - } - - public Url getUrl() { - return url; - } - - public void setUrl(Url url) { - this.url = url; - } - - public UrlPath getUrlPath() { - return urlPath; - } - - public void setUrlPath(UrlPath urlPath) { - this.urlPath = urlPath; - } - - public Headers getHeaders() { - return headers; - } - - public void setHeaders(Headers headers) { - this.headers = headers; - } - - public Cookies getCookies() { - return cookies; - } - - public void setCookies(Cookies cookies) { - this.cookies = cookies; - } - - public Multipart getMultipart() { - return multipart; - } - - public void setMultipart(Multipart multipart) { - this.multipart = multipart; - } - - public BodyMatchers getBodyMatchers() { - return bodyMatchers; - } - - public void setBodyMatchers(BodyMatchers bodyMatchers) { - this.bodyMatchers = bodyMatchers; - } - - @Override - public ClientDslProperty anyAlphaUnicode() { - return property.anyAlphaUnicode(); - } - - @Override - public ClientDslProperty anyAlphaNumeric() { - return property.anyAlphaNumeric(); - } - - @Override - public ClientDslProperty anyNumber() { - return property.anyNumber(); - } - - @Override - public ClientDslProperty anyInteger() { - return property.anyInteger(); - } - - @Override - public ClientDslProperty anyPositiveInt() { - return property.anyPositiveInt(); - } - - @Override - public ClientDslProperty anyDouble() { - return property.anyDouble(); - } - - @Override - public ClientDslProperty anyHex() { - return property.anyHex(); - } - - @Override - public ClientDslProperty aBoolean() { - return property.aBoolean(); - } - - @Override - public ClientDslProperty anyIpAddress() { - return property.anyIpAddress(); - } - - @Override - public ClientDslProperty anyHostname() { - return property.anyHostname(); - } - - @Override - public ClientDslProperty anyEmail() { - return property.anyEmail(); - } - - @Override - public ClientDslProperty anyUrl() { - return property.anyUrl(); - } - - @Override - public ClientDslProperty anyHttpsUrl() { - return property.anyHttpsUrl(); - } - - @Override - public ClientDslProperty anyUuid() { - return property.anyUuid(); - } - - @Override - public ClientDslProperty anyDate() { - return property.anyDate(); - } - - @Override - public ClientDslProperty anyDateTime() { - return property.anyDateTime(); - } - - @Override - public ClientDslProperty anyTime() { - return property.anyTime(); - } - - @Override - public ClientDslProperty anyIso8601WithOffset() { - return property.anyIso8601WithOffset(); - } - - @Override - public ClientDslProperty anyNonBlankString() { - return property.anyNonBlankString(); - } - - @Override - public ClientDslProperty anyNonEmptyString() { - return property.anyNonEmptyString(); - } - - @Override - public ClientDslProperty anyOf(String... values) { - return property.anyOf(values); - } - - public String GET() { - return HttpMethods.GET; - } - - public String HEAD() { - return HttpMethods.HEAD; - } - - public String POST() { - return HttpMethods.POST; - } - - public String PUT() { - return HttpMethods.PUT; - } - - public String PATCH() { - return HttpMethods.PATCH; - } - - public String DELETE() { - return HttpMethods.DELETE; - } - - public String OPTIONS() { - return HttpMethods.OPTIONS; - } - - public String TRACE() { - return HttpMethods.TRACE; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Request request = (Request) o; - return Objects.equals(method, request.method) && Objects.equals(url, request.url) - && Objects.equals(urlPath, request.urlPath) && Objects.equals(headers, request.headers) - && Objects.equals(cookies, request.cookies) && Objects.equals(body, request.body) - && Objects.equals(multipart, request.multipart) && Objects.equals(bodyMatchers, request.bodyMatchers); - } - - @Override - public int hashCode() { - return Objects.hash(method, url, urlPath, headers, cookies, body, multipart, bodyMatchers); - } - - @Override - public String toString() { - return "Request{" + "\nmethod=" + method + ", \n\turl=" + url + ", \n\turlPath=" + urlPath + ", \n\theaders=" - + headers + ", \n\tcookies=" + cookies + ", \n\tbody=" + body + ", \n\tmultipart=" + multipart - + ", \n\tbodyMatchers=" + bodyMatchers + '}'; - } - - /** - * The URL of the contract. - * @param url url value - * @param consumer function to manipulate the URL - */ - public void url(Object url, Consumer consumer) { - this.url = new Url(url); - consumer.accept(this.url); - } - - /** - * URL to which the request will be sent. Allows to customize additional query - * parameters if needed - * @param url url value - * @param consumer function to manipulate the URL - */ - public void url(DslProperty url, Consumer consumer) { - this.url = new Url(url); - consumer.accept(this.url); - } - - /** - * URL to which the request will be sent. Allows to customize additional query. - * parameters if needed - * @param path url value - * @param consumer function to manipulate the URL - */ - public void urlPath(String path, Consumer consumer) { - this.urlPath = new UrlPath(path); - consumer.accept(this.urlPath); - } - - /** - * URL to which the request will be sent. Allows to customize additional query. - * parameters if needed - * @param path url value - * @param consumer function to manipulate the URL - */ - public void urlPath(DslProperty path, Consumer consumer) { - this.urlPath = new UrlPath(path); - consumer.accept(this.urlPath); - } - - /** - * Allows to configure HTTP headers. - * @param consumer function to manipulate the headers - */ - public void headers(Consumer consumer) { - this.headers = new Request.RequestHeaders(); - consumer.accept(this.headers); - } - - /** - * Allows to configure HTTP cookies. - * @param consumer function to manipulate the cookies - */ - public void cookies(Consumer consumer) { - this.cookies = new Request.RequestCookies(); - consumer.accept(this.cookies); - } - - /** - * Allows to set matchers for the body. - * @param consumer function to manipulate the URL - */ - public void bodyMatchers(Consumer consumer) { - this.bodyMatchers = new BodyMatchers(); - consumer.accept(this.bodyMatchers); - } - - /** - * The URL of the contract. - * @param url url value - * @param consumer function to manipulate the URL - */ - public void url(Object url, @DelegatesTo(Url.class) Closure consumer) { - this.url = new Url(url); - consumer.setDelegate(this.url); - consumer.call(); - } - - /** - * URL to which the request will be sent. Allows to customize additional query - * parameters if needed - * @param url url value - * @param consumer function to manipulate the URL - */ - public void url(DslProperty url, @DelegatesTo(Url.class) Closure consumer) { - this.url = new Url(url); - consumer.setDelegate(this.url); - consumer.call(); - } - - /** - * URL to which the request will be sent. Allows to customize additional query. - * parameters if needed - * @param path url value - * @param consumer function to manipulate the URL - */ - public void urlPath(String path, @DelegatesTo(UrlPath.class) Closure consumer) { - this.urlPath = new UrlPath(path); - consumer.setDelegate(this.urlPath); - consumer.call(); - } - - /** - * URL to which the request will be sent. Allows to customize additional query. - * parameters if needed - * @param path url value - * @param consumer function to manipulate the URL - */ - public void urlPath(DslProperty path, @DelegatesTo(UrlPath.class) Closure consumer) { - this.urlPath = new UrlPath(path); - consumer.setDelegate(this.urlPath); - consumer.call(); - } - - /** - * Allows to configure HTTP headers. - * @param consumer function to manipulate the headers - */ - public void headers(@DelegatesTo(Headers.class) Closure consumer) { - this.headers = new Request.RequestHeaders(); - consumer.setDelegate(this.headers); - consumer.call(); - } - - /** - * Allows to configure HTTP cookies. - * @param consumer function to manipulate the cookies - */ - public void cookies(@DelegatesTo(Cookies.class) Closure consumer) { - this.cookies = new Request.RequestCookies(); - consumer.setDelegate(this.cookies); - consumer.call(); - } - - /** - * Allows to set matchers for the body. - * @param consumer function to manipulate the URL - */ - public void bodyMatchers(@DelegatesTo(BodyMatchers.class) Closure consumer) { - this.bodyMatchers = new BodyMatchers(); - consumer.setDelegate(this.bodyMatchers); - consumer.call(); - } - - static class RequestHeaders extends Headers { - - private final Common common = new Common(); - - @Override - public DslProperty matching(String value) { - return this.common.$( - this.common.c(this.common.regex(RegexpUtils.escapeSpecialRegexWithSingleEscape(value) + ".*")), - this.common.p(value)); - } - - } - - static class RequestCookies extends Cookies { - - private final Common common = new Common(); - - @Override - public DslProperty matching(String value) { - return this.common.$( - this.common.c(this.common.regex(RegexpUtils.escapeSpecialRegexWithSingleEscape(value) + ".*")), - this.common.p(value)); - } - - } - - private class ServerRequest extends Request { - - ServerRequest(Request enclosing, Request request) { - super(request); - } - - } - - private class ClientRequest extends Request { - - ClientRequest(Request enclosing, Request request) { - super(request); - } - - } - - private class ClientPatternValueDslProperty extends PatternValueDslProperty { - - @Override - protected ClientDslProperty createProperty(Pattern pattern, Object generatedValue) { - return new ClientDslProperty(pattern, generatedValue); - } - - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Response.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Response.java deleted file mode 100644 index 4761dfa33d..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Response.java +++ /dev/null @@ -1,790 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.function.Consumer; -import java.util.regex.Pattern; - -import groovy.lang.Closure; -import groovy.lang.DelegatesTo; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.spec.util.RegexpUtils; - -/** - * Represents the response side of the HTTP communication. - * - * @author Marcin Grzejszczak - * @author Tim Ysewyn - * @since 1.0.0 - */ -public class Response extends Common implements RegexCreatingProperty { - - private static final Log log = LogFactory.getLog(Response.class); - - private DslProperty status; - - private DslProperty delay; - - private Headers headers; - - private Cookies cookies; - - private Body body; - - private boolean async; - - private ResponseBodyMatchers bodyMatchers; - - private ServerPatternValueDslProperty property = new ServerPatternValueDslProperty(); - - public Response() { - } - - public Response(Response response) { - this.status = response.getStatus(); - this.headers = response.getHeaders(); - this.cookies = response.getCookies(); - this.body = response.getBody(); - } - - /** - * Allows to set the HTTP status. - * @param status HTTP status - */ - public void status(int status) { - this.status = toDslProperty(status); - } - - /** - * Allows to set the HTTP status. - * @param status HTTP status - */ - public void status(DslProperty status) { - this.status = toDslProperty(status); - } - - /** - * Allows set an HTTP body. - * @param body body to set - */ - public void body(Map body) { - this.body = new Body(convertObjectsToDslProperties(body)); - } - - /** - * Allows set an HTTP body. - * @param body body to set - */ - public void body(List body) { - this.body = new Body(convertObjectsToDslProperties(body)); - } - - /** - * Allows set an HTTP body. - * @param bodyAsValue body to set - */ - public void body(Object bodyAsValue) { - if (bodyAsValue instanceof List) { - body((List) bodyAsValue); - } - else { - this.body = new Body(bodyAsValue); - } - - } - - /** - * Allows to set a fixed delay of the response in milliseconds. - * @param timeInMilliseconds delay in millis - */ - public void fixedDelayMilliseconds(int timeInMilliseconds) { - this.delay = toDslProperty(timeInMilliseconds); - } - - /** - * Turns on the asynchronous mode for this contract. Used with MockMvc and the Servlet - * 3.0 features. - */ - public void async() { - this.async = true; - } - - @Override - public void assertThatSidesMatch(Object stubSide, Object testSide) { - if (stubSide instanceof OptionalProperty) { - throw new IllegalStateException("Optional can be used only in the test side of the response!"); - } - super.assertThatSidesMatch(stubSide, testSide); - } - - /** - * Allows to set a dynamic value for the given element. - * @param server server value - * @return dsl property - */ - public DslProperty value(ServerDslProperty server) { - Object dynamicValue = server.getServerValue(); - Object concreteValue = server.getClientValue(); - if (dynamicValue instanceof RegexProperty && server.isSingleValue()) { - return ((RegexProperty) dynamicValue).concreteClientDynamicProducer(); - } - return new DslProperty(concreteValue, dynamicValue); - } - - /** - * Allows to set a dynamic value for the given element. - * @param server server value - * @return dsl property - */ - public DslProperty $(ServerDslProperty server) { - return value(server); - } - - /** - * Allows to set a dynamic value for the given element. - * @param server server value - * @return dsl property - */ - public DslProperty value(Pattern server) { - return value(new RegexProperty(server)); - } - - /** - * Allows to set a dynamic value for the given element. - * @param server server value - * @return dsl property - */ - public DslProperty value(RegexProperty server) { - return value(new ServerDslProperty(server)); - } - - /** - * Allows to set a dynamic value for the given element. - * @param server server value - * @return dsl property - */ - public DslProperty $(RegexProperty server) { - return value(server); - } - - /** - * Allows to set a dynamic value for the given element. - * @param server server value - * @return dsl property - */ - public DslProperty $(Pattern server) { - return value(new RegexProperty(server)); - } - - @Override - public RegexProperty regexProperty(Object object) { - return new RegexProperty(object).concreteClientDynamicProducer(); - } - - /** - * Allows to reference entries from the request. - * @return from request object - */ - public FromRequest fromRequest() { - return new FromRequest(); - } - - /** - * Allows to set a dynamic value for the given element. - * @param client client value - * @param server server value - * @return dsl property - */ - @Override - public DslProperty value(ClientDslProperty client, ServerDslProperty server) { - if (client.getClientValue() instanceof RegexProperty) { - throw new IllegalStateException("You can't have a regular expression for the response on the client side"); - } - - return super.value(client, server); - } - - /** - * Allows to set a dynamic value for the given element. - * @param server server value - * @param client client value - * @return dsl property - */ - @Override - public DslProperty value(ServerDslProperty server, ClientDslProperty client) { - if (client.getClientValue() instanceof RegexProperty) { - throw new IllegalStateException("You can't have a regular expression for the response on the client side"); - } - - return super.value(server, client); - } - - public ServerPatternValueDslProperty getProperty() { - return property; - } - - public void setProperty(ServerPatternValueDslProperty property) { - this.property = property; - } - - public DslProperty getStatus() { - return status; - } - - public void setStatus(DslProperty status) { - this.status = status; - } - - public DslProperty getDelay() { - return delay; - } - - public void setDelay(DslProperty delay) { - this.delay = delay; - } - - public Headers getHeaders() { - return headers; - } - - public void setHeaders(Headers headers) { - this.headers = headers; - } - - public Cookies getCookies() { - return cookies; - } - - public void setCookies(Cookies cookies) { - this.cookies = cookies; - } - - public Body getBody() { - return body; - } - - public void setBody(Body body) { - this.body = body; - } - - public boolean getAsync() { - return async; - } - - public boolean isAsync() { - return async; - } - - public void setAsync(boolean async) { - this.async = async; - } - - public ResponseBodyMatchers getBodyMatchers() { - return bodyMatchers; - } - - public void setBodyMatchers(ResponseBodyMatchers bodyMatchers) { - this.bodyMatchers = bodyMatchers; - } - - @Override - public ServerDslProperty anyAlphaUnicode() { - return property.anyAlphaUnicode(); - } - - @Override - public ServerDslProperty anyAlphaNumeric() { - return property.anyAlphaNumeric(); - } - - @Override - public ServerDslProperty anyNumber() { - return property.anyNumber(); - } - - @Override - public ServerDslProperty anyInteger() { - return property.anyInteger(); - } - - @Override - public ServerDslProperty anyPositiveInt() { - return property.anyPositiveInt(); - } - - @Override - public ServerDslProperty anyDouble() { - return property.anyDouble(); - } - - @Override - public ServerDslProperty anyHex() { - return property.anyHex(); - } - - @Override - public ServerDslProperty aBoolean() { - return property.aBoolean(); - } - - @Override - public ServerDslProperty anyIpAddress() { - return property.anyIpAddress(); - } - - @Override - public ServerDslProperty anyHostname() { - return property.anyHostname(); - } - - @Override - public ServerDslProperty anyEmail() { - return property.anyEmail(); - } - - @Override - public ServerDslProperty anyUrl() { - return property.anyUrl(); - } - - @Override - public ServerDslProperty anyHttpsUrl() { - return property.anyHttpsUrl(); - } - - @Override - public ServerDslProperty anyUuid() { - return property.anyUuid(); - } - - @Override - public ServerDslProperty anyDate() { - return property.anyDate(); - } - - @Override - public ServerDslProperty anyDateTime() { - return property.anyDateTime(); - } - - @Override - public ServerDslProperty anyTime() { - return property.anyTime(); - } - - @Override - public ServerDslProperty anyIso8601WithOffset() { - return property.anyIso8601WithOffset(); - } - - @Override - public ServerDslProperty anyNonBlankString() { - return property.anyNonBlankString(); - } - - @Override - public ServerDslProperty anyNonEmptyString() { - return property.anyNonEmptyString(); - } - - @Override - public ServerDslProperty anyOf(String... values) { - return property.anyOf(values); - } - - public int CONTINUE() { - return HttpStatus.CONTINUE; - } - - public int SWITCHING_PROTOCOLS() { - return HttpStatus.SWITCHING_PROTOCOLS; - } - - public int PROCESSING() { - return HttpStatus.PROCESSING; - } - - public int CHECKPOINT() { - return HttpStatus.CHECKPOINT; - } - - public int OK() { - return HttpStatus.OK; - } - - public int CREATED() { - return HttpStatus.CREATED; - } - - public int ACCEPTED() { - return HttpStatus.ACCEPTED; - } - - public int NON_AUTHORITATIVE_INFORMATION() { - return HttpStatus.NON_AUTHORITATIVE_INFORMATION; - } - - public int NO_CONTENT() { - return HttpStatus.NO_CONTENT; - } - - public int RESET_CONTENT() { - return HttpStatus.RESET_CONTENT; - } - - public int PARTIAL_CONTENT() { - return HttpStatus.PARTIAL_CONTENT; - } - - public int MULTI_STATUS() { - return HttpStatus.MULTI_STATUS; - } - - public int ALREADY_REPORTED() { - return HttpStatus.ALREADY_REPORTED; - } - - public int IM_USED() { - return HttpStatus.IM_USED; - } - - public int MULTIPLE_CHOICES() { - return HttpStatus.MULTIPLE_CHOICES; - } - - public int MOVED_PERMANENTLY() { - return HttpStatus.MOVED_PERMANENTLY; - } - - public int FOUND() { - return HttpStatus.FOUND; - } - - public int SEE_OTHER() { - return HttpStatus.SEE_OTHER; - } - - public int NOT_MODIFIED() { - return HttpStatus.NOT_MODIFIED; - } - - public int TEMPORARY_REDIRECT() { - return HttpStatus.TEMPORARY_REDIRECT; - } - - public int PERMANENT_REDIRECT() { - return HttpStatus.PERMANENT_REDIRECT; - } - - public int BAD_REQUEST() { - return HttpStatus.BAD_REQUEST; - } - - public int UNAUTHORIZED() { - return HttpStatus.UNAUTHORIZED; - } - - public int PAYMENT_REQUIRED() { - return HttpStatus.PAYMENT_REQUIRED; - } - - public int FORBIDDEN() { - return HttpStatus.FORBIDDEN; - } - - public int NOT_FOUND() { - return HttpStatus.NOT_FOUND; - } - - public int METHOD_NOT_ALLOWED() { - return HttpStatus.METHOD_NOT_ALLOWED; - } - - public int NOT_ACCEPTABLE() { - return HttpStatus.NOT_ACCEPTABLE; - } - - public int PROXY_AUTHENTICATION_REQUIRED() { - return HttpStatus.PROXY_AUTHENTICATION_REQUIRED; - } - - public int REQUEST_TIMEOUT() { - return HttpStatus.REQUEST_TIMEOUT; - } - - public int CONFLICT() { - return HttpStatus.CONFLICT; - } - - public int GONE() { - return HttpStatus.GONE; - } - - public int LENGTH_REQUIRED() { - return HttpStatus.LENGTH_REQUIRED; - } - - public int PRECONDITION_FAILED() { - return HttpStatus.PRECONDITION_FAILED; - } - - public int PAYLOAD_TOO_LARGE() { - return HttpStatus.PAYLOAD_TOO_LARGE; - } - - public int URI_TOO_LONG() { - return HttpStatus.URI_TOO_LONG; - } - - public int UNSUPPORTED_MEDIA_TYPE() { - return HttpStatus.UNSUPPORTED_MEDIA_TYPE; - } - - public int REQUESTED_RANGE_NOT_SATISFIABLE() { - return HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE; - } - - public int EXPECTATION_FAILED() { - return HttpStatus.EXPECTATION_FAILED; - } - - public int I_AM_A_TEAPOT() { - return HttpStatus.I_AM_A_TEAPOT; - } - - public int UNPROCESSABLE_ENTITY() { - return HttpStatus.UNPROCESSABLE_ENTITY; - } - - public int LOCKED() { - return HttpStatus.LOCKED; - } - - public int FAILED_DEPENDENCY() { - return HttpStatus.FAILED_DEPENDENCY; - } - - public int UPGRADE_REQUIRED() { - return HttpStatus.UPGRADE_REQUIRED; - } - - public int PRECONDITION_REQUIRED() { - return HttpStatus.PRECONDITION_REQUIRED; - } - - public int TOO_MANY_REQUESTS() { - return HttpStatus.TOO_MANY_REQUESTS; - } - - public int REQUEST_HEADER_FIELDS_TOO_LARGE() { - return HttpStatus.REQUEST_HEADER_FIELDS_TOO_LARGE; - } - - public int UNAVAILABLE_FOR_LEGAL_REASONS() { - return HttpStatus.UNAVAILABLE_FOR_LEGAL_REASONS; - } - - public int INTERNAL_SERVER_ERROR() { - return HttpStatus.INTERNAL_SERVER_ERROR; - } - - public int NOT_IMPLEMENTED() { - return HttpStatus.NOT_IMPLEMENTED; - } - - public int BAD_GATEWAY() { - return HttpStatus.BAD_GATEWAY; - } - - public int SERVICE_UNAVAILABLE() { - return HttpStatus.SERVICE_UNAVAILABLE; - } - - public int GATEWAY_TIMEOUT() { - return HttpStatus.GATEWAY_TIMEOUT; - } - - public int HTTP_VERSION_NOT_SUPPORTED() { - return HttpStatus.HTTP_VERSION_NOT_SUPPORTED; - } - - public int VARIANT_ALSO_NEGOTIATES() { - return HttpStatus.VARIANT_ALSO_NEGOTIATES; - } - - public int INSUFFICIENT_STORAGE() { - return HttpStatus.INSUFFICIENT_STORAGE; - } - - public int LOOP_DETECTED() { - return HttpStatus.LOOP_DETECTED; - } - - public int BANDWIDTH_LIMIT_EXCEEDED() { - return HttpStatus.BANDWIDTH_LIMIT_EXCEEDED; - } - - public int NOT_EXTENDED() { - return HttpStatus.NOT_EXTENDED; - } - - public int NETWORK_AUTHENTICATION_REQUIRED() { - return HttpStatus.NETWORK_AUTHENTICATION_REQUIRED; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Response response = (Response) o; - return async == response.async && Objects.equals(status, response.status) - && Objects.equals(delay, response.delay) && Objects.equals(headers, response.headers) - && Objects.equals(cookies, response.cookies) && Objects.equals(body, response.body) - && Objects.equals(bodyMatchers, response.bodyMatchers); - } - - @Override - public int hashCode() { - return Objects.hash(status, delay, headers, cookies, body, async, bodyMatchers); - } - - @Override - public String toString() { - return "Response{" + "\nstatus=" + status + ", \n\tdelay=" + delay + ", \n\theaders=" + headers - + ", \n\tcookies=" + cookies + ", \n\tbody=" + body + ", \n\tasync=" + async + ", \n\tbodyMatchers=" - + bodyMatchers + '}'; - } - - /** - * Allows to configure HTTP headers. - * @param consumer function to manipulate the URL - */ - public void headers(Consumer consumer) { - this.headers = new Response.ResponseHeaders(); - consumer.accept(this.headers); - } - - /** - * Allows to configure HTTP cookies. - * @param consumer function to manipulate the URL - */ - public void cookies(Consumer consumer) { - this.cookies = new Response.ResponseCookies(); - consumer.accept(this.cookies); - } - - /** - * Allows to set matchers for the body. - * @param consumer function to manipulate the URL - */ - public void bodyMatchers(Consumer consumer) { - this.bodyMatchers = new ResponseBodyMatchers(); - consumer.accept(this.bodyMatchers); - } - - /** - * Allows to configure HTTP headers. - * @param consumer function to manipulate the URL - */ - public void headers(@DelegatesTo(Headers.class) Closure consumer) { - this.headers = new Response.ResponseHeaders(); - consumer.setDelegate(this.headers); - consumer.call(); - } - - /** - * Allows to configure HTTP cookies. - * @param consumer function to manipulate the URL - */ - public void cookies(@DelegatesTo(Cookies.class) Closure consumer) { - this.cookies = new Response.ResponseCookies(); - consumer.setDelegate(this.cookies); - consumer.call(); - } - - /** - * Allows to set matchers for the body. - * @param consumer function to manipulate the URL - */ - public void bodyMatchers(@DelegatesTo(ResponseBodyMatchers.class) Closure consumer) { - this.bodyMatchers = new ResponseBodyMatchers(); - consumer.setDelegate(this.bodyMatchers); - consumer.call(); - } - - static class ResponseHeaders extends Headers { - - private final Common common = new Common(); - - @Override - public DslProperty matching(final String value) { - return this.common.$( - this.common.p( - notEscaped(Pattern.compile(RegexpUtils.escapeSpecialRegexWithSingleEscape(value) + ".*"))), - this.common.c(value)); - } - - } - - static class ResponseCookies extends Cookies { - - private final Common common = new Common(); - - @Override - public DslProperty matching(final String value) { - return this.common.$( - this.common.p(this.common.regex(RegexpUtils.escapeSpecialRegexWithSingleEscape(value) + ".*")), - this.common.c(value)); - } - - } - - private class ServerResponse extends Response { - - ServerResponse(Response enclosing, Response request) { - super(request); - } - - } - - private class ClientResponse extends Response { - - ClientResponse(Response enclosing, Response request) { - super(request); - } - - } - - private class ServerPatternValueDslProperty extends PatternValueDslProperty { - - @Override - protected ServerDslProperty createProperty(Pattern pattern, Object generatedValue) { - return new ServerDslProperty(pattern, generatedValue); - } - - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ResponseBodyMatchers.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ResponseBodyMatchers.java deleted file mode 100644 index f25078c709..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ResponseBodyMatchers.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -/** - * Body matchers for the response side (output message, REST response). - * - * @author Marcin Grzejszczak - * @author Tim Ysewyn - * @since 1.0.3 - */ -public class ResponseBodyMatchers extends BodyMatchers { - - public MatchingTypeValue byType() { - MatchingTypeValue value = new MatchingTypeValue(); - value.setType(MatchingType.TYPE); - return value; - } - - public MatchingTypeValue byCommand(String execute) { - MatchingTypeValue value = new MatchingTypeValue(); - value.setType(MatchingType.COMMAND); - value.setValue(new ExecutionProperty(execute)); - return value; - } - - public MatchingTypeValue byNull() { - MatchingTypeValue value = new MatchingTypeValue(); - value.setType(MatchingType.NULL); - return value; - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ServerDslProperty.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ServerDslProperty.java deleted file mode 100644 index 614d77ed5c..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ServerDslProperty.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -/** - * Represents a server side {@link DslProperty}. - * - * @since 1.0.0 - */ -public class ServerDslProperty extends DslProperty { - - public ServerDslProperty(Object singleValue) { - super(singleValue); - } - - public ServerDslProperty(Object server, Object client) { - super(client, server); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ServerOutputMessage.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ServerOutputMessage.java deleted file mode 100644 index 20a01cdf76..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/ServerOutputMessage.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -class ServerOutputMessage extends OutputMessage { - - ServerOutputMessage(OutputMessage request) { - super(request); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Url.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Url.java deleted file mode 100644 index 02ac52eed1..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/Url.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.util.Objects; -import java.util.function.Consumer; - -import groovy.lang.Closure; -import groovy.lang.DelegatesTo; - -import org.springframework.cloud.contract.spec.util.ValidateUtils; - -/** - * Represents a URL that may contain query parameters. - * - * @since 1.0.0 - */ -public class Url extends DslProperty { - - private QueryParameters queryParameters; - - public Url(DslProperty prop) { - super(prop.getClientValue(), prop.getServerValue()); - ValidateUtils.validateServerValueIsAvailable(prop.getServerValue(), "Url"); - } - - public Url(Object url) { - super(url, testUrl(url)); - ValidateUtils.validateServerValueIsAvailable(url, "Url"); - } - - // Can be overridable by extensions - private static Object testUrl(Object url) { - return DslPropertyConverter.INSTANCE.testSide(url); - } - - public QueryParameters getQueryParameters() { - return queryParameters; - } - - public void setQueryParameters(QueryParameters queryParameters) { - this.queryParameters = queryParameters; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - if (!super.equals(o)) { - return false; - } - Url url = (Url) o; - return Objects.equals(queryParameters, url.queryParameters); - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), queryParameters); - } - - @Override - public String toString() { - return "Url{" + "\nqueryParameters=" + queryParameters + "} \n" + super.toString(); - } - - /** - * The query parameters part of the contract. - * @param consumer function to manipulate the query parameters - */ - public void queryParameters(Consumer consumer) { - this.queryParameters = new QueryParameters(); - consumer.accept(this.queryParameters); - } - - /** - * The query parameters part of the contract. - * @param consumer function to manipulate the query parameters - */ - public void queryParameters(@DelegatesTo(QueryParameters.class) Closure consumer) { - this.queryParameters = new QueryParameters(); - consumer.setDelegate(this.queryParameters); - consumer.call(); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/UrlHelper.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/UrlHelper.java deleted file mode 100644 index 5031775249..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/UrlHelper.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.util.regex.Pattern; - -/** - * Taken from https://gist.github.com/skeller88/5eb73dc0090d4ff1249a. - */ -final class UrlHelper { - - /** - * Example: "http". Also called 'protocol'. Scheme component is optional, even though - * the RFC doesn't make it optional. Since ((RegexProperty) this regex is validating a - * submitted callback url, which determines where the browser will navigate to after a - * successful authentication, the browser will use http or https for the scheme by - * default. Not borrowed from dperini in order to allow any scheme type. - */ - private static final String REGEX_SCHEME = "[A-Za-z][+-.\\w^_]*:"; - - private static final String HTTPS_REGEX_SCHEME = "https:"; - - private static final String REGEX_AUTHORATIVE_DECLARATION = "/{2}"; - - private static final String REGEX_USERINFO = "(?:\\S+(?::\\S*)?@)?"; - - private static final String REGEX_HOST = "(?:" - + "(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" + "|" - + "(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)" - + "(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*" - + "(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))|(?:localhost))"; - - private static final String REGEX_PORT = "(?::\\d{2,5})?"; - - private static final String REGEX_RESOURCE_PATH = "(?:/\\S*)?"; - - protected static final Pattern HTTPS_URL = Pattern.compile("^(?:" + HTTPS_REGEX_SCHEME - + REGEX_AUTHORATIVE_DECLARATION + REGEX_USERINFO + REGEX_HOST + REGEX_PORT + REGEX_RESOURCE_PATH + ")$"); - - protected static final Pattern URL = Pattern.compile("^(?:(?:" + REGEX_SCHEME + REGEX_AUTHORATIVE_DECLARATION + ")?" - + REGEX_USERINFO + REGEX_HOST + REGEX_PORT + REGEX_RESOURCE_PATH + ")$"); - - private UrlHelper() { - throw new IllegalStateException("Can't instantiate an utility class"); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/UrlPath.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/UrlPath.java deleted file mode 100644 index 1faff32128..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/internal/UrlPath.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -/** - * Represents a url path. Syntactic sugar when working with {@link QueryParameters}. It's - * logically equal to {@link Url}. - * - * @since 1.0.0 - */ -public class UrlPath extends Url { - - public UrlPath(Object path) { - super(path); - } - - public UrlPath(String path) { - super(path); - } - - public UrlPath(DslProperty path) { - super(path); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/util/RegexpUtils.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/util/RegexpUtils.java deleted file mode 100644 index 73438339b7..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/util/RegexpUtils.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.util; - -import java.util.regex.Pattern; - -/** - * Useful utility methods to work with regular expressions. - * - * @since 1.0.2 - */ -public final class RegexpUtils { - - private RegexpUtils() { - throw new IllegalStateException("Can't instantiate a utility class"); - } - - public static String escapeSpecialRegexChars(String str) { - return SPECIAL_REGEX_CHARS.matcher(str).replaceAll("\\\\\\\\$0"); - } - - public static String escapeSpecialRegexWithSingleEscape(String str) { - return SPECIAL_REGEX_CHARS.matcher(str).replaceAll("\\\\$0"); - } - - private static final Pattern SPECIAL_REGEX_CHARS = Pattern.compile("[{}()\\[\\].+*?^$\\\\|]"); - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/util/ValidateUtils.java b/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/util/ValidateUtils.java deleted file mode 100644 index f4525ef541..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/org/springframework/cloud/contract/spec/util/ValidateUtils.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.util; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.regex.Pattern; - -import org.springframework.cloud.contract.spec.internal.DslProperty; -import org.springframework.cloud.contract.spec.internal.MatchingStrategy; -import org.springframework.cloud.contract.spec.internal.RegexProperty; - -/** - * Checks the validity of DSL entries. - * - * @since 1.0.0 - */ -public final class ValidateUtils { - - private ValidateUtils() { - throw new IllegalStateException("Can't instantiate an utility class"); - } - - /** - * Allowed matching types on the server side. - */ - public static List ALLOWED_MATCHING_TYPES_ON_SERVER_SIDE = new ArrayList<>( - Arrays.asList(MatchingStrategy.Type.EQUAL_TO, MatchingStrategy.Type.ABSENT)); - - /** - * Validates if for given object the server value is present. - * @param value value to check - * @param msg potential exception message - * @return object if everything is fine - */ - public static Object validateServerValueIsAvailable(Object value, String msg) { - if (value instanceof Pattern) { - validateServerValue((Pattern) value, msg); - } - else if (value instanceof RegexProperty) { - RegexProperty property = (RegexProperty) value; - validateServerValue(property.getPattern(), msg); - } - else if (value instanceof MatchingStrategy) { - validateServerValue((MatchingStrategy) value, msg); - } - else if (value instanceof DslProperty) { - validateServerValue((DslProperty) value, msg); - } - else { - validateServerValue(value, msg); - } - - return value; - } - - public static void validateServerValue(Pattern pattern, String msg) { - throw new IllegalStateException(msg + " can\'t be a pattern for the server side"); - } - - public static void validateServerValue(MatchingStrategy matchingStrategy, String msg) { - if (!ALLOWED_MATCHING_TYPES_ON_SERVER_SIDE.contains(matchingStrategy.getType())) { - throw new IllegalStateException(msg + " can\'t be of a matching type: " - + String.valueOf(matchingStrategy.getType()) + " for the server side"); - } - - validateServerValue(matchingStrategy.getServerValue(), msg); - } - - public static void validateServerValue(DslProperty value, String msg) { - validateServerValue(value.getServerValue(), msg); - } - - public static void validateServerValue(Object value, String msg) { - // OK - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/main/java/repackaged/nl/flotsam/xeger/Xeger.java b/specs/spring-cloud-contract-spec-java/src/main/java/repackaged/nl/flotsam/xeger/Xeger.java deleted file mode 100644 index dbcc72c55a..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/main/java/repackaged/nl/flotsam/xeger/Xeger.java +++ /dev/null @@ -1,143 +0,0 @@ -/** - * Copyright 2009 Wilfred Springer - * Copyright 2012 Jason Pell - * Copyright 2013 Antonio García-Domínguez - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * https://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *

- * The class is bundled together with our code because it has not been - * released to any central repository. - */ - -package repackaged.nl.flotsam.xeger; - -import java.util.List; -import java.util.Random; - -import dk.brics.automaton.Automaton; -import dk.brics.automaton.RegExp; -import dk.brics.automaton.State; -import dk.brics.automaton.Transition; -import org.apache.commons.lang3.StringUtils; - -/** - * An object that will generate text from a regular expression. In a way, it's the - * opposite of a regular expression matcher: an instance of this class will produce text - * that is guaranteed to match the regular expression passed in. - * - * slight modifications by Marcin Grzejszczak - */ -public class Xeger { - - // Added by Marcin Grzejszczak - // may lead to stackoverflow when regex is unbounded - static int ITERATION_LIMIT = 200; - - private final Automaton automaton; - - private Random random; - - /** - * Constructs a new instance, accepting the regular expression and the randomizer. - * @param regex The regular expression. (Not null.) - * @param random The object that will randomize the way the String is generated. (Not - * null.) - * @throws IllegalArgumentException If the regular expression is invalid. - */ - public Xeger(String regex, Random random) { - assert regex != null; - assert random != null; - // https://stackoverflow.com/questions/1578789/how-do-i-generate-text-matching-a-regular-expression-from-a-regular-expression - String pattern = regex.replace("\\d", "[0-9]") // Used d=Digit - .replace("\\w", "[A-Za-z0-9_]") // Used =Word - .replace("\\s", "[ \t\r\n]"); // Used s="White"Space - this.automaton = new RegExp(pattern).toAutomaton(); - this.random = random; - String generatedCharsSysProp = System.getProperty("springCloudContractGeneratedCharsFromRegex"); - String generatedCharsEnvVar = System.getenv("SPRING_CLOUD_CONTRACT_GENERATED_CHARS_FROM_REGEX"); - if (StringUtils.isNotEmpty(generatedCharsSysProp)) { - ITERATION_LIMIT = Integer.parseInt(generatedCharsSysProp); - } - else if (StringUtils.isNotEmpty(generatedCharsEnvVar)) { - ITERATION_LIMIT = Integer.parseInt(generatedCharsEnvVar); - } - } - - /** - * As {@link Xeger#Xeger(String, java.util.Random)}, creating a - * {@link java.util.Random} instance implicityly. - * @param regex as string - */ - public Xeger(String regex) { - this(regex, new Random()); - } - - /** - * Generates a random number within the given bounds. - * @param min The minimum number (inclusive). - * @param max The maximum number (inclusive). - * @param random The object used as the randomizer. - * @return A random number in the given range. - */ - static int getRandomInt(int min, int max, Random random) { - // Use random.nextInt as it guarantees a uniform distribution - int maxForRandom = max - min + 1; - return random.nextInt(maxForRandom) + min; - } - - /** - * Generates a random String that is guaranteed to match the regular expression passed - * to the constructor. - * @return generated regexp - */ - public String generate() { - StringBuilder builder = new StringBuilder(); - int counter = 0; - generate(builder, this.automaton.getInitialState(), counter); - return builder.toString(); - } - - private void generate(StringBuilder builder, State state, int counter) { - if (counter >= ITERATION_LIMIT) { - return; - } - List transitions = state.getSortedTransitions(false); - if (transitions.size() == 0) { - assert state.isAccept(); - return; - } - int nroptions = state.isAccept() ? transitions.size() : transitions.size() - 1; - int option = Xeger.getRandomInt(0, nroptions, this.random); - if (state.isAccept() && option == 0) { // 0 is considered stop - return; - } - // Moving on to next transition - Transition transition = transitions.get(option - (state.isAccept() ? 1 : 0)); - appendChoice(builder, transition); - generate(builder, transition.getDest(), ++counter); - } - - private void appendChoice(StringBuilder builder, Transition transition) { - char c = (char) Xeger.getRandomInt(transition.getMin(), transition.getMax(), this.random); - builder.append(c); - } - - public Random getRandom() { - return this.random; - } - - public void setRandom(Random random) { - this.random = random; - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/test/groovy/org/springframework/cloud/contract/spec/internal/HttpHeadersTests.java b/specs/spring-cloud-contract-spec-java/src/test/groovy/org/springframework/cloud/contract/spec/internal/HttpHeadersTests.java deleted file mode 100644 index 1855393068..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/test/groovy/org/springframework/cloud/contract/spec/internal/HttpHeadersTests.java +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import org.assertj.core.api.BDDAssertions; -import org.junit.jupiter.api.Test; - -/** - * @author Tim Ysewyn - */ -class HttpHeadersTests { - - @Test - public void ACCEPT() { - BDDAssertions.then(HttpHeaders.ACCEPT).isEqualTo("Accept"); - } - - @Test - public void ACCEPT_CHARSET() { - BDDAssertions.then(HttpHeaders.ACCEPT_CHARSET).isEqualTo("Accept-Charset"); - } - - @Test - public void ACCEPT_ENCODING() { - BDDAssertions.then(HttpHeaders.ACCEPT_ENCODING).isEqualTo("Accept-Encoding"); - } - - @Test - public void ACCEPT_LANGUAGE() { - BDDAssertions.then(HttpHeaders.ACCEPT_LANGUAGE).isEqualTo("Accept-Language"); - } - - @Test - public void ACCEPT_RANGES() { - BDDAssertions.then(HttpHeaders.ACCEPT_RANGES).isEqualTo("Accept-Ranges"); - } - - @Test - public void ACCESS_CONTROL_ALLOW_CREDENTIALS() { - BDDAssertions.then(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS).isEqualTo("Access-Control-Allow-Credentials"); - } - - @Test - public void ACCESS_CONTROL_ALLOW_HEADERS() { - BDDAssertions.then(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS).isEqualTo("Access-Control-Allow-Headers"); - } - - @Test - public void ACCESS_CONTROL_ALLOW_METHODS() { - BDDAssertions.then(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS).isEqualTo("Access-Control-Allow-Methods"); - } - - @Test - public void ACCESS_CONTROL_ALLOW_ORIGIN() { - BDDAssertions.then(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN).isEqualTo("Access-Control-Allow-Origin"); - } - - @Test - public void ACCESS_CONTROL_EXPOSE_HEADERS() { - BDDAssertions.then(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS).isEqualTo("Access-Control-Expose-Headers"); - } - - @Test - public void ACCESS_CONTROL_MAX_AGE() { - BDDAssertions.then(HttpHeaders.ACCESS_CONTROL_MAX_AGE).isEqualTo("Access-Control-Max-Age"); - } - - @Test - public void ACCESS_CONTROL_REQUEST_HEADERS() { - BDDAssertions.then(HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS).isEqualTo("Access-Control-Request-Headers"); - } - - @Test - public void ACCESS_CONTROL_REQUEST_METHOD() { - BDDAssertions.then(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD).isEqualTo("Access-Control-Request-Method"); - } - - @Test - public void AGE() { - BDDAssertions.then(HttpHeaders.AGE).isEqualTo("Age"); - } - - @Test - public void ALLOW() { - BDDAssertions.then(HttpHeaders.ALLOW).isEqualTo("Allow"); - } - - @Test - public void AUTHORIZATION() { - BDDAssertions.then(HttpHeaders.AUTHORIZATION).isEqualTo("Authorization"); - } - - @Test - public void CACHE_CONTROL() { - BDDAssertions.then(HttpHeaders.CACHE_CONTROL).isEqualTo("Cache-Control"); - } - - @Test - public void CONNECTION() { - BDDAssertions.then(HttpHeaders.CONNECTION).isEqualTo("Connection"); - } - - @Test - public void CONTENT_ENCODING() { - BDDAssertions.then(HttpHeaders.CONTENT_ENCODING).isEqualTo("Content-Encoding"); - } - - @Test - public void CONTENT_DISPOSITION() { - BDDAssertions.then(HttpHeaders.CONTENT_DISPOSITION).isEqualTo("Content-Disposition"); - } - - @Test - public void CONTENT_LANGUAGE() { - BDDAssertions.then(HttpHeaders.CONTENT_LANGUAGE).isEqualTo("Content-Language"); - } - - @Test - public void CONTENT_LENGTH() { - BDDAssertions.then(HttpHeaders.CONTENT_LENGTH).isEqualTo("Content-Length"); - } - - @Test - public void CONTENT_LOCATION() { - BDDAssertions.then(HttpHeaders.CONTENT_LOCATION).isEqualTo("Content-Location"); - } - - @Test - public void CONTENT_RANGE() { - BDDAssertions.then(HttpHeaders.CONTENT_RANGE).isEqualTo("Content-Range"); - } - - @Test - public void CONTENT_TYPE() { - BDDAssertions.then(HttpHeaders.CONTENT_TYPE).isEqualTo("Content-Type"); - } - - @Test - public void COOKIE() { - BDDAssertions.then(HttpHeaders.COOKIE).isEqualTo("Cookie"); - } - - @Test - public void DATE() { - BDDAssertions.then(HttpHeaders.DATE).isEqualTo("Date"); - } - - @Test - public void ETAG() { - BDDAssertions.then(HttpHeaders.ETAG).isEqualTo("ETag"); - } - - @Test - public void EXPECT() { - BDDAssertions.then(HttpHeaders.EXPECT).isEqualTo("Expect"); - } - - @Test - public void EXPIRES() { - BDDAssertions.then(HttpHeaders.EXPIRES).isEqualTo("Expires"); - } - - @Test - public void FROM() { - BDDAssertions.then(HttpHeaders.FROM).isEqualTo("From"); - } - - @Test - public void HOST() { - BDDAssertions.then(HttpHeaders.HOST).isEqualTo("Host"); - } - - @Test - public void IF_MATCH() { - BDDAssertions.then(HttpHeaders.IF_MATCH).isEqualTo("If-Match"); - } - - @Test - public void IF_MODIFIED_SINCE() { - BDDAssertions.then(HttpHeaders.IF_MODIFIED_SINCE).isEqualTo("If-Modified-Since"); - } - - @Test - public void IF_NONE_MATCH() { - BDDAssertions.then(HttpHeaders.IF_NONE_MATCH).isEqualTo("If-None-Match"); - } - - @Test - public void IF_RANGE() { - BDDAssertions.then(HttpHeaders.IF_RANGE).isEqualTo("If-Range"); - } - - @Test - public void IF_UNMODIFIED_SINCE() { - BDDAssertions.then(HttpHeaders.IF_UNMODIFIED_SINCE).isEqualTo("If-Unmodified-Since"); - } - - @Test - public void LAST_MODIFIED() { - BDDAssertions.then(HttpHeaders.LAST_MODIFIED).isEqualTo("Last-Modified"); - } - - @Test - public void LINK() { - BDDAssertions.then(HttpHeaders.LINK).isEqualTo("Link"); - } - - @Test - public void LOCATION() { - BDDAssertions.then(HttpHeaders.LOCATION).isEqualTo("Location"); - } - - @Test - public void MAX_FORWARDS() { - BDDAssertions.then(HttpHeaders.MAX_FORWARDS).isEqualTo("Max-Forwards"); - } - - @Test - public void ORIGIN() { - BDDAssertions.then(HttpHeaders.ORIGIN).isEqualTo("Origin"); - } - - @Test - public void PRAGMA() { - BDDAssertions.then(HttpHeaders.PRAGMA).isEqualTo("Pragma"); - } - - @Test - public void PROXY_AUTHENTICATE() { - BDDAssertions.then(HttpHeaders.PROXY_AUTHENTICATE).isEqualTo("Proxy-Authenticate"); - } - - @Test - public void PROXY_AUTHORIZATION() { - BDDAssertions.then(HttpHeaders.PROXY_AUTHORIZATION).isEqualTo("Proxy-Authorization"); - } - - @Test - public void RANGE() { - BDDAssertions.then(HttpHeaders.RANGE).isEqualTo("Range"); - } - - @Test - public void REFERER() { - BDDAssertions.then(HttpHeaders.REFERER).isEqualTo("Referer"); - } - - @Test - public void RETRY_AFTER() { - BDDAssertions.then(HttpHeaders.RETRY_AFTER).isEqualTo("Retry-After"); - } - - @Test - public void SERVER() { - BDDAssertions.then(HttpHeaders.SERVER).isEqualTo("Server"); - } - - @Test - public void SET_COOKIE() { - BDDAssertions.then(HttpHeaders.SET_COOKIE).isEqualTo("Set-Cookie"); - } - - @Test - public void SET_COOKIE_2() { - BDDAssertions.then(HttpHeaders.SET_COOKIE_2).isEqualTo("Set-Cookie2"); - } - - @Test - public void TE() { - BDDAssertions.then(HttpHeaders.TE).isEqualTo("TE"); - } - - @Test - public void TRAILER() { - BDDAssertions.then(HttpHeaders.TRAILER).isEqualTo("Trailer"); - } - - @Test - public void TRANSFER_ENCODING() { - BDDAssertions.then(HttpHeaders.TRANSFER_ENCODING).isEqualTo("Transfer-Encoding"); - } - - @Test - public void UPGRADE() { - BDDAssertions.then(HttpHeaders.UPGRADE).isEqualTo("Upgrade"); - } - - @Test - public void USER_AGENT() { - BDDAssertions.then(HttpHeaders.USER_AGENT).isEqualTo("User-Agent"); - } - - @Test - public void VARY() { - BDDAssertions.then(HttpHeaders.VARY).isEqualTo("Vary"); - } - - @Test - public void VIA() { - BDDAssertions.then(HttpHeaders.VIA).isEqualTo("Via"); - } - - @Test - public void WARNING() { - BDDAssertions.then(HttpHeaders.WARNING).isEqualTo("Warning"); - } - - @Test - public void WWW_AUTHENTICATE() { - BDDAssertions.then(HttpHeaders.WWW_AUTHENTICATE).isEqualTo("WWW-Authenticate"); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/test/groovy/org/springframework/cloud/contract/spec/internal/HttpMethodsTests.java b/specs/spring-cloud-contract-spec-java/src/test/groovy/org/springframework/cloud/contract/spec/internal/HttpMethodsTests.java deleted file mode 100644 index d8cab7176e..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/test/groovy/org/springframework/cloud/contract/spec/internal/HttpMethodsTests.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import org.assertj.core.api.BDDAssertions; -import org.junit.jupiter.api.Test; - -/** - * @author Tim Ysewyn - */ -class HttpMethodsTests { - - @Test - public void GET() { - BDDAssertions.then(HttpMethods.GET).isEqualTo("GET"); - } - - @Test - public void HEAD() { - BDDAssertions.then(HttpMethods.HEAD).isEqualTo("HEAD"); - } - - @Test - public void POST() { - BDDAssertions.then(HttpMethods.POST).isEqualTo("POST"); - } - - @Test - public void PUT() { - BDDAssertions.then(HttpMethods.PUT).isEqualTo("PUT"); - } - - @Test - public void PATCH() { - BDDAssertions.then(HttpMethods.PATCH).isEqualTo("PATCH"); - } - - @Test - public void DELETE() { - BDDAssertions.then(HttpMethods.DELETE).isEqualTo("DELETE"); - } - - @Test - public void OPTIONS() { - BDDAssertions.then(HttpMethods.OPTIONS).isEqualTo("OPTIONS"); - } - - @Test - public void TRACE() { - BDDAssertions.then(HttpMethods.TRACE).isEqualTo("TRACE"); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/test/groovy/org/springframework/cloud/contract/spec/internal/MediaTypesTests.java b/specs/spring-cloud-contract-spec-java/src/test/groovy/org/springframework/cloud/contract/spec/internal/MediaTypesTests.java deleted file mode 100644 index a35754f573..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/test/groovy/org/springframework/cloud/contract/spec/internal/MediaTypesTests.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import org.assertj.core.api.BDDAssertions; -import org.junit.jupiter.api.Test; - -/** - * @author Tim Ysewyn - */ -class MediaTypesTests { - - @Test - public void ALL_VALUE() { - BDDAssertions.then(MediaTypes.ALL_VALUE).isEqualTo("*/*"); - } - - @Test - public void APPLICATION_ATOM_XML() { - BDDAssertions.then(MediaTypes.APPLICATION_ATOM_XML).isEqualTo("application/atom+xml"); - } - - @Test - public void APPLICATION_FORM_URLENCODED() { - BDDAssertions.then(MediaTypes.APPLICATION_FORM_URLENCODED).isEqualTo("application/x-www-form-urlencoded"); - } - - @Test - public void APPLICATION_JSON() { - BDDAssertions.then(MediaTypes.APPLICATION_JSON).isEqualTo("application/json"); - } - - @Test - public void APPLICATION_JSON_UTF8() { - BDDAssertions.then(MediaTypes.APPLICATION_JSON_UTF8).isEqualTo("application/json;charset=UTF-8"); - } - - @Test - public void APPLICATION_OCTET_STREAM() { - BDDAssertions.then(MediaTypes.APPLICATION_OCTET_STREAM).isEqualTo("application/octet-stream"); - } - - @Test - public void APPLICATION_PDF() { - BDDAssertions.then(MediaTypes.APPLICATION_PDF).isEqualTo("application/pdf"); - } - - @Test - public void APPLICATION_XHTML_XML() { - BDDAssertions.then(MediaTypes.APPLICATION_XHTML_XML).isEqualTo("application/xhtml+xml"); - } - - @Test - public void APPLICATION_XML() { - BDDAssertions.then(MediaTypes.APPLICATION_XML).isEqualTo("application/xml"); - } - - @Test - public void IMAGE_GIF() { - BDDAssertions.then(MediaTypes.IMAGE_GIF).isEqualTo("image/gif"); - } - - @Test - public void IMAGE_JPEG() { - BDDAssertions.then(MediaTypes.IMAGE_JPEG).isEqualTo("image/jpeg"); - } - - @Test - public void IMAGE_PNG() { - BDDAssertions.then(MediaTypes.IMAGE_PNG).isEqualTo("image/png"); - } - - @Test - public void MULTIPART_FORM_DATA() { - BDDAssertions.then(MediaTypes.MULTIPART_FORM_DATA).isEqualTo("multipart/form-data"); - } - - @Test - public void TEXT_HTML() { - BDDAssertions.then(MediaTypes.TEXT_HTML).isEqualTo("text/html"); - } - - @Test - public void TEXT_MARKDOWN() { - BDDAssertions.then(MediaTypes.TEXT_MARKDOWN).isEqualTo("text/markdown"); - } - - @Test - public void TEXT_PLAIN() { - BDDAssertions.then(MediaTypes.TEXT_PLAIN).isEqualTo("text/plain"); - } - - @Test - public void TEXT_XML() { - BDDAssertions.then(MediaTypes.TEXT_XML).isEqualTo("text/xml"); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/test/groovy/org/springframework/cloud/contract/spec/internal/MessagingHeadersTests.java b/specs/spring-cloud-contract-spec-java/src/test/groovy/org/springframework/cloud/contract/spec/internal/MessagingHeadersTests.java deleted file mode 100644 index 34930f691b..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/test/groovy/org/springframework/cloud/contract/spec/internal/MessagingHeadersTests.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import org.assertj.core.api.BDDAssertions; -import org.junit.jupiter.api.Test; - -/** - * @author Tim Ysewyn - */ -class MessagingHeadersTests { - - @Test - public void MESSAGING_CONTENT_TYPE() { - BDDAssertions.then(MessagingHeaders.MESSAGING_CONTENT_TYPE).isEqualTo("contentType"); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/test/groovy/org/springframework/cloud/contract/spec/internal/RegexPropertyTests.java b/specs/spring-cloud-contract-spec-java/src/test/groovy/org/springframework/cloud/contract/spec/internal/RegexPropertyTests.java deleted file mode 100644 index 47cd5d7f43..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/test/groovy/org/springframework/cloud/contract/spec/internal/RegexPropertyTests.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import java.nio.charset.StandardCharsets; -import java.util.regex.Pattern; - -import org.assertj.core.api.BDDAssertions; -import org.junit.jupiter.api.Test; - -class RegexPropertyTests { - - @Test - void should_generate_utf8_compliant_text_from_regex() { - RegexProperty regexProperty = new RegexProperty(Pattern.compile("......................")); - - String object = (String) regexProperty.generate(); - - String utf8EncodedString = new String(object.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8); - BDDAssertions.then(object).isEqualTo(utf8EncodedString); - } - - @Test - void should_generate_custom_charset_compliant_text_from_regex() { - RegexProperty regexProperty = new RegexProperty(Pattern.compile("......................")); - - String object = (String) regexProperty.asString(StandardCharsets.US_ASCII).generate(); - - String utf8EncodedString = new String(object.getBytes(StandardCharsets.US_ASCII), StandardCharsets.US_ASCII); - BDDAssertions.then(object).isEqualTo(utf8EncodedString); - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/test/groovy/repackaged/nl/flotsam/xeger/XegerTest.java b/specs/spring-cloud-contract-spec-java/src/test/groovy/repackaged/nl/flotsam/xeger/XegerTest.java deleted file mode 100644 index 08be62eed1..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/test/groovy/repackaged/nl/flotsam/xeger/XegerTest.java +++ /dev/null @@ -1,106 +0,0 @@ -/** - * Copyright 2009 Wilfred Springer - * Copyright 2012 Jason Pell - * Copyright 2013 Antonio García-Domínguez - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package repackaged.nl.flotsam.xeger; - -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -public class XegerTest { - - @Test - public void shouldGenerateTextCorrectly() { - String regex = "[ab]{4,6}c"; - Xeger generator = new Xeger(regex); - for (int i = 0; i < 100; i++) { - String text = generator.generate(); - assertThat(text.matches(regex)).isTrue(); - } - } - - @Test - public void shouldNotGenerateMoreThanTheLimit() { - String regex = "[ab]{5}"; - Xeger.ITERATION_LIMIT = 1; - Xeger generator = new Xeger(regex); - for (int i = 0; i < 100; i++) { - String text = generator.generate(); - assertThat(text.length() == 1).isTrue(); - } - } - - @Test - public void shouldGenerateTextCorrectlyForDigitSign() { - String regex = "\\d+"; - Xeger generator = new Xeger(regex); - for (int i = 0; i < 100; i++) { - String text = generator.generate(); - assertThat(text.matches(regex)).isTrue(); - } - } - - @Test - public void shouldGenerateTextCorrectlyForWordSign() { - String regex = "\\w+"; - Xeger generator = new Xeger(regex); - for (int i = 0; i < 100; i++) { - String text = generator.generate(); - assertThat(text.matches(regex)).isTrue(); - } - } - - @Test - public void shouldGenerateTextCorrectlyForWhiteSpaceSign() { - String regex = "\\s+"; - Xeger generator = new Xeger(regex); - for (int i = 0; i < 100; i++) { - String text = generator.generate(); - assertThat(text.matches(regex)).isTrue(); - } - } - - @Test - public void testRepeatableRegex() { - for (int x = 0; x < 1000; x++) { - Xeger generator = new Xeger("[ab]{4,6}c", new Random(1000)); - Xeger generator2 = new Xeger("[ab]{4,6}c", new Random(1000)); - - List firstRegexList = generateRegex(generator, 100); - List secondRegexList = generateRegex(generator2, 100); - - for (int i = 0; i < firstRegexList.size(); i++) { - assertThat(firstRegexList.get(i)).isEqualTo(secondRegexList.get(i)); - } - } - } - - private List generateRegex(Xeger generator, int count) { - List regexList = new ArrayList<>(); - for (int i = 0; i < count; i++) { - regexList.add(generator.generate()); - } - return regexList; - } - -} diff --git a/specs/spring-cloud-contract-spec-java/src/test/groovy/repackaged/nl/flotsam/xeger/XegerUtilsTest.java b/specs/spring-cloud-contract-spec-java/src/test/groovy/repackaged/nl/flotsam/xeger/XegerUtilsTest.java deleted file mode 100644 index 8705316413..0000000000 --- a/specs/spring-cloud-contract-spec-java/src/test/groovy/repackaged/nl/flotsam/xeger/XegerUtilsTest.java +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright 2009 Wilfred Springer - * Copyright 2012 Jason Pell - * Copyright 2013 Antonio García-Domínguez - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * https://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package repackaged.nl.flotsam.xeger; - -import java.util.Random; - -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -public class XegerUtilsTest { - - @Test - public void shouldGenerateRandomNumberCorrectly() { - Random random = new Random(); - for (int i = 0; i < 100; i++) { - int number = Xeger.getRandomInt(3, 7, random); - assertThat(number).isGreaterThanOrEqualTo(3).isLessThanOrEqualTo(7); - } - } - -} diff --git a/specs/spring-cloud-contract-spec-kotlin/README.adoc b/specs/spring-cloud-contract-spec-kotlin/README.adoc deleted file mode 100644 index 45e46ae714..0000000000 --- a/specs/spring-cloud-contract-spec-kotlin/README.adoc +++ /dev/null @@ -1,3 +0,0 @@ -=== Spring Cloud Contract Specification Kotlin - -This module contains the Contract specification written in Kotlin. \ No newline at end of file diff --git a/specs/spring-cloud-contract-spec-kotlin/pom.xml b/specs/spring-cloud-contract-spec-kotlin/pom.xml deleted file mode 100644 index e5281123e6..0000000000 --- a/specs/spring-cloud-contract-spec-kotlin/pom.xml +++ /dev/null @@ -1,109 +0,0 @@ - - - 4.0.0 - - org.springframework.cloud - spring-cloud-contract-parent - 4.1.0-SNAPSHOT - ../.. - - spring-cloud-contract-spec-kotlin - jar - Spring Cloud Contract Spec Kotlin - Spring Cloud Contract Spec Kotlin - - - org.springframework.cloud - spring-cloud-contract-spec-java - - - org.jetbrains.kotlin - kotlin-stdlib-jdk8 - - - org.jetbrains.kotlin - kotlin-compiler-embeddable - - - org.jetbrains.kotlin - kotlin-scripting-common - - - org.jetbrains.kotlin - kotlin-scripting-jvm - - - org.jetbrains.kotlin - kotlin-scripting-jvm-host - - - org.jetbrains.kotlin - kotlin-scripting-compiler-embeddable - - - org.jetbrains.kotlin - kotlin-script-util - - - org.springframework.boot - spring-boot-starter-test - test - - - org.jetbrains.kotlin - kotlin-test - test - - - - src/main/kotlin - src/test/kotlin - - - - kotlin-maven-plugin - ${contract.kotlin.version} - org.jetbrains.kotlin - - 17 - - - - compile - compile - - compile - - - - ${project.basedir}/src/main/kotlin - - - - - test-compile - test-compile - - test-compile - - - - ${project.basedir}/src/test/kotlin - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - - - diff --git a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/ContractDsl.kt b/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/ContractDsl.kt deleted file mode 100644 index 4315f902aa..0000000000 --- a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/ContractDsl.kt +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec - -import org.springframework.cloud.contract.spec.internal.* - -/** - * @author Tim Ysewyn - * @since 2.2.0 - */ -@ContractDslMarker -class ContractDsl { - - companion object { - fun contract(dsl: ContractDsl.() -> Unit): Contract = ContractDsl().apply(dsl).get() - } - - /** - * You can set the level of priority of this contract. If there are two contracts - * mapped for example to the same endpoint, then the one with greater priority should - * take precedence. A priority of 1 is highest and takes precedence over a priority of - * 2. - */ - var priority: Int? = null - - /** - * The label by which you'll reference the contract on the message consumer side. - */ - var label: String? = null - - /** - * Description of a contract. May be used in the documentation generation. - */ - var description: String? = null - - /** - * Name of the generated test / stub. If not provided then the file name will be used. - * If you have multiple contracts in a single file and you don't provide this value - * then a prefix will be added to the file with the index number while iterating over - * the collection of contracts. - * - * Remember to have a unique name for every single contract. Otherwise you might - * generate tests that have two identical methods or you will override the stubs. - */ - var name: String? = null - - /** - * Whether the contract should be ignored or not. - */ - var ignored: Boolean = false - - /** - * Whether the contract is in progress. It's not ignored, but the feature is not yet - * finished. Used together with the {@code generateStubs} option. - */ - var inProgress: Boolean = false - - /** - * The HTTP request part of the contract. - */ - var request: Request? = null - - /** - * The HTTP response part of the contract. - */ - var response: Response? = null - - /** - * The input side of a messaging contract. - */ - var input: Input? = null - - /** - * The output side of a messaging contract. - */ - var outputMessage: OutputMessage? = null - - /** - * Mapping of metadata. Can be used for external integrations. - */ - var metadata: Map = HashMap() - - /** - * The HTTP request part of the contract. - * @param configurer lambda to configure the HTTP request - */ - fun request(configurer: RequestDsl.() -> Unit) { - request = RequestDsl().apply(configurer).get() - } - - /** - * The HTTP response part of the contract. - * @param configurer lambda to configure the HTTP response - */ - fun response(configurer: ResponseDsl.() -> Unit) { - response = ResponseDsl().apply(configurer).get() - } - - /** - * The input part of the contract. - * @param configurer lambda to configure the input message - */ - fun input(configurer: InputDsl.() -> Unit) { - input = InputDsl().apply(configurer).get() - } - - /** - * The output part of the contract. - * @param configurer lambda to configure the output message - */ - fun outputMessage(configurer: OutputMessageDsl.() -> Unit) { - outputMessage = OutputMessageDsl().apply(configurer).get() - } - - /** - * The metadata. - * @param map metadata to set - */ - fun metadata(map: Map) { - metadata = metadata.plus(map) - } - - /** - * The metadata. - * @param metadata metadata to set - */ - fun metadata(vararg metadata: Pair) = metadata(metadata.toMap()) - - private fun get(): Contract { - val contract = Contract() - priority?.also { contract.priority = priority } - label?.also { contract.label = label } - description?.also { contract.description = description } - name?.also { contract.name = name } - contract.metadata = metadata - contract.ignored = ignored - contract.inProgress = inProgress - request?.also { contract.request = request } - response?.also { contract.response = response } - input?.also { contract.input = input } - outputMessage?.also { contract.outputMessage = outputMessage } - return contract - } - -} diff --git a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/ContractDslExtensions.kt b/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/ContractDslExtensions.kt deleted file mode 100644 index 8030e46698..0000000000 --- a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/ContractDslExtensions.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec - -import org.springframework.cloud.contract.spec.internal.DslProperty -import org.springframework.cloud.contract.spec.internal.QueryParameters -import org.springframework.cloud.contract.spec.internal.Url -import org.springframework.cloud.contract.spec.internal.UrlPath -import java.util.stream.Collectors - -/** - * Class extension functions which make our lives easier. - * @author Tim Ysewyn - * @since 2.2.0 - */ -infix fun Url.withQueryParameters(parameters: QueryParameters.() -> Unit) = apply { - queryParameters = QueryParameters().apply(parameters) -} - -infix fun UrlPath.withQueryParameters(parameters: QueryParameters.() -> Unit) = apply { - queryParameters = QueryParameters().apply(parameters) -} - -fun T.toDslProperty(): DslProperty = DslProperty(this) - -fun Map.toDslProperties(): Map> { - return entries.stream().collect(Collectors.toMap( - { entry -> entry.key }, - { entry -> entry.value.toDslProperty() }, - { t, _ -> throw IllegalStateException(String.format("Duplicate key %s", t)) }, - { LinkedHashMap>() } - )) -} - -fun List.toDslProperties(): List> { - return stream().map(Any::toDslProperty).collect(Collectors.toList()) -} \ No newline at end of file diff --git a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/BodyMatchersDsl.kt b/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/BodyMatchersDsl.kt deleted file mode 100644 index 98fec86fbc..0000000000 --- a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/BodyMatchersDsl.kt +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal - -import java.util.regex.Pattern - -/** - * Matching strategy of dynamic parts of the body. - * - * @author Tim Ysewyn - * @since 2.2.0 - */ -open class BodyMatchersDsl { - - private val jsonPathMatchers = LinkedHashMap() - private val xPathMatchers = LinkedHashMap() - - /** - * Adds a JSON path matcher. - * - * @param path The path. - * @param matcher The matcher. - */ - fun jsonPath(path: String, matcher: MatchingTypeValue) { - this.jsonPathMatchers[path] = matcher - } - - /** - * Adds an xPath matcher. - * - * @param path The path. - * @param matcher The matcher. - */ - fun xPath(path: String, matcher: MatchingTypeValue) { - this.xPathMatchers[path] = matcher - } - - /* HELPER VARIABLES */ - - val byDate - get() = MatchingTypeValue(MatchingType.DATE, RegexPatterns.isoDate()) - - val byTime - get() = MatchingTypeValue(MatchingType.TIME, RegexPatterns.isoTime()) - - val byTimestamp - get() = MatchingTypeValue(MatchingType.TIMESTAMP, RegexPatterns.isoDateTime()) - - val byEquality - get() = MatchingTypeValue(MatchingType.EQUALITY) - - /* HELPER FUNCTIONS */ - - fun byRegex(regex: String) = byRegex(Pattern.compile(regex)) - - fun byRegex(regex: RegexProperty) = RegexMatchingTypeValue(MatchingType.REGEX, regex) - - fun byRegex(regex: Pattern) = RegexMatchingTypeValue(MatchingType.REGEX, RegexProperty(regex)) - - fun byType(configurer: MatchingTypeValueHolder.() -> Unit): MatchingTypeValue = MatchingTypeValueHolder().apply(configurer).matchingTypeValue - - internal open fun get(): BodyMatchers = configureBodyMatchers(BodyMatchers()) - - internal fun configureBodyMatchers(bodyMatchers: T): T { - this.jsonPathMatchers.forEach(bodyMatchers::jsonPath) - this.xPathMatchers.forEach(bodyMatchers::xPath) - return bodyMatchers - } - -} \ No newline at end of file diff --git a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/CommonDsl.kt b/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/CommonDsl.kt deleted file mode 100644 index 7da61810ef..0000000000 --- a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/CommonDsl.kt +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal - -import java.io.File -import java.net.URISyntaxException -import java.nio.charset.Charset -import java.util.regex.Pattern - -/** - * Composed out of common variables and funtions. - * - * @author Tim Ysewyn - * @since 2.2.0 - */ -open class CommonDsl { - - /* HELPER VARIABLES */ - - /* REGEX */ - - val onlyAlphaUnicode: RegexProperty - get() = RegexPatterns.onlyAlphaUnicode() - - val alphaNumeric: RegexProperty - get() = RegexPatterns.alphaNumeric() - - val number: RegexProperty - get() = RegexPatterns.number() - - val positiveInt: RegexProperty - get() = RegexPatterns.positiveInt() - - val anyBoolean: RegexProperty - get() = RegexPatterns.anyBoolean() - - val anInteger: RegexProperty - get() = RegexPatterns.anInteger() - - val aDouble: RegexProperty - get() = RegexPatterns.aDouble() - - val ipAddress: RegexProperty - get() = RegexPatterns.ipAddress() - - val hostname: RegexProperty - get() = RegexPatterns.hostname() - - val email: RegexProperty - get() = RegexPatterns.email() - - val anUrl: RegexProperty - get() = RegexPatterns.url() - - val anHttpsUrl: RegexProperty - get() = RegexPatterns.httpsUrl() - - val uuid: RegexProperty - get() = RegexPatterns.uuid() - - val isoDate: RegexProperty - get() = RegexPatterns.isoDate() - - val isoDateTime: RegexProperty - get() = RegexPatterns.isoDateTime() - - val isoTime: RegexProperty - get() = RegexPatterns.isoTime() - - val iso8601WithOffset: RegexProperty - get() = RegexPatterns.iso8601WithOffset() - - val nonEmpty: RegexProperty - get() = RegexPatterns.nonEmpty() - - val nonBlank: RegexProperty - get() = RegexPatterns.nonBlank() - - /* HELPER FUNCTIONS */ - - /** - * Helper method to provide a better name for the consumer side. - * @param clientValue client value - * @return client dsl property - */ - fun client(clientValue: Any?) = ClientDslProperty(clientValue) - - /** - * Helper method to provide a better name for the consumer side. - * @param clientValue client value - * @return client dsl property - */ - fun c(clientValue: Any?) = ClientDslProperty(clientValue) - - /** - * Helper method to provide a better name for the consumer side. - * @param clientValue client value - * @return client dsl property - */ - fun consumer(clientValue: Any?) = ClientDslProperty(clientValue) - - /** - * Helper method to provide a better name for the consumer side. - * @param clientValue client value - * @return client dsl property - */ - fun stub(clientValue: Any?) = ClientDslProperty(clientValue) - - /** - * Helper method to provide a better name for the server side. - * @param serverValue server value - * @return server dsl property - */ - fun server(serverValue: Any?) = ServerDslProperty(serverValue) - - /** - * Helper method to provide a better name for the server side. - * @param serverValue server value - * @return server dsl property - */ - fun p(serverValue: Any?) = ServerDslProperty(serverValue) - - /** - * Helper method to provide a better name for the server side. - * @param serverValue server value - * @return server dsl property - */ - fun producer(serverValue: Any?) = ServerDslProperty(serverValue) - - /** - * Helper method to provide a better name for the server side. - * @param serverValue server value - * @return server dsl property - */ - fun test(serverValue: Any?) = ServerDslProperty(serverValue) - - /** - * Helper method to indicate an optional property. - * @param value the optional property value - * @return optional dsl property - */ - fun optional(value: Any?) = OptionalProperty(value) - - /** - * Helper method to indicate that a method needs to be executed during testing. - * @param commandToExecute the name of the method to execute - * @return execution dsl property - */ - fun execute(commandToExecute: String) = ExecutionProperty(commandToExecute) - - /** - * Read file contents as String. - * @param relativePath of the file to read - * @return String file contents - */ - fun file(relativePath: String) = file(relativePath, Charset.defaultCharset()) - - /** - * Read file contents as String with the given Charset. - * @param relativePath of the file to read - * @param charset to use for converting the bytes to String - * @return String file contents - */ - fun file(relativePath: String, charset: Charset) = FromFileProperty(fileLocation(relativePath), String::class.java, charset) - - /** - * Read file contents as String with the given Charset. - * @param relativePath of the file to read - * @param charset to use for converting the bytes to String - * @return String file contents - */ - fun fileAsBytes(relativePath: String) = FromFileProperty(fileLocation(relativePath), ByteArray::class.java) - - /** - * Read file contents as String using a default charset (mostly UTF-8). - * @param relativePath of the file to read - * @return Body DSL property with the content of the file as String - */ - fun bodyFromFile(relativePath: String) = bodyFromFile(relativePath, Charset.defaultCharset()) - - /** - * Read file contents as String using the provided file encoding. - * @param relativePath of the file to read - * @param charset of the file's encoding - * @return Body the body with the String as its content - */ - fun bodyFromFile(relativePath: String, charset: Charset) = Body(FromFileProperty(fileLocation(relativePath), String::class.java, charset)) - - /** - * Read file contents as bytes[]. - * @param relativePath of the file to read - * @return Body the body with the byte array as its content - */ - fun bodyFromFileAsBytes(relativePath: String) = Body(FromFileProperty(fileLocation(relativePath), ByteArray::class.java)) - - /** - * Read file contents as array of bytes. - * @param relativePath of the file to read - * @return file contents as an array of bytes - */ - private fun fileLocation(relativePath: String): File { - val resource = Thread.currentThread().contextClassLoader - .getResource(relativePath) ?: throw IllegalStateException("File [$relativePath] is not present") - try { - return File(resource.toURI()) - } catch (ex: URISyntaxException) { - throw IllegalStateException(ex) - } - } - - fun named(name: DslProperty, value: DslProperty) = NamedProperty(name, value) - - fun named(name: DslProperty, value: DslProperty, - contentType: DslProperty) = NamedProperty(name, value, contentType) - - fun named(namedMap: Map>) = NamedProperty(namedMap) - - /* REGEX FUNCTIONS */ - - fun regexProperty(value: Any) = RegexProperty(value) - - fun regex(regex: String) = regexProperty(Pattern.compile(regex)) - - fun regex(regex: Pattern) = regexProperty(regex) - - fun regex(regex: RegexProperty) = regex -} \ No newline at end of file diff --git a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/ContractDslMarker.kt b/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/ContractDslMarker.kt deleted file mode 100644 index 3b7482a36a..0000000000 --- a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/ContractDslMarker.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal - -/** - * Marker to narrow the scope inside the lamda. - * @author Tim Ysewyn - * @since 2.2.0 - */ -@DslMarker -annotation class ContractDslMarker \ No newline at end of file diff --git a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/CookiesDsl.kt b/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/CookiesDsl.kt deleted file mode 100644 index 38f974f30c..0000000000 --- a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/CookiesDsl.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal - -/** - * Represents the cookies when sending/receiving HTTP traffic. - * - * @author Tim Ysewyn - * @since 2.2.0 - */ -open class CookiesDsl : CommonDsl() { - - private val cookies = LinkedHashMap() - - open fun matching(value: Any?): Any? = value - - /** - * Adds a cookie. - * - * @param name The name of the cookie. - * @param value The value of the cookie. - */ - fun cookie(name: String, value: Any) { - this.cookies[name] = value - } - - internal fun get(): Cookies { - val cookies = Cookies() - this.cookies.forEach { (name, value) -> cookies.cookie(name, value) } - return cookies - } - -} diff --git a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/FromRequestDsl.kt b/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/FromRequestDsl.kt deleted file mode 100644 index f94ae2a63e..0000000000 --- a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/FromRequestDsl.kt +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal - -import org.springframework.cloud.contract.spec.ContractTemplate - -/** - * Helper class to reference the request body parameters. - * - * @author Tim Ysewyn - * @since 2.2.0 - */ -class FromRequestDsl { - - private val template: ContractTemplate = HandlebarsContractTemplate() - - /** - * @return URL path and query. - */ - fun url() = FromRequestDslProperty(template.escapedUrl()) - - /** - * First value of a query parameter e.g. request.query.search. - * @param key key for the query param - * @return dsl property - */ - fun query(key: String) = FromRequestDslProperty(template.escapedQuery(key)) - - /** - * nth value of a query parameter (zero indexed) e.g. request.query.search.[5]. - * @param key key for the query param - * @param index index of the query param - * @return dsl property - */ - fun query(key: String, index: Int) = FromRequestDslProperty(template.escapedQuery(key, index)) - - /** - * URL path. - * @return dsl property - */ - fun path() = FromRequestDslProperty(template.escapedPath()) - - /** - * nth value of a URL path (zero indexed) e.g. {{{ request.path.[2] }}}. - * @param index path index - * @return dsl property - */ - fun path(index: Int) = FromRequestDslProperty(template.escapedPath(index)) - - /** - * First value of a request header e.g. request.headers.X-Request-Id. - * @param key header key - * @return dsl property - */ - fun header(key: String) = FromRequestDslProperty(template.escapedHeader(key)) - - /** - * nth value of a request header (zero indexed) e.g. request.headers.X-Request-Id. - * @param key header key - * @param index header index - * @return dsl property - */ - fun header(key: String, index: Int) = FromRequestDslProperty(template.escapedHeader(key, index)) - - /** - * Returns the template for retrieving the first value of a cookie with certain key. - * @param key cookie key - * @return dsl property - */ - fun cookie(key: String) = FromRequestDslProperty(template.escapedCookie(key)) - - /** - * Request body text (avoid for non-text bodies). - * @return dsl property - */ - fun body() = FromRequestDslProperty(template.escapedBody()) - - /** - * Request body text for the given JsonPath. - * @param jsonPath json path body - * @return dsl property - */ - fun body(jsonPath: String) = FromRequestDslProperty(template.escapedBody(jsonPath)) - - /** - * Unescaped URL path and query. - * @return dsl property - */ - fun rawUrl() = FromRequestDslProperty(template.url()) - - /** - * Unescaped first value of a query parameter e.g. request.query.search. - * @param key query key - * @return dsl property - */ - fun rawQuery(key: String) = FromRequestDslProperty(template.query(key)) - - /** - * Unescaped nth value of a query parameter (zero indexed) e.g. - * request.query.search.[5]. - * @param key query key - * @param index query index - * @return dsl property - */ - fun rawQuery(key: String, index: Int) = FromRequestDslProperty(template.query(key, index)) - - /** - * Unescaped URL path. - * @return dsl property - */ - fun rawPath() = FromRequestDslProperty(template.path()) - - /** - * Unescaped nth value of a URL path (zero indexed) e.g. {{{ request.path.[2]. }}}. - * @param index path index - * @return dsl property - */ - fun rawPath(index: Int) = FromRequestDslProperty(template.path(index)) - - /** - * Unescaped first value of a request header e.g. request.headers.X-Request-Id. - * @param key header key - * @return dsl property - */ - fun rawHeader(key: String) = FromRequestDslProperty(template.header(key)) - - /** - * Unescaped nth value of a request header (zero indexed) e.g. - * request.headers.X-Request-Id. - * @param key header key - * @param index header index - * @return dsl property - */ - fun rawHeader(key: String, index: Int) = FromRequestDslProperty(template.header(key, index)) - - /** - * Unescaped Returns the template for retrieving the first value of a cookie with - * certain key. - * @param key cookie key - * @return dsl property - */ - fun rawCookie(key: String) = FromRequestDslProperty(template.cookie(key)) - - /** - * Unescaped Request body text (avoid for non-text bodies). - * @return dsl property - */ - fun rawBody() = FromRequestDslProperty(template.body()) - - /** - * Unescaped Request body text for the given JsonPath. - * @param jsonPath json path body - * @return dsl property - */ - fun rawBody(jsonPath: String) = FromRequestDslProperty(template.body(jsonPath)) - -} - -class FromRequestDslProperty(private val content: String) : DslProperty(content) { - // Overridden to support String interpolation - override fun toString(): String = content -} \ No newline at end of file diff --git a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/HeadersDsl.kt b/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/HeadersDsl.kt deleted file mode 100644 index fddbb9beb7..0000000000 --- a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/HeadersDsl.kt +++ /dev/null @@ -1,459 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal - -/** - * Represents the headers when sending/receiving HTTP traffic. - * - * @author Tim Ysewyn - * @since 2.2.0 - */ -open class HeadersDsl : CommonDsl() { - - internal val headers = LinkedHashMap() - - var accept: Any? - get() = headers[HttpHeaders.ACCEPT] - set(accept) = storeHeaderValue(HttpHeaders.ACCEPT, matching(accept)) - - var acceptCharset: Any? - get() = headers[HttpHeaders.ACCEPT_CHARSET] - set(acceptCharset) = storeHeaderValue(HttpHeaders.ACCEPT_CHARSET, acceptCharset) - - var acceptEncoding: Any? - get() = headers[HttpHeaders.ACCEPT_ENCODING] - set(acceptEncoding) = storeHeaderValue(HttpHeaders.ACCEPT_ENCODING, acceptEncoding) - - var acceptLanguage: Any? - get() = headers[HttpHeaders.ACCEPT_LANGUAGE] - set(acceptLanguage) = storeHeaderValue(HttpHeaders.ACCEPT_LANGUAGE, acceptLanguage) - - var acceptRanges: Any? - get() = headers[HttpHeaders.ACCEPT_RANGES] - set(acceptRanges) = storeHeaderValue(HttpHeaders.ACCEPT_RANGES, acceptRanges) - - var accessControlAllowCredentials: Any? - get() = headers[HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS] - set(accessControlAllowCredentials) = storeHeaderValue(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, accessControlAllowCredentials) - - var accessControlAllowHeaders: Any? - get() = headers[HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS] - set(accessControlAllowHeaders) = storeHeaderValue(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, accessControlAllowHeaders) - - var accessControlAllowMethods: Any? - get() = headers[HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS] - set(accessControlAllowMethods) = storeHeaderValue(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, accessControlAllowMethods) - - var accessControlAllowOrigin: Any? - get() = headers[HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN] - set(accessControlAllowOrigin) = storeHeaderValue(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, accessControlAllowOrigin) - - var accessControlExposeHeaders: Any? - get() = headers[HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS] - set(accessControlExposeHeaders) = storeHeaderValue(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, accessControlExposeHeaders) - - var accessControlMaxAge: Any? - get() = headers[HttpHeaders.ACCESS_CONTROL_MAX_AGE] - set(accessControlMaxAge) = storeHeaderValue(HttpHeaders.ACCESS_CONTROL_MAX_AGE, accessControlMaxAge) - - var accessControlRequestHeaders: Any? - get() = headers[HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS] - set(accessControlRequestHeaders) = storeHeaderValue(HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS, accessControlRequestHeaders) - - var accessControlRequestMethod: Any? - get() = headers[HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD] - set(accessControlRequestMethod) = storeHeaderValue(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, accessControlRequestMethod) - - var age: Any? - get() = headers[HttpHeaders.AGE] - set(age) = storeHeaderValue(HttpHeaders.AGE, age) - - var allow: Any? - get() = headers[HttpHeaders.ALLOW] - set(allow) = storeHeaderValue(HttpHeaders.ALLOW, allow) - - var authorization: Any? - get() = headers[HttpHeaders.AUTHORIZATION] - set(authorization) = storeHeaderValue(HttpHeaders.AUTHORIZATION, authorization) - - var cacheControl: Any? - get() = headers[HttpHeaders.CACHE_CONTROL] - set(cacheControl) = storeHeaderValue(HttpHeaders.CACHE_CONTROL, cacheControl) - - var connection: Any? - get() = headers[HttpHeaders.CONNECTION] - set(connection) = storeHeaderValue(HttpHeaders.CONNECTION, connection) - - var contentEncoding: Any? - get() = headers[HttpHeaders.CONTENT_ENCODING] - set(contentEncoding) = storeHeaderValue(HttpHeaders.CONTENT_ENCODING, contentEncoding) - - var contentDisposition: Any? - get() = headers[HttpHeaders.CONTENT_DISPOSITION] - set(contentDisposition) = storeHeaderValue(HttpHeaders.CONTENT_DISPOSITION, contentDisposition) - - var contentLanguage: Any? - get() = headers[HttpHeaders.CONTENT_LANGUAGE] - set(contentLanguage) = storeHeaderValue(HttpHeaders.CONTENT_LANGUAGE, contentLanguage) - - var contentLength: Any? - get() = headers[HttpHeaders.CONTENT_LENGTH] - set(contentLength) = storeHeaderValue(HttpHeaders.CONTENT_LENGTH, contentLength) - - var contentLocation: Any? - get() = headers[HttpHeaders.CONTENT_LOCATION] - set(contentLocation) = storeHeaderValue(HttpHeaders.CONTENT_LOCATION, contentLocation) - - var contentRange: Any? - get() = headers[HttpHeaders.CONTENT_RANGE] - set(contentRange) = storeHeaderValue(HttpHeaders.CONTENT_RANGE, contentRange) - - var contentType: Any? - get() = headers[HttpHeaders.CONTENT_TYPE] - set(contentType) = storeHeaderValue(HttpHeaders.CONTENT_TYPE, matching(contentType)) - - var cookie: Any? - get() = headers[HttpHeaders.COOKIE] - set(cookie) = storeHeaderValue(HttpHeaders.COOKIE, cookie) - - var date: Any? - get() = headers[HttpHeaders.DATE] - set(date) = storeHeaderValue(HttpHeaders.DATE, date) - - var etag: Any? - get() = headers[HttpHeaders.ETAG] - set(etag) = storeHeaderValue(HttpHeaders.ETAG, etag) - - var expect: Any? - get() = headers[HttpHeaders.EXPECT] - set(expect) = storeHeaderValue(HttpHeaders.EXPECT, expect) - - var expires: Any? - get() = headers[HttpHeaders.EXPIRES] - set(expires) = storeHeaderValue(HttpHeaders.EXPIRES, expires) - - var from: Any? - get() = headers[HttpHeaders.FROM] - set(from) = storeHeaderValue(HttpHeaders.FROM, from) - - var host: Any? - get() = headers[HttpHeaders.HOST] - set(host) = storeHeaderValue(HttpHeaders.HOST, host) - - var ifMatch: Any? - get() = headers[HttpHeaders.IF_MATCH] - set(ifMatch) = storeHeaderValue(HttpHeaders.IF_MATCH, ifMatch) - - var ifModifiedSince: Any? - get() = headers[HttpHeaders.IF_MODIFIED_SINCE] - set(ifModifiedSince) = storeHeaderValue(HttpHeaders.IF_MODIFIED_SINCE, ifModifiedSince) - - var ifNoneMatch: Any? - get() = headers[HttpHeaders.IF_NONE_MATCH] - set(ifNoneMatch) = storeHeaderValue(HttpHeaders.IF_NONE_MATCH, ifNoneMatch) - - var ifRange: Any? - get() = headers[HttpHeaders.IF_RANGE] - set(ifRange) = storeHeaderValue(HttpHeaders.IF_RANGE, ifRange) - - var ifUnmodifiedSince: Any? - get() = headers[HttpHeaders.IF_UNMODIFIED_SINCE] - set(ifUnmodifiedSince) = storeHeaderValue(HttpHeaders.IF_UNMODIFIED_SINCE, ifUnmodifiedSince) - - var lastModified: Any? - get() = headers[HttpHeaders.LAST_MODIFIED] - set(lastModified) = storeHeaderValue(HttpHeaders.LAST_MODIFIED, lastModified) - - var link: Any? - get() = headers[HttpHeaders.LINK] - set(link) = storeHeaderValue(HttpHeaders.LINK, link) - - var location: Any? - get() = headers[HttpHeaders.LOCATION] - set(location) = storeHeaderValue(HttpHeaders.LOCATION, location) - - var max_forwards: Any? - get() = headers[HttpHeaders.MAX_FORWARDS] - set(max_forwards) = storeHeaderValue(HttpHeaders.MAX_FORWARDS, max_forwards) - - var origin: Any? - get() = headers[HttpHeaders.ORIGIN] - set(origin) = storeHeaderValue(HttpHeaders.ORIGIN, origin) - - var pragma: Any? - get() = headers[HttpHeaders.PRAGMA] - set(pragma) = storeHeaderValue(HttpHeaders.PRAGMA, pragma) - - var proxyAuthenticate: Any? - get() = headers[HttpHeaders.PROXY_AUTHENTICATE] - set(proxyAuthenticate) = storeHeaderValue(HttpHeaders.PROXY_AUTHENTICATE, proxyAuthenticate) - - var proxyAuthorization: Any? - get() = headers[HttpHeaders.PROXY_AUTHORIZATION] - set(proxyAuthorization) = storeHeaderValue(HttpHeaders.PROXY_AUTHORIZATION, proxyAuthorization) - - var range: Any? - get() = headers[HttpHeaders.RANGE] - set(range) = storeHeaderValue(HttpHeaders.RANGE, range) - - var referer: Any? - get() = headers[HttpHeaders.REFERER] - set(referer) = storeHeaderValue(HttpHeaders.REFERER, referer) - - var retryAfter: Any? - get() = headers[HttpHeaders.RETRY_AFTER] - set(retryAfter) = storeHeaderValue(HttpHeaders.RETRY_AFTER, retryAfter) - - var server: Any? - get() = headers[HttpHeaders.SERVER] - set(server) = storeHeaderValue(HttpHeaders.SERVER, server) - - var setCookie: Any? - get() = headers[HttpHeaders.SET_COOKIE] - set(setCookie) = storeHeaderValue(HttpHeaders.SET_COOKIE, setCookie) - - var setCookie2: Any? - get() = headers[HttpHeaders.SET_COOKIE_2] - set(setCookie2) = storeHeaderValue(HttpHeaders.SET_COOKIE_2, setCookie2) - - var te: Any? - get() = headers[HttpHeaders.TE] - set(te) = storeHeaderValue(HttpHeaders.TE, te) - - var trailer: Any? - get() = headers[HttpHeaders.TRAILER] - set(trailer) = storeHeaderValue(HttpHeaders.TRAILER, trailer) - - var transferEncoding: Any? - get() = headers[HttpHeaders.TRANSFER_ENCODING] - set(transferEncoding) = storeHeaderValue(HttpHeaders.TRANSFER_ENCODING, transferEncoding) - - var upgrade: Any? - get() = headers[HttpHeaders.UPGRADE] - set(upgrade) = storeHeaderValue(HttpHeaders.UPGRADE, upgrade) - - var user_agent: Any? - get() = headers[HttpHeaders.USER_AGENT] - set(user_agent) = storeHeaderValue(HttpHeaders.USER_AGENT, user_agent) - - var vary: Any? - get() = headers[HttpHeaders.VARY] - set(vary) = storeHeaderValue(HttpHeaders.VARY, vary) - - var via: Any? - get() = headers[HttpHeaders.VIA] - set(via) = storeHeaderValue(HttpHeaders.VIA, via) - - var warning: Any? - get() = headers[HttpHeaders.WARNING] - set(warning) = storeHeaderValue(HttpHeaders.WARNING, warning) - - var wwwAuthenticate: Any? - get() = headers[HttpHeaders.WWW_AUTHENTICATE] - set(wwwAuthenticate) = storeHeaderValue(HttpHeaders.WWW_AUTHENTICATE, wwwAuthenticate) - - var messagingContentType: Any? - get() = headers[MessagingHeaders.MESSAGING_CONTENT_TYPE] - set(messagingContentType) = storeHeaderValue(MessagingHeaders.MESSAGING_CONTENT_TYPE, matching(messagingContentType)) - - open fun matching(value: Any?): Any? = value - - private fun storeHeaderValue(header: String, value: Any?) { - value?.also { headers[header] = value } - } - - /* HELPER VARIABLES */ - - /* HTTP HEADERS */ - - val ACCEPT = HttpHeaders.ACCEPT - - val ACCEPT_CHARSET = HttpHeaders.ACCEPT_CHARSET - - val ACCEPT_ENCODING = HttpHeaders.ACCEPT_ENCODING - - val ACCEPT_LANGUAGE = HttpHeaders.ACCEPT_LANGUAGE - - val ACCEPT_RANGES = HttpHeaders.ACCEPT_RANGES - - val ACCESS_CONTROL_ALLOW_CREDENTIALS = HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS - - val ACCESS_CONTROL_ALLOW_HEADERS = HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS - - val ACCESS_CONTROL_ALLOW_METHODS = HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS - - val ACCESS_CONTROL_ALLOW_ORIGIN = HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN - - val ACCESS_CONTROL_EXPOSE_HEADERS = HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS - - val ACCESS_CONTROL_MAX_AGE = HttpHeaders.ACCESS_CONTROL_MAX_AGE - - val ACCESS_CONTROL_REQUEST_HEADERS = HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS - - val ACCESS_CONTROL_REQUEST_METHOD = HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD - - val AGE = HttpHeaders.AGE - - val ALLOW = HttpHeaders.ALLOW - - val AUTHORIZATION = HttpHeaders.AUTHORIZATION - - val CACHE_CONTROL = HttpHeaders.CACHE_CONTROL - - val CONNECTION = HttpHeaders.CONNECTION - - val CONTENT_ENCODING = HttpHeaders.CONTENT_ENCODING - - val CONTENT_DISPOSITION = HttpHeaders.CONTENT_DISPOSITION - - val CONTENT_LANGUAGE = HttpHeaders.CONTENT_LANGUAGE - - val CONTENT_LENGTH = HttpHeaders.CONTENT_LENGTH - - val CONTENT_LOCATION = HttpHeaders.CONTENT_LOCATION - - val CONTENT_RANGE = HttpHeaders.CONTENT_RANGE - - val CONTENT_TYPE = HttpHeaders.CONTENT_TYPE - - val COOKIE = HttpHeaders.COOKIE - - val DATE = HttpHeaders.DATE - - val ETAG = HttpHeaders.ETAG - - val EXPECT = HttpHeaders.EXPECT - - val EXPIRES = HttpHeaders.EXPIRES - - val FROM = HttpHeaders.FROM - - val HOST = HttpHeaders.HOST - - val IF_MATCH = HttpHeaders.IF_MATCH - - val IF_MODIFIED_SINCE = HttpHeaders.IF_MODIFIED_SINCE - - val IF_NONE_MATCH = HttpHeaders.IF_NONE_MATCH - - val IF_RANGE = HttpHeaders.IF_RANGE - - val IF_UNMODIFIED_SINCE = HttpHeaders.IF_UNMODIFIED_SINCE - - val LAST_MODIFIED = HttpHeaders.LAST_MODIFIED - - val LINK = HttpHeaders.LINK - - val LOCATION = HttpHeaders.LOCATION - - val MAX_FORWARDS = HttpHeaders.MAX_FORWARDS - - val ORIGIN = HttpHeaders.ORIGIN - - val PRAGMA = HttpHeaders.PRAGMA - - val PROXY_AUTHENTICATE = HttpHeaders.PROXY_AUTHENTICATE - - val PROXY_AUTHORIZATION = HttpHeaders.PROXY_AUTHORIZATION - - val RANGE = HttpHeaders.RANGE - - val REFERER = HttpHeaders.REFERER - - val RETRY_AFTER = HttpHeaders.RETRY_AFTER - - val SERVER = HttpHeaders.SERVER - - val SET_COOKIE = HttpHeaders.SET_COOKIE - - val SET_COOKIE_2 = HttpHeaders.SET_COOKIE_2 - - val TE = HttpHeaders.TE - - val TRAILER = HttpHeaders.TRAILER - - val TRANSFER_ENCODING = HttpHeaders.TRANSFER_ENCODING - - val UPGRADE = HttpHeaders.UPGRADE - - val USER_AGENT = HttpHeaders.USER_AGENT - - val VARY = HttpHeaders.VARY - - val VIA = HttpHeaders.VIA - - val WARNING = HttpHeaders.WARNING - - val WWW_AUTHENTICATE = HttpHeaders.WWW_AUTHENTICATE - - /* MESSAGING HEADERS */ - - val MESSAGING_CONTENT_TYPE = MessagingHeaders.MESSAGING_CONTENT_TYPE - - /* MEDIA TYPES */ - - val ALL_VALUE = MediaTypes.ALL_VALUE - - val APPLICATION_ATOM_XML = MediaTypes.APPLICATION_ATOM_XML - - val APPLICATION_FORM_URLENCODED = MediaTypes.APPLICATION_FORM_URLENCODED - - val APPLICATION_JSON = MediaTypes.APPLICATION_JSON - - val APPLICATION_JSON_UTF8 = MediaTypes.APPLICATION_JSON_UTF8 - - val APPLICATION_OCTET_STREAM = MediaTypes.APPLICATION_OCTET_STREAM - - val APPLICATION_PDF = MediaTypes.APPLICATION_PDF - - val APPLICATION_XHTML_XML = MediaTypes.APPLICATION_XHTML_XML - - val APPLICATION_XML = MediaTypes.APPLICATION_XML - - val IMAGE_GIF = MediaTypes.IMAGE_GIF - - val IMAGE_JPEG = MediaTypes.IMAGE_JPEG - - val IMAGE_PNG = MediaTypes.IMAGE_PNG - - val MULTIPART_FORM_DATA = MediaTypes.MULTIPART_FORM_DATA - - val TEXT_HTML = MediaTypes.TEXT_HTML - - val TEXT_MARKDOWN = MediaTypes.TEXT_MARKDOWN - - val TEXT_PLAIN = MediaTypes.TEXT_PLAIN - - val TEXT_XML = MediaTypes.TEXT_XML - - /** - * Adds a header. - * - * @param name The name of the header. - * @param value The value of the header. - */ - fun header(name: String, value: Any) { - this.headers[name] = value - } - - internal fun get(): Headers { - val headers = Headers() - this.headers.forEach { (key, value) -> headers.header(key, value) } - return headers - } - -} diff --git a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/InputDsl.kt b/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/InputDsl.kt deleted file mode 100644 index 33dcc3a0e9..0000000000 --- a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/InputDsl.kt +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal - -import org.springframework.cloud.contract.spec.toDslProperty -import java.util.regex.Pattern - -/** - * Represents an input for messaging. - * The input can be a message or some action inside the application. - * - * @author Tim Ysewyn - * @since 2.2.0 - */ -@ContractDslMarker -class InputDsl : CommonDsl() { - - private val delegate = Input() - - /** - * Function that needs to be executed to trigger action in the system. - */ - var triggeredBy: String? = null - - /** - * Function that needs to be executed after the message has been received/processed by the system. - */ - var assertThat: String? = null - - /* HELPER VARIABLES */ - - val anyAlphaUnicode: ClientDslProperty - get() = delegate.anyAlphaUnicode() - - val anyAlphaNumeric: ClientDslProperty - get() = delegate.anyAlphaNumeric() - - val anyNumber: ClientDslProperty - get() = delegate.anyNumber() - - val anyInteger: ClientDslProperty - get() = delegate.anyInteger() - - val anyPositiveInt: ClientDslProperty - get() = delegate.anyPositiveInt() - - val anyDouble: ClientDslProperty - get() = delegate.anyDouble() - - val anyHex: ClientDslProperty - get() = delegate.anyHex() - - val aBoolean: ClientDslProperty - get() = delegate.aBoolean() - - val anyIpAddress: ClientDslProperty - get() = delegate.anyIpAddress() - - val anyHostname: ClientDslProperty - get() = delegate.anyHostname() - - val anyEmail: ClientDslProperty - get() = delegate.anyEmail() - - val anyUrl: ClientDslProperty - get() = delegate.anyUrl() - - val anyHttpsUrl: ClientDslProperty - get() = delegate.anyHttpsUrl() - - val anyUuid: ClientDslProperty - get() = delegate.anyUuid() - - val anyDate: ClientDslProperty - get() = delegate.anyDate() - - val anyDateTime: ClientDslProperty - get() = delegate.anyDateTime() - - val anyTime: ClientDslProperty - get() = delegate.anyTime() - - val anyIso8601WithOffset: ClientDslProperty - get() = delegate.anyIso8601WithOffset() - - val anyNonBlankString: ClientDslProperty - get() = delegate.anyNonBlankString() - - val anyNonEmptyString: ClientDslProperty - get() = delegate.anyNonEmptyString() - - /* HELPER FUNCTIONS */ - - fun value(value: DslProperty): DslProperty = delegate.value(value) - - fun v(value: DslProperty): DslProperty = delegate.value(value) - - fun value(value: Pattern): DslProperty = delegate.value(value) - - fun v(value: Pattern): DslProperty = delegate.value(value) - - fun value(value: RegexProperty): DslProperty = delegate.value(value) - - fun v(value: RegexProperty): DslProperty = delegate.value(value) - - fun value(value: Any?): DslProperty = delegate.value(value) - - fun v(value: Any?): DslProperty = delegate.value(value) - - fun value(client: ClientDslProperty, server: ServerDslProperty): DslProperty = delegate.value(client, server) - - fun v(client: ClientDslProperty, server: ServerDslProperty): DslProperty = delegate.value(client, server) - - fun value(server: ServerDslProperty, client: ClientDslProperty): DslProperty = delegate.value(client, server) - - fun v(server: ServerDslProperty, client: ClientDslProperty): DslProperty = delegate.value(client, server) - - fun anyOf(vararg values: String?) = delegate.anyOf(*values) - - internal fun get(): Input { - val input = Input() - triggeredBy?.also { input.triggeredBy(triggeredBy) } - assertThat?.also { input.assertThat(assertThat) } - return input - } -} diff --git a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/KotlinContractConverter.kt b/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/KotlinContractConverter.kt deleted file mode 100644 index d332462f6d..0000000000 --- a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/KotlinContractConverter.kt +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal - -import org.apache.commons.lang3.ObjectUtils -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.spec.ContractConverter -import java.io.File -import java.net.URLClassLoader.newInstance -import java.util.concurrent.atomic.AtomicInteger -import kotlin.script.experimental.api.EvaluationResult -import kotlin.script.experimental.api.ResultValue -import kotlin.script.experimental.api.ResultWithDiagnostics -import kotlin.script.experimental.api.ScriptCompilationConfiguration -import kotlin.script.experimental.host.toScriptSource -import kotlin.script.experimental.jvm.dependenciesFromCurrentContext -import kotlin.script.experimental.jvm.jvm -import kotlin.script.experimental.jvmhost.BasicJvmScriptingHost - -/** - * Converter that will convert the Kotlin DSL to Java DSL. - * - * @author Tim Ysewyn - * @since 2.2.0 - */ -class KotlinContractConverter : ContractConverter> { - - private val ext = "kts" - - constructor() { - // Sets an {@code idea.use.native.fs.for.win} system property to {@code false} - // to disable a native engine discovery for Windows: may be resolved in the future Kotlin versions. - System.setProperty("idea.use.native.fs.for.win", "false") - } - - override fun isAccepted(file: File): Boolean { - return ext == file.extension - } - - override fun convertFrom(file: File): Collection { - val eval = withUpdatedClassloader(file) { - BasicJvmScriptingHost().eval(file.toScriptSource(), ScriptWithCurrentClasspathConfiguration(), null) - } - when (eval) { - is ResultWithDiagnostics.Success<*> -> { - val contracts = when (val parsedValue = ((eval.value as EvaluationResult).returnValue as ResultValue.Value).value) { - is Contract -> listOf(parsedValue) - is Iterable<*> -> parsedValue.filterIsInstance(Contract::class.java) - is Array<*> -> parsedValue.filterIsInstance(Contract::class.java) - else -> emptyList() - } - - return withName(file, contracts) - } - - else -> throw IllegalStateException("Failed to parse kotlin script due to ${(eval as ResultWithDiagnostics.Failure).reports}") - } - } - - private fun withName(file: File, contracts: Collection): Collection { - val counter = AtomicInteger(0) - return contracts.onEach { contract -> - if (ObjectUtils.isEmpty(contract.name)) { - contract.name = defaultContractName(file, contracts, counter.get()) - } - counter.incrementAndGet() - } - } - - private fun defaultContractName(file: File, contracts: Collection<*>, counter: Int): String { - val lastIndexOfDot = file.name.lastIndexOf(".") - val tillExtension = file.name.substring(0, lastIndexOfDot) - return tillExtension + if (counter > 0 || contracts.size > 1) "_$counter" else "" - } - - override fun convertTo(contract: Collection) = contract.toList() - - private fun withUpdatedClassloader(file: File, block: ClassLoader.() -> Any): Any { - val currentClassLoader = Thread.currentThread().contextClassLoader - try { - val tempClassLoader = newInstance(arrayOf(file.parentFile.toURI().toURL()), currentClassLoader) - Thread.currentThread().contextClassLoader = tempClassLoader - return tempClassLoader.block() - } finally { - Thread.currentThread().contextClassLoader = currentClassLoader - } - } - - class ScriptWithCurrentClasspathConfiguration : ScriptCompilationConfiguration( - { - jvm { - // Extract the whole classpath from context classloader and use it as dependencies - dependenciesFromCurrentContext(wholeClasspath = true) - } - } - ) -} diff --git a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/MultipartDsl.kt b/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/MultipartDsl.kt deleted file mode 100644 index ce92a2a8cf..0000000000 --- a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/MultipartDsl.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal - -import org.springframework.cloud.contract.spec.toDslProperty - -/** - * Represents the content when sending multipart HTTP requests. - * - * @author Tim Ysewyn - * @since 2.2.0 - */ -class MultipartDsl { - - private val fields = LinkedHashMap>() - - fun field(name: String, content: Any) { - this.fields[name] = content.toDslProperty() - } - - internal fun get(): Multipart { - return Multipart(fields) - } - -} \ No newline at end of file diff --git a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/OutputMessageDsl.kt b/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/OutputMessageDsl.kt deleted file mode 100644 index 91150efd92..0000000000 --- a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/OutputMessageDsl.kt +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal - -import org.springframework.cloud.contract.spec.toDslProperties -import org.springframework.cloud.contract.spec.toDslProperty -import java.util.regex.Pattern - -/** - * Represents an output for messaging. - * Used for verifying the body and headers that are sent. - * - * @author Tim Ysewyn - * @since 2.2.0 - */ -@ContractDslMarker -class OutputMessageDsl : CommonDsl() { - - private val delegate = OutputMessage() - - /** - * Name of a destination to which a message should be sent. - */ - var sentTo: DslProperty? = null - - /** - * The message headers part of the contract. - */ - var headers: Headers? = null - - /** - * Name of a destination from which message would come to trigger action in the - * system. - */ - var body: DslProperty? = null - - /** - * Function that needs to be executed after the message has been sent out of the system. - */ - var assertThat: String? = null - - /** - * The body matchers part of the contract. - */ - var bodyMatchers: ResponseBodyMatchers? = null - - fun sentTo(sentTo: String) = sentTo.toDslProperty() - - fun headers(headers: HeadersDsl.() -> Unit) { - this.headers = HeadersDsl().apply(headers).get() - } - - fun body(body: Any) = body.toDslProperty() - - fun body(vararg body: Pair) = Body(body.toMap().toDslProperties()) - - fun bodyMatchers(configurer: ResponseBodyMatchersDsl.() -> Unit) { - this.bodyMatchers = ResponseBodyMatchersDsl().apply(configurer).get() - } - - /* HELPER VARIABLES */ - - val anyAlphaUnicode: ServerDslProperty - get() = delegate.anyAlphaUnicode() - - val anyAlphaNumeric: ServerDslProperty - get() = delegate.anyAlphaNumeric() - - val anyNumber: ServerDslProperty - get() = delegate.anyNumber() - - val anyInteger: ServerDslProperty - get() = delegate.anyInteger() - - val anyPositiveInt: ServerDslProperty - get() = delegate.anyPositiveInt() - - val anyDouble: ServerDslProperty - get() = delegate.anyDouble() - - val anyHex: ServerDslProperty - get() = delegate.anyHex() - - val aBoolean: ServerDslProperty - get() = delegate.aBoolean() - - val anyIpAddress: ServerDslProperty - get() = delegate.anyIpAddress() - - val anyHostname: ServerDslProperty - get() = delegate.anyHostname() - - val anyEmail: ServerDslProperty - get() = delegate.anyEmail() - - val anyUrl: ServerDslProperty - get() = delegate.anyUrl() - - val anyHttpsUrl: ServerDslProperty - get() = delegate.anyHttpsUrl() - - val anyUuid: ServerDslProperty - get() = delegate.anyUuid() - - val anyDate: ServerDslProperty - get() = delegate.anyDate() - - val anyDateTime: ServerDslProperty - get() = delegate.anyDateTime() - - val anyTime: ServerDslProperty - get() = delegate.anyTime() - - val anyIso8601WithOffset: ServerDslProperty - get() = delegate.anyIso8601WithOffset() - - val anyNonBlankString: ServerDslProperty - get() = delegate.anyNonBlankString() - - val anyNonEmptyString: ServerDslProperty - get() = delegate.anyNonEmptyString() - - /* HELPER FUNCTIONS */ - - fun value(value: DslProperty): DslProperty = delegate.value(value) - - fun v(value: DslProperty): DslProperty = delegate.value(value) - - fun value(value: Pattern): DslProperty = delegate.value(value) - - fun v(value: Pattern): DslProperty = delegate.value(value) - - fun value(value: RegexProperty): DslProperty = delegate.value(value) - - fun v(value: RegexProperty): DslProperty = delegate.value(value) - - fun value(value: Any?): DslProperty = delegate.value(value) - - fun v(value: Any?): DslProperty = delegate.value(value) - - fun value(client: ClientDslProperty, server: ServerDslProperty): DslProperty = delegate.value(client, server) - - fun v(client: ClientDslProperty, server: ServerDslProperty): DslProperty = delegate.value(client, server) - - fun value(server: ServerDslProperty, client: ClientDslProperty): DslProperty = delegate.value(client, server) - - fun v(server: ServerDslProperty, client: ClientDslProperty): DslProperty = delegate.value(client, server) - - fun anyOf(vararg values: String?) = delegate.anyOf(*values) - - internal fun get(): OutputMessage { - val outputMessage = OutputMessage() - sentTo?.also { outputMessage.sentTo = sentTo } - body?.also { outputMessage.body = body } - headers?.also { outputMessage.headers = headers } - assertThat?.also { outputMessage.assertThat(assertThat) } - bodyMatchers?.also { outputMessage.bodyMatchers = bodyMatchers } - return outputMessage - } -} diff --git a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/RequestDsl.kt b/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/RequestDsl.kt deleted file mode 100644 index 5f316ebe6e..0000000000 --- a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/RequestDsl.kt +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal - -import org.springframework.cloud.contract.spec.toDslProperties -import org.springframework.cloud.contract.spec.toDslProperty -import org.springframework.cloud.contract.spec.util.RegexpUtils -import java.util.regex.Pattern - -/** - * Represents the request side of the HTTP communication. - * - * @author Tim Ysewyn - * @since 2.2.0 - */ -@ContractDslMarker -open class RequestDsl : CommonDsl() { - - private val delegate = Request() - - /** - * The HTTP method. - */ - var method: DslProperty<*>? = null - - /** - * The URL to which the request will be sent. - */ - var url: Url? = null - - /** - * The URL to which the request will be sent. - */ - var urlPath: UrlPath? = null - - /** - * The HTTP headers which should be sent with the request. - */ - var headers: Headers? = null - - /** - * The HTTP cookies which should be sent with the request. - */ - var cookies: Cookies? = null - - /** - * The HTTP request body which should be sent. - */ - var body: Body? = null - - /** - * The content that needs to be sent with a multipart HTTP request. - */ - var multipart: Multipart? = null - - /** - * The HTTP request body matchers. - */ - var bodyMatchers: BodyMatchers? = null - - fun method(method: String) = method.toDslProperty() - - fun url(url: String) = Url(url) - - fun url(url: DslProperty) = Url(url) - - fun url(client: ClientDslProperty, server: ServerDslProperty) = Url(value(client, server)) - - fun path(path: String) = UrlPath(path) - - fun path(path: DslProperty) = UrlPath(path) - - fun headers(headers: HeadersDsl.() -> Unit) { - this.headers = RequestHeadersDsl().apply(headers).get() - } - - fun cookies(cookies: CookiesDsl.() -> Unit) { - this.cookies = RequestCookiesDsl().apply(cookies).get() - } - - fun body(body: Map) = Body(body.toDslProperties()) - - fun body(vararg body: Pair) = Body(body.toMap().toDslProperties()) - - fun body(body: Pair) = Body(mapOf(body).toDslProperties()) - - fun body(body: List) = Body(body.toDslProperties()) - - fun body(body: Any) = Body(body) - - fun multipart(configurer: MultipartDsl.() -> Unit) { - this.multipart = MultipartDsl().apply(configurer).get() - } - - fun bodyMatchers(configurer: BodyMatchersDsl.() -> Unit) { - this.bodyMatchers = BodyMatchersDsl().apply(configurer).get() - } - - /* HELPER VARIABLES */ - - /* HTTP METHODS */ - - val GET: DslProperty - get() = method(HttpMethods.GET) - - val HEAD: DslProperty - get() = method(HttpMethods.HEAD) - - val POST: DslProperty - get() = method(HttpMethods.POST) - - val PUT: DslProperty - get() = method(HttpMethods.PUT) - - val PATCH: DslProperty - get() = method(HttpMethods.PATCH) - - val DELETE: DslProperty - get() = method(HttpMethods.DELETE) - - val OPTIONS: DslProperty - get() = method(HttpMethods.OPTIONS) - - val TRACE: DslProperty - get() = method(HttpMethods.TRACE) - - /* REGEX */ - - val anyAlphaUnicode: ClientDslProperty - get() = delegate.anyAlphaUnicode() - - val anyAlphaNumeric: ClientDslProperty - get() = delegate.anyAlphaNumeric() - - val anyNumber: ClientDslProperty - get() = delegate.anyNumber() - - val anyInteger: ClientDslProperty - get() = delegate.anyInteger() - - val anyPositiveInt: ClientDslProperty - get() = delegate.anyPositiveInt() - - val anyDouble: ClientDslProperty - get() = delegate.anyDouble() - - val anyHex: ClientDslProperty - get() = delegate.anyHex() - - val aBoolean: ClientDslProperty - get() = delegate.aBoolean() - - val anyIpAddress: ClientDslProperty - get() = delegate.anyIpAddress() - - val anyHostname: ClientDslProperty - get() = delegate.anyHostname() - - val anyEmail: ClientDslProperty - get() = delegate.anyEmail() - - val anyUrl: ClientDslProperty - get() = delegate.anyUrl() - - val anyHttpsUrl: ClientDslProperty - get() = delegate.anyHttpsUrl() - - val anyUuid: ClientDslProperty - get() = delegate.anyUuid() - - val anyDate: ClientDslProperty - get() = delegate.anyDate() - - val anyDateTime: ClientDslProperty - get() = delegate.anyDateTime() - - val anyTime: ClientDslProperty - get() = delegate.anyTime() - - val anyIso8601WithOffset: ClientDslProperty - get() = delegate.anyIso8601WithOffset() - - val anyNonBlankString: ClientDslProperty - get() = delegate.anyNonBlankString() - - val anyNonEmptyString: ClientDslProperty - get() = delegate.anyNonEmptyString() - - /* HELPER FUNCTIONS */ - - /** - * Sets the equality check to the given query parameter. - * @param value value to check against - * @return matching strategy - */ - fun equalTo(value: Any) = MatchingStrategy(value, MatchingStrategy.Type.EQUAL_TO) - - /** - * Sets the containing check to the given query parameter. - * @param value value to check against - * @return matching strategy - */ - fun containing(value: Any) = MatchingStrategy(value, MatchingStrategy.Type.CONTAINS) - - /** - * Sets the matching check to the given query parameter. - * @param value value to check against - * @return matching strategy - */ - fun matching(value: Any) = MatchingStrategy(value, MatchingStrategy.Type.MATCHING) - - /** - * Sets the not matching check to the given query parameter. - * @param value value to check against - * @return matching strategy - */ - fun notMatching(value: Any) = MatchingStrategy(value, MatchingStrategy.Type.NOT_MATCHING) - - /** - * Sets the XML equality check to the body. - * @param value value to check against - * @return matching strategy - */ - fun equalToXml(value: Any) = MatchingStrategy(value, MatchingStrategy.Type.EQUAL_TO_XML) - - /** - * Sets the JSON equality check to the body. - * @param value value to check against - * @return matching strategy - */ - fun equalToJson(value: Any) = MatchingStrategy(value, MatchingStrategy.Type.EQUAL_TO_JSON) - - /** - * Sets absence check to the given query parameter. - * @return matching strategy - */ - fun absent() = MatchingStrategy(true, MatchingStrategy.Type.ABSENT) - - fun value(value: ClientDslProperty): DslProperty = delegate.value(value) - - fun v(value: ClientDslProperty): DslProperty = delegate.value(value) - - fun value(value: DslProperty): DslProperty = delegate.value(value) - - fun v(value: DslProperty): DslProperty = delegate.value(value) - - fun value(value: Pattern): DslProperty = delegate.value(value) - - fun v(value: Pattern): DslProperty = delegate.value(value) - - fun value(value: RegexProperty): DslProperty = delegate.value(value) - - fun v(value: RegexProperty): DslProperty = delegate.value(value) - - fun value(value: Any?): DslProperty = delegate.value(value) - - fun v(value: Any?): DslProperty = delegate.value(value) - - fun value(client: ClientDslProperty, server: ServerDslProperty): DslProperty = delegate.value(client, server) - - fun v(client: ClientDslProperty, server: ServerDslProperty): DslProperty = delegate.value(client, server) - - fun value(server: ServerDslProperty, client: ClientDslProperty): DslProperty = delegate.value(client, server) - - fun v(server: ServerDslProperty, client: ClientDslProperty): DslProperty = delegate.value(client, server) - - fun anyOf(vararg values: String?): ClientDslProperty = delegate.anyOf(*values) - - internal fun get(): Request { - val request = Request() - method?.also { request.method = method } - url?.also { request.url = url } - urlPath?.also { request.urlPath = urlPath } - headers?.also { request.headers = headers } - cookies?.also { request.cookies = cookies } - body?.also { request.body = body } - multipart?.also { request.multipart = multipart } - bodyMatchers?.also { request.bodyMatchers = bodyMatchers } - return request - } - - private class RequestHeadersDsl : HeadersDsl() { - - private val common = Common() - - override fun matching(value: Any?): Any? { - return value?.also { - return when (value) { - is String -> this.common.value( - c(regex(RegexpUtils.escapeSpecialRegexWithSingleEscape(value) + ".*")), - p(value) - ) - else -> value - } - } - } - - } - - private class RequestCookiesDsl : CookiesDsl() { - - private val common = Common() - - override fun matching(value: Any?): Any? { - return value?.also { - return when (value) { - is String -> this.common.value( - c(regex(RegexpUtils.escapeSpecialRegexWithSingleEscape(value) + ".*")), - p(value) - ) - else -> value - } - } - } - - } -} \ No newline at end of file diff --git a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/ResponseBodyMatchersDsl.kt b/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/ResponseBodyMatchersDsl.kt deleted file mode 100644 index ea13053736..0000000000 --- a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/ResponseBodyMatchersDsl.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2019-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal - -/** - * Additional matchers for the response or output message part. - * - * @author Tim Ysewyn - * @since 2.2.0 - */ -class ResponseBodyMatchersDsl : BodyMatchersDsl() { - - val byType - get() = MatchingTypeValue(MatchingType.TYPE) - - val byNull - get() = MatchingTypeValue(MatchingType.NULL) - - fun byCommand(execute: String) = MatchingTypeValue().apply { - type = MatchingType.COMMAND - value = ExecutionProperty(execute) - } - - override fun get() = configureBodyMatchers(ResponseBodyMatchers()) - -} \ No newline at end of file diff --git a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/ResponseDsl.kt b/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/ResponseDsl.kt deleted file mode 100644 index 27b540d61a..0000000000 --- a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/ResponseDsl.kt +++ /dev/null @@ -1,425 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal - -import org.springframework.cloud.contract.spec.toDslProperties -import org.springframework.cloud.contract.spec.toDslProperty -import org.springframework.cloud.contract.spec.util.RegexpUtils -import java.util.regex.Pattern - -/** - * Represents the response side of the HTTP communication. - * - * @author Tim Ysewyn - * @since 2.2.0 - */ -@ContractDslMarker -class ResponseDsl : CommonDsl() { - - private val delegate = Response() - - /** - * The HTTP response status. - */ - var status: DslProperty? = null - - /** - * The HTTP response delay in milliseconds. - */ - var delay: DslProperty? = null - - /** - * The HTTP response headers. - */ - var headers: Headers? = null - - /** - * The HTTP response cookies. - */ - var cookies: Cookies? = null - - /** - * The HTTP response body. - */ - var body: Body? = null - - /** - * Indicates asynchronous communication. - */ - var async: Boolean = false - - /** - * The HTTP response body matchers. - */ - var bodyMatchers: ResponseBodyMatchers? = null - - fun code(code: Int): DslProperty = code.toDslProperty() - - fun fixedMilliseconds(delay: Int): DslProperty = delay.toDslProperty() - - /** - * @deprecated Use the {@link #fixedMilliseconds(int) fixedMilliseconds} method. - */ - fun fixedMilliseconds(delay: Long): DslProperty = fixedMilliseconds(delay.toInt()) - - fun headers(headers: HeadersDsl.() -> Unit) { - this.headers = ResponseHeadersDsl().apply(headers).get() - } - - fun cookies(cookies: CookiesDsl.() -> Unit) { - this.cookies = ResponseCookiesDsl().apply(cookies).get() - } - - fun body(body: Map) = Body(body.toDslProperties()) - - fun body(vararg body: Pair) = Body(body.toMap().toDslProperties()) - - fun body(body: Pair) = Body(mapOf(body).toDslProperties()) - - fun body(body: List) = Body(body.toDslProperties()) - - fun body(body: Any) = Body(body) - - fun bodyMatchers(configurer: ResponseBodyMatchersDsl.() -> Unit) { - bodyMatchers = ResponseBodyMatchersDsl().apply(configurer).get() - } - - /* HELPER VARIABLES */ - - /* HTTP STATUS CODES */ - - val CONTINUE - get() = code(HttpStatus.CONTINUE) - - val SWITCHING_PROTOCOLS - get() = code(HttpStatus.SWITCHING_PROTOCOLS) - - val PROCESSING - get() = code(HttpStatus.PROCESSING) - - val CHECKPOINT - get() = code(HttpStatus.CHECKPOINT) - - val OK - get() = code(HttpStatus.OK) - - val CREATED - get() = code(HttpStatus.CREATED) - - val ACCEPTED - get() = code(HttpStatus.ACCEPTED) - - val NON_AUTHORITATIVE_INFORMATION - get() = code(HttpStatus.NON_AUTHORITATIVE_INFORMATION) - - val NO_CONTENT - get() = code(HttpStatus.NO_CONTENT) - - val RESET_CONTENT - get() = code(HttpStatus.RESET_CONTENT) - - val PARTIAL_CONTENT - get() = code(HttpStatus.PARTIAL_CONTENT) - - val MULTI_STATUS - get() = code(HttpStatus.MULTI_STATUS) - - val ALREADY_REPORTED - get() = code(HttpStatus.ALREADY_REPORTED) - - val IM_USED - get() = code(HttpStatus.IM_USED) - - val MULTIPLE_CHOICES - get() = code(HttpStatus.MULTIPLE_CHOICES) - - val MOVED_PERMANENTLY - get() = code(HttpStatus.MOVED_PERMANENTLY) - - val FOUND - get() = code(HttpStatus.FOUND) - - val SEE_OTHER - get() = code(HttpStatus.SEE_OTHER) - - val NOT_MODIFIED - get() = code(HttpStatus.NOT_MODIFIED) - - val TEMPORARY_REDIRECT - get() = code(HttpStatus.TEMPORARY_REDIRECT) - - val PERMANENT_REDIRECT - get() = code(HttpStatus.PERMANENT_REDIRECT) - - val BAD_REQUEST - get() = code(HttpStatus.BAD_REQUEST) - - val UNAUTHORIZED - get() = code(HttpStatus.UNAUTHORIZED) - - val PAYMENT_REQUIRED - get() = code(HttpStatus.PAYMENT_REQUIRED) - - val FORBIDDEN - get() = code(HttpStatus.FORBIDDEN) - - val NOT_FOUND - get() = code(HttpStatus.NOT_FOUND) - - val METHOD_NOT_ALLOWED - get() = code(HttpStatus.METHOD_NOT_ALLOWED) - - val NOT_ACCEPTABLE - get() = code(HttpStatus.NOT_ACCEPTABLE) - - val PROXY_AUTHENTICATION_REQUIRED - get() = code(HttpStatus.PROXY_AUTHENTICATION_REQUIRED) - - val REQUEST_TIMEOUT - get() = code(HttpStatus.REQUEST_TIMEOUT) - - val CONFLICT - get() = code(HttpStatus.CONFLICT) - - val GONE - get() = code(HttpStatus.GONE) - - val LENGTH_REQUIRED - get() = code(HttpStatus.LENGTH_REQUIRED) - - val PRECONDITION_FAILED - get() = code(HttpStatus.PRECONDITION_FAILED) - - val PAYLOAD_TOO_LARGE - get() = code(HttpStatus.PAYLOAD_TOO_LARGE) - - val UNSUPPORTED_MEDIA_TYPE - get() = code(HttpStatus.UNSUPPORTED_MEDIA_TYPE) - - val REQUESTED_RANGE_NOT_SATISFIABLE - get() = code(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE) - - val EXPECTATION_FAILED - get() = code(HttpStatus.EXPECTATION_FAILED) - - val I_AM_A_TEAPOT - get() = code(HttpStatus.I_AM_A_TEAPOT) - - val UNPROCESSABLE_ENTITY - get() = code(HttpStatus.UNPROCESSABLE_ENTITY) - - val LOCKED - get() = code(HttpStatus.LOCKED) - - val FAILED_DEPENDENCY - get() = code(HttpStatus.FAILED_DEPENDENCY) - - val UPGRADE_REQUIRED - get() = code(HttpStatus.UPGRADE_REQUIRED) - - val PRECONDITION_REQUIRED - get() = code(HttpStatus.PRECONDITION_REQUIRED) - - val TOO_MANY_REQUESTS - get() = code(HttpStatus.TOO_MANY_REQUESTS) - - val REQUEST_HEADER_FIELDS_TOO_LARGE - get() = code(HttpStatus.REQUEST_HEADER_FIELDS_TOO_LARGE) - - val UNAVAILABLE_FOR_LEGAL_REASONS - get() = code(HttpStatus.UNAVAILABLE_FOR_LEGAL_REASONS) - - val INTERNAL_SERVER_ERROR - get() = code(HttpStatus.INTERNAL_SERVER_ERROR) - - val NOT_IMPLEMENTED - get() = code(HttpStatus.NOT_IMPLEMENTED) - - val BAD_GATEWAY - get() = code(HttpStatus.BAD_GATEWAY) - - val SERVICE_UNAVAILABLE - get() = code(HttpStatus.SERVICE_UNAVAILABLE) - - val GATEWAY_TIMEOUT - get() = code(HttpStatus.GATEWAY_TIMEOUT) - - val HTTP_VERSION_NOT_SUPPORTED - get() = code(HttpStatus.HTTP_VERSION_NOT_SUPPORTED) - - val VARIANT_ALSO_NEGOTIATES - get() = code(HttpStatus.VARIANT_ALSO_NEGOTIATES) - - val INSUFFICIENT_STORAGE - get() = code(HttpStatus.INSUFFICIENT_STORAGE) - - val LOOP_DETECTED - get() = code(HttpStatus.LOOP_DETECTED) - - val BANDWIDTH_LIMIT_EXCEEDED - get() = code(HttpStatus.BANDWIDTH_LIMIT_EXCEEDED) - - val NOT_EXTENDED - get() = code(HttpStatus.NOT_EXTENDED) - - val NETWORK_AUTHENTICATION_REQUIRED - get() = code(HttpStatus.NETWORK_AUTHENTICATION_REQUIRED) - - /* REGEX */ - - val anyAlphaUnicode - get() = delegate.anyAlphaUnicode() - - val anyAlphaNumeric - get() = delegate.anyAlphaNumeric() - - val anyNumber - get() = delegate.anyNumber() - - val anyInteger - get() = delegate.anyInteger() - - val anyPositiveInt - get() = delegate.anyPositiveInt() - - val anyDouble - get() = delegate.anyDouble() - - val anyHex - get() = delegate.anyHex() - - val aBoolean - get() = delegate.aBoolean() - - val anyIpAddress - get() = delegate.anyIpAddress() - - val anyHostname - get() = delegate.anyHostname() - - val anyEmail - get() = delegate.anyEmail() - - val anyUrl - get() = delegate.anyUrl() - - val anyHttpsUrl - get() = delegate.anyHttpsUrl() - - val anyUuid - get() = delegate.anyUuid() - - val anyDate - get() = delegate.anyDate() - - val anyDateTime - get() = delegate.anyDateTime() - - val anyTime - get() = delegate.anyTime() - - val anyIso8601WithOffset - get() = delegate.anyIso8601WithOffset() - - val anyNonBlankString - get() = delegate.anyNonBlankString() - - val anyNonEmptyString - get() = delegate.anyNonEmptyString() - - /* HELPER FUNCTIONS */ - - fun value(value: ClientDslProperty) = delegate.value(value) - - fun v(value: ClientDslProperty) = delegate.value(value) - - fun value(value: DslProperty) = delegate.value(value) - - fun v(value: DslProperty) = delegate.value(value) - - fun value(value: Pattern) = delegate.value(value) - - fun v(value: Pattern) = delegate.value(value) - - fun value(value: RegexProperty) = delegate.value(value) - - fun v(value: RegexProperty) = delegate.value(value) - - fun value(value: Any?) = delegate.value(value) - - fun v(value: Any?) = delegate.value(value) - - fun value(client: ClientDslProperty, server: ServerDslProperty) = delegate.value(client, server) - - fun v(client: ClientDslProperty, server: ServerDslProperty) = delegate.value(client, server) - - fun value(server: ServerDslProperty, client: ClientDslProperty) = delegate.value(client, server) - - fun v(server: ServerDslProperty, client: ClientDslProperty) = delegate.value(client, server) - - fun fromRequest() = FromRequestDsl() - - fun anyOf(vararg values: String?) = delegate.anyOf(*values) - - internal fun get(): Response { - val response = Response() - status?.also { response.status = status } - delay?.also { response.delay = delay } - headers?.also { response.headers = headers } - cookies?.also { response.cookies = cookies } - body?.also { response.body = body } - response.async = async - bodyMatchers?.also { response.bodyMatchers = bodyMatchers } - return response - } - - private class ResponseHeadersDsl : HeadersDsl() { - - private val common = Common() - - override fun matching(value: Any?): Any? { - return value?.also { - return when (value) { - is String -> return this.common.value( - c(value), - p(NotToEscapePattern(Pattern.compile(RegexpUtils.escapeSpecialRegexWithSingleEscape(value) + ".*"))) - ) - else -> value - } - } - } - - } - - private class ResponseCookiesDsl : CookiesDsl() { - - private val common = Common() - - override fun matching(value: Any?): Any? { - return value?.also { - return when (value) { - is String -> return this.common.value( - c(value), - p(regex(RegexpUtils.escapeSpecialRegexWithSingleEscape(value) + ".*")) - ) - else -> value - } - } - } - - } -} diff --git a/specs/spring-cloud-contract-spec-kotlin/src/main/resources/META-INF/services/javax.script.ScriptEngineFactory b/specs/spring-cloud-contract-spec-kotlin/src/main/resources/META-INF/services/javax.script.ScriptEngineFactory deleted file mode 100644 index f8f5900378..0000000000 --- a/specs/spring-cloud-contract-spec-kotlin/src/main/resources/META-INF/services/javax.script.ScriptEngineFactory +++ /dev/null @@ -1 +0,0 @@ -org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngineFactory \ No newline at end of file diff --git a/specs/spring-cloud-contract-spec-kotlin/src/main/resources/META-INF/spring.factories b/specs/spring-cloud-contract-spec-kotlin/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 331f97675a..0000000000 --- a/specs/spring-cloud-contract-spec-kotlin/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,2 +0,0 @@ -org.springframework.cloud.contract.spec.ContractConverter=\ -org.springframework.cloud.contract.spec.internal.KotlinContractConverter diff --git a/specs/spring-cloud-contract-spec-kotlin/src/test/kotlin/org/springframework/cloud/contract/spec/ContractTests.kt b/specs/spring-cloud-contract-spec-kotlin/src/test/kotlin/org/springframework/cloud/contract/spec/ContractTests.kt deleted file mode 100644 index 16e7797038..0000000000 --- a/specs/spring-cloud-contract-spec-kotlin/src/test/kotlin/org/springframework/cloud/contract/spec/ContractTests.kt +++ /dev/null @@ -1,807 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec - -import java.io.File - -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertDoesNotThrow -import org.junit.jupiter.api.assertThrows - -import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract -import org.springframework.cloud.contract.spec.internal.Cookie -import org.springframework.cloud.contract.spec.internal.DslProperty -import org.springframework.cloud.contract.spec.internal.FromFileProperty -import org.springframework.cloud.contract.spec.internal.KotlinContractConverter -import org.springframework.cloud.contract.spec.internal.MatchingType -import org.springframework.cloud.contract.spec.internal.NamedProperty -import org.springframework.cloud.contract.spec.internal.RegexProperty - -/** - * Tests written based on the Java contract tests written in Groovy - * - * @author Tim Ysewyn - */ -class ContractTests { - - @Test - fun `should work for http`() { - val contract = contract { - request { - url = url("/foo") - method = PUT - headers { - header("foo", "bar") - } - body = body("foo" to "bar") - } - response { - status = OK - headers { - header("foo2", "bar") - } - body = body("foo2" to "bar") - } - } - - assertDoesNotThrow { - Contract.assertContract(contract) - }.also { - val request = contract.request - assertThat(request.url.clientValue).isEqualTo("/foo") - assertThat(request.url.serverValue).isEqualTo("/foo") - assertThat(request.method.clientValue).isEqualTo("PUT") - assertThat(request.method.serverValue).isEqualTo("PUT") - val headers = request.headers.entries - assertThat(headers).hasSize(1) - assertThat(headers.elementAt(0).name).isEqualTo("foo") - assertThat(headers.elementAt(0).clientValue).isEqualTo("bar") - assertThat(headers.elementAt(0).serverValue).isEqualTo("bar") - assertThat(request.body.clientValue).isEqualTo(mapOf("foo" to "bar")) - assertThat(request.body.serverValue).isEqualTo(mapOf("foo" to "bar")) - }.also { - val response = contract.response - assertThat(response.status.clientValue).isEqualTo(200) - assertThat(response.status.serverValue).isEqualTo(200) - val headers = response.headers.entries - assertThat(headers).hasSize(1) - assertThat(headers.elementAt(0).name).isEqualTo("foo2") - assertThat(headers.elementAt(0).clientValue).isEqualTo("bar") - assertThat(headers.elementAt(0).serverValue).isEqualTo("bar") - assertThat(response.body.clientValue).isEqualTo(mapOf("foo2" to "bar")) - assertThat(response.body.serverValue).isEqualTo(mapOf("foo2" to "bar")) - } - } - - @Test - fun `should fail when no method is present`() { - val contract = contract { - request { - url = url("/foo") - } - response { - status = OK - } - } - - assertThrows { - Contract.assertContract(contract) - }.also { - assertThat(it.message).contains("Method is missing for HTTP contract") - } - } - - @Test - fun `should fail when no url is present`() { - val contract = contract { - request { - method = GET - } - response { - status = OK - } - } - - assertThrows { - Contract.assertContract(contract) - }.also { - assertThat(it.message).contains("URL is missing for HTTP contract") - } - } - - @Test - fun `should fail when no status is present`() { - val contract = contract { - request { - url = url("/foo") - method = GET - } - response { - } - } - - assertThrows { - Contract.assertContract(contract) - }.also { - assertThat(it.message).contains("Status is missing for HTTP contract") - } - } - - @Test - fun `should set a description`() { - val contract = -// @formatter: off -// tag::description[] -contract { - description = """ -given: - An input -when: - Sth happens -then: - Output -""" -} -// end::description[] -// @formatter: on - assertDoesNotThrow { - Contract.assertContract(contract) - }.also { - assertThat(contract.description).isEqualTo(""" -given: - An input -when: - Sth happens -then: - Output -""") - } - } - - @Test - fun `should set a name`() { - val contract = - // tag::name[] - contract { - name = "some_special_name" - } - // end::name[] - - assertDoesNotThrow { - Contract.assertContract(contract) - }.also { - assertThat(contract.name).isEqualTo("some_special_name") - } - } - - @Test - fun `should mark a contract ignored`() { - val contract = - // tag::ignored[] - contract { - ignored = true - } - // end::ignored[] - - assertDoesNotThrow { - Contract.assertContract(contract) - }.also { - assertThat(contract.ignored).isTrue() - } - } - - @Test - fun `should mark a contract in progress`() { - val contract = - // tag::in_progress[] - contract { - inProgress = true - } - // end::in_progress[] - - assertDoesNotThrow { - Contract.assertContract(contract) - }.also { - assertThat(contract.inProgress).isTrue() - } - } - - @Test - fun `should set contract metadata`() { - val contract = - // tag::metadata[] - contract { - metadata("wiremock" to ("stubmapping" to """ - { - "response" : { - "fixedDelayMilliseconds": 2000 - } - }""")) - } - // end::metadata[] - - assertDoesNotThrow { - Contract.assertContract(contract) - }.also { - assertThat(contract.metadata).isNotEmpty - } - } - - @Test - fun `should make equals and hashcode work properly for URL`() { - val a: Contract = contract { - request { - method = GET - url = url("/1") - } - } - val b: Contract = contract { - request { - method = GET - url = url("/1") - } - } - - assertDoesNotThrow { - Contract.assertContract(a) - Contract.assertContract(b) - }.also { - assertThat(a).isEqualTo(b) - } - } - - @Test - fun `should make equals and hashcode work properly for URL with consumer producer`() { - val a: Contract = contract { - request { - method = GET - url = url(c("/1"), p("/1")) - } - } - val b: Contract = contract { - request { - method = GET - url = url(c("/1"), p("/1")) - } - } - - assertDoesNotThrow { - Contract.assertContract(a) - Contract.assertContract(b) - }.also { - assertThat(a).isEqualTo(b) - } - } - - @Test - fun `should return true when comparing two equal contracts with interpolated string`() { - val index = 1 - val a: Contract = contract { - request { - method = PUT - headers { - contentType = APPLICATION_JSON - } - url = url("/$index") - } - response { - status = OK - } - } - val b: Contract = contract { - request { - method = PUT - headers { - contentType = APPLICATION_JSON - } - url = url("/$index") - } - response { - status = OK - } - } - - assertDoesNotThrow { - Contract.assertContract(a) - Contract.assertContract(b) - }.also { - assertThat(a).isEqualTo(b) - } - } - - @Test - fun `should return false when comparing two unequal contracts with interpolated string`() { - var index = 1 - val a: Contract = contract { - request { - method = PUT - headers { - contentType = APPLICATION_JSON - } - url = url("/$index") - } - response { - status = OK - } - } - index = 2 - val b: Contract = contract { - request { - method = PUT - headers { - contentType = APPLICATION_JSON - } - url = url("/$index") - } - response { - status = OK - } - } - - assertDoesNotThrow { - Contract.assertContract(a) - Contract.assertContract(b) - }.also { - assertThat(a).isNotEqualTo(b) - } - } - - @Test - fun `should return true when comparing two equal complex contracts`() { - val a: Contract = contract { - request { - method = GET - url = url("/path") - headers { - header(name = "Accept", - value = value( - consumer(regex("text/.*")), - producer("text/plain") - ) - ) - header(name = "X-Custom-Header", - value = value( - consumer(regex("^.*2134.*$")), - producer("121345") - ) - ) - } - } - response { - status = OK - body = body("id" to mapOf("value" to "132"), - "surname" to "Kowalsky", - "name" to "Jan", - "created" to "2014-02-02 12:23:43" - ) - headers { - header("Content-Type", "text/plain") - header("X-Custom-Header", - value( - stub("121345"), - test(regex("^.*2134.*$")) - ) - ) - } - } - } - val b: Contract = contract { - request { - method = GET - url = url("/path") - headers { - header(name = "Accept", - value = value( - consumer(regex("text/.*")), - producer("text/plain") - ) - ) - header(name = "X-Custom-Header", - value = value( - consumer(regex("^.*2134.*$")), - producer("121345") - ) - ) - } - } - response { - status = OK - body = body("id" to mapOf("value" to "132"), - "surname" to "Kowalsky", - "name" to "Jan", - "created" to "2014-02-02 12:23:43" - ) - headers { - header("Content-Type", "text/plain") - header("X-Custom-Header", - value( - stub("121345"), - test(regex("^.*2134.*$")) - ) - ) - } - } - } - assertDoesNotThrow { - Contract.assertContract(a) - Contract.assertContract(b) - }.also { - assertThat(a).isEqualTo(b) - }. also { - val request = a.request - assertThat(request.url.clientValue).isEqualTo("/path") - assertThat(request.url.serverValue).isEqualTo("/path") - assertThat(request.method.clientValue).isEqualTo("GET") - assertThat(request.method.serverValue).isEqualTo("GET") - val headers = request.headers.entries - assertThat(headers).hasSize(2) - assertThat(headers.elementAt(0).name).isEqualTo("Accept") - assertThat(headers.elementAt(0).clientValue).isInstanceOf(RegexProperty::class.java) - assertThat((headers.elementAt(0).clientValue as RegexProperty).pattern()).isEqualTo("text/.*") - assertThat(headers.elementAt(0).serverValue).isEqualTo("text/plain") - assertThat(headers.elementAt(1).name).isEqualTo("X-Custom-Header") - assertThat(headers.elementAt(1).clientValue).isInstanceOf(RegexProperty::class.java) - assertThat((headers.elementAt(1).clientValue as RegexProperty).pattern()).isEqualTo("^.*2134.*\$") - assertThat(headers.elementAt(1).serverValue).isEqualTo("121345") - }.also { - val response = a.response - assertThat(response.status.clientValue).isEqualTo(200) - assertThat(response.status.serverValue).isEqualTo(200) - val headers = response.headers.entries - assertThat(headers).hasSize(2) - assertThat(headers.elementAt(0).name).isEqualTo("Content-Type") - assertThat(headers.elementAt(0).clientValue).isEqualTo("text/plain") - assertThat(headers.elementAt(0).serverValue).isEqualTo("text/plain") - assertThat(headers.elementAt(1).name).isEqualTo("X-Custom-Header") - assertThat(headers.elementAt(1).clientValue).isEqualTo("121345") - assertThat(headers.elementAt(1).serverValue).isInstanceOf(RegexProperty::class.java) - assertThat((headers.elementAt(1).serverValue as RegexProperty).pattern()).isEqualTo("^.*2134.*\$") - assertThat(response.body.clientValue).isEqualTo(mapOf("id" to mapOf("value" to "132"), - "surname" to "Kowalsky", - "name" to "Jan", - "created" to "2014-02-02 12:23:43" - )) - assertThat(response.body.serverValue).isEqualTo(mapOf("id" to mapOf("value" to "132"), - "surname" to "Kowalsky", - "name" to "Jan", - "created" to "2014-02-02 12:23:43" - )) - } - } - - @Test - fun `should support bodyMatchers`() { - val contract = contract { - request { - method = GET - url = url("/path") - body = body("id" to mapOf("value" to "132")) - bodyMatchers { - jsonPath( "$.id.value", byRegex(anInteger)) - } - } - response { - status = OK - body = body("id" to mapOf("value" to "132"), - "surname" to "Kowalsky", - "name" to "Jan", - "created" to "2014-02-02 12:23:43" - ) - headers { - contentType = APPLICATION_JSON - } - bodyMatchers { - jsonPath("$.id.value", byTimestamp) - } - } - } - - assertDoesNotThrow { - Contract.assertContract(contract) - }.also { - val request = contract.request - assertThat(request.url.clientValue).isEqualTo("/path") - assertThat(request.url.serverValue).isEqualTo("/path") - assertThat(request.method.clientValue).isEqualTo("GET") - assertThat(request.method.serverValue).isEqualTo("GET") - assertThat(request.bodyMatchers.hasMatchers()).isTrue() - val matchers = request.bodyMatchers.matchers() - assertThat(matchers[0].path()).isEqualTo("$.id.value") - assertThat(matchers[0].matchingType()).isEqualTo(MatchingType.REGEX) - }.also { - val response = contract.response - assertThat(response.status.clientValue).isEqualTo(200) - assertThat(response.status.serverValue).isEqualTo(200) - assertThat(response.bodyMatchers.hasMatchers()).isTrue() - val matchers = response.bodyMatchers.matchers() - assertThat(matchers[0].path()).isEqualTo("$.id.value") - assertThat(matchers[0].matchingType()).isEqualTo(MatchingType.TIMESTAMP) - } - } - - @Test - fun `should support query parameters for url`() { - val contract = contract { - request { - method = GET - url = url("/path") withQueryParameters { - parameter("foo", "bar") - } - } - response { - status = OK - } - } - - assertDoesNotThrow { - Contract.assertContract(contract) - }.also { - val request = contract.request - assertThat(request.url.clientValue).isEqualTo("/path") - val queryParameters = request.url.queryParameters.parameters - assertThat(queryParameters[0].name).isEqualTo("foo") - assertThat(queryParameters[0].clientValue).isEqualTo("bar") - assertThat(queryParameters[0].serverValue).isEqualTo("bar") - assertThat(request.url.serverValue).isEqualTo("/path") - assertThat(request.method.clientValue).isEqualTo("GET") - assertThat(request.method.serverValue).isEqualTo("GET") - }.also { - val response = contract.response - assertThat(response.status.clientValue).isEqualTo(200) - assertThat(response.status.serverValue).isEqualTo(200) - } - } - - @Test - fun `should support query parameters for url path`() { - val contract = contract { - request { - method = GET - urlPath = path("/path") withQueryParameters { - parameter("foo", "bar") - } - } - response { - status = OK - } - } - - assertDoesNotThrow { - Contract.assertContract(contract) - }.also { - val request = contract.request - assertThat(request.urlPath.clientValue).isEqualTo("/path") - assertThat(request.urlPath.serverValue).isEqualTo("/path") - val queryParameters = request.urlPath.queryParameters.parameters - assertThat(queryParameters[0].name).isEqualTo("foo") - assertThat(queryParameters[0].clientValue).isEqualTo("bar") - assertThat(queryParameters[0].serverValue).isEqualTo("bar") - assertThat(request.method.clientValue).isEqualTo("GET") - assertThat(request.method.serverValue).isEqualTo("GET") - }.also { - val response = contract.response - assertThat(response.status.clientValue).isEqualTo(200) - assertThat(response.status.serverValue).isEqualTo(200) - } - } - - @Test - fun `should work with list as body`() { - val contract = contract { - request { - method = PUT - url = url("/path") - body = body(listOf("foo", "bar")) - } - response { - status = OK - body = body(listOf("foo2", "bar2")) - } - } - - assertDoesNotThrow { - Contract.assertContract(contract) - }.also { - val request = contract.request - assertThat(request.body.clientValue).isEqualTo(listOf("foo", "bar")) - assertThat(request.body.serverValue).isEqualTo(listOf("foo", "bar")) - }.also { - val response = contract.response - assertThat(response.body.clientValue).isEqualTo(listOf("foo2", "bar2")) - assertThat(response.body.serverValue).isEqualTo(listOf("foo2", "bar2")) - } - } - - @Test - fun `should work with cookies`() { - val contract = contract { - request { - method = GET - url = url("/cookie") - cookies { - cookie("name", "foo") - cookie("name2", "bar") - } - } - response { - status = OK - cookies { - cookie("name", "foo") - cookie("name2", "bar") - } - } - } - - assertDoesNotThrow { - Contract.assertContract(contract) - }.also { - val request = contract.request - val cookies = request.cookies.entries - assertThat(cookies).hasSize(2) - assertThat(cookies).containsExactlyInAnyOrder(Cookie.build("name", "foo"), Cookie.build("name2", "bar")) - }.also { - val response = contract.response - val cookies = response.cookies.entries - assertThat(cookies).hasSize(2) - assertThat(cookies).containsExactlyInAnyOrder(Cookie.build("name", "foo"), Cookie.build("name2", "bar")) - } - } - - @Test - fun `should support fromRequest`() { - val contract = contract { - request { - method = GET - url = url("/path") - body = body("id" to mapOf("value" to "132")) - headers { - accept = APPLICATION_JSON - } - } - response { - status = OK - body = body("value is ${fromRequest().body("$.value")}") - headers { - contentType = fromRequest().header(ACCEPT) - } - } - } - - assertDoesNotThrow { - Contract.assertContract(contract) - }.also { - val response = contract.response - assertThat(response.body.clientValue).isEqualTo("value is {{{jsonPath request.body '$.value'}}}") - val headers = response.headers.entries - assertThat(headers).hasSize(1) - assertThat(headers.elementAt(0).name).isEqualTo("Content-Type") - assertThat(headers.elementAt(0).clientValue).isEqualTo("{{{request.headers.Accept.[0]}}}") - assertThat(headers.elementAt(0).serverValue).isEqualTo("{{{request.headers.Accept.[0]}}}") - } - } - - @Test - @Suppress("UNCHECKED_CAST") - fun `should support multipart`() { - val contract = KotlinContractConverter() - .convertFrom(File(javaClass.classLoader.getResource("contracts/multipart.kts")!!.toURI())) - .elementAt(0) - - assertDoesNotThrow { - Contract.assertContract(contract) - }.also { - val request = contract.request - assertThat(request.multipart).isNotNull() - assertThat(request.multipart.clientValue).isNotNull() - assertThat(request.multipart.clientValue).isInstanceOf(LinkedHashMap::class.java) - val multipartData = request.multipart.clientValue as LinkedHashMap - assertThat(multipartData).hasSize(3) - assertThat(multipartData.keys).containsExactly("file1", "file2", "test") - var namedProperty: NamedProperty - - assertThat(multipartData["file1"]).isInstanceOf(NamedProperty::class.java) - namedProperty = multipartData["file1"] as NamedProperty - assertThat(((namedProperty.name as DslProperty).clientValue as RegexProperty).pattern()).isEqualTo("[\\S\\s]+") - assertThat((namedProperty.name as DslProperty).serverValue as String).isEqualTo("filename1") - assertThat(((namedProperty.value as DslProperty).clientValue as RegexProperty).pattern()).isEqualTo("[\\S\\s]+") - assertThat((namedProperty.value as DslProperty).serverValue as String).isEqualTo("content1") - assertThat(namedProperty.contentType).isNull() - - assertThat(multipartData["file2"]).isInstanceOf(NamedProperty::class.java) - namedProperty = multipartData["file2"] as NamedProperty - assertThat(((namedProperty.name as DslProperty).clientValue as RegexProperty).pattern()).isEqualTo("[\\S\\s]+") - assertThat((namedProperty.name as DslProperty).serverValue as String).isEqualTo("filename2") - assertThat(((namedProperty.value as DslProperty).clientValue as RegexProperty).pattern()).isEqualTo("[\\S\\s]+") - assertThat((namedProperty.value as DslProperty).serverValue as String).isEqualTo("content2") - assertThat(namedProperty.contentType).isNull() - - assertThat(multipartData["test"]).isInstanceOf(NamedProperty::class.java) - namedProperty = multipartData["test"] as NamedProperty - assertThat(((namedProperty.name as DslProperty).clientValue as RegexProperty).pattern()).isEqualTo("[\\S\\s]+") - assertThat((namedProperty.name as DslProperty).serverValue as String).isEqualTo("filename3") - assertThat(((namedProperty.value as DslProperty).clientValue as RegexProperty).pattern()).isEqualTo("[\\S\\s]+") - assertThat(((namedProperty.value as DslProperty).serverValue as FromFileProperty).fileName()).isEqualTo("test.json") - assertThat((namedProperty.contentType as DslProperty).clientValue).isEqualTo("application/json") - assertThat((namedProperty.contentType as DslProperty).serverValue).isEqualTo("application/json") - } - } - - @Test - fun `should use filename as fallback for single unnamed contract`() { - val contract = KotlinContractConverter() - .convertFrom(File(javaClass.classLoader.getResource("contracts/unnamed_single.kts")!!.toURI())) - .single() - assertDoesNotThrow { - Contract.assertContract(contract) - }.also { - assertThat(contract.name).isEqualTo("unnamed_single") - } - } - - @Test - fun `should use filename with index as fallback for multiple unnamed contracts`() { - val contracts = KotlinContractConverter() - .convertFrom(File(javaClass.classLoader.getResource("contracts/unnamed_multiple.kts")!!.toURI())) - .toList() - assertDoesNotThrow { - contracts.forEach(Contract::assertContract) - }.also { - assertThat(contracts[0].name).isEqualTo("unnamed_multiple_0") - assertThat(contracts[1].name).isEqualTo("unnamed_multiple_1") - } - } - - @Test - /** - * See issue https://github.com/spring-cloud/spring-cloud-contract/issues/1668 - */ - fun `should convert delay from long to int`() { - val contract = contract { - name = "Test Controller" - description = "Some description" - request { - method = GET - url = url("/credentials") withQueryParameters { - parameter("type", "foo") - } - } - response { - delay = fixedMilliseconds(1000L) - status = OK - body = body( - listOf( - mapOf( - "type" to "test1" - ) - ) - ) - } - } - - assertDoesNotThrow { - Contract.assertContract(contract) - }.also { - val response = contract.response - assertThat(response.delay.clientValue).isInstanceOf(java.lang.Integer::class.java) - assertThat(response.delay.clientValue).isEqualTo(1000) - assertThat(response.delay.serverValue).isInstanceOf(java.lang.Integer::class.java) - assertThat(response.delay.serverValue).isEqualTo(1000) - } - } - -} diff --git a/specs/spring-cloud-contract-spec-kotlin/src/test/kotlin/org/springframework/cloud/contract/spec/internal/KotlinContractConverterTests.kt b/specs/spring-cloud-contract-spec-kotlin/src/test/kotlin/org/springframework/cloud/contract/spec/internal/KotlinContractConverterTests.kt deleted file mode 100644 index 81ddf82233..0000000000 --- a/specs/spring-cloud-contract-spec-kotlin/src/test/kotlin/org/springframework/cloud/contract/spec/internal/KotlinContractConverterTests.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal - -import org.junit.jupiter.api.Test -import org.springframework.cloud.contract.spec.Contract -import java.io.File -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -class KotlinContractConverterTests { - - @Test - fun `accept kts files`() { - assertTrue(KotlinContractConverter().isAccepted(file("contracts/singleDefinition.kts"))) - } - - @Test - fun `should convert single contract definition`() { - val converter = KotlinContractConverter() - val contracts = converter.convertFrom(file("contracts/singleDefinition.kts")) - assertEquals(1, contracts.size) - contracts.forEach(Contract::assertContract) - } - - @Test - fun `should convert multiple contract definitions`() { - val converter = KotlinContractConverter() - val contracts = converter.convertFrom(file("contracts/multipleDefinitions.kts")) - assertEquals(2, contracts.size) - contracts.forEach(Contract::assertContract) - } - - @Test - fun `should work with binary payload`() { - val converter = KotlinContractConverter() - val contracts = converter.convertFrom(file("contracts/shouldWorkWithBinaryPayload.kts")) - assertEquals(1, contracts.size) - contracts.forEach(Contract::assertContract) - } - - private fun file(filename: String) = File(javaClass.classLoader.getResource(filename)!!.toURI()) -} \ No newline at end of file diff --git a/specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/multipart.kts b/specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/multipart.kts deleted file mode 100644 index c301b99fa3..0000000000 --- a/specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/multipart.kts +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts - -import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract - -contract { - request { - method = POST - url = url("/tests") - multipart { - field("file1", named( - value(consumer(regex(nonEmpty)), producer("filename1")), - value(consumer(regex(nonEmpty)), producer("content1")))) - field("file2", named( - value(consumer(regex(nonEmpty)), producer("filename2")), - value(consumer(regex(nonEmpty)), producer("content2")))) - field("test", named( - value(consumer(regex(nonEmpty)), producer("filename3")), - value(consumer(regex(nonEmpty)), producer(file("test.json"))), - value("application/json"))) - } - headers { - contentType = "multipart/form-data" - } - } - response { - status = OK - headers { - contentType = "application/json" - } - } -} diff --git a/specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/multipleDefinitions.kts b/specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/multipleDefinitions.kts deleted file mode 100644 index 5ced6d0868..0000000000 --- a/specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/multipleDefinitions.kts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts - -import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract - -arrayOf( - contract { - request { - method = GET - url = url("/frauds") - } - response { - status = OK - body = body("count" to 200) - headers { - contentType = "application/vnd.fraud.v1+json" - } - } - }, - contract { - request { - method = GET - url = url("/drunks") - } - response { - status = OK - body = body("count" to 100) - headers { - contentType = "application/vnd.fraud.v1+json" - } - } - } -) \ No newline at end of file diff --git a/specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/request.pdf b/specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/request.pdf deleted file mode 100644 index 69503635d87cbdfa660d5cd8be66d3e74b3b20e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14631 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 diff --git a/specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/response.pdf b/specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/response.pdf deleted file mode 100644 index c3b233056b758d1cc9bf3176e99a95add89ba607..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15767 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 - - 4.0.0 - - org.springframework.cloud - spring-cloud-contract-parent - 4.1.0-SNAPSHOT - ../.. - - spring-cloud-contract-spec - jar - Spring Cloud Contract Spec - Spring Cloud Contract Spec - - - org.springframework.cloud - spring-cloud-contract-spec-java - - - org.springframework.cloud - spring-cloud-contract-spec-groovy - - - org.spockframework - spock-core - test - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - - - addTestSources - generateTestStubs - compileTests - removeTestStubs - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - - - diff --git a/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy b/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy deleted file mode 100644 index d261db7b31..0000000000 --- a/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy +++ /dev/null @@ -1,391 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal - -import spock.lang.Issue -import spock.lang.Specification - -import org.springframework.cloud.contract.spec.Contract -/** - * @author Marcin Grzejszczak - */ -class ContractSpec extends Specification { - - def 'should work for http'() { - when: - Contract.make { - request { - url('/foo') - method('PUT') - headers { - header([ - foo: 'bar' - ]) - } - body([ - foo: 'bar' - ]) - } - response { - status 200 - headers { - header([ - foo2: 'bar' - ]) - } - body([ - foo2: 'bar' - ]) - } - } - then: - noExceptionThrown() - } - - def 'should fail when no method is present'() { - when: - Contract.make { - request { - url('/foo') - } - response { - status 200 - } - } - then: - IllegalStateException ex = thrown(IllegalStateException) - ex.message.contains("Method is missing for HTTP contract") - } - - def 'should fail when no url is present'() { - when: - Contract.make { - request { - method("GET") - } - response { - status 200 - } - } - then: - IllegalStateException ex = thrown(IllegalStateException) - ex.message.contains("URL is missing for HTTP contract") - } - - def 'should fail when no status is present'() { - when: - Contract.make { - request { - url("/foo") - method("GET") - } - response { - } - } - then: - IllegalStateException ex = thrown(IllegalStateException) - ex.message.contains("Status is missing for HTTP contract") - } - - - def 'should set a description'() { - given: - // tag::description[] - org.springframework.cloud.contract.spec.Contract.make { - description(''' -given: - An input -when: - Sth happens -then: - Output -''') - } - // end::description[] - } - - def 'should set a name'() { - given: - // tag::name[] - org.springframework.cloud.contract.spec.Contract.make { - name("some_special_name") - } - // end::name[] - } - - def 'should mark a contract ignored'() { - given: - // tag::ignored[] - org.springframework.cloud.contract.spec.Contract.make { - ignored() - } - // end::ignored[] - } - - def 'should mark a contract in progress'() { - given: - // tag::in_progress[] - org.springframework.cloud.contract.spec.Contract.make { - inProgress() - } - // end::in_progress[] - } - - def 'should make equals and hashcode work properly for URL'() { - expect: - def a = Contract.make { - request { - method("GET") - url("/1") - } - } - def b = Contract.make { - request { - method("GET") - url("/1") - } - } - a == b - } - - def 'should make equals and hashcode work properly for URL with consumer producer'() { - expect: - Contract.make { - request { - method("GET") - url($(c("/1"), p("/1"))) - } - } == Contract.make { - request { - method("GET") - url($(c("/1"), p("/1"))) - } - } - } - - def 'should return true when comparing two equal contracts with gstring'() { - expect: - int index = 1 - def a = Contract.make { - request { - method(PUT()) - headers { - contentType(applicationJson()) - } - url "/${index}" - } - response { - status OK() - } - } - def b = Contract.make { - request { - method(PUT()) - headers { - contentType(applicationJson()) - } - url "/${index}" - } - response { - status OK() - } - } - a.request.method == b.request.method - a.request.url == b.request.url - def firstHeader = a.request.headers.entries.first() - def secondHeader = b.request.headers.entries.first() - firstHeader == secondHeader - a.request.headers.entries == b.request.headers.entries - a.request.headers == b.request.headers - a.request == b.request - a.response.status == b.response.status - a.response == b.response - a == b - } - - def 'should return false when comparing two unequal contracts with gstring'() { - expect: - int index = 1 - def a = Contract.make { - request { - method(PUT()) - headers { - contentType(applicationJson()) - } - url "/${index}" - } - response { - status OK() - } - } - int index2 = 2 - def b = Contract.make { - request { - method(PUT()) - headers { - contentType(applicationJson()) - } - url "/${index2}" - } - response { - status OK() - } - } - a != b - } - - def 'should return true when comparing two equal complex contracts'() { - expect: - def a = Contract.make { - request { - method 'GET' - url '/path' - headers { - header('Accept': $( - consumer(regex('text/.*')), - producer('text/plain') - )) - header('X-Custom-Header': $( - consumer(regex('^.*2134.*$')), - producer('121345') - )) - } - } - response { - status OK() - body( - id: [value: '132'], - surname: 'Kowalsky', - name: 'Jan', - created: '2014-02-02 12:23:43' - ) - headers { - header 'Content-Type': 'text/plain' - } - } - } - def b = Contract.make { - request { - method 'GET' - url '/path' - headers { - header('Accept': $( - consumer(regex('text/.*')), - producer('text/plain') - )) - header('X-Custom-Header': $( - consumer(regex('^.*2134.*$')), - producer('121345') - )) - } - } - response { - status OK() - body( - id: [value: '132'], - surname: 'Kowalsky', - name: 'Jan', - created: '2014-02-02 12:23:43' - ) - headers { - header 'Content-Type': 'text/plain' - } - } - } - a.request.method == b.request.method - a.request.url == b.request.url - def aFirstHeader = a.request.headers.entries.first() - def bFirstHeader = b.request.headers.entries.first() - aFirstHeader == bFirstHeader - def aLastHeader = a.request.headers.entries.last() - def bLastHeader = b.request.headers.entries.last() - aLastHeader == bLastHeader - a.request.headers.entries == b.request.headers.entries - a.request.headers == b.request.headers - a.request.body == b.request.body - a.request == b.request - a.response.status == b.response.status - def aRespFirstHeader = a.response.headers.entries.first() - def bRespFirstHeader = b.response.headers.entries.first() - aRespFirstHeader == bRespFirstHeader - a.response.body == b.response.body - a.response == b.response - a == b - } - - def 'should work with optional and null value of a field'() { - given: - def contract = Contract.make { - description("Creating user") - name("Create user") - request { - method 'POST' - url '/api/user' - body( - address: $(consumer(optional(regex(alphaNumeric()))), producer(null)), - name: $(consumer(optional(regex(alphaNumeric()))), producer('')) - ) - headers { - contentType(applicationJson()) - } - } - response { - status 201 - } - } - expect: - contract != null - } - - @Issue("1200") - def 'should fail when regex do not match the concrete value'() { - when: - Contract.make { - request { - method 'GET' - url '/any' - } - response { - status OK() - body([ - time: $(p(regex(iso8601WithOffset())),c( "thisIsNotADate")) - ]) - } - } - then: - thrown(IllegalStateException) - } - - @Issue("1215") - def 'should work fine when dealing with anyOf'() { - when: - Contract.make { - request { - method 'GET' - url '/any' - body ( - foo: $(consumer(optional(anyOf('WORKS','MIGHTY', 'DESPAIR'))), producer('DESPAIR')) - ) - } - response { - status OK() - } - } - then: - noExceptionThrown() - } -} diff --git a/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/CookiesSpec.groovy b/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/CookiesSpec.groovy deleted file mode 100644 index a41f808f1f..0000000000 --- a/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/CookiesSpec.groovy +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal - -import spock.lang.Specification - -/** - * @author Marcin Grzejszczak - */ -class CookiesSpec extends Specification { - - Cookies cookies = cookie() - - def "should convert cookies to a stub side map"() { - expect: - cookies.asStubSideMap() == [foo: "client", bar: "client"] - } - - def "should convert cookies to a test side map"() { - expect: - cookies.asTestSideMap() == [foo: "server", bar: "server"] - } - - private Cookies cookie() { - Cookies cookies = new Cookies() - cookies.cookie("foo", new DslProperty("client", "server")) - cookies.cookie(["bar": new DslProperty<>("client", "server")]) - return cookies - } -} diff --git a/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/ExecutionPropertySpec.groovy b/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/ExecutionPropertySpec.groovy deleted file mode 100644 index 8f3de9f1b8..0000000000 --- a/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/ExecutionPropertySpec.groovy +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal - -import spock.lang.Specification - -class ExecutionPropertySpec extends Specification { - - def 'should insert passed value in place of $it placeholder'() { - given: - String commandToExecute = 'commandToExecute($it)' - ExecutionProperty executionProperty = new ExecutionProperty(commandToExecute) - and: - String valueToInsert = 'someObject.itsValue' - when: - String commandWithInsertedValue = executionProperty.insertValue(valueToInsert) - then: - 'commandToExecute(someObject.itsValue)' == commandWithInsertedValue - } - - def 'should insert passed value with a $ sign in place of $it placeholder'() { - given: - String commandToExecute = 'commandToExecute($it)' - ExecutionProperty executionProperty = new ExecutionProperty(commandToExecute) - and: - String valueToInsert = '$.someObject.itsValue' - when: - String commandWithInsertedValue = executionProperty.insertValue(valueToInsert) - then: - 'commandToExecute($.someObject.itsValue)' == commandWithInsertedValue - } - -} diff --git a/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/HttpStatusTests.java b/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/HttpStatusTests.java deleted file mode 100644 index cac73eb81e..0000000000 --- a/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/HttpStatusTests.java +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal; - -import org.assertj.core.api.BDDAssertions; -import org.junit.jupiter.api.Test; - -/** - * @author Marcin Grzejszczak - * @author Tim Ysewyn - */ -public class HttpStatusTests { - - @Test - public void CONTINUE() { - BDDAssertions.then(HttpStatus.CONTINUE).isEqualTo(100); - } - - @Test - public void SWITCHING_PROTOCOLS() { - BDDAssertions.then(HttpStatus.SWITCHING_PROTOCOLS).isEqualTo(101); - } - - @Test - public void PROCESSING() { - BDDAssertions.then(HttpStatus.PROCESSING).isEqualTo(102); - } - - @Test - public void CHECKPOINT() { - BDDAssertions.then(HttpStatus.CHECKPOINT).isEqualTo(103); - } - - @Test - public void OK() { - BDDAssertions.then(HttpStatus.OK).isEqualTo(200); - } - - @Test - public void CREATED() { - BDDAssertions.then(HttpStatus.CREATED).isEqualTo(201); - } - - @Test - public void ACCEPTED() { - BDDAssertions.then(HttpStatus.ACCEPTED).isEqualTo(202); - } - - @Test - public void NON_AUTHORITATIVE_INFORMATION() { - BDDAssertions.then(HttpStatus.NON_AUTHORITATIVE_INFORMATION).isEqualTo(203); - } - - @Test - public void NO_CONTENT() { - BDDAssertions.then(HttpStatus.NO_CONTENT).isEqualTo(204); - } - - @Test - public void RESET_CONTENT() { - BDDAssertions.then(HttpStatus.RESET_CONTENT).isEqualTo(205); - } - - @Test - public void PARTIAL_CONTENT() { - BDDAssertions.then(HttpStatus.PARTIAL_CONTENT).isEqualTo(206); - } - - @Test - public void MULTI_STATUS() { - BDDAssertions.then(HttpStatus.MULTI_STATUS).isEqualTo(207); - } - - @Test - public void ALREADY_REPORTED() { - BDDAssertions.then(HttpStatus.ALREADY_REPORTED).isEqualTo(208); - } - - @Test - public void IM_USED() { - BDDAssertions.then(HttpStatus.IM_USED).isEqualTo(226); - } - - @Test - public void MULTIPLE_CHOICES() { - BDDAssertions.then(HttpStatus.MULTIPLE_CHOICES).isEqualTo(300); - } - - @Test - public void MOVED_PERMANENTLY() { - BDDAssertions.then(HttpStatus.MOVED_PERMANENTLY).isEqualTo(301); - } - - @Test - public void FOUND() { - BDDAssertions.then(HttpStatus.FOUND).isEqualTo(302); - } - - @Test - public void SEE_OTHER() { - BDDAssertions.then(HttpStatus.SEE_OTHER).isEqualTo(303); - } - - @Test - public void NOT_MODIFIED() { - BDDAssertions.then(HttpStatus.NOT_MODIFIED).isEqualTo(304); - } - - @Test - public void TEMPORARY_REDIRECT() { - BDDAssertions.then(HttpStatus.TEMPORARY_REDIRECT).isEqualTo(307); - } - - @Test - public void PERMANENT_REDIRECT() { - BDDAssertions.then(HttpStatus.PERMANENT_REDIRECT).isEqualTo(308); - } - - @Test - public void BAD_REQUEST() { - BDDAssertions.then(HttpStatus.BAD_REQUEST).isEqualTo(400); - } - - @Test - public void UNAUTHORIZED() { - BDDAssertions.then(HttpStatus.UNAUTHORIZED).isEqualTo(401); - } - - @Test - public void PAYMENT_REQUIRED() { - BDDAssertions.then(HttpStatus.PAYMENT_REQUIRED).isEqualTo(402); - } - - @Test - public void FORBIDDEN() { - BDDAssertions.then(HttpStatus.FORBIDDEN).isEqualTo(403); - } - - @Test - public void NOT_FOUND() { - BDDAssertions.then(HttpStatus.NOT_FOUND).isEqualTo(404); - } - - @Test - public void METHOD_NOT_ALLOWED() { - BDDAssertions.then(HttpStatus.METHOD_NOT_ALLOWED).isEqualTo(405); - } - - @Test - public void NOT_ACCEPTABLE() { - BDDAssertions.then(HttpStatus.NOT_ACCEPTABLE).isEqualTo(406); - } - - @Test - public void PROXY_AUTHENTICATION_REQUIRED() { - BDDAssertions.then(HttpStatus.PROXY_AUTHENTICATION_REQUIRED).isEqualTo(407); - } - - @Test - public void REQUEST_TIMEOUT() { - BDDAssertions.then(HttpStatus.REQUEST_TIMEOUT).isEqualTo(408); - } - - @Test - public void CONFLICT() { - BDDAssertions.then(HttpStatus.CONFLICT).isEqualTo(409); - } - - @Test - public void GONE() { - BDDAssertions.then(HttpStatus.GONE).isEqualTo(410); - } - - @Test - public void LENGTH_REQUIRED() { - BDDAssertions.then(HttpStatus.LENGTH_REQUIRED).isEqualTo(411); - } - - @Test - public void PRECONDITION_FAILED() { - BDDAssertions.then(HttpStatus.PRECONDITION_FAILED).isEqualTo(412); - } - - @Test - public void PAYLOAD_TOO_LARGE() { - BDDAssertions.then(HttpStatus.PAYLOAD_TOO_LARGE).isEqualTo(413); - } - - @Test - public void URI_TOO_LONG() { - BDDAssertions.then(HttpStatus.URI_TOO_LONG).isEqualTo(414); - } - - @Test - public void UNSUPPORTED_MEDIA_TYPE() { - BDDAssertions.then(HttpStatus.UNSUPPORTED_MEDIA_TYPE).isEqualTo(415); - } - - @Test - public void REQUESTED_RANGE_NOT_SATISFIABLE() { - BDDAssertions.then(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE).isEqualTo(416); - } - - @Test - public void EXPECTATION_FAILED() { - BDDAssertions.then(HttpStatus.EXPECTATION_FAILED).isEqualTo(417); - } - - @Test - public void I_AM_A_TEAPOT() { - BDDAssertions.then(HttpStatus.I_AM_A_TEAPOT).isEqualTo(418); - } - - @Test - public void UNPROCESSABLE_ENTITY() { - BDDAssertions.then(HttpStatus.UNPROCESSABLE_ENTITY).isEqualTo(422); - } - - @Test - public void LOCKED() { - BDDAssertions.then(HttpStatus.LOCKED).isEqualTo(423); - } - - @Test - public void FAILED_DEPENDENCY() { - BDDAssertions.then(HttpStatus.FAILED_DEPENDENCY).isEqualTo(424); - } - - @Test - public void UPGRADE_REQUIRED() { - BDDAssertions.then(HttpStatus.UPGRADE_REQUIRED).isEqualTo(426); - } - - @Test - public void PRECONDITION_REQUIRED() { - BDDAssertions.then(HttpStatus.PRECONDITION_REQUIRED).isEqualTo(428); - } - - @Test - public void TOO_MANY_REQUESTS() { - BDDAssertions.then(HttpStatus.TOO_MANY_REQUESTS).isEqualTo(429); - } - - @Test - public void REQUEST_HEADER_FIELDS_TOO_LARGE() { - BDDAssertions.then(HttpStatus.REQUEST_HEADER_FIELDS_TOO_LARGE).isEqualTo(431); - } - - @Test - public void UNAVAILABLE_FOR_LEGAL_REASONS() { - BDDAssertions.then(HttpStatus.UNAVAILABLE_FOR_LEGAL_REASONS).isEqualTo(451); - } - - @Test - public void INTERNAL_SERVER_ERROR() { - BDDAssertions.then(HttpStatus.INTERNAL_SERVER_ERROR).isEqualTo(500); - } - - @Test - public void NOT_IMPLEMENTED() { - BDDAssertions.then(HttpStatus.NOT_IMPLEMENTED).isEqualTo(501); - } - - @Test - public void BAD_GATEWAY() { - BDDAssertions.then(HttpStatus.BAD_GATEWAY).isEqualTo(502); - } - - @Test - public void SERVICE_UNAVAILABLE() { - BDDAssertions.then(HttpStatus.SERVICE_UNAVAILABLE).isEqualTo(503); - } - - @Test - public void GATEWAY_TIMEOUT() { - BDDAssertions.then(HttpStatus.GATEWAY_TIMEOUT).isEqualTo(504); - } - - @Test - public void HTTP_VERSION_NOT_SUPPORTED() { - BDDAssertions.then(HttpStatus.HTTP_VERSION_NOT_SUPPORTED).isEqualTo(505); - } - - @Test - public void VARIANT_ALSO_NEGOTIATES() { - BDDAssertions.then(HttpStatus.VARIANT_ALSO_NEGOTIATES).isEqualTo(506); - } - - @Test - public void INSUFFICIENT_STORAGE() { - BDDAssertions.then(HttpStatus.INSUFFICIENT_STORAGE).isEqualTo(507); - } - - @Test - public void LOOP_DETECTED() { - BDDAssertions.then(HttpStatus.LOOP_DETECTED).isEqualTo(508); - } - - @Test - public void BANDWIDTH_LIMIT_EXCEEDED() { - BDDAssertions.then(HttpStatus.BANDWIDTH_LIMIT_EXCEEDED).isEqualTo(509); - } - - @Test - public void NOT_EXTENDED() { - BDDAssertions.then(HttpStatus.NOT_EXTENDED).isEqualTo(510); - } - - @Test - public void NETWORK_AUTHENTICATION_REQUIRED() { - BDDAssertions.then(HttpStatus.NETWORK_AUTHENTICATION_REQUIRED).isEqualTo(511); - } - -} diff --git a/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/InputSpec.groovy b/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/InputSpec.groovy deleted file mode 100644 index 28ba598942..0000000000 --- a/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/InputSpec.groovy +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal - -import spock.lang.Specification - -/** - * @author Tim Ysewyn - */ -class InputSpec extends Specification { - - def 'should set property when using the $() convenience method'() { - given: - Input input = new Input() - DslProperty property - when: - input.with { - property = $(consumer(regex("[0-9]{5}"))) - } - def generatedValue = property.serverValue - generatedValue instanceof String - def value = Integer.valueOf(generatedValue as String) - then: - value >= 0 - value <= 99_999 - } - - def 'should set property when using the $() convenience method for Double'() { - given: - Input input = new Input() - DslProperty property - when: - input.with { - property = $(consumer(regex("[0-9]{5}").asDouble())) - } - def value = property.serverValue - value instanceof Double - then: - value >= 0 - value <= 99_999 - } - - def 'should set property when using the $() convenience method for Short'() { - given: - Input input = new Input() - DslProperty property - when: - input.with { - property = $(consumer(regex("[0-9]{1}").asShort())) - } - def value = property.serverValue - value instanceof Short - then: - value >= 0 - value <= 9 - } - - def 'should set property when using the $() convenience method for Long'() { - given: - Input input = new Input() - DslProperty property - when: - input.with { - property = $(consumer(regex("[0-9]{5}").asLong())) - } - def value = property.serverValue - value instanceof Long - then: - value >= 0 - value <= 99_999 - } - - def 'should set property when using the $() convenience method for Integer'() { - given: - Input input = new Input() - DslProperty property - when: - input.with { - property = $(consumer(regex("[0-9]{5}").asInteger())) - } - def value = property.serverValue - value instanceof Integer - then: - value >= 0 - value <= 99_999 - } - - def 'should set property when using the $() convenience method for Float'() { - given: - Input input = new Input() - DslProperty property - when: - input.with { - property = $(consumer(regex("[0-9]{5}").asFloat())) - } - def value = property.serverValue - value instanceof Float - then: - value >= 0 - value <= 99_999 - } -} diff --git a/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/MatchingTypeSpec.groovy b/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/MatchingTypeSpec.groovy deleted file mode 100644 index 0e816a2bfa..0000000000 --- a/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/MatchingTypeSpec.groovy +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal - -import spock.lang.Specification - -/** - * @author Marcin Grzejszczak - */ -class MatchingTypeSpec extends Specification { - def "should return [#expected] for type [#type]"() { - expect: - MatchingType.regexRelated(type) == expected - where: - type | expected - MatchingType.EQUALITY | false - MatchingType.TYPE | false - MatchingType.COMMAND | false - MatchingType.REGEX | true - MatchingType.DATE | true - MatchingType.TIME | true - MatchingType.TIMESTAMP | true - - } -} diff --git a/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/OutputMessageSpec.groovy b/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/OutputMessageSpec.groovy deleted file mode 100644 index 2815e2f0d6..0000000000 --- a/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/OutputMessageSpec.groovy +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal - -import spock.lang.Specification - -/** - * @author Tim Ysewyn - */ -class OutputMessageSpec extends Specification { - - def 'should set property when using the $() convenience method'() { - given: - OutputMessage contract = new OutputMessage() - DslProperty property - when: - contract.with { - property = $(producer(regex("[0-9]{5}"))) - } - def generatedValue = property.clientValue - generatedValue instanceof String - def value = Integer.valueOf(generatedValue as String) - then: - value >= 0 - value <= 99_999 - } - - def 'should set property when using the $() convenience method for Double'() { - given: - OutputMessage contract = new OutputMessage() - DslProperty property - when: - contract.with { - property = $(producer(regex("[0-9]{5}").asDouble())) - } - def value = property.clientValue - value instanceof Double - then: - value >= 0 - value <= 99_999 - } - - def 'should set property when using the $() convenience method for Short'() { - given: - OutputMessage contract = new OutputMessage() - DslProperty property - when: - contract.with { - property = $(producer(regex("[0-9]{1}").asShort())) - } - def value = property.clientValue - value instanceof Short - then: - value >= 0 - value <= 9 - } - - def 'should set property when using the $() convenience method for Long'() { - given: - OutputMessage contract = new OutputMessage() - DslProperty property - when: - contract.with { - property = $(producer(regex("[0-9]{5}").asLong())) - } - def value = property.clientValue - value instanceof Long - then: - value >= 0 - value <= 99_999 - } - - def 'should set property when using the $() convenience method for Integer'() { - given: - OutputMessage contract = new OutputMessage() - DslProperty property - when: - contract.with { - property = $(producer(regex("[0-9]{5}").asInteger())) - } - def value = property.clientValue - value instanceof Integer - then: - value >= 0 - value <= 99_999 - } - - def 'should set property when using the $() convenience method for Float'() { - given: - OutputMessage contract = new OutputMessage() - DslProperty property - when: - contract.with { - property = $(producer(regex("[0-9]{5}").asFloat())) - } - def value = property.clientValue - value instanceof Float - then: - value >= 0 - value <= 99_999 - } -} diff --git a/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/RegexPatternsSpec.groovy b/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/RegexPatternsSpec.groovy deleted file mode 100644 index 97334d1cbd..0000000000 --- a/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/RegexPatternsSpec.groovy +++ /dev/null @@ -1,391 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal - -import spock.lang.Specification - -class RegexPatternsSpec extends Specification { - - def "should generate a regex for ip address [#textToMatch] that is a match [#shouldMatch]"() { - expect: - shouldMatch == RegexPatterns.ipAddress().matcher(textToMatch).matches() - where: - textToMatch || shouldMatch - '123.123.123.123' || true - 'a.b.' || false - } - - def "should generate a regex for hostname [#textToMatch] that is a match [#shouldMatch]"() { - expect: - shouldMatch == RegexPatterns.hostname().matcher(textToMatch).matches() - where: - textToMatch || shouldMatch - 'https://asd.com' || true - 'https://asd.com:8080' || true - 'https://localhost' || true - 'https://localhost:8080' || true - 'https://asd.com/asd' || false - 'asd.com' || false - } - - def "should generate a regex for email [#textToMatch] that is a match [#shouldMatch]"() { - expect: - shouldMatch == RegexPatterns.email().matcher(textToMatch).matches() - where: - textToMatch || shouldMatch - 'asd@asd.com' || true - 'a.b.' || false - 'asdf@asdf.online' || true - } - - // @see https://formvalidation.io/validators/uri/ - def "should generate a regex for url [#textToMatch] that is a match [#shouldMatch]"() { - expect: - shouldMatch == RegexPatterns.url().matcher(textToMatch).matches() - where: - textToMatch || shouldMatch - 'ftp://asd.com:9090/asd/a?a=b' || true - 'http://www.foo.com/blah_blah' || true - 'ftp://localhost/api' || true - 'http://localhost:8080/api' || true - 'http://www.foo.com/blah_blah/' || true - 'http://www.foo.com/blah_blah_(wikipedia)' || true - 'http://www.foo.com/blah_blah_(wikipedia)_(again)' || true - 'https://www.example.com/wpstyle/?p=364' || true - 'https://www.example.com/foo/?bar=baz&inga=42&quux' || true - 'http://✪df.ws/123' || true - 'https://userid:password@example.com:8080' || true - 'https://userid:password@example.com:8080/' || true - 'https://userid@example.com' || true - 'https://userid@example.com/' || true - 'https://userid@example.com:8080' || true - 'https://userid@example.com:8080/' || true - 'https://userid:password@example.com' || true - 'https://userid:password@example.com/' || true - 'https://142.42.1.1/' || true - 'https://142.42.1.1:8080/' || true - 'http://⌘.ws' || true - 'http://⌘.ws/' || true - 'http://www.foo.com/blah_(wikipedia)#cite-1' || true - 'http://www.foo.com/blah_(wikipedia)_blah#cite-1' || true - 'http://www.foo.com/unicode_(✪)_in_parens' || true - 'http://www.foo.com/(something)?after=parens' || true - 'http://☺.damowmow.com/' || true - 'https://code.google.com/events/#&product=browser' || true - 'https://j.mp' || true - 'ftp://foo.bar/baz' || true - 'https://foo.bar/?q=Test%20URL-encoded%20stuff' || true - 'https://1224.net/' || true - 'https://a.b-c.de' || true - 'https://223.255.255.254' || true - 'foo.com' || true - 'a.b.' || false - 'http://' || false - 'http://.' || false - 'http://..' || false - 'https://../' || false - 'http://?' || false - 'http://??' || false - 'https://??/' || false - 'http://#' || false - 'http://##' || false - 'http://##/' || false - 'https://foo.bar?q=Spaces should be encoded' || false - '//' || false - '//a' || false - '///a' || false - '///' || false - 'https:///a' || false - 'rdar://1234' || false - 'h://test' || false - 'http:// shouldfail.com' || false - ':// should fail' || false - 'https://foo.bar/foo(bar)baz quux' || false - 'https://-error-.invalid/' || false - 'https://-a.b.co' || false - 'https://a.b-.co' || false - 'https://1.1.1.1.1' || false - 'https://123.123.123' || false - 'https://3628126748' || false - 'https://.www.foo.bar/' || false - 'https://www.foo.bar./' || false - 'https://.www.foo.bar./' || false - } - - def "should generate a regex for httpsUrl [#textToMatch] that is a match [#shouldMatch]"() { - expect: - shouldMatch == RegexPatterns.httpsUrl().matcher(textToMatch).matches() - where: - textToMatch || shouldMatch - 'ftp://asd.com:9090/asd/a?a=b' || false - 'https://foo.com/blah_blah/' || true - 'https://foo.com/blah_blah' || true - 'http://www.foo.com/blah_blah' || false - 'http://www.foo.com/blah_blah/' || false - 'https://foo.com/blah_blah_(wikipedia)' || true - 'https://foo.com/blah_blah_(wikipedia)_(again)' || true - 'https://www.example.com/wpstyle/?p=364' || true - 'https://www.example.com/foo/?bar=baz&inga=42&quux' || true - 'https://✪df.ws/123' || true - 'https://userid:password@example.com:8080' || true - 'https://userid:password@example.com:8080/' || true - 'https://userid@example.com' || true - 'https://userid@example.com/' || true - 'https://userid@example.com:8080' || true - 'https://userid@example.com:8080/' || true - 'https://userid:password@example.com' || true - 'https://userid:password@example.com/' || true - 'https://142.42.1.1/' || true - 'https://142.42.1.1:8080/' || true - 'https://⌘.ws' || true - 'https://⌘.ws/' || true - 'https://foo.com/blah_(wikipedia)#cite-1' || true - 'https://foo.com/blah_(wikipedia)_blah#cite-1' || true - 'https://foo.com/unicode_(✪)_in_parens' || true - 'https://foo.com/(something)?after=parens' || true - 'https://☺.damowmow.com/' || true - 'https://code.google.com/events/#&product=browser' || true - 'https://j.mp' || true - 'ftp://foo.bar/baz' || false - 'https://foo.bar/?q=Test%20URL-encoded%20stuff' || true - 'https://1337.net' || true - 'https://a.b-c.de' || true - 'https://223.255.255.254' || true - 'foo.com' || false - 'a.b.' || false - 'https://' || false - 'https://.' || false - 'https://..' || false - 'https://../' || false - 'https://?' || false - 'https://??' || false - 'https://??/' || false - 'https://#' || false - 'https://##' || false - 'https://##/' || false - 'https://foo.bar?q=Spaces should be encoded' || false - '//' || false - '//a' || false - '///a' || false - '///' || false - 'https:///a' || false - 'rdar://1234' || false - 'h://test' || false - 'https:// shouldfail.com' || false - ':// should fail' || false - 'https://foo.bar/foo(bar)baz quux' || false - 'https://-error-.invalid/' || false - 'https://-a.b.co' || false - 'https://a.b-.co' || false - 'https://1.1.1.1.1' || false - 'https://123.123.123' || false - 'https://3628126748' || false - 'https://.www.foo.bar/' || false - 'https://www.foo.bar./' || false - 'https://.www.foo.bar./' || false - } - - def "should generate a regex for a number [#textToMatch] that is a match [#shouldMatch]"() { - expect: - shouldMatch == RegexPatterns.number().matcher(textToMatch).matches() - where: - textToMatch || shouldMatch - '1' || true - '1.0' || true - '0.1' || true - '.1' || true - '1.' || false - } - - def "should generate a regex for a positive integer [#textToMatch] that is a match [#shouldMatch]"() { - expect: - shouldMatch == RegexPatterns.positiveInt().matcher(textToMatch).matches() - where: - textToMatch || shouldMatch - '1' || true - '12345' || true - '-1' || false - '0' || false - '1.0' || false - } - - def "should generate a regex for a double [#textToMatch] that is a match [#shouldMatch]"() { - expect: - shouldMatch == RegexPatterns.aDouble().matcher(textToMatch).matches() - where: - textToMatch || shouldMatch - '1' || false - '1.0' || true - '0.1' || true - '.1' || true - '1.' || false - } - - def "should generate a regex for a uuid [#textToMatch] that is a match [#shouldMatch]"() { - expect: - shouldMatch == RegexPatterns.uuid().matcher(textToMatch).matches() - where: - textToMatch || shouldMatch - UUID.randomUUID().toString() || true - UUID.randomUUID().toString() || true - UUID.randomUUID().toString().toUpperCase() || true - UUID.randomUUID().toString() + "!" || false - '23e4567-z89b-12z3-j456-426655440000' || false - 'dog' || false - '5' || false - } - - def "should generate a regex for a uuidv4 [#textToMatch] that is a match [#shouldMatch]"() { - expect: - shouldMatch == RegexPatterns.uuid4().matcher(textToMatch).matches() - where: - textToMatch || shouldMatch - UUID.randomUUID().toString() || true - UUID.randomUUID().toString() || true - UUID.randomUUID().toString().toUpperCase() || true - '123e4567-e89b-42d3-a456-556642440000' || true - '00000000-0000-4000-8000-000000000000' || true - '00000000-0000-4000-9000-000000000000' || true - '00000000-0000-4000-a000-000000000000' || true - '00000000-0000-4000-b000-000000000000' || true - '00000000-0000-4000-1000-000000000000' || false - UUID.randomUUID().toString() + "!" || false - '00000000-0000-0000-0000-000000000000' || false - 'dog' || false - '5' || false - } - - def "should generate a regex with date [#textToMatch] in YYYY-MM-DD format that should match [#shouldMatch]"() { - expect: - shouldMatch == RegexPatterns.isoDate().matcher(textToMatch).matches() - where: - textToMatch || shouldMatch - "2014-03-01" || true - "1014-03-01" || true - "1014-3-01" || false - "14-03-01" || false - "1014-12-01" || true - "1014-12-31" || true - "1014-12-1" || false - "1014-12-32" || false - "1014-13-31" || false - "1014-20-30" || false - '5' || false - } - - def "should generate a regex with datetime [#textToMatch] in YYYY-MM-DDTHH:mm:ss format that should match [#shouldMatch]"() { - expect: - shouldMatch == RegexPatterns.isoDateTime().matcher(textToMatch).matches() - where: - textToMatch || shouldMatch - "2014-03-01T12:23:45" || true - "1014-03-01T23:59:59" || true - "1014-3-01T01:01:01" || false - "1014-03-01T00:00:00" || true - "1014-03-01T00:00:0" || false - "1014-03-01T00:0:01" || false - "1014-03-01T0:01:01" || false - "1014-03-0100:01:01" || false - "14-03-01T12:23:45" || false - "1014-12-01T12:23:45" || true - "1014-12-31T12:23:45" || true - "1014-12-1T12:23:45" || false - "1014-12-32T12:23:45" || false - "1014-13-31T12:23:45" || false - "1014-20-30T12:23:45" || false - "1014-20-30T24:23:45" || false - "1014-20-30T23:60:45" || false - "1014-20-30T23:59:60" || false - } - - def "should generate a regex with time [#textToMatch] in HH:mm:ss format that should match [#shouldMatch]"() { - expect: - shouldMatch == RegexPatterns.isoTime().matcher(textToMatch).matches() - where: - textToMatch || shouldMatch - "12:23:45" || true - "23:59:59" || true - "00:00:00" || true - "00:00:0" || false - "00:0:01" || false - "0:01:01" || false - "24:23:45" || false - "23:60:45" || false - "23:59:60" || false - } - - def "should generate a regex with iso8601DateTimeWithTimezone [#textToMatch] in YYYY-MM-DDTHH:mm:ss.SSSZZ format that should match [#shouldMatch]"() { - expect: - shouldMatch == RegexPatterns.iso8601WithOffset().matcher(textToMatch).matches() - where: - textToMatch || shouldMatch - '2014-03-01T12:23:45Z' || true - '2014-03-01T12:23:45+01:00' || true - '2014-03-01T12:23:45.1Z' || true - '2014-03-01T12:23:45.12Z' || true - '2014-03-01T12:23:45.123Z' || true - '2014-03-01T12:23:45.1234Z' || true - '2014-03-01T12:23:45.12345Z' || true - '2014-03-01T12:23:45.123456Z' || true - '2014-03-01T12:23:45.1+01:00' || true - '2014-03-01T12:23:45.12+01:00' || true - '2014-03-01T12:23:45.123+01:00' || true - '2014-03-01T12:23:45.1234+01:00' || true - '2014-03-01T12:23:45.12345+01:00' || true - '2014-03-01T12:23:45.123456+01:00' || true - '2014-03-01T12:23:45' || false - '2014-03-01T12:23:45.123' || false - } - - def "should generate a regex for a non blank string [#textToMatch] that should match [#shouldMatch]"() { - expect: - shouldMatch == RegexPatterns.nonBlank().matcher(textToMatch).matches() - where: - textToMatch || shouldMatch - 'Not Empty' || true - '' || false - ' ' || false - '\nFoo\nBar\n' || true - '\r\n' || false - ' \r\n\t' || false - - } - - def "should generate a regex for a non empty string [#textToMatch] that should match [#shouldMatch]"() { - expect: - shouldMatch == RegexPatterns.nonEmpty().matcher(textToMatch).matches() - where: - textToMatch || shouldMatch - 'Not Empty' || true - '' || false - ' ' || true - '\nFoo\nBar\n' || true - '\r\n' || true - ' \r\n\t' || true - - } - - def "should generate a regex for an enumerated value [#textToMatch] that should match [#shouldMatch]"() { - expect: - shouldMatch == RegexPatterns.anyOf('foo', 'bar').matcher(textToMatch).matches() - where: - textToMatch || shouldMatch - 'foo' || true - 'bar' || true - 'baz' || false - } -} diff --git a/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/RequestSpec.groovy b/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/RequestSpec.groovy deleted file mode 100644 index b0195c86f5..0000000000 --- a/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/RequestSpec.groovy +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal - -import spock.lang.Specification - -/** - * @author Marcin Grzejszczak - */ -class RequestSpec extends Specification { - - def 'should throw exception when on request side a value contains regex for server'() { - given: - Request contract = new Request() - when: - contract.with { - value(consumer("foo"), producer(regex("foo"))) - } - then: - thrown(IllegalStateException) - when: - contract.with { - value(producer(regex("foo")), consumer("foo")) - } - then: - thrown(IllegalStateException) - } - - def 'should set property when using the $() convenience method'() { - given: - Request contract = new Request() - DslProperty property - when: - contract.with { - property = $(consumer(regex("[0-9]{5}"))) - } - def generatedValue = property.serverValue - generatedValue instanceof String - def value = Integer.valueOf(generatedValue as String) - then: - value >= 0 - value <= 99_999 - } - - def 'should set property when using the $() convenience method for Double'() { - given: - Request contract = new Request() - DslProperty property - when: - contract.with { - property = $(consumer(regex("[0-9]{5}").asDouble())) - } - def value = property.serverValue - value instanceof Double - then: - value >= 0 - value <= 99_999 - } - - def 'should set property when using the $() convenience method for Short'() { - given: - Request contract = new Request() - DslProperty property - when: - contract.with { - property = $(consumer(regex("[0-9]{1}").asShort())) - } - def value = property.serverValue - value instanceof Short - then: - value >= 0 - value <= 9 - } - - def 'should set property when using the $() convenience method for Long'() { - given: - Request contract = new Request() - DslProperty property - when: - contract.with { - property = $(consumer(regex("[0-9]{5}").asLong())) - } - def value = property.serverValue - value instanceof Long - then: - value >= 0 - value <= 99_999 - } - - def 'should set property when using the $() convenience method for Integer'() { - given: - Request contract = new Request() - DslProperty property - when: - contract.with { - property = $(consumer(regex("[0-9]{5}").asInteger())) - } - def value = property.serverValue - value instanceof Integer - then: - value >= 0 - value <= 99_999 - } - - def 'should set property when using the $() convenience method for Float'() { - given: - Request contract = new Request() - DslProperty property - when: - contract.with { - property = $(consumer(regex("[0-9]{5}").asFloat())) - } - def value = property.serverValue - value instanceof Float - then: - value >= 0 - value <= 99_999 - } - - def 'should generate a value if only regex is passed for client'() { - given: - Request request = new Request() - DslProperty property - when: - request.with { - property = value(consumer(regex("[0-9]{5}"))) - } - def value = Integer.valueOf(property.serverValue as String) - then: - value >= 0 - value <= 99_999 - } -} diff --git a/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/ResponseSpec.groovy b/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/ResponseSpec.groovy deleted file mode 100644 index 98dd6f9e7c..0000000000 --- a/specs/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/ResponseSpec.groovy +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.spec.internal - -import spock.lang.Specification - -/** - * @author Marcin Grzejszczak - */ -class ResponseSpec extends Specification { - - def 'should throw exception when on response side a value contains regex for client'() { - given: - Response response = new Response() - when: - response.with { - value(producer("foo"), consumer(regex("foo"))) - } - then: - thrown(IllegalStateException) - when: - response.with { - value(consumer(regex("foo")), producer("foo")) - } - then: - thrown(IllegalStateException) - } - - - def 'should set property when using the $() convenience method'() { - given: - Response contract = new Response() - DslProperty property - when: - contract.with { - property = $(producer(regex("[0-9]{5}"))) - } - def generatedValue = property.clientValue - generatedValue instanceof String - def value = Integer.valueOf(generatedValue as String) - then: - value >= 0 - value <= 99_999 - } - - def 'should set property when using the $() convenience method for Double'() { - given: - Response contract = new Response() - DslProperty property - when: - contract.with { - property = $(producer(regex("[0-9]{5}").asDouble())) - } - def value = property.clientValue - value instanceof Double - then: - value >= 0 - value <= 99_999 - } - - def 'should set property when using the $() convenience method for Short'() { - given: - Response contract = new Response() - DslProperty property - when: - contract.with { - property = $(producer(regex("[0-9]{1}").asShort())) - } - def value = property.clientValue - value instanceof Short - then: - value >= 0 - value <= 9 - } - - def 'should set property when using the $() convenience method for Long'() { - given: - Response contract = new Response() - DslProperty property - when: - contract.with { - property = $(producer(regex("[0-9]{5}").asLong())) - } - def value = property.clientValue - value instanceof Long - then: - value >= 0 - value <= 99_999 - } - - def 'should set property when using the $() convenience method for Integer'() { - given: - Response contract = new Response() - DslProperty property - when: - contract.with { - property = $(producer(regex("[0-9]{5}").asInteger())) - } - def value = property.clientValue - value instanceof Integer - then: - value >= 0 - value <= 99_999 - } - - def 'should set property when using the $() convenience method for Float'() { - given: - Response contract = new Response() - DslProperty property - when: - contract.with { - property = $(producer(regex("[0-9]{5}").asFloat())) - } - def value = property.clientValue - value instanceof Float - then: - value >= 0 - value <= 99_999 - } -} diff --git a/spring-cloud-contract-dependencies/.factorypath b/spring-cloud-contract-dependencies/.factorypath deleted file mode 100644 index e91bd5122d..0000000000 --- a/spring-cloud-contract-dependencies/.factorypath +++ /dev/null @@ -1,167 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/spring-cloud-contract-dependencies/pom.xml b/spring-cloud-contract-dependencies/pom.xml deleted file mode 100644 index 5b97e2388f..0000000000 --- a/spring-cloud-contract-dependencies/pom.xml +++ /dev/null @@ -1,171 +0,0 @@ - - - 4.0.0 - - spring-cloud-dependencies-parent - org.springframework.cloud - 4.1.0-SNAPSHOT - - - spring-cloud-contract-dependencies - 4.1.0-SNAPSHOT - pom - spring-cloud-contract-dependencies - Spring Cloud Contract Dependencies - - 2.35.0 - 0.6.2 - - - - - org.springframework.cloud - spring-cloud-contract-wiremock - ${project.version} - - - org.springframework.cloud - spring-cloud-contract-spec - ${project.version} - - - org.springframework.cloud - spring-cloud-contract-spec-java - ${project.version} - - - org.springframework.cloud - spring-cloud-contract-spec-groovy - ${project.version} - - - org.springframework.cloud - spring-cloud-contract-spec-kotlin - ${project.version} - - - org.springframework.cloud - spring-cloud-contract-verifier - ${project.version} - - - org.springframework.cloud - spring-cloud-contract-converters - ${project.version} - - - org.springframework.cloud - spring-cloud-contract-stub-runner - ${project.version} - - - org.springframework.cloud - spring-cloud-contract-stub-runner-boot - ${project.version} - - - org.springframework.cloud - spring-cloud-contract-shade - ${project.version} - - - org.springframework.cloud - spring-cloud-starter-contract-verifier - ${project.version} - - - org.springframework.cloud - spring-cloud-starter-contract-stub-runner - ${project.version} - - - org.springframework.cloud - spring-cloud-starter-contract-stub-runner-jetty - ${project.version} - - - org.springframework.cloud - spring-cloud-contract-maven-plugin - ${project.version} - - - org.springframework.cloud - spring-cloud-contract-gradle-plugin - ${project.version} - - - com.github.tomakehurst - wiremock-jre8-standalone - ${wiremock.version} - - - - com.toomuchcoding.jsonassert - jsonassert - ${jsonassert.version} - - - com.toomuchcoding.jsonassert - jsonassert-shade - ${jsonassert.version} - - - - - - spring - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - false - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - false - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - - - diff --git a/spring-cloud-contract-shade/dependency-reduced-pom.xml b/spring-cloud-contract-shade/dependency-reduced-pom.xml new file mode 100644 index 0000000000..a0819f8a30 --- /dev/null +++ b/spring-cloud-contract-shade/dependency-reduced-pom.xml @@ -0,0 +1,205 @@ + + + + spring-cloud-contract-parent + org.springframework.cloud + 4.1.0-SNAPSHOT + + 4.0.0 + spring-cloud-contract-shade + Spring Cloud Contract Shaded Dependencies + Spring Cloud Contract Shaded Dependencies + + + + maven-shade-plugin + + + package + + shade + + + true + false + true + true + false + + + com.google + shaded.com.google + + + org.eclipse.aether.connector + shaded.org.eclipse.aether.connector + + + org.eclipse.aether.transport + shaded.org.eclipse.aether.transport + + + org.eclipse.aether.impl + shaded.org.eclipse.aether.impl + + + org.eclipse.aether.internal + shaded.org.eclipse.aether.internal + + + org.eclipse.aether.spi + shaded.org.eclipse.aether.spi + + + org.apache.maven + shaded.org.apache.maven + + + + + + org/slf4j/ + + + + + + + + + maven-dependency-plugin + ${maven-dependency-plugin.version} + + + unpack-dependencies + package + + unpack + + + + + org.springframework.cloud + spring-cloud-contract-shade + ${project.version} + sources + jar + false + ${project.build.directory}/sources + + + **/shaded/**/*.*,**/org/eclipse/**/*.*,**/org/codehaus/plexus/**/*.* + + + + + + org.codehaus.mojo + build-helper-maven-plugin + ${build-helper-maven-plugin.version} + + + attach-zip + none + + + add-source + package + + add-source + + + + ${project.build.directory}/sources + + + + + + + maven-surefire-plugin + + false + + + + + + + org.eclipse.sisu + org.eclipse.sisu.inject + 0.3.5 + provided + true + + + org.eclipse.sisu + org.eclipse.sisu.plexus + 0.3.5 + provided + + + cdi-api + javax.enterprise + + + true + + + org.sonatype.sisu + sisu-guice + 4.2.0 + no_aop + provided + + + aopalliance + aopalliance + + + jsr305 + com.google.code.findbugs + + + guava + com.google.guava + + + true + + + org.ow2.asm + asm + 9.4 + provided + true + + + cglib + cglib + 3.3.0 + provided + true + + + org.checkerframework + checker + 3.25.0 + provided + true + + + + 5.0.0 + 0.3.5 + 3.25.0 + 4.2.0 + 9.4 + 3.0.0 + 30.0-jre + 3.5.0 + 0.3.5 + 3.1.2 + 4.5.13 + + diff --git a/spring-cloud-contract-shade/pom.xml b/spring-cloud-contract-shade/pom.xml deleted file mode 100644 index 875630a8aa..0000000000 --- a/spring-cloud-contract-shade/pom.xml +++ /dev/null @@ -1,311 +0,0 @@ - - - 4.0.0 - - 0.3.5 - 0.3.5 - 4.2.0 - 5.0.0 - 30.0-jre - 9.4 - 3.25.0 - 3.1.2 - 3.0.0 - 3.5.0 - 4.5.13 - - - org.springframework.cloud - spring-cloud-contract-parent - 4.1.0-SNAPSHOT - .. - - spring-cloud-contract-shade - jar - Spring Cloud Contract Shaded Dependencies - Spring Cloud Contract Shaded Dependencies - - - org.apache.maven.resolver - maven-resolver-api - true - - - org.apache.maven.resolver - maven-resolver-spi - true - - - org.apache.maven.resolver - maven-resolver-util - true - - - org.apache.maven.resolver - maven-resolver-impl - true - - - org.apache.maven.resolver - maven-resolver-connector-basic - true - - - org.apache.maven.resolver - maven-resolver-transport-classpath - true - - - org.apache.maven.resolver - maven-resolver-transport-file - true - - - org.apache.maven.resolver - maven-resolver-transport-http - true - - - org.apache.maven.resolver - maven-resolver-transport-wagon - true - - - org.apache.maven - maven-resolver-provider - true - - - com.google.guava - guava - - - - - org.apache.maven - maven-artifact - true - - - org.apache.maven - maven-settings-builder - true - - - - org.codehaus.plexus - plexus-utils - ${plexus-utils.version} - true - - - org.eclipse.sisu - org.eclipse.sisu.inject - ${org.eclipse.sisu.inject.version} - true - provided - - - org.eclipse.sisu - org.eclipse.sisu.plexus - ${org.eclipse.sisu.plexus.version} - - - javax.enterprise - cdi-api - - - true - provided - - - org.sonatype.sisu - sisu-guice - ${sisu-guice.version} - no_aop - - - aopalliance - aopalliance - - - com.google.code.findbugs - jsr305 - - - com.google.guava - guava - - - true - provided - - - com.google.guava - guava - ${guava.version} - true - - - com.google.inject - guice - ${guice.version} - true - - - org.ow2.asm - asm - ${asm.version} - true - provided - - - cglib - cglib - true - provided - - - org.checkerframework - checker - ${checker.version} - true - provided - - - org.apache.httpcomponents - httpclient - ${apache-client.version} - true - - - - - - org.apache.maven.plugins - maven-shade-plugin - - - package - - shade - - - true - false - true - true - false - - - - com.google - shaded.com.google - - - - org.eclipse.aether.connector - shaded.org.eclipse.aether.connector - - - - org.eclipse.aether.transport - shaded.org.eclipse.aether.transport - - - - org.eclipse.aether.impl - shaded.org.eclipse.aether.impl - - - - org.eclipse.aether.internal - shaded.org.eclipse.aether.internal - - - - org.eclipse.aether.spi - shaded.org.eclipse.aether.spi - - - - org.apache.maven - shaded.org.apache.maven - - - - - - org/slf4j/ - - - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - ${maven-dependency-plugin.version} - - - unpack-dependencies - package - - unpack - - - - - org.springframework.cloud - spring-cloud-contract-shade - ${project.version} - sources - jar - false - ${project.build.directory}/sources - - - - **/shaded/**/*.*,**/org/eclipse/**/*.*,**/org/codehaus/plexus/**/*.* - - - - - - - org.codehaus.mojo - build-helper-maven-plugin - ${build-helper-maven-plugin.version} - - - attach-zip - none - - - add-source - package - - add-source - - - - ${project.build.directory}/sources - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - - - - - diff --git a/spring-cloud-contract-starters/pom.xml b/spring-cloud-contract-starters/pom.xml deleted file mode 100644 index cc6bdffef3..0000000000 --- a/spring-cloud-contract-starters/pom.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - 4.0.0 - - - org.springframework.cloud - spring-cloud-contract-parent - 4.1.0-SNAPSHOT - .. - - - spring-cloud-contract-starters - pom - - Spring Cloud Contract Starters - Spring Cloud Contract Starters - - - spring-cloud-starter-contract-stub-runner - spring-cloud-starter-contract-stub-runner-jetty - spring-cloud-starter-contract-verifier - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - - - - - - diff --git a/spring-cloud-contract-starters/spring-cloud-starter-contract-stub-runner-jetty/README.adoc b/spring-cloud-contract-starters/spring-cloud-starter-contract-stub-runner-jetty/README.adoc deleted file mode 100644 index f6daee95db..0000000000 --- a/spring-cloud-contract-starters/spring-cloud-starter-contract-stub-runner-jetty/README.adoc +++ /dev/null @@ -1,3 +0,0 @@ -=== Stub Runner Jetty - -Convenience module that pulls together the dependencies needed to run the Stub Runner with WireMock, but without Spring Boot. \ No newline at end of file diff --git a/spring-cloud-contract-starters/spring-cloud-starter-contract-stub-runner-jetty/pom.xml b/spring-cloud-contract-starters/spring-cloud-starter-contract-stub-runner-jetty/pom.xml deleted file mode 100644 index 190682a451..0000000000 --- a/spring-cloud-contract-starters/spring-cloud-starter-contract-stub-runner-jetty/pom.xml +++ /dev/null @@ -1,80 +0,0 @@ - - - 4.0.0 - - org.springframework.cloud - spring-cloud-contract-starters - 4.1.0-SNAPSHOT - .. - - spring-cloud-starter-contract-stub-runner-jetty - jar - Spring Cloud Contract Stub Runner Starter Jetty - Spring Cloud Contract Stub Runner Jetty runs wiremock stubs with "native" - jetty. Don't use this in a Spring Boot app with its own embedded container. - - - - org.springframework.cloud - spring-cloud-contract-stub-runner - - - jetty-ee10-servlet - org.eclipse.jetty.ee10 - - - jetty-ee10-servlet - org.eclipse.jetty.ee10 - - - jetty-ee10-servlets - org.eclipse.jetty.ee10 - - - cglib - cglib - - - org.spockframework - spock-core - - - org.spockframework - spock-spring - - - org.springframework.boot - spring-boot-starter-test - - - org.junit.vintage - junit-vintage-engine - - - - - org.springframework.boot - spring-boot-starter-web - - - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - true - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - - - - - diff --git a/spring-cloud-contract-starters/spring-cloud-starter-contract-stub-runner/pom.xml b/spring-cloud-contract-starters/spring-cloud-starter-contract-stub-runner/pom.xml deleted file mode 100644 index f223da81a8..0000000000 --- a/spring-cloud-contract-starters/spring-cloud-starter-contract-stub-runner/pom.xml +++ /dev/null @@ -1,103 +0,0 @@ - - - - - 4.0.0 - - org.springframework.cloud - spring-cloud-contract-starters - 4.1.0-SNAPSHOT - .. - - spring-cloud-starter-contract-stub-runner - jar - Spring Cloud Contract Stub Runner Starter - Spring Cloud Contract Stub Runner Starter - - - org.springframework.cloud - spring-cloud-contract-stub-runner - - - org.junit.vintage - junit-vintage-engine - - - - - org.springframework.boot - spring-boot-starter-web - true - - - org.springframework.boot - spring-boot-starter-test - - - org.junit.vintage - junit-vintage-engine - - - - - org.springframework.cloud - spring-cloud-stream-test-binder - true - test - - - org.springframework.cloud - spring-cloud-contract-wiremock - - - org.junit.vintage - junit-vintage-engine - - - - - - org.apache.maven.resolver - maven-resolver-api - - - org.sonatype.sisu - sisu-inject-plexus - - - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - true - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - - - - - diff --git a/spring-cloud-contract-starters/spring-cloud-starter-contract-verifier/pom.xml b/spring-cloud-contract-starters/spring-cloud-starter-contract-verifier/pom.xml deleted file mode 100644 index 5d0d5d22fd..0000000000 --- a/spring-cloud-contract-starters/spring-cloud-starter-contract-verifier/pom.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - 4.0.0 - - org.springframework.cloud - spring-cloud-contract-starters - 4.1.0-SNAPSHOT - .. - - spring-cloud-starter-contract-verifier - jar - Spring Cloud Contract Verifier Starter - Spring Cloud Contract Verifier Starter - - - org.springframework.cloud - spring-cloud-contract-verifier - - - io.rest-assured - rest-assured - - - io.rest-assured - spring-mock-mvc - - - com.toomuchcoding.jsonassert - jsonassert - - - cglib - cglib - - - org.springframework.boot - spring-boot-starter-test - - - org.junit.vintage - junit-vintage-engine - - - - - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - true - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - - - - - diff --git a/spring-cloud-contract-stub-runner-boot/.gitignore b/spring-cloud-contract-stub-runner-boot/.gitignore deleted file mode 100644 index c71ea97aba..0000000000 --- a/spring-cloud-contract-stub-runner-boot/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/.apt_generated/ diff --git a/spring-cloud-contract-stub-runner-boot/log.log b/spring-cloud-contract-stub-runner-boot/log.log new file mode 100644 index 0000000000..fc39c89808 --- /dev/null +++ b/spring-cloud-contract-stub-runner-boot/log.log @@ -0,0 +1,169 @@ +[INFO] Scanning for projects... +[INFO] +[INFO] --< org.springframework.cloud:spring-cloud-contract-stub-runner-boot >-- +[INFO] Building Spring Cloud Contract Stub Runner Boot 4.0.0-SNAPSHOT +[INFO] --------------------------------[ jar ]--------------------------------- +[INFO] +[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ spring-cloud-contract-stub-runner-boot --- +[WARNING] The artifact xml-apis:xml-apis:jar:2.0.2 has been relocated to xml-apis:xml-apis:jar:1.0.b2 +[INFO] org.springframework.cloud:spring-cloud-contract-stub-runner-boot:jar:4.0.0-SNAPSHOT +[INFO] +- org.springframework.cloud:spring-cloud-starter-contract-stub-runner:jar:4.0.0-SNAPSHOT:compile +[INFO] | +- org.springframework.cloud:spring-cloud-contract-stub-runner:jar:4.0.0-SNAPSHOT:compile +[INFO] | | +- org.springframework.cloud:spring-cloud-contract-verifier:jar:4.0.0-SNAPSHOT:compile +[INFO] | | | +- javax.inject:javax.inject:jar:1:compile +[INFO] | | | +- com.toomuchcoding.jsonassert:jsonassert:jar:0.6.2:compile +[INFO] | | | +- com.rackspace.eclipse.webtools.sourceediting:org.eclipse.wst.xml.xpath2.processor:jar:2.1.100:compile +[INFO] | | | | +- edu.princeton.cup:java-cup:jar:10k:compile +[INFO] | | | | \- com.ibm.icu:icu4j:jar:4.6:compile +[INFO] | | | +- org.apache.groovy:groovy-nio:jar:4.0.0:compile +[INFO] | | | +- org.apache.groovy:groovy-json:jar:4.0.0:compile +[INFO] | | | +- org.apache.groovy:groovy-xml:jar:4.0.0:compile +[INFO] | | | +- com.github.jknack:handlebars:jar:4.3.0:compile +[INFO] | | | +- commons-beanutils:commons-beanutils:jar:1.9.4:compile +[INFO] | | | | +- commons-logging:commons-logging:jar:1.2:compile +[INFO] | | | | \- commons-collections:commons-collections:jar:3.2.2:compile +[INFO] | | | +- com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:jar:2.14.0-rc3:compile +[INFO] | | | +- net.javacrumbs.json-unit:json-unit-assertj:jar:2.32.0:compile +[INFO] | | | | +- net.javacrumbs.json-unit:json-unit-core:jar:2.32.0:compile +[INFO] | | | | | \- org.hamcrest:hamcrest-core:jar:1.3:test +[INFO] | | | | \- net.javacrumbs.json-unit:json-unit-json-path:jar:2.32.0:compile +[INFO] | | | \- org.junit.jupiter:junit-jupiter-api:jar:5.9.1:compile +[INFO] | | | +- org.opentest4j:opentest4j:jar:1.2.0:compile +[INFO] | | | +- org.junit.platform:junit-platform-commons:jar:1.9.1:compile +[INFO] | | | \- org.apiguardian:apiguardian-api:jar:1.1.2:compile +[INFO] | | +- org.springframework.cloud:spring-cloud-contract-shade:jar:4.0.0-SNAPSHOT:compile +[INFO] | | +- org.springframework.cloud:spring-cloud-contract-converters:jar:4.0.0-SNAPSHOT:compile +[INFO] | | +- org.springframework.cloud:spring-cloud-contract-spec:jar:4.0.0-SNAPSHOT:compile +[INFO] | | | \- org.springframework.cloud:spring-cloud-contract-spec-groovy:jar:4.0.0-SNAPSHOT:compile +[INFO] | | +- org.eclipse.jgit:org.eclipse.jgit:jar:6.1.0.202203080745-r:compile +[INFO] | | | \- com.googlecode.javaewah:JavaEWAH:jar:1.1.13:compile +[INFO] | | +- org.eclipse.jgit:org.eclipse.jgit.ssh.jsch:jar:6.1.0.202203080745-r:compile +[INFO] | | | +- com.jcraft:jsch:jar:0.1.55:compile +[INFO] | | | \- com.jcraft:jzlib:jar:1.1.1:compile +[INFO] | | +- com.jcraft:jsch.agentproxy.sshagent:jar:0.0.9:compile +[INFO] | | | \- com.jcraft:jsch.agentproxy.core:jar:0.0.9:compile +[INFO] | | +- com.jcraft:jsch.agentproxy.jsch:jar:0.0.9:compile +[INFO] | | \- com.jcraft:jsch.agentproxy.usocket-jna:jar:0.0.9:compile +[INFO] | | \- net.java.dev.jna:jna-platform:jar:4.1.0:compile +[INFO] | +- org.springframework.boot:spring-boot-starter-test:jar:3.0.0-RC2:compile +[INFO] | | +- org.springframework.boot:spring-boot-test:jar:3.0.0-RC2:compile +[INFO] | | +- org.springframework.boot:spring-boot-test-autoconfigure:jar:3.0.0-RC2:compile +[INFO] | | +- com.jayway.jsonpath:json-path:jar:2.7.0:compile +[INFO] | | | \- net.minidev:json-smart:jar:2.4.8:compile +[INFO] | | | \- net.minidev:accessors-smart:jar:2.4.8:compile +[INFO] | | | \- org.ow2.asm:asm:jar:9.1:compile +[INFO] | | +- jakarta.xml.bind:jakarta.xml.bind-api:jar:4.0.0:compile +[INFO] | | | \- jakarta.activation:jakarta.activation-api:jar:2.1.0:compile +[INFO] | | +- org.assertj:assertj-core:jar:3.23.1:compile +[INFO] | | | \- net.bytebuddy:byte-buddy:jar:1.12.18:compile +[INFO] | | +- org.hamcrest:hamcrest:jar:2.2:compile +[INFO] | | +- org.junit.jupiter:junit-jupiter:jar:5.9.1:compile +[INFO] | | | +- org.junit.jupiter:junit-jupiter-params:jar:5.9.1:compile +[INFO] | | | \- org.junit.jupiter:junit-jupiter-engine:jar:5.9.1:runtime +[INFO] | | | \- org.junit.platform:junit-platform-engine:jar:1.9.1:runtime +[INFO] | | +- org.mockito:mockito-core:jar:2.23.0:test +[INFO] | | | +- net.bytebuddy:byte-buddy-agent:jar:1.12.18:test +[INFO] | | | \- org.objenesis:objenesis:jar:2.6:test +[INFO] | | +- org.mockito:mockito-junit-jupiter:jar:4.8.1:compile +[INFO] | | +- org.skyscreamer:jsonassert:jar:1.5.1:compile +[INFO] | | | \- com.vaadin.external.google:android-json:jar:0.0.20131108.vaadin1:compile +[INFO] | | +- org.springframework:spring-core:jar:6.0.0-RC4:compile +[INFO] | | +- org.springframework:spring-test:jar:6.0.0-RC4:compile +[INFO] | | \- org.xmlunit:xmlunit-core:jar:2.9.0:compile +[INFO] | +- org.springframework.cloud:spring-cloud-contract-wiremock:jar:4.0.0-SNAPSHOT:compile +[INFO] | | +- jakarta.servlet:jakarta.servlet-api:jar:6.0.0:compile +[INFO] | | +- com.github.tomakehurst:wiremock-jre8-standalone:jar:2.35.0:compile +[INFO] | | +- org.apache.httpcomponents.client5:httpclient5:jar:5.1.3:compile +[INFO] | | | +- org.apache.httpcomponents.core5:httpcore5:jar:5.1.4:compile +[INFO] | | | +- org.apache.httpcomponents.core5:httpcore5-h2:jar:5.1.4:compile +[INFO] | | | \- commons-codec:commons-codec:jar:1.15:compile +[INFO] | | \- org.springframework.cloud:spring-cloud-test-support:jar:4.0.0-SNAPSHOT:compile +[INFO] | | +- org.apache.maven.resolver:maven-resolver-connector-basic:jar:1.4.1:compile +[INFO] | | | +- org.apache.maven.resolver:maven-resolver-spi:jar:1.4.1:compile +[INFO] | | | \- org.apache.maven.resolver:maven-resolver-util:jar:1.4.1:compile +[INFO] | | +- org.apache.maven.resolver:maven-resolver-impl:jar:1.4.1:compile +[INFO] | | +- org.apache.maven:maven-resolver-provider:jar:3.6.3:compile +[INFO] | | | +- org.apache.maven:maven-model:jar:3.6.3:compile +[INFO] | | | +- org.apache.maven:maven-model-builder:jar:3.6.3:compile +[INFO] | | | | +- org.codehaus.plexus:plexus-interpolation:jar:1.25:compile +[INFO] | | | | +- org.apache.maven:maven-artifact:jar:3.6.3:compile +[INFO] | | | | \- org.apache.maven:maven-builder-support:jar:3.6.3:compile +[INFO] | | | \- org.apache.maven:maven-repository-metadata:jar:3.6.3:compile +[INFO] | | \- org.apache.maven.resolver:maven-resolver-transport-http:jar:1.4.1:compile +[INFO] | | +- org.apache.httpcomponents:httpclient:jar:4.5.13:compile +[INFO] | | \- org.apache.httpcomponents:httpcore:jar:4.4.15:compile +[INFO] | +- org.apache.maven.resolver:maven-resolver-api:jar:1.4.1:compile +[INFO] | \- org.sonatype.sisu:sisu-inject-plexus:jar:2.6.0:compile +[INFO] | +- org.codehaus.plexus:plexus-component-annotations:jar:1.7.1:compile +[INFO] | +- org.codehaus.plexus:plexus-classworlds:jar:2.5.2:compile +[INFO] | +- org.codehaus.plexus:plexus-utils:jar:3.0.18:compile +[INFO] | +- org.sonatype.sisu:sisu-inject-bean:jar:2.6.0:compile +[INFO] | | +- javax.enterprise:cdi-api:jar:1.0:compile +[INFO] | | | \- javax.annotation:jsr250-api:jar:1.0:compile +[INFO] | | +- org.sonatype.sisu:sisu-guice:jar:no_aop:3.2.6:compile +[INFO] | | | \- com.google.guava:guava:jar:16.0.1:compile +[INFO] | | \- org.eclipse.sisu:org.eclipse.sisu.inject:jar:0.3.3:compile +[INFO] | \- org.eclipse.sisu:org.eclipse.sisu.plexus:jar:0.3.3:compile +[INFO] +- org.springframework.cloud:spring-cloud-contract-spec-kotlin:jar:4.0.0-SNAPSHOT:compile +[INFO] | +- org.springframework.cloud:spring-cloud-contract-spec-java:jar:4.0.0-SNAPSHOT:compile +[INFO] | | +- org.apache.groovy:groovy:jar:4.0.0:compile +[INFO] | | +- dk.brics:automaton:jar:1.12-4:compile +[INFO] | | +- org.apache.commons:commons-text:jar:1.10.0:compile +[INFO] | | | \- org.apache.commons:commons-lang3:jar:3.12.0:compile +[INFO] | | \- org.springframework:spring-jcl:jar:6.0.0-RC4:compile +[INFO] | +- org.jetbrains.kotlin:kotlin-stdlib-jdk8:jar:1.6.21:compile +[INFO] | | +- org.jetbrains.kotlin:kotlin-stdlib:jar:1.6.21:compile +[INFO] | | | +- org.jetbrains.kotlin:kotlin-stdlib-common:jar:1.6.21:compile +[INFO] | | | \- org.jetbrains:annotations:jar:13.0:compile +[INFO] | | \- org.jetbrains.kotlin:kotlin-stdlib-jdk7:jar:1.6.21:compile +[INFO] | +- org.jetbrains.kotlin:kotlin-compiler-embeddable:jar:1.6.21:compile +[INFO] | | +- org.jetbrains.kotlin:kotlin-script-runtime:jar:1.6.21:compile +[INFO] | | +- org.jetbrains.kotlin:kotlin-reflect:jar:1.6.21:runtime +[INFO] | | +- org.jetbrains.kotlin:kotlin-daemon-embeddable:jar:1.6.21:runtime +[INFO] | | +- org.jetbrains.intellij.deps:trove4j:jar:1.0.20200330:compile +[INFO] | | \- net.java.dev.jna:jna:jar:5.6.0:compile +[INFO] | +- org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:jar:1.6.21:compile +[INFO] | | \- org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:jar:1.6.21:runtime +[INFO] | | \- org.jetbrains.kotlin:kotlin-scripting-common:jar:1.6.21:compile +[INFO] | \- org.jetbrains.kotlin:kotlin-script-util:jar:1.6.21:compile +[INFO] | +- org.jetbrains.kotlin:kotlin-scripting-jvm:jar:1.6.21:compile +[INFO] | \- org.jetbrains.kotlin:kotlin-daemon-client:jar:1.6.21:compile +[INFO] | \- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:jar:1.6.4:compile +[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:3.0.0-RC2:compile +[INFO] | +- org.springframework.boot:spring-boot-starter:jar:3.0.0-RC2:compile +[INFO] | | +- org.springframework.boot:spring-boot:jar:3.0.0-RC2:compile +[INFO] | | +- org.springframework.boot:spring-boot-autoconfigure:jar:3.0.0-RC2:compile +[INFO] | | +- org.springframework.boot:spring-boot-starter-logging:jar:3.0.0-RC2:compile +[INFO] | | | +- ch.qos.logback:logback-classic:jar:1.4.4:compile +[INFO] | | | | \- ch.qos.logback:logback-core:jar:1.4.4:compile +[INFO] | | | +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.19.0:compile +[INFO] | | | | \- org.apache.logging.log4j:log4j-api:jar:2.19.0:compile +[INFO] | | | \- org.slf4j:jul-to-slf4j:jar:2.0.3:compile +[INFO] | | +- jakarta.annotation:jakarta.annotation-api:jar:2.1.1:compile +[INFO] | | \- org.yaml:snakeyaml:jar:1.33:compile +[INFO] | +- org.springframework.boot:spring-boot-starter-json:jar:3.0.0-RC2:compile +[INFO] | | +- com.fasterxml.jackson.core:jackson-databind:jar:2.14.0-rc3:compile +[INFO] | | | +- com.fasterxml.jackson.core:jackson-annotations:jar:2.14.0-rc3:compile +[INFO] | | | \- com.fasterxml.jackson.core:jackson-core:jar:2.14.0-rc3:compile +[INFO] | | +- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.14.0-rc3:compile +[INFO] | | +- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.14.0-rc3:compile +[INFO] | | \- com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.14.0-rc3:compile +[INFO] | +- org.springframework.boot:spring-boot-starter-tomcat:jar:3.0.0-RC2:compile +[INFO] | | +- org.apache.tomcat.embed:tomcat-embed-core:jar:10.1.1:compile +[INFO] | | +- org.apache.tomcat.embed:tomcat-embed-el:jar:10.1.1:compile +[INFO] | | \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:10.1.1:compile +[INFO] | +- org.springframework:spring-web:jar:6.0.0-RC4:compile +[INFO] | | +- org.springframework:spring-beans:jar:6.0.0-RC4:compile +[INFO] | | \- io.micrometer:micrometer-observation:jar:1.10.0:compile +[INFO] | | \- io.micrometer:micrometer-commons:jar:1.10.0:compile +[INFO] | \- org.springframework:spring-webmvc:jar:6.0.0-RC4:compile +[INFO] | +- org.springframework:spring-aop:jar:6.0.0-RC4:compile +[INFO] | +- org.springframework:spring-context:jar:6.0.0-RC4:compile +[INFO] | \- org.springframework:spring-expression:jar:6.0.0-RC4:compile +[INFO] \- org.slf4j:slf4j-api:jar:2.0.3:compile +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ +[INFO] Total time: 0.752 s +[INFO] Finished at: 2022-11-16T14:04:05+01:00 +[INFO] ------------------------------------------------------------------------ diff --git a/spring-cloud-contract-stub-runner-boot/pom.xml b/spring-cloud-contract-stub-runner-boot/pom.xml deleted file mode 100644 index db023e07a6..0000000000 --- a/spring-cloud-contract-stub-runner-boot/pom.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - 4.0.0 - - org.springframework.cloud - spring-cloud-contract-parent - 4.1.0-SNAPSHOT - .. - - spring-cloud-contract-stub-runner-boot - jar - Spring Cloud Contract Stub Runner Boot - Spring Cloud Contract Stub Runner Boot - - - org.springframework.cloud - spring-cloud-starter-contract-stub-runner - - - org.springframework.cloud - spring-cloud-contract-spec-kotlin - - - org.springframework.boot - spring-boot-starter-web - - - org.slf4j - slf4j-api - ${slf4j.version} - compile - - - - - - org.springframework.boot - spring-boot-maven-plugin - - true - - - - org.springframework.boot.experimental - spring-boot-thin-layout - ${thin-jar.version} - - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - - - - - diff --git a/spring-cloud-contract-stub-runner-boot/src/main/java/org/springframework/cloud/contract/stubrunner/server/StubRunnerBoot.java b/spring-cloud-contract-stub-runner-boot/src/main/java/org/springframework/cloud/contract/stubrunner/server/StubRunnerBoot.java deleted file mode 100644 index d75d44fc16..0000000000 --- a/spring-cloud-contract-stub-runner-boot/src/main/java/org/springframework/cloud/contract/stubrunner/server/StubRunnerBoot.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.server; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * @author Marcin Grzejszczak - */ -@SpringBootApplication -@EnableStubRunnerServer -public class StubRunnerBoot { - - public static void main(String[] args) { - SpringApplication.run(StubRunnerBoot.class, args); - } - -} diff --git a/spring-cloud-contract-stub-runner-boot/src/main/resources/META-INF/thin-kafka.properties b/spring-cloud-contract-stub-runner-boot/src/main/resources/META-INF/thin-kafka.properties deleted file mode 100644 index 7827667d8e..0000000000 --- a/spring-cloud-contract-stub-runner-boot/src/main/resources/META-INF/thin-kafka.properties +++ /dev/null @@ -1,2 +0,0 @@ -exclusions.spring-cloud-stream-binder-rabbit: org.springframework.cloud:spring-cloud-stream-binder-rabbit -dependencies.spring-cloud-stream-binder-kafka: org.springframework.cloud:spring-cloud-stream-binder-kafka diff --git a/spring-cloud-contract-stub-runner-boot/src/main/resources/META-INF/thin-rabbit.properties b/spring-cloud-contract-stub-runner-boot/src/main/resources/META-INF/thin-rabbit.properties deleted file mode 100644 index 1145b0300c..0000000000 --- a/spring-cloud-contract-stub-runner-boot/src/main/resources/META-INF/thin-rabbit.properties +++ /dev/null @@ -1,2 +0,0 @@ -exclusions.spring-cloud-stream-binder-kafka: org.springframework.cloud:spring-cloud-stream-binder-kafka -dependencies.spring-cloud-stream-binder-rabbit: org.springframework.cloud:spring-cloud-stream-binder-rabbit diff --git a/spring-cloud-contract-stub-runner-boot/src/main/resources/application.yml b/spring-cloud-contract-stub-runner-boot/src/main/resources/application.yml deleted file mode 100644 index d65102df1f..0000000000 --- a/spring-cloud-contract-stub-runner-boot/src/main/resources/application.yml +++ /dev/null @@ -1,11 +0,0 @@ -spring: - application: - name: stubrunner - -server: - port: 8750 - -info: - artifactId: "@project.artifactId@" - description: "@project.description@" - version: "@project.version@" \ No newline at end of file diff --git a/spring-cloud-contract-stub-runner/.gitignore b/spring-cloud-contract-stub-runner/.gitignore deleted file mode 100644 index c71ea97aba..0000000000 --- a/spring-cloud-contract-stub-runner/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/.apt_generated/ diff --git a/spring-cloud-contract-stub-runner/pom.xml b/spring-cloud-contract-stub-runner/pom.xml deleted file mode 100644 index d018e0f8b6..0000000000 --- a/spring-cloud-contract-stub-runner/pom.xml +++ /dev/null @@ -1,290 +0,0 @@ - - - 4.0.0 - - org.springframework.cloud - spring-cloud-contract-parent - 4.1.0-SNAPSHOT - .. - - spring-cloud-contract-stub-runner - jar - Spring Cloud Contract Stub Runner - Spring Cloud Contract Stub Runner - - - org.springframework.cloud - spring-cloud-contract-verifier - - - org.springframework.cloud - spring-cloud-contract-shade - - - org.springframework.cloud - spring-cloud-contract-converters - - - org.springframework.cloud - spring-cloud-stream - ${spring-cloud-stream.version} - true - - - org.springframework.cloud - spring-cloud-stream-test-binder - true - ${spring-cloud-stream.version} - compile - - - org.springframework.cloud - spring-cloud-contract-wiremock - true - - - org.springframework.cloud - spring-cloud-starter - true - - - org.springframework.cloud - spring-cloud-contract-spec - - - org.springframework.boot - spring-boot-configuration-processor - true - - - org.apache.maven - maven-embedder - true - - - org.apache.maven.resolver - maven-resolver-api - true - - - net.sf.jopt-simple - jopt-simple - true - - - org.springframework.kafka - spring-kafka - true - - - org.springframework - spring-jms - true - - - org.springframework.kafka - spring-kafka-test - true - - - org.slf4j - slf4j-log4j12 - - - - - org.apache.camel.springboot - camel-spring-boot-starter - true - - - org.apache.camel.springboot - camel-spring-boot - true - - - org.apache.camel - camel-jackson - true - - - junit - junit - compile - true - - - - org.eclipse.jgit - org.eclipse.jgit - - - org.eclipse.jgit - org.eclipse.jgit.ssh.jsch - - - - com.jcraft - jsch.agentproxy.sshagent - - - com.jcraft - jsch.agentproxy.jsch - - - com.jcraft - jsch.agentproxy.usocket-jna - - - jakarta.jms - jakarta.jms-api - true - - - org.springframework - spring-test - true - - - org.springframework.boot - spring-boot-autoconfigure-processor - true - - - - io.specto - hoverfly-junit - test - - - org.glassfish.jersey.core - jersey-client - 2.35 - true - - - cglib - cglib - test - - - io.rest-assured - spring-mock-mvc - test - - - org.spockframework - spock-spring - test - - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.boot - spring-boot-starter-web - test - - - org.springframework.cloud - spring-cloud-test-support - test - - - org.springframework.cloud - spring-cloud-starter-zookeeper-discovery - true - - - org.apache.curator - curator-test - test - - - org.springframework.cloud - spring-cloud-netflix-eureka-server - true - - - org.springframework.cloud - spring-cloud-starter-consul-discovery - true - - - org.junit.jupiter - junit-jupiter-engine - true - - - org.junit.jupiter - junit-jupiter-api - true - - - org.springframework.boot - spring-boot-starter-webflux - test - - - org.spockframework - spock-junit4 - test - - - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - - - org.apache.maven.plugins - maven-surefire-plugin - - - - org.apache.maven.plugins - maven-failsafe-plugin - ${maven-failsafe-plugin.version} - - - - org.junit.jupiter - junit-jupiter-engine - ${junit-jupiter.version} - - - org.junit.vintage - junit-vintage-engine - ${junit-vintage.version} - - - - - **/junit4/*Test.* - **/junit4/*Tests.* - **/junit4/*Spec.* - - plain - true - - org.junit.jupiter:junit-vintage-engine - - - - - - integration-test - verify - - - - - - - diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherFactories.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherFactories.java deleted file mode 100644 index 6f89bd1358..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherFactories.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.util.Random; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.eclipse.aether.DefaultRepositorySystemSession; -import org.eclipse.aether.RepositorySystem; -import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.repository.LocalRepository; -import org.eclipse.aether.repository.RepositoryPolicy; -import shaded.org.apache.maven.repository.internal.MavenRepositorySystemUtils; -import shaded.org.apache.maven.settings.Settings; -import shaded.org.apache.maven.settings.building.DefaultSettingsBuilderFactory; -import shaded.org.apache.maven.settings.building.DefaultSettingsBuildingRequest; -import shaded.org.apache.maven.settings.building.SettingsBuilder; -import shaded.org.apache.maven.settings.building.SettingsBuildingException; -import shaded.org.apache.maven.settings.building.SettingsBuildingRequest; -import shaded.org.apache.maven.settings.building.SettingsBuildingResult; -import shaded.org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory; -import shaded.org.eclipse.aether.impl.DefaultServiceLocator; -import shaded.org.eclipse.aether.spi.connector.RepositoryConnectorFactory; -import shaded.org.eclipse.aether.spi.connector.transport.TransporterFactory; -import shaded.org.eclipse.aether.transport.file.FileTransporterFactory; -import shaded.org.eclipse.aether.transport.http.HttpTransporterFactory; - -import org.springframework.util.StringUtils; - -final class AetherFactories { - - private static final Log log = LogFactory.getLog(AetherFactories.class); - - private static final String MAVEN_LOCAL_REPOSITORY_LOCATION = "maven.repo.local"; - - private static final String MAVEN_USER_SETTINGS_LOCATION = "org.apache.maven.user-settings"; - - private static final String MAVEN_GLOBAL_SETTINGS_LOCATION = "org.apache.maven.global-settings"; - - private static final Random RANDOM = new Random(); - - private AetherFactories() { - throw new IllegalStateException("Can't instantiate a utility class"); - } - - public static RepositorySystem newRepositorySystem() { - DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator(); - locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class); - locator.addService(TransporterFactory.class, FileTransporterFactory.class); - locator.addService(TransporterFactory.class, HttpTransporterFactory.class); - return locator.getService(RepositorySystem.class); - } - - public static RepositorySystemSession newSession(RepositorySystem system, boolean workOffline) { - DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession(); - session.setOffline(workOffline); - if (!workOffline) { - session.setUpdatePolicy(RepositoryPolicy.UPDATE_POLICY_ALWAYS); - } - session.setChecksumPolicy(RepositoryPolicy.CHECKSUM_POLICY_WARN); - String localRepositoryDirectory = localRepositoryDirectory(workOffline); - if (log.isDebugEnabled()) { - log.debug("Local Repository Directory set to [" + localRepositoryDirectory + "]. Work offline: [" - + workOffline + "]"); - } - LocalRepository localRepo = new LocalRepository(localRepositoryDirectory); - session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepo)); - return session; - } - - protected static String localRepositoryDirectory(boolean workOffline) { - String localRepoLocationFromSettings = settings().getLocalRepository(); - String currentLocalRepo = readPropertyFromSystemProps(localRepoLocationFromSettings); - if (workOffline) { - return currentLocalRepo; - } - return temporaryDirectory(); - } - - private static String temporaryDirectory() { - try { - return Files.createTempDirectory("aether-local").toString(); - } - catch (IOException e) { - if (log.isDebugEnabled()) { - log.debug("Failed to create a new temporary directory, will generate a new one under temp dir"); - } - return System.getProperty("java.io.tmpdir") + File.separator + RANDOM.nextInt(); - } - } - - private static String readPropertyFromSystemProps(String localRepoLocationFromSettings) { - String mavenLocalRepo = fromSystemPropOrEnv(MAVEN_LOCAL_REPOSITORY_LOCATION); - return StringUtils.hasText(mavenLocalRepo) ? mavenLocalRepo - : localRepoLocationFromSettings != null ? localRepoLocationFromSettings - : System.getProperty("user.home") + File.separator + ".m2" + File.separator + "repository"; - } - - // system prop takes precedence over env var - private static String fromSystemPropOrEnv(String prop) { - String resolvedProp = System.getProperty(prop); - if (StringUtils.hasText(resolvedProp)) { - return resolvedProp; - } - return System.getenv(prop); - } - - private static File userSettings() { - String user = fromSystemPropOrEnv(MAVEN_USER_SETTINGS_LOCATION); - if (user == null) { - File file = new File(new File(System.getProperty("user.home")).getAbsoluteFile(), - File.separator + ".m2" + File.separator + "settings.xml"); - if (log.isDebugEnabled()) { - log.debug("No custom maven user settings provided, will use [" + file + "]"); - } - return file; - } - if (log.isDebugEnabled()) { - log.debug("Custom location provided for user settings [" + user + "]"); - } - return new File(user); - } - - protected static Settings settings() { - SettingsBuilder builder = new DefaultSettingsBuilderFactory().newInstance(); - SettingsBuildingRequest request = new DefaultSettingsBuildingRequest(); - request.setUserSettingsFile(userSettings()); - String global = fromSystemPropOrEnv(MAVEN_GLOBAL_SETTINGS_LOCATION); - if (global != null) { - request.setGlobalSettingsFile(new File(global)); - } - SettingsBuildingResult result; - try { - result = builder.build(request); - } - catch (SettingsBuildingException ex) { - throw new IllegalStateException(ex); - } - return result.getEffectiveSettings(); - } - -} 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 deleted file mode 100644 index 57887bb438..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherStubDownloader.java +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.net.URI; -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.eclipse.aether.RepositorySystem; -import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.artifact.Artifact; -import org.eclipse.aether.artifact.DefaultArtifact; -import org.eclipse.aether.repository.Authentication; -import org.eclipse.aether.repository.Proxy; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.resolution.ArtifactRequest; -import org.eclipse.aether.resolution.ArtifactResult; -import org.eclipse.aether.resolution.VersionRangeRequest; -import org.eclipse.aether.resolution.VersionRangeResolutionException; -import org.eclipse.aether.resolution.VersionRangeResult; -import org.eclipse.aether.util.repository.AuthenticationBuilder; -import shaded.org.apache.maven.settings.Server; -import shaded.org.apache.maven.settings.Settings; -import shaded.org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest; -import shaded.org.apache.maven.settings.crypto.SettingsDecryptionRequest; - -import org.springframework.cloud.contract.stubrunner.StubRunnerOptions.StubRunnerProxyOptions; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.util.StringUtils; - -import static org.springframework.cloud.contract.stubrunner.AetherFactories.newRepositorySystem; -import static org.springframework.cloud.contract.stubrunner.AetherFactories.newSession; -import static org.springframework.cloud.contract.stubrunner.AetherFactories.settings; -import static org.springframework.cloud.contract.stubrunner.util.ZipCategory.unzipTo; - -/** - * @author Mariusz Smykula - * @author Eddú Meléndez - */ -public class AetherStubDownloader implements StubDownloader { - - private static final Log log = LogFactory.getLog(AetherStubDownloader.class); - - private static final String TEMP_DIR_PREFIX = "contracts"; - - private static final String ARTIFACT_EXTENSION = "jar"; - - private static final String LATEST_ARTIFACT_VERSION = "(,]"; - - private static final String LATEST_VERSION_IN_IVY = "+"; - - // Preloading class for the shutdown hook not to throw ClassNotFound - private static final Class CLAZZ = TemporaryFileStorage.class; - - private final List remoteRepos; - - private final RepositorySystem repositorySystem; - - private final RepositorySystemSession session; - - private final boolean workOffline; - - private final boolean deleteStubsAfterTest; - - private final Settings settings; - - public AetherStubDownloader(StubRunnerOptions stubRunnerOptions) { - this.deleteStubsAfterTest = stubRunnerOptions.isDeleteStubsAfterTest(); - if (log.isDebugEnabled()) { - log.debug("Will be resolving versions for the following options: [" + stubRunnerOptions + "]"); - } - this.settings = settings(); - this.remoteRepos = remoteRepositories(stubRunnerOptions); - boolean remoteReposMissing = remoteReposMissing(); - switch (stubRunnerOptions.stubsMode) { - case LOCAL: - log.info("Remote repos not passed but the switch to work offline was set. " - + "Stubs will be used from your local Maven repository."); - break; - case REMOTE: - if (remoteReposMissing) { - throw new IllegalStateException( - "Remote repositories for stubs are not specified and work offline flag wasn't passed"); - } - break; - case CLASSPATH: - throw new UnsupportedOperationException( - "You can't use Aether downloader when you use classpath to find stubs"); - } - this.repositorySystem = newRepositorySystem(); - this.workOffline = stubRunnerOptions.stubsMode == StubRunnerProperties.StubsMode.LOCAL; - this.session = newSession(this.repositorySystem, this.workOffline); - registerShutdownHook(); - } - - /** - * Used by the Maven Plugin. - * @param repositorySystem Maven repository system - * @param remoteRepositories remote artifact repositories - * @param session repository system session - */ - public AetherStubDownloader(RepositorySystem repositorySystem, List remoteRepositories, - RepositorySystemSession session, Settings settings) { - this.deleteStubsAfterTest = true; - this.remoteRepos = remoteRepositories; - this.settings = settings; - this.repositorySystem = repositorySystem; - this.session = session; - if (remoteReposMissing()) { - log.error("Remote repositories for stubs are not specified and work offline flag wasn't passed"); - } - this.workOffline = false; - registerShutdownHook(); - } - - private static File unpackStubJarToATemporaryFolder(URI stubJarUri) { - File tmpDirWhereStubsWillBeUnzipped = TemporaryFileStorage.createTempDir(TEMP_DIR_PREFIX); - log.info("Unpacking stub from JAR [URI: " + stubJarUri + "]"); - unzipTo(new File(stubJarUri), tmpDirWhereStubsWillBeUnzipped); - TemporaryFileStorage.add(tmpDirWhereStubsWillBeUnzipped); - return tmpDirWhereStubsWillBeUnzipped; - } - - private boolean remoteReposMissing() { - return this.remoteRepos == null || this.remoteRepos.isEmpty(); - } - - private List remoteRepositories(StubRunnerOptions stubRunnerOptions) { - if (stubRunnerOptions.stubRepositoryRoot == null) { - return new ArrayList<>(); - } - final String[] repos = stubRunnerOptions.getStubRepositoryRootAsString().split(","); - final List remoteRepos = new ArrayList<>(); - for (int i = 0; i < repos.length; i++) { - if (StringUtils.hasText(repos[i])) { - final RemoteRepository.Builder builder = new RemoteRepository.Builder("remote" + i, "default", repos[i]) - .setAuthentication(resolveAuthentication(stubRunnerOptions)); - if (stubRunnerOptions.getProxyOptions() != null) { - final StubRunnerProxyOptions p = stubRunnerOptions.getProxyOptions(); - builder.setProxy(new Proxy(null, p.getProxyHost(), p.getProxyPort())); - } - remoteRepos.add(builder.build()); - } - } - if (log.isDebugEnabled()) { - log.debug("Using the following remote repos " + remoteRepos); - } - return remoteRepos; - } - - private Authentication resolveAuthentication(StubRunnerOptions stubRunnerOptions) { - if (StringUtils.hasText(stubRunnerOptions.serverId)) { - Server stubServer = this.settings.getServer(stubRunnerOptions.serverId); - if (stubServer != null) { - if (log.isDebugEnabled()) { - log.debug("Custom server id [" + stubServer.getId() + "] passed will resolve credentials"); - } - SettingsDecryptionRequest settingsDecryptionRequest = new DefaultSettingsDecryptionRequest(stubServer); - String stubServerPassword = new MavenSettings().createSettingsDecrypter() - .decrypt(settingsDecryptionRequest).getServer().getPassword(); - return buildAuthentication(stubServerPassword, stubServer.getUsername()); - } - } - return buildAuthentication(stubRunnerOptions.password, stubRunnerOptions.username); - } - - Authentication buildAuthentication(String stubServerPassword, String username) { - return new AuthenticationBuilder().addUsername(username).addPassword(stubServerPassword).build(); - } - - private File unpackedJar(String resolvedVersion, String stubsGroup, String stubsModule, String classifier) { - try { - log.info("Resolved version is [" + resolvedVersion + "]"); - if (!StringUtils.hasText(resolvedVersion)) { - log.warn("Stub for group [" + stubsGroup + "] module [" + stubsModule + "] and classifier [" - + classifier + "] not found in " + this.remoteRepos); - return null; - } - Artifact artifact = new DefaultArtifact(stubsGroup, stubsModule, classifier, ARTIFACT_EXTENSION, - resolvedVersion); - ArtifactRequest request = new ArtifactRequest(artifact, this.remoteRepos, null); - if (log.isDebugEnabled()) { - log.debug("Resolving artifact [" + artifact + "] using remote repositories " + this.remoteRepos); - } - ArtifactResult result = this.repositorySystem.resolveArtifact(this.session, request); - log.info("Resolved artifact [" + artifact + "] to " + result.getArtifact().getFile()); - File temporaryFile = unpackStubJarToATemporaryFolder(result.getArtifact().getFile().toURI()); - log.info("Unpacked file to [" + temporaryFile + "]"); - return temporaryFile; - } - catch (IllegalStateException ise) { - throw ise; - } - catch (Exception e) { - throw new IllegalStateException( - "Exception occurred while trying to download a stub for group [" + stubsGroup + "] module [" - + stubsModule + "] and classifier [" + classifier + "] in " + this.remoteRepos, - e); - } - } - - private String getVersion(String stubsGroup, String stubsModule, String version, String classifier) { - if (!StringUtils.hasText(version) || LATEST_VERSION_IN_IVY.equals(version)) { - log.info("Desired version is [" + version + "] - will try to resolve the latest version"); - return resolveHighestArtifactVersion(stubsGroup, stubsModule, classifier, LATEST_ARTIFACT_VERSION); - } - return resolveHighestArtifactVersion(stubsGroup, stubsModule, classifier, version); - } - - @Override - public Map.Entry downloadAndUnpackStubJar(StubConfiguration stubConfiguration) { - try { - String version = getVersion(stubConfiguration.groupId, stubConfiguration.artifactId, - stubConfiguration.version, stubConfiguration.classifier); - if (log.isDebugEnabled()) { - log.debug("Will download the stub for version [" + version + "]"); - } - File unpackedJar = unpackedJar(version, stubConfiguration.groupId, stubConfiguration.artifactId, - stubConfiguration.classifier); - if (unpackedJar == null) { - return null; - } - return new AbstractMap.SimpleEntry<>(new StubConfiguration(stubConfiguration.groupId, - stubConfiguration.artifactId, version, stubConfiguration.classifier), unpackedJar); - } - catch (Exception ex) { - log.warn("Exception occurred while trying to fetch the stubs", ex); - return null; - } - } - - private String resolveHighestArtifactVersion(String stubsGroup, String stubsModule, String classifier, - String version) { - Artifact artifact = new DefaultArtifact(stubsGroup, stubsModule, classifier, ARTIFACT_EXTENSION, version); - VersionRangeRequest versionRangeRequest = new VersionRangeRequest(artifact, this.remoteRepos, null); - VersionRangeResult rangeResult; - try { - rangeResult = this.repositorySystem.resolveVersionRange(this.session, versionRangeRequest); - if (log.isDebugEnabled()) { - log.debug("Resolved version range is [" + rangeResult + "]"); - } - } - catch (VersionRangeResolutionException e) { - throw new IllegalStateException("Cannot resolve version range", e); - } - if (rangeResult.getHighestVersion() == null) { - throw new IllegalArgumentException( - "For groupId [" + stubsGroup + "] artifactId [" + stubsModule + "] " + "and classifier [" - + classifier + "] the version was not resolved! The following exceptions took place " - + rangeResult.getExceptions()); - } - return rangeResult.getHighestVersion() == null ? null : rangeResult.getHighestVersion().toString(); - } - - private void registerShutdownHook() { - Runtime.getRuntime().addShutdownHook( - new Thread(() -> TemporaryFileStorage.cleanup(AetherStubDownloader.this.deleteStubsAfterTest))); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherStubDownloaderBuilder.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherStubDownloaderBuilder.java deleted file mode 100644 index 7d90bc442c..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherStubDownloaderBuilder.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; - -/** - * @author Marcin Grzejszczak - * @since 2.0.0 - */ -public class AetherStubDownloaderBuilder implements StubDownloaderBuilder { - - private static final Log log = LogFactory.getLog(AetherStubDownloaderBuilder.class); - - @Override - public StubDownloader build(StubRunnerOptions stubRunnerOptions) { - if (stubRunnerOptions.stubsMode == StubRunnerProperties.StubsMode.CLASSPATH) { - return null; - } - log.info("Will download stubs and contracts via Aether"); - return new AetherStubDownloader(stubRunnerOptions); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/Arguments.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/Arguments.java deleted file mode 100644 index 5aee204d00..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/Arguments.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -/** - * Arguments passed to the {@link StubRunner} application. - * - * @see StubRunner - */ -class Arguments { - - final private StubRunnerOptions stubRunnerOptions; - - final private String repositoryPath; - - final private StubConfiguration stub; - - Arguments(StubRunnerOptions stubRunnerOptions) { - this(stubRunnerOptions, "", null); - } - - Arguments(StubRunnerOptions stubRunnerOptions, String repositoryPath, StubConfiguration stub) { - this.stubRunnerOptions = stubRunnerOptions; - this.repositoryPath = repositoryPath == null ? "" : repositoryPath; - this.stub = stub; - } - - public StubRunnerOptions getStubRunnerOptions() { - return this.stubRunnerOptions; - } - - public String getRepositoryPath() { - return this.repositoryPath; - } - - public StubConfiguration getStub() { - return this.stub; - } - - @Override - public String toString() { - return "Arguments{" + "stubRunnerOptions=" + this.stubRunnerOptions + ", repositoryPath='" + this.repositoryPath - + '\'' + ", stub=" + this.stub + '}'; - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AvailablePortScanner.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AvailablePortScanner.java deleted file mode 100644 index b27dbaf244..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AvailablePortScanner.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.IOException; -import java.net.ServerSocket; -import java.util.Random; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Tries to execute a closure with an available port from the given range. - */ -class AvailablePortScanner { - - private static final Log log = LogFactory.getLog(AvailablePortScanner.class); - - private static final int MAX_RETRY_COUNT = 1000; - - private final int minPortNumber; - - private final int maxPortNumber; - - private final int maxRetryCount; - - AvailablePortScanner(int minPortNumber, int maxPortNumber) { - this(minPortNumber, maxPortNumber, MAX_RETRY_COUNT); - } - - AvailablePortScanner(int minPortNumber, int maxPortNumber, int maxRetryCount) { - checkPortRanges(minPortNumber, maxPortNumber); - this.minPortNumber = minPortNumber; - this.maxPortNumber = maxPortNumber; - this.maxRetryCount = maxRetryCount; - } - - private void checkPortRanges(int minPortNumber, int maxPortNumber) { - if (minPortNumber > maxPortNumber) { - throw new InvalidPortRange(minPortNumber, maxPortNumber); - } - } - - public T tryToExecuteWithFreePort(PortCallback closure) { - for (int i = 0; i < this.maxRetryCount; i++) { - try { - int numberOfPortsToBind = this.maxPortNumber - this.minPortNumber + 1; - int portToScan = new Random().nextInt(numberOfPortsToBind) + this.minPortNumber; - checkIfPortIsAvailable(portToScan); - return executeLogicForAvailablePort(portToScan, closure); - } - catch (IOException exception) { - if (log.isDebugEnabled()) { - log.debug("Failed to execute callback (try: " + i + "/" + this.maxRetryCount + ")", exception); - } - } - } - throw new NoPortAvailableException(this.minPortNumber, this.maxPortNumber); - } - - private T executeLogicForAvailablePort(int portToScan, PortCallback closure) throws IOException { - if (log.isDebugEnabled()) { - log.debug("Trying to execute closure with port [" + portToScan + "]"); - } - return closure.call(portToScan); - } - - private void checkIfPortIsAvailable(int portToScan) throws IOException { - ServerSocket socket = null; - try { - socket = new ServerSocket(portToScan); - } - finally { - if (socket != null) { - socket.close(); - } - } - } - - public interface PortCallback { - - T call(int port) throws IOException; - - } - - @SuppressWarnings("serial") - static class NoPortAvailableException extends RuntimeException { - - NoPortAvailableException(int lowerBound, int upperBound) { - super("Could not find available port in range " + lowerBound + ":" + upperBound); - } - - } - - @SuppressWarnings("serial") - static class InvalidPortRange extends RuntimeException { - - InvalidPortRange(int lowerBound, int upperBound) { - super("Invalid bounds exceptions, min port [" + lowerBound + "] is greater to max port [" + upperBound - + "]"); - } - - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/BatchStubRunner.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/BatchStubRunner.java deleted file mode 100644 index 261940b4d4..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/BatchStubRunner.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.IOException; -import java.net.URL; -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Map.Entry; - -import org.springframework.cloud.contract.spec.Contract; - -/** - * Manages lifecycle of multiple {@link StubRunner} instances. - * - * @author Marcin Grzejszczak - * @see StubRunner - */ -public class BatchStubRunner implements StubRunning { - - private final Iterable stubRunners; - - public BatchStubRunner(Iterable stubRunners) { - this.stubRunners = stubRunners; - } - - @Override - public RunningStubs runStubs() { - Map map = new LinkedHashMap<>(); - for (StubRunner value : this.stubRunners) { - RunningStubs runningStubs = value.runStubs(); - map.putAll(runningStubs.validNamesAndPorts()); - } - return new RunningStubs(map); - } - - @Override - public URL findStubUrl(String groupId, String artifactId) { - for (StubRunner stubRunner : this.stubRunners) { - try { - return stubRunner.findStubUrl(groupId, artifactId); - } - catch (StubNotFoundException e) { - } - } - throw new StubNotFoundException(groupId, artifactId); - } - - @Override - public URL findStubUrl(String ivyNotation) { - for (StubRunner stubRunner : this.stubRunners) { - try { - return stubRunner.findStubUrl(ivyNotation); - } - catch (StubNotFoundException e) { - } - } - throw new StubNotFoundException(ivyNotation); - } - - @Override - public RunningStubs findAllRunningStubs() { - Collection running = new LinkedHashSet<>(); - for (StubRunner stubRunner : this.stubRunners) { - running.add(stubRunner.findAllRunningStubs()); - } - return new RunningStubs(running); - } - - @Override - public Map> getContracts() { - Map> map = new LinkedHashMap<>(); - for (StubRunner stubRunner : this.stubRunners) { - for (Entry> entry : stubRunner.getContracts().entrySet()) { - if (map.containsKey(entry.getKey())) { - map.get(entry.getKey()).addAll(entry.getValue()); - } - else { - map.put(entry.getKey(), new LinkedHashSet<>(entry.getValue())); - } - } - } - return map; - } - - @Override - public boolean trigger(String ivyNotation, String labelName) { - boolean success = false; - for (StubRunner stubRunner : this.stubRunners) { - if (stubRunner.trigger(ivyNotation, labelName)) { - success = true; - } - } - if (!success) { - throw new IllegalArgumentException("No label with name [" + labelName + "] for " + "dependency [" - + ivyNotation + "] was found. Here you have the list of dependencies " + "and their labels [" - + ivyToLabels() + "]"); - } - return success; - } - - private String ivyToLabels() { - StringBuilder builder = new StringBuilder(); - for (Entry> entry : labels().entrySet()) { - if (builder.length() > 0) { - builder.append("\n"); - } - builder.append("Dependency [").append(entry.getKey()).append("] has labels ").append(entry.getValue()); - } - return builder.toString(); - } - - @Override - public boolean trigger(String labelName) { - boolean success = false; - for (StubRunner stubRunner : this.stubRunners) { - if (stubRunner.trigger(labelName)) { - success = true; - } - } - if (!success) { - throw new IllegalArgumentException("No label with name [" + labelName + "] was found. " - + "Here you have the list of dependencies and their labels [" + ivyToLabels() + "]"); - } - return success; - } - - @Override - public boolean trigger() { - boolean success = false; - for (StubRunner stubRunner : this.stubRunners) { - if (stubRunner.trigger()) { - success = true; - } - } - return success; - } - - @Override - public Map> labels() { - Map> map = new LinkedHashMap<>(); - for (StubRunner stubRunner : this.stubRunners) { - for (Entry> entry : stubRunner.labels().entrySet()) { - if (map.containsKey(entry.getKey())) { - map.get(entry.getKey()).addAll(entry.getValue()); - } - else { - map.put(entry.getKey(), new LinkedHashSet<>(entry.getValue())); - } - } - } - return map; - } - - @Override - public void close() throws IOException { - for (StubRunner stubRunner : this.stubRunners) { - stubRunner.close(); - } - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/BatchStubRunnerFactory.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/BatchStubRunnerFactory.java deleted file mode 100644 index c325f1f148..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/BatchStubRunnerFactory.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender; -import org.springframework.cloud.contract.verifier.messaging.noop.NoOpStubMessages; - -/** - * Manages lifecycle of multiple {@link StubRunner} instances. - * - * @author Marcin Grzejszczak - * @see StubRunner - * @see BatchStubRunner - */ -public class BatchStubRunnerFactory { - - private final StubRunnerOptions stubRunnerOptions; - - private final StubDownloader stubDownloader; - - private final MessageVerifierSender contractVerifierMessaging; - - public BatchStubRunnerFactory(StubRunnerOptions stubRunnerOptions) { - this(stubRunnerOptions, new NoOpStubMessages<>()); - } - - public BatchStubRunnerFactory(StubRunnerOptions stubRunnerOptions, MessageVerifierSender verifier) { - this(stubRunnerOptions, aetherStubDownloader(stubRunnerOptions), verifier); - } - - public BatchStubRunnerFactory(StubRunnerOptions stubRunnerOptions, StubDownloader stubDownloader) { - this(stubRunnerOptions, stubDownloader, new NoOpStubMessages<>()); - } - - public BatchStubRunnerFactory(StubRunnerOptions stubRunnerOptions, StubDownloader stubDownloader, - MessageVerifierSender contractVerifierMessaging) { - this.stubRunnerOptions = stubRunnerOptions; - this.stubDownloader = stubDownloader; - this.contractVerifierMessaging = contractVerifierMessaging; - } - - private static StubDownloader aetherStubDownloader(StubRunnerOptions stubRunnerOptions) { - StubDownloaderBuilderProvider provider = new StubDownloaderBuilderProvider(); - return provider.get(stubRunnerOptions); - } - - public BatchStubRunner buildBatchStubRunner() { - StubRunnerFactory stubRunnerFactory = new StubRunnerFactory(this.stubRunnerOptions, this.stubDownloader, - this.contractVerifierMessaging); - return new BatchStubRunner(stubRunnerFactory.createStubsFromServiceConfiguration()); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ClasspathStubProvider.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ClasspathStubProvider.java deleted file mode 100644 index 7ea5911348..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ClasspathStubProvider.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.util.regex.Pattern; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; -import org.springframework.util.StringUtils; - -/** - * Stub downloader that picks stubs and contracts from the provided resource. If - * {@link org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties#stubsMode} - * is set to - * {@link org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties.StubsMode#CLASSPATH} - * then classpath is searched according to what has been passed in - * {@link org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties#ids}. - * The pattern to search for stubs looks like this - * - *

- * - * examples - * - *
    - *
  • {@code META-INF/com.example/fooservice/1.0.0/ **}
  • - *
  • {@code contracts/com.example/artifactid/ ** /*.* }
  • - *
  • {@code mappings/com.example/artifactid/ ** /*.* }
  • - *
- * - * @author Marcin Grzejszczak - * @since 1.1.1 - */ -public class ClasspathStubProvider implements StubDownloaderBuilder { - - private static final Log log = LogFactory.getLog(ClasspathStubProvider.class); - - @Override - public StubDownloader build(final StubRunnerOptions stubRunnerOptions) { - if (stubRunnerOptions.stubsMode != StubRunnerProperties.StubsMode.CLASSPATH) { - return null; - } - log.info("Will download stubs from classpath"); - return new ResourceResolvingStubDownloader(stubRunnerOptions, this::repoRoot, this::gavPattern); - } - - private RepoRoots repoRoot(StubRunnerOptions stubRunnerOptions, StubConfiguration configuration) { - Resource repositoryRoot = stubRunnerOptions.getStubRepositoryRoot(); - if (repositoryRoot instanceof ClassPathResource) { - ClassPathResource classPathResource = (ClassPathResource) repositoryRoot; - String path = classPathResource.getPath(); - if (StringUtils.hasText(path)) { - return RepoRoots.asList(new RepoRoot(stubRunnerOptions.getStubRepositoryRootAsString())); - } - } - String path = "/**/" + configuration.getGroupId() + "/" + configuration.getArtifactId(); - return RepoRoots.asList(new RepoRoot("classpath*:/META-INF" + path, "/**/*.*"), - new RepoRoot("classpath*:/contracts" + path, "/**/*.*"), - new RepoRoot("classpath*:/mappings" + path, "/**/*.*")); - } - - private Pattern gavPattern(StubConfiguration config) { - String ga = config.getGroupId() + "." + config.getArtifactId(); - return Pattern.compile("^(.*)(" + ga + ")(.*)$"); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/CompositeStubDownloaderBuilder.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/CompositeStubDownloaderBuilder.java deleted file mode 100644 index 08e955f1b8..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/CompositeStubDownloaderBuilder.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * @author Marcin Grzejszczak - * @since 2.0.0 - */ -class CompositeStubDownloaderBuilder implements StubDownloaderBuilder { - - private final List builders; - - CompositeStubDownloaderBuilder(List builders) { - this.builders = builders; - } - - @Override - public StubDownloader build(StubRunnerOptions stubRunnerOptions) { - if (this.builders == null) { - return null; - } - return new CompositeStubDownloader(this.builders, stubRunnerOptions); - } - -} - -class CompositeStubDownloader implements StubDownloader { - - private static final Log log = LogFactory.getLog(CompositeStubDownloader.class); - - private final List builders; - - private final StubRunnerOptions stubRunnerOptions; - - CompositeStubDownloader(List builders, StubRunnerOptions stubRunnerOptions) { - this.builders = builders; - this.stubRunnerOptions = stubRunnerOptions; - if (log.isDebugEnabled()) { - log.debug("Registered following stub downloaders " - + this.builders.stream().map(b -> b.getClass().getName()).collect(Collectors.toList())); - } - } - - @Override - public Map.Entry downloadAndUnpackStubJar(StubConfiguration stubConfiguration) { - Map.Entry entry = entry(stubConfiguration); - if (entry != null) { - return entry; - } - log.warn("No matching stubs or contracts were found"); - if (this.stubRunnerOptions.isFailOnNoStubs()) { - throw new IllegalArgumentException( - "No stubs or contracts were found for [" + stubConfiguration.toColonSeparatedDependencyNotation() - + "] and the switch to fail on no stubs was set."); - } - return null; - } - - private Map.Entry entry(StubConfiguration stubConfiguration) { - for (StubDownloaderBuilder builder : this.builders) { - StubDownloader downloader = builder.build(this.stubRunnerOptions); - if (downloader == null) { - continue; - } - if (log.isDebugEnabled()) { - log.debug("Found a matching stub downloader [" + downloader.getClass().getName() + "]"); - } - Map.Entry entry = downloader.downloadAndUnpackStubJar(stubConfiguration); - if (entry != null) { - if (log.isDebugEnabled()) { - log.debug("Found a matching entry [" + entry + "] by stub downloader [" - + downloader.getClass().getName() + "]"); - } - return entry; - } - else { - log.warn("Stub Downloader [" + downloader.getClass().getName() + "] " + "failed to find an entry for [" - + stubConfiguration.toColonSeparatedDependencyNotation() + "]. " - + "Will proceed to the next one"); - } - } - return null; - } - -} 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 deleted file mode 100644 index 81189596fd..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ContractDownloader.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.lang.invoke.MethodHandles; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties; -import org.springframework.util.StringUtils; - -/** - * Downloads a JAR with contracts and sets up the plugin configuration with proper - * inclusion patterns. - * - * @author Marcin Grzejszczak - * @since 1.0.0 - */ -public class ContractDownloader { - - private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass()); - - private final StubDownloader stubDownloader; - - private final StubConfiguration contractsJarStubConfiguration; - - private final String contractsPath; - - private final String projectGroupId; - - private final String projectArtifactId; - - private final String projectVersion; - - public ContractDownloader(StubDownloader stubDownloader, StubConfiguration contractsJarStubConfiguration, - String contractsPath, String projectGroupId, String projectArtifactId, String projectVersion) { - this.stubDownloader = stubDownloader; - this.contractsJarStubConfiguration = contractsJarStubConfiguration; - this.contractsPath = contractsPath; - this.projectGroupId = projectGroupId; - this.projectArtifactId = projectArtifactId; - this.projectVersion = projectVersion; - } - - /** - * Downloads JAR containing all the contracts. The JAR with the contracts contains all - * the contracts for all the projects. We're interested only in its subset. - * @return location of the unpacked downloaded stubs - */ - public File unpackAndDownloadContracts() { - if (log.isDebugEnabled()) { - log.debug("Will download contracts for [" + this.contractsJarStubConfiguration + "]"); - } - Map.Entry unpackedContractStubs = this.stubDownloader - .downloadAndUnpackStubJar(this.contractsJarStubConfiguration); - if (unpackedContractStubs == null) { - throw new IllegalStateException("The contracts failed to be downloaded!"); - } - return unpackedContractStubs.getValue(); - } - - /** - * After JAR with all the contracts is downloaded and unpacked - we need to get new - * inclusion pattern for those contracts. The JAR with the contracts contains all the - * contracts for all the projects. We're interested only in its subset. - * @param contractsDirectory - location of the unpacked downloaded stubs. - * @return new inclusion properties, calculated for those downloaded contracts. - */ - public InclusionProperties createNewInclusionProperties(File contractsDirectory) { - String pattern; - String includedAntPattern; - if (StringUtils.hasText(this.contractsPath)) { - pattern = patternFromProperty(contractsDirectory); - log.info("Will pick a pattern from the contractPath property"); - includedAntPattern = wrapWithAntPattern(contractsPath()); - } - 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 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); - } - } - log.info("Pattern to pick contracts equals [" + pattern + "]"); - log.info("Ant Pattern to pick files equals [" + includedAntPattern + "]"); - return new InclusionProperties(pattern, includedAntPattern); - } - - private File contractsSubDirIfPresent(File contractsDirectory) { - File contracts = new File(contractsDirectory, "contracts"); - if (contracts.exists()) { - if (log.isDebugEnabled()) { - log.debug("Contracts folder found [" + contracts + "]"); - } - contractsDirectory = contracts; - } - return contractsDirectory; - } - - private boolean hasGavInPath(File file) { - return hasVersionInPath(file) && hasSeparatedGroupInPath(file, File.separator) - || hasSeparatedGroupInPath(file, "."); - } - - private boolean hasVersionInPath(File file) { - return file.getAbsolutePath().contains(this.projectVersion); - } - - private boolean hasSeparatedGroupInPath(File file, String separator) { - return file.getAbsolutePath().contains(groupAndArtifact(separator)); - } - - private String groupAndArtifact(String separator) { - return this.projectGroupId + separator + this.projectArtifactId; - } - - private String patternFromProperty(File contractsDirectory) { - return ("^" + contractsDirectory.getAbsolutePath() + "(" + File.separator + ")?" + ".*" - + contractsPath().replace("/", File.separator) + ".*$").replace("\\", "\\\\"); - } - - private String contractsPath() { - return surroundWithSeparator(this.contractsPath); - } - - private String surroundWithSeparator(String string) { - String path = string.startsWith(File.separator) ? string : File.separator + string; - return path.endsWith(File.separator) ? path : path + File.separator; - } - - private String wrapWithAntPattern(String path) { - String changedPath = surroundWithSeparator(path).replace(File.separator, "/"); - return "**" + changedPath.replace(File.separator, "/") + "**/"; - } - - private String groupArtifactToPattern(File contractsDirectory) { - return ("^" + contractsDirectory.getAbsolutePath() + "(" + File.separator + ")?" + ".*" - + slashSeparatedGroupId() + File.separator + this.projectArtifactId + File.separator + ".*$") - .replace("\\", "\\\\"); - } - - private String fileToPattern(File contractsDirectory) { - return ("^" + contractsDirectory.getAbsolutePath() + ".*$").replace("\\", "\\\\"); - } - - private String slashSeparatedGroupId() { - return this.projectGroupId.replace(".", File.separator); - } - - /** - * Holder for updated inclusion properties, which are calculated after jar with - * contracts was downloaded / unpacked. - */ - public static class InclusionProperties { - - /** - * @see ContractVerifierConfigProperties.includedContracts - */ - private final String includedContracts; - - /** - * @see ContractVerifierConfigProperties.includedRootFolderAntPattern - */ - private final String includedRootFolderAntPattern; - - InclusionProperties(final String includedContracts, final String includedRootFolderAntPattern) { - this.includedContracts = includedContracts; - this.includedRootFolderAntPattern = includedRootFolderAntPattern; - } - - public String getIncludedContracts() { - return includedContracts; - } - - public String getIncludedRootFolderAntPattern() { - return includedRootFolderAntPattern; - } - - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ContractProjectUpdater.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ContractProjectUpdater.java deleted file mode 100644 index f819bd7492..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ContractProjectUpdater.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.io.IOException; -import java.nio.file.DirectoryNotEmptyException; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.StandardCopyOption; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Arrays; -import java.util.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.lang.Nullable; -import org.springframework.util.StringUtils; - -/** - * Updates the project containing contracts. - * - * @author Marcin Grzejszczak - * @since 2.0.0 - */ -public class ContractProjectUpdater { - - private static final Log log = LogFactory.getLog(ContractProjectUpdater.class); - - private static final int DEFAULT_ATTEMPTS_NO = 10; - - private static final long DEFAULT_WAIT_BETWEEN_ATTEMPTS = 1000; - - // TODO: Add this to the documentation - private static final String DEFAULT_COMMIT_MESSAGE = "Updating project [$project] with stubs"; - - private static final String GIT_ATTEMPTS_NO_PROP = "git.no-of-attempts"; - - private static final String GIT_WAIT_BETWEEN_ATTEMPTS = "git.wait-between-attempts"; - - private static final String GIT_COMMIT_MESSAGE = "git.commit-message"; - - private final StubRunnerOptions stubRunnerOptions; - - private final GitContractsRepo gitContractsRepo; - - public ContractProjectUpdater(StubRunnerOptions stubRunnerOptions) { - this.stubRunnerOptions = stubRunnerOptions; - this.gitContractsRepo = new GitContractsRepo(stubRunnerOptions); - } - - /** - * Merges the folder with stubs with the project containing contracts. - * @param projectName name of the project - * @param rootStubsFolder root folder of the stubs - */ - public void updateContractProject(String projectName, Path rootStubsFolder) { - File clonedRepo = this.gitContractsRepo.clonedRepo(this.stubRunnerOptions.stubRepositoryRoot); - GitStubDownloaderProperties properties = new GitStubDownloaderProperties( - this.stubRunnerOptions.stubRepositoryRoot, this.stubRunnerOptions); - copyStubs(projectName, rootStubsFolder, clonedRepo); - GitRepo gitRepo = new GitRepo(clonedRepo, properties); - String msg = StubRunnerPropertyUtils.getProperty(this.stubRunnerOptions.getProperties(), GIT_COMMIT_MESSAGE); - GitRepo.CommitResult commit = gitRepo.commit(clonedRepo, commitMessage(projectName, msg)); - if (commit == GitRepo.CommitResult.EMPTY) { - log.info("There were no changes to commit. Won't push the changes"); - return; - } - String attempts = StubRunnerPropertyUtils.getProperty(this.stubRunnerOptions.getProperties(), - GIT_ATTEMPTS_NO_PROP); - int intAttempts = StringUtils.hasText(attempts) ? Integer.parseInt(attempts) : DEFAULT_ATTEMPTS_NO; - String wait = StubRunnerPropertyUtils.getProperty(this.stubRunnerOptions.getProperties(), - GIT_WAIT_BETWEEN_ATTEMPTS); - long longWait = StringUtils.hasText(wait) ? Long.parseLong(wait) : DEFAULT_WAIT_BETWEEN_ATTEMPTS; - tryToPushCurrentBranch(clonedRepo, gitRepo, intAttempts, longWait); - } - - private void tryToPushCurrentBranch(File clonedRepo, GitRepo gitRepo, int intAttempts, long longWait) { - int currentAttempt = 0; - while (currentAttempt < intAttempts) { - log.info("Trying to push changes, attempt " + (currentAttempt + 1) + "/" + intAttempts); - gitRepo.pull(clonedRepo); - log.info("Successfully pulled changes from remote for project with contract and stubs"); - try { - gitRepo.pushCurrentBranch(clonedRepo); - log.info("Successfully pushed changes with current stubs"); - break; - } - catch (IllegalStateException e) { - // empty - log.error("Exception occurred while trying to push the changes", e); - currentAttempt++; - if (currentAttempt == intAttempts) { - throw new IllegalStateException( - "Failed to push changes to the project with contracts and stubs. Exceeded number of retries [" - + intAttempts + "]"); - } - try { - Thread.sleep(longWait); - } - catch (InterruptedException e1) { - throw new IllegalStateException(e1); - } - } - } - } - - private String commitMessage(String projectName, String msg) { - return StringUtils.hasText(msg) ? replaceProject(projectName, msg) - : replaceProject(projectName, DEFAULT_COMMIT_MESSAGE); - } - - private String replaceProject(String projectName, String msg) { - return msg.replace("$project", projectName); - } - - private void copyStubs(String projectName, Path rootStubsFolder, File clonedRepo) { - try { - if (log.isDebugEnabled()) { - log.debug("Copying stubs from [" + rootStubsFolder.toString() + "] to the cloned repo [" - + clonedRepo.getAbsolutePath() + "] for project [" + projectName + "]"); - } - Files.walkFileTree(rootStubsFolder, new DirectoryCopyingVisitor(rootStubsFolder, clonedRepo.toPath())); - if (log.isDebugEnabled()) { - log.debug("Successfully copied stubs to the cloned repo for project [" + projectName + "]"); - } - } - catch (IOException e) { - throw new IllegalStateException(e); - } - } - -} - -class DirectoryCopyingVisitor extends SimpleFileVisitor { - - private static final List FOLDERS_TO_DELETE = Arrays.asList("contracts", "mappings"); - - private static final Log log = LogFactory.getLog(DirectoryCopyingVisitor.class); - - private final Path from; - - private final Path to; - - DirectoryCopyingVisitor(Path from, Path to) { - this.from = from; - this.to = to; - if (log.isDebugEnabled()) { - log.debug("Will copy from [" + from.toString() + "] to [" + to.toString() + "]"); - } - } - - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { - Path relativePath = this.from.relativize(dir); - if (".git".equals(relativePath.toString())) { - return FileVisitResult.SKIP_SUBTREE; - } - Path targetPath = this.to.resolve(relativePath); - if (!Files.exists(targetPath)) { - if (log.isDebugEnabled()) { - log.debug("Created a folder [" + targetPath.toString() + "]"); - } - Files.createDirectory(targetPath); - } - else { - if (log.isDebugEnabled()) { - log.debug("Folder [" + targetPath.toString() + "] already exists"); - } - if (FOLDERS_TO_DELETE.contains(targetPath.toFile().getName())) { - if (log.isDebugEnabled()) { - log.debug("Will remove the folder [" + targetPath.toString() + "]"); - } - deleteRecursively(targetPath); - Files.createDirectory(targetPath); - if (log.isDebugEnabled()) { - log.debug("Recreated folder [" + targetPath.toString() + "]"); - } - } - } - return FileVisitResult.CONTINUE; - } - - private boolean deleteRecursively(@Nullable Path root) throws IOException { - if (root == null) { - return false; - } - if (!Files.exists(root)) { - return false; - } - Files.walkFileTree(root, new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - Files.delete(file); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { - // a hack for Windows not to fail when directory is removed - // related to - // https://github.com/spring-cloud/spring-cloud-sleuth/issues/834 - if (exc == null) { - int maxTries = 5; - int count = 0; - boolean deleted; - do { - deleted = this.isDeleted(dir); - if (deleted) { - if (log.isDebugEnabled()) { - log.debug("Deleted [" + dir + "]"); - } - break; - } - if (log.isDebugEnabled()) { - log.debug("Failed to delete [" + dir + "]"); - } - // wait a bit and try again - count++; - try { - Thread.sleep(2); - } - catch (InterruptedException e1) { - Thread.currentThread().interrupt(); - break; - } - - } - while (count < maxTries); - if (!deleted) { - if (log.isDebugEnabled()) { - log.debug("Failed to delete [" + dir + "] after [" + maxTries + "] attempts to do it"); - } - throw new DirectoryNotEmptyException(dir.toString()); - } - return FileVisitResult.CONTINUE; - } - throw exc; - } - - private boolean isDeleted(Path dir) throws IOException { - try { - Files.delete(dir); - return true; - } - catch (DirectoryNotEmptyException e) { - // happens sometimes if Windows is too slow to remove children of a - // directory - return false; - } - } - }); - return true; - } - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - Path relativePath = this.to.resolve(this.from.relativize(file)); - Files.copy(file, relativePath, StandardCopyOption.REPLACE_EXISTING); - if (log.isDebugEnabled()) { - log.debug("Copied file from [" + file.toString() + "] to [" + relativePath.toString() + "]"); - } - return FileVisitResult.CONTINUE; - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/FileStubDownloader.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/FileStubDownloader.java deleted file mode 100644 index 1d76538c84..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/FileStubDownloader.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.regex.Pattern; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.core.io.AbstractResource; -import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; -import org.springframework.util.StringUtils; - -/** - * Allows to read stubs and contracts from a given location. Contrary to - * {@link org.springframework.cloud.contract.stubrunner.AetherStubDownloaderBuilder}, - * doesn't require the location to be a maven repository. - * - * @author Marcin Grzejszczak - */ -public class FileStubDownloader implements StubDownloaderBuilder { - - private static final List ACCEPTABLE_PROTOCOLS = Collections.singletonList("stubs"); - - /** - * Does any of the accepted protocols matches the URL of the repository. - * @param url - of the repository - * @return {@code true} if protocol is accepted - */ - public static boolean isProtocolAccepted(String url) { - return ACCEPTABLE_PROTOCOLS.stream().anyMatch(url::startsWith); - } - - @Override - public StubDownloader build(StubRunnerOptions stubRunnerOptions) { - // should work only in remote and local option - if (stubRunnerOptions.getStubsMode() == StubRunnerProperties.StubsMode.CLASSPATH - || stubRunnerOptions.getStubRepositoryRoot() == null) { - return null; - } - Resource resource = stubRunnerOptions.getStubRepositoryRoot(); - // we verify whether the protocol starts with `stubs://` - if (!(resource instanceof StubsResource)) { - return null; - } - return new StubsStubDownloader(stubRunnerOptions); - } - - @Override - public Resource resolve(String location, ResourceLoader resourceLoader) { - if (!StringUtils.hasText(location) || !isProtocolAccepted(location)) { - return null; - } - // Can be resolving a resource for Classpath as fallback - if (!location.startsWith("stubs://file://")) { - return new StubsResource(location); - } - // Convert any windows file format path to a uri - String correctlyFormattedLocation = convertLocationToUriFormat(location); - return new StubsResource(correctlyFormattedLocation); - } - - private String convertLocationToUriFormat(String location) { - final String correctlyFormattedLocation = separatorsToUnix(location); - final String rawPath = correctlyFormattedLocation.replace("stubs://file://", ""); - if (rawPath.charAt(0) != '/') { - return "stubs://file:///" + rawPath; - } - return correctlyFormattedLocation; - } - - private String separatorsToUnix(String location) { - return location != null && location.indexOf(92) != -1 ? location.replace('\\', '/') : location; - } - -} - -/** - * Primitive version of a Stubs {@link Resource}. Automatically makes Spring convert the - * URL to a Resource. - */ -class StubsResource extends AbstractResource { - - private final String rawLocation; - - StubsResource(String location) { - this.rawLocation = location; - } - - @Override - public String getDescription() { - return this.rawLocation; - } - - @Override - public InputStream getInputStream() throws IOException { - return null; - } - - @Override - public URI getURI() throws IOException { - return URI.create(this.rawLocation); - } - -} - -/** - * Concrete logic of picking stubs. - */ -class StubsStubDownloader implements StubDownloader { - - private static final Log log = LogFactory.getLog(StubsStubDownloader.class); - - private static final String STUBS_FIND_PRODUCER_PROPERTY = "stubs.find-producer"; - - private static final String LATEST_VERSION = "+"; - - private final StubRunnerOptions stubRunnerOptions; - - StubsStubDownloader(StubRunnerOptions stubRunnerOptions) { - this.stubRunnerOptions = stubRunnerOptions; - } - - // StubConfiguration is the concrete stub to be fetched - @Override - public Map.Entry downloadAndUnpackStubJar(StubConfiguration stubConfiguration) { - boolean shouldFindProducer = shouldFindProducer(); - if (!shouldFindProducer) { - String schemeSpecific = schemeSpecificPart(); - log.info("Stubs are present under [" + schemeSpecific + "]. Will copy them to a temporary directory."); - return new ResourceResolvingStubDownloader(stubRunnerOptions, this::repoRootForSchemeSpecificPart, - this::anyPattern).downloadAndUnpackStubJar(stubConfiguration); - } - return new ResourceResolvingStubDownloader(stubRunnerOptions, this::repoRoot, this::gavPattern) - .downloadAndUnpackStubJar(stubConfiguration); - } - - private RepoRoots repoRootForSchemeSpecificPart(StubRunnerOptions stubRunnerOptions, - StubConfiguration configuration) { - String specificPart = schemeSpecificPart(); - specificPart = specificPart.endsWith("/") ? specificPart : (specificPart + "/"); - specificPart = specificPart + "**/*.*"; - return new RepoRoots(Collections.singleton(new RepoRoot(specificPart))); - } - - private Pattern anyPattern(StubConfiguration config) { - return Pattern.compile(resolvePath() + "(.*)"); - } - - private String resolvePath() { - String schemeSpecificPart = schemeSpecificPart(); - Resource resource = ResourceResolver.resource(schemeSpecificPart); - if (resource != null) { - try { - return resource.getURL().getFile(); - } - catch (IOException ex) { - return schemeSpecificPart; - } - } - return schemeSpecificPart; - } - - // for group id a.b.c and artifact id d - // a.b.c/d - // a/b/c/d - private RepoRoots repoRoot(StubRunnerOptions stubRunnerOptions, StubConfiguration configuration) { - String pathWithGroupAndArtifactId = "/" + configuration.getGroupId() + "/" + configuration.getArtifactId(); - String pathWithGroupAndArtifactIdSlashSeparated = "/" + configuration.getGroupId().replace(".", File.separator) - + "/" + configuration.getArtifactId(); - String anyFileSuffix = "/**/*.*"; - RepoRoots roots = RepoRoots.asList( - new RepoRoot(schemeSpecificPart() + pathWithGroupAndArtifactId, anyFileSuffix), - new RepoRoot(schemeSpecificPart() + pathWithGroupAndArtifactIdSlashSeparated, anyFileSuffix), - new RepoRoot(schemeSpecificPart() + anyFileSuffix)); - if (!latestVersionIsSet(configuration)) { - String pathWithGAV = pathWithGroupAndArtifactId + "/" + configuration.getVersion(); - String pathWithSlashSeparatedGAV = pathWithGroupAndArtifactIdSlashSeparated + "/" - + configuration.getVersion(); - roots.addAll(RepoRoots.asList(new RepoRoot(schemeSpecificPart() + pathWithGAV, anyFileSuffix), - new RepoRoot(schemeSpecificPart() + pathWithSlashSeparatedGAV, anyFileSuffix))); - } - return roots; - } - - private Pattern gavPattern(StubConfiguration config) { - String version = config.getVersion(); - String ga = config.getGroupId() + "." + config.getArtifactId(); - String gav = latestVersionIsSet(config) ? ga : (ga + "." + version); - return Pattern.compile("^(.*)(" + gav + ")(.*)$"); - } - - private boolean latestVersionIsSet(StubConfiguration configuration) { - return LATEST_VERSION.equals(configuration.getVersion()); - } - - private boolean shouldFindProducer() { - Map args = this.stubRunnerOptions.getProperties(); - String findProducer = StubRunnerPropertyUtils.getProperty(args, STUBS_FIND_PRODUCER_PROPERTY); - return Boolean.parseBoolean(findProducer); - } - - // stubs://foo -> foo - private String schemeSpecificPart() { - try { - String part = this.stubRunnerOptions.getStubRepositoryRoot().getURI().getSchemeSpecificPart(); - if (!StringUtils.hasText(part)) { - return part; - } - return part.startsWith("//") ? part.substring(2) : part; - } - catch (IOException ex) { - throw new IllegalStateException(ex); - } - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/GitRepo.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/GitRepo.java deleted file mode 100644 index f2bd946c0e..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/GitRepo.java +++ /dev/null @@ -1,415 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.lang.invoke.MethodHandles; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.List; - -import com.jcraft.jsch.IdentityRepository; -import com.jcraft.jsch.JSch; -import com.jcraft.jsch.JSchException; -import com.jcraft.jsch.Session; -import com.jcraft.jsch.agentproxy.AgentProxyException; -import com.jcraft.jsch.agentproxy.Connector; -import com.jcraft.jsch.agentproxy.RemoteIdentityRepository; -import com.jcraft.jsch.agentproxy.USocketFactory; -import com.jcraft.jsch.agentproxy.connector.SSHAgentConnector; -import com.jcraft.jsch.agentproxy.usocket.JNAUSocketFactory; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.eclipse.jgit.api.CheckoutCommand; -import org.eclipse.jgit.api.CloneCommand; -import org.eclipse.jgit.api.CreateBranchCommand; -import org.eclipse.jgit.api.Git; -import org.eclipse.jgit.api.ListBranchCommand; -import org.eclipse.jgit.api.PullCommand; -import org.eclipse.jgit.api.PushCommand; -import org.eclipse.jgit.api.RemoteSetUrlCommand; -import org.eclipse.jgit.api.ResetCommand; -import org.eclipse.jgit.api.TransportConfigCallback; -import org.eclipse.jgit.api.errors.EmptyCommitException; -import org.eclipse.jgit.api.errors.GitAPIException; -import org.eclipse.jgit.lib.Ref; -import org.eclipse.jgit.transport.CredentialsProvider; -import org.eclipse.jgit.transport.SshSessionFactory; -import org.eclipse.jgit.transport.SshTransport; -import org.eclipse.jgit.transport.URIish; -import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; -import org.eclipse.jgit.transport.ssh.jsch.JschConfigSessionFactory; -import org.eclipse.jgit.transport.ssh.jsch.OpenSshConfig; -import org.eclipse.jgit.util.FS; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.util.FileSystemUtils; -import org.springframework.util.ResourceUtils; - -/** - * Abstraction over a Git repo. Can cloned repo from a given location and check its - * branch. - * - * taken from: https://github.com/spring-cloud/spring-cloud-release-tools - * - * @author Marcin Grzejszczak - */ -class GitRepo { - - private static final Log log = LogFactory.getLog(GitRepo.class); - - final JGitFactory gitFactory; - - private final File basedir; - - private final boolean ensureGitSuffix; - - GitRepo(File basedir, GitStubDownloaderProperties properties) { - this.basedir = basedir; - this.gitFactory = new JGitFactory(properties); - this.ensureGitSuffix = properties.ensureGitSuffix; - } - - // for tests - GitRepo(File basedir) { - this.basedir = basedir; - this.gitFactory = new JGitFactory(); - this.ensureGitSuffix = true; - } - - // for tests - GitRepo(File basedir, boolean ensureGitSuffix) { - this.basedir = basedir; - this.gitFactory = new JGitFactory(); - this.ensureGitSuffix = ensureGitSuffix; - } - - // for tests - GitRepo(File basedir, JGitFactory factory) { - this.basedir = basedir; - this.gitFactory = factory; - this.ensureGitSuffix = true; - } - - /** - * Clones the project. - * @param projectUri - URI of the project - * @return file where the project was cloned - */ - File cloneProject(URI projectUri) { - try { - log.info("Cloning repo from [" + projectUri + "] to [" + this.basedir + "]"); - Git git = cloneToBasedir(projectUri, this.basedir); - if (git != null) { - git.close(); - } - File clonedRepo = git.getRepository().getWorkTree(); - log.info("Cloned repo to [" + clonedRepo + "]"); - return clonedRepo; - } - catch (Exception e) { - throw new IllegalStateException("Exception occurred while cloning repo", e); - } - } - - /** - * Checks out a branch for a project. - * @param project - a Git project - * @param branch - branch to check out - */ - void checkout(File project, String branch) { - try { - String currentBranch = currentBranch(project); - if (currentBranch.equals(branch)) { - log.info("Won't check out the same branch. Skipping"); - return; - } - log.info("Checking out branch [" + branch + "]"); - checkoutBranch(project, branch); - log.info("Successfully checked out the branch [" + branch + "]"); - } - catch (Exception e) { - throw new IllegalStateException(e); - } - } - - /** - * Pulls changes for the project. - * @param project - a Git project - */ - void pull(File project) { - try { - try (Git git = this.gitFactory.open(project)) { - PullCommand command = this.gitFactory.pull(git); - command.setRebase(true).call(); - } - } - catch (Exception e) { - throw new IllegalStateException(e); - } - } - - /** - * Performs a commit. - * @param project - a Git project - * @param message - commit message - * @return result of the commit - */ - CommitResult commit(File project, String message) { - try (Git git = this.gitFactory.open(file(project))) { - git.add().addFilepattern(".").call(); - git.commit().setAllowEmpty(false).setMessage(message).call(); - log.info("Commited successfully with message [" + message + "]"); - return CommitResult.SUCCESSFUL; - } - catch (EmptyCommitException e) { - log.info("There were no changes detected. Will not commit an empty commit"); - return CommitResult.EMPTY; - } - catch (Exception e) { - throw new IllegalStateException(e); - } - } - - void reset(File project) { - try (Git git = this.gitFactory.open(file(project))) { - git.reset().setMode(ResetCommand.ResetType.HARD).call(); - } - catch (Exception e) { - throw new IllegalStateException(e); - } - } - - /** - * Pushes the commits od current branch. - * @param project - Git project - */ - void pushCurrentBranch(File project) { - try (Git git = this.gitFactory.open(file(project))) { - this.gitFactory.push(git).call(); - } - catch (Exception e) { - throw new IllegalStateException(e); - } - } - - private File file(File project) throws FileNotFoundException { - return ResourceUtils.getFile(project.toURI()).getAbsoluteFile(); - } - - private Git cloneToBasedir(URI projectUrl, File destinationFolder) { - String projectGitUrl = sanitizeGitUrl(projectUrl); - if (log.isDebugEnabled()) { - log.debug("Project git url [" + projectGitUrl + "]"); - } - CloneCommand command = this.gitFactory.getCloneCommandByCloneRepository().setURI(projectGitUrl) - .setDirectory(destinationFolder); - try { - Git git = command.call(); - if (git.getRepository().getRemoteNames().isEmpty()) { - log.info("No remote added. Will add remote of the cloned project"); - git.remoteSetUrl().setRemoteUri(new URIish(projectGitUrl)); - git.remoteSetUrl().setRemoteName("origin"); - git.remoteSetUrl().setUriType(RemoteSetUrlCommand.UriType.PUSH); - } - return git; - } - catch (GitAPIException | URISyntaxException e) { - deleteBaseDirIfExists("Failed to initialize base directory"); - throw new IllegalStateException(e); - } - } - - protected String sanitizeGitUrl(URI uri) { - String urlString = uri.toString(); - return (urlString.endsWith(".git") || !this.ensureGitSuffix) ? urlString : urlString + ".git"; - } - - private Ref checkoutBranch(File projectDir, String branch) throws GitAPIException { - Git git = this.gitFactory.open(projectDir); - CheckoutCommand command = git.checkout().setName(branch); - try { - if (shouldTrack(git, branch)) { - trackBranch(command, branch); - } - return command.call(); - } - catch (GitAPIException e) { - deleteBaseDirIfExists("Failed to delete base directory"); - throw e; - } - finally { - git.close(); - } - } - - private String currentBranch(File projectDir) { - Git git = this.gitFactory.open(projectDir); - try { - return git.getRepository().getBranch(); - } - catch (IOException e) { - throw new IllegalStateException(e); - } - finally { - git.close(); - } - } - - private boolean shouldTrack(Git git, String label) throws GitAPIException { - return isBranch(git, label) && !isLocalBranch(git, label); - } - - private void trackBranch(CheckoutCommand checkout, String label) { - checkout.setCreateBranch(true).setName(label).setUpstreamMode(CreateBranchCommand.SetupUpstreamMode.TRACK) - .setStartPoint("origin/" + label); - } - - private boolean isBranch(Git git, String label) throws GitAPIException { - return containsBranch(git, label, ListBranchCommand.ListMode.ALL); - } - - private boolean isLocalBranch(Git git, String label) throws GitAPIException { - return containsBranch(git, label, null); - } - - private boolean containsBranch(Git git, String label, ListBranchCommand.ListMode listMode) throws GitAPIException { - ListBranchCommand command = git.branchList(); - if (listMode != null) { - command.setListMode(listMode); - } - List branches = command.call(); - for (Ref ref : branches) { - if (ref.getName().endsWith("/" + label)) { - return true; - } - } - return false; - } - - private void deleteBaseDirIfExists(String errorMessage) { - if (this.basedir.exists()) { - if (!FileSystemUtils.deleteRecursively(this.basedir)) { - throw new IllegalStateException(errorMessage); - } - } - } - - enum CommitResult { - - SUCCESSFUL, EMPTY - - } - - /** - * Wraps the static method calls to {@link Git} and {@link CloneCommand} allowing for - * easier unit testing. - */ - static class JGitFactory { - - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - final CredentialsProvider provider; - - private final SshSessionFactory factory = new JschConfigSessionFactory() { - - @Override - protected void configure(OpenSshConfig.Host host, Session session) { - } - - @Override - protected JSch createDefaultJSch(FS fs) throws JSchException { - Connector connector = null; - try { - if (SSHAgentConnector.isConnectorAvailable()) { - USocketFactory usf = new JNAUSocketFactory(); - connector = new SSHAgentConnector(usf); - } - log.info("Successfully connected to an agent"); - } - catch (AgentProxyException e) { - log.error("Exception occurred while trying to connect to agent. Will create" - + "the default JSch connection", e); - return super.createDefaultJSch(fs); - } - final JSch jsch = super.createDefaultJSch(fs); - if (connector != null) { - JSch.setConfig("PreferredAuthentications", "publickey,password"); - IdentityRepository identityRepository = new RemoteIdentityRepository(connector); - jsch.setIdentityRepository(identityRepository); - } - return jsch; - } - }; - - private final TransportConfigCallback callback = transport -> { - if (transport instanceof SshTransport) { - SshTransport sshTransport = (SshTransport) transport; - sshTransport.setSshSessionFactory(this.factory); - } - }; - - JGitFactory(GitStubDownloaderProperties properties) { - if (org.springframework.util.StringUtils.hasText(properties.username)) { - log.info("Passed username and password - will set a custom credentials provider"); - this.provider = credentialsProvider(properties); - } - else { - if (log.isDebugEnabled()) { - log.debug("No custom credentials provider will be set"); - } - this.provider = null; - } - } - - // for tests - JGitFactory() { - this.provider = null; - } - - CredentialsProvider credentialsProvider(GitStubDownloaderProperties properties) { - return new UsernamePasswordCredentialsProvider(properties.username, properties.password); - } - - CloneCommand getCloneCommandByCloneRepository() { - return Git.cloneRepository().setCredentialsProvider(this.provider) - .setTransportConfigCallback(this.callback); - } - - PushCommand push(Git git) { - return git.push().setCredentialsProvider(this.provider).setTransportConfigCallback(this.callback); - } - - PullCommand pull(Git git) { - return git.pull().setCredentialsProvider(this.provider).setTransportConfigCallback(this.callback); - } - - Git open(File file) { - try { - return Git.open(file); - } - catch (IOException e) { - throw new IllegalStateException(e); - } - } - - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/HttpServerStub.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/HttpServerStub.java deleted file mode 100644 index 3749d23ea8..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/HttpServerStub.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.util.Collection; - -/** - * Describes an HTTP Server Stub. - * - * @author Marcin Grzejszczak - * @since 1.1.0 - */ -public interface HttpServerStub { - - /** - * @return port on which the server is running. Return {@code -1} if not applicable. - */ - int port(); - - /** - * @return https port on which the server is running. Return {@code -1} if not - * applicable. - */ - default int httpsPort() { - return -1; - } - - /** - * @return {@code true} if the server is running - */ - boolean isRunning(); - - /** - * Starts the server. Should return itself to allow chaining. - * @param configuration - setup for the given stub - * @return this - */ - HttpServerStub start(HttpServerStubConfiguration configuration); - - /** - * Stops the server. Should return itself to allow chaining. - * @return this - */ - HttpServerStub stop(); - - /** - * Resets the server. Should return itself to allow chaining. - * @return this - */ - default HttpServerStub reset() { - return this; - } - - /** - * Registers the stub files in the HTTP server stub. Should return itself to allow - * chaining. - * @param stubFiles collection of files containing stubs - * @return this - */ - HttpServerStub registerMappings(Collection stubFiles); - - /** - * @return a collection of registered mappings. - */ - String registeredMappings(); - - /** - * @param file file to check if can be accepted. - * @return {@code true} if the file is a valid stub mapping - */ - boolean isAccepted(File file); - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/HttpServerStubConfiguration.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/HttpServerStubConfiguration.java deleted file mode 100644 index c3977747dd..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/HttpServerStubConfiguration.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -/** - * Configuration class for an {@link HttpServerStub}. - * - * @author Marcin Grzejszczak - * @since 2.1.0 - */ -public final class HttpServerStubConfiguration { - - /** - * Allows to perform additional configuration of the HTTP Server stub. - */ - public final HttpServerStubConfigurer configurer; - - /** - * Options of Stub Runner itself. - */ - public final StubRunnerOptions stubRunnerOptions; - - /** - * Configuration of a particular stub. - */ - public final StubConfiguration stubConfiguration; - - /** - * Port at which the stub will be started. - */ - public final Integer port; - - /** - * Is port a random one or was it fixed. - */ - public boolean randomPort; - - public HttpServerStubConfiguration(HttpServerStubConfigurer configurer, StubRunnerOptions stubRunnerOptions, - StubConfiguration stubConfiguration, Integer port) { - this(configurer, stubRunnerOptions, stubConfiguration, port, randomPort(port)); - } - - public HttpServerStubConfiguration(HttpServerStubConfigurer configurer, StubRunnerOptions stubRunnerOptions, - StubConfiguration stubConfiguration, Integer port, boolean randomPort) { - this.configurer = configurer; - this.stubRunnerOptions = stubRunnerOptions; - this.stubConfiguration = stubConfiguration; - this.port = port; - this.randomPort = randomPort; - } - - private static boolean randomPort(Integer port) { - return port == null || port == 0; - } - - public boolean isRandomPort() { - return randomPort(this.port); - } - - public String toColonSeparatedDependencyNotation() { - return this.stubConfiguration != null ? this.stubConfiguration.toColonSeparatedDependencyNotation() : ""; - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/HttpServerStubConfigurer.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/HttpServerStubConfigurer.java deleted file mode 100644 index 23b66fc5e7..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/HttpServerStubConfigurer.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -/** - * Allows to perform additional configuration of the HTTP Server stub. - * - * @param type of the stub configuration - * @author Marcin Grzejszczak - * @since 2.1.0 - */ -public interface HttpServerStubConfigurer { - - /** - * Ensures that the HTTP server stub implementation configuration type is accepted. - * @param httpStubConfiguration - HTTP server stub implementation - * @return {@code true} when this configurer can be applied for this object - */ - boolean isAccepted(Object httpStubConfiguration); - - /** - * Performs additional configuration of the HTTP Server Stub. - * @param httpStubConfiguration - stub implementation to configure - * @param httpServerStubConfiguration - Spring Cloud Contract stub configuration - * @return the modified stub configuration - */ - default T configure(T httpStubConfiguration, HttpServerStubConfiguration httpServerStubConfiguration) { - return httpStubConfiguration; - } - - /** - * Implementation that does nothing. - */ - class NoOpHttpServerStubConfigurer implements HttpServerStubConfigurer { - - /** - * Singleton instance. - */ - public static HttpServerStubConfigurer INSTANCE = new NoOpHttpServerStubConfigurer(); - - @Override - public boolean isAccepted(Object httpStubConfiguration) { - return false; - } - - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/MappingGenerator.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/MappingGenerator.java deleted file mode 100644 index 60d708a6ac..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/MappingGenerator.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Collection; -import java.util.LinkedList; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.spec.Contract; -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.wiremock.DslToWireMockClientConverter; -import org.springframework.util.StringUtils; - -final class MappingGenerator { - - private static final Log log = LogFactory.getLog(MappingGenerator.class); - - private MappingGenerator() { - throw new IllegalStateException("Can't instantiate utility class"); - } - - static Collection toMappings(File contractFile, Collection contracts, File mappingsFolder) { - StubGeneratorProvider provider = new StubGeneratorProvider(); - Collection stubGenerators = provider.allOrDefault(new DslToWireMockClientConverter()); - if (log.isDebugEnabled()) { - log.debug("Found following matching stub generators " + stubGenerators); - } - Collection mappings = new LinkedList<>(); - for (StubGenerator stubGenerator : stubGenerators) { - Map map = stubGenerator.convertContents(contractFile.getName(), - new ContractMetadata(contractFile.toPath(), false, contracts.size(), null, contracts)); - for (Map.Entry entry : map.entrySet()) { - String value = entry.getValue(); - File mapping = new File(mappingsFolder, StringUtils.stripFilenameExtension(contractFile.getName()) + "_" - + Math.abs(entry.getKey().hashCode()) + stubGenerator.fileExtension()); - mappings.add(storeFile(mapping.toPath(), value.getBytes())); - } - } - return mappings; - } - - private static Path storeFile(Path path, byte[] contents) { - try { - Path storedPath = Files.write(path, contents); - if (log.isDebugEnabled()) { - log.debug("Stored file [" + path.toString() + "]"); - } - return storedPath; - } - catch (IOException e) { - throw new IllegalStateException(e); - } - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/MavenSettings.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/MavenSettings.java deleted file mode 100644 index 6edadc72d1..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/MavenSettings.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; - -import org.sonatype.plexus.components.cipher.DefaultPlexusCipher; -import org.sonatype.plexus.components.cipher.PlexusCipherException; -import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher; -import shaded.org.apache.maven.settings.crypto.DefaultSettingsDecrypter; -import shaded.org.apache.maven.settings.crypto.SettingsDecrypter; - -import org.springframework.util.StringUtils; - -public class MavenSettings { - - private static final String MAVEN_USER_CONFIG_DIRECTORY = "maven.user.config.dir"; - - private final String homeDir; - - public MavenSettings() { - this(userSettings()); - } - - private static String fromSystemPropOrEnv(String prop) { - String resolvedProp = System.getProperty(prop); - if (StringUtils.hasText(resolvedProp)) { - return resolvedProp; - } - return System.getenv(prop); - } - - private static String userSettings() { - String user = fromSystemPropOrEnv(MAVEN_USER_CONFIG_DIRECTORY); - if (user == null) { - return System.getProperty("user.home"); - } - return user; - } - - public MavenSettings(String homeDir) { - this.homeDir = homeDir; - } - - public SettingsDecrypter createSettingsDecrypter() { - return new DefaultSettingsDecrypter(new SpringCloudContractSecDispatcher()); - } - - private class SpringCloudContractSecDispatcher extends DefaultSecDispatcher { - - private static final String SECURITY_XML = "settings-security.xml"; - - SpringCloudContractSecDispatcher() { - File file = new File(MavenSettings.this.homeDir, SECURITY_XML); - this._configurationFile = file.getAbsolutePath(); - try { - this._cipher = new DefaultPlexusCipher(); - } - catch (PlexusCipherException e) { - throw new IllegalStateException(e); - } - } - - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/MessageNotMatchingException.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/MessageNotMatchingException.java deleted file mode 100644 index ef1edced28..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/MessageNotMatchingException.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -/** - * Exception thrown when message is not matched. - * - * @author Marcin Grzejszczak - */ -@SuppressWarnings("serial") -class MessageNotMatchingException extends RuntimeException { - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/NoOpHttpServerStub.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/NoOpHttpServerStub.java deleted file mode 100644 index e1d0ee5402..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/NoOpHttpServerStub.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.util.Collection; - -/** - * @author Marcin Grzejszczak - */ -class NoOpHttpServerStub implements HttpServerStub { - - @Override - public int port() { - return -1; - } - - @Override - public boolean isRunning() { - return false; - } - - @Override - public HttpServerStub start(HttpServerStubConfiguration configuration) { - return this; - } - - @Override - public HttpServerStub stop() { - return this; - } - - @Override - public HttpServerStub registerMappings(Collection stubFiles) { - return this; - } - - @Override - public String registeredMappings() { - return ""; - } - - @Override - public boolean isAccepted(File file) { - return true; - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ProjectVersion.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ProjectVersion.java deleted file mode 100644 index 180957de04..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ProjectVersion.java +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.Serializable; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.regex.Pattern; - -import org.springframework.util.StringUtils; - -/** - * Object representing a root project's version. Knows how to provide a minor bumped - * version; - * - * @author Marcin Grzejszczak - */ -class ProjectVersion implements Comparable, Serializable { - - private static final Pattern SNAPSHOT_PATTERN = Pattern.compile("^.*[\\.|\\-](BUILD-)?SNAPSHOT.*$"); - - private static final String MILESTONE_REGEX = ".*[\\.|\\-]M[0-9]+"; - - private static final String RC_REGEX = "^.*[\\.|\\-]RC.*$"; - - private static final String RELEASE_REGEX = "^.*[\\.|\\-]RELEASE.*$"; - - private static final String SR_REGEX = "^.*[\\.|\\-]SR[0-9]+.*$"; - - private static final List VALID_PATTERNS = Arrays.asList(SNAPSHOT_PATTERN, - Pattern.compile(MILESTONE_REGEX), Pattern.compile(RC_REGEX), Pattern.compile(RELEASE_REGEX), - Pattern.compile(SR_REGEX)); - - /** - * Version of the project. - */ - final String version; - - private final ReleaseType releaseType; - - ProjectVersion(String version) { - this.version = version; - this.releaseType = toReleaseType(); - } - - private SplitVersion assertVersion() { - if (this.version == null) { - throw new IllegalStateException("Version can't be null!"); - } - SplitVersion splitByHyphen = tryHyphenSeparatedVersion(); - if (splitByHyphen != null) { - return splitByHyphen; - } - return dotSeparatedReleaseTrainsAndVersions(); - } - - private SplitVersion tryHyphenSeparatedVersion() { - // Check for hyphen separated BOMs versioning - // Dysprosium-BUILD-SNAPSHOT or Dysprosium-RELEASE - // 1.0.0-BUILD-SNAPSHOT or 1.0.0-RELEASE - String[] splitByHyphen = this.version.split("\\-"); - int splitByHyphens = splitByHyphen.length; - int numberOfHyphens = splitByHyphens - 1; - int indexOfFirstHyphen = this.version.indexOf("-"); - boolean buildSnapshot = this.version.endsWith("BUILD-SNAPSHOT"); - if (numberOfHyphens == 1 && !buildSnapshot || (numberOfHyphens > 1 && buildSnapshot)) { - // Dysprosium or 1.0.0 - String versionName = this.version.substring(0, indexOfFirstHyphen); - boolean hasDots = versionName.contains("."); - // BUILD-SNAPSHOT - String versionType = this.version.substring(indexOfFirstHyphen + 1); - // Dysprosium-BUILD-SNAPSHOT - if (splitByHyphens > 1 && !hasDots && validVersionType()) { - return SplitVersion.hyphen(versionName, versionType); - } - // Dysprosium-RELEASE - else if (splitByHyphens == 1 && !hasDots && validVersionType()) { - return SplitVersion.hyphen(splitByHyphen[0], splitByHyphen[1]); - } - // 1.0.0-RELEASE or 1.0.0-BUILD-SNAPSHOT - else if (splitByHyphens >= 1 && hasDots) { - String[] newArray = combinedArrays(versionName, versionType); - return SplitVersion.hyphen(newArray); - } - else { - throw new UnsupportedOperationException("Unknown version [" + this.version + "]"); - } - } - return null; - } - - private boolean validVersionType() { - return VALID_PATTERNS.stream().anyMatch(p -> p.matcher(this.version).matches()); - } - - private String[] combinedArrays(String versionName, String versionType) { - String[] split = versionName.split("\\."); - String[] newArray = new String[split.length + 1]; - for (int i = 0; i < split.length; i++) { - newArray[i] = split[i]; - } - newArray[split.length] = versionType; - return newArray; - } - - private SplitVersion dotSeparatedReleaseTrainsAndVersions() { - // Hoxton.BUILD-SNAPSHOT or 1.0.0.BUILD-SNAPSHOT - String[] splitVersion = this.version.split("\\."); - return SplitVersion.dot(splitVersion); - } - - boolean isSnapshot() { - return this.version != null && this.version.contains("SNAPSHOT"); - } - - boolean isRc() { - return this.version != null && this.version.matches(RC_REGEX); - } - - boolean isMilestone() { - return this.version != null && this.version.matches(MILESTONE_REGEX); - } - - boolean isRelease() { - return this.version != null && this.version.contains("RELEASE"); - } - - boolean isReleaseOrServiceRelease() { - return isRelease() || isServiceRelease(); - } - - boolean isServiceRelease() { - return this.version != null && this.version.matches(".*.SR[0-9]+"); - } - - private ReleaseType toReleaseType() { - if (isMilestone()) { - return ReleaseType.M; - } - else if (isRc()) { - return ReleaseType.RC; - } - else if (isRelease()) { - return ReleaseType.RELEASE; - } - else if (isServiceRelease()) { - return ReleaseType.SR; - } - return ReleaseType.SNAPSHOT; - } - - int isMoreMature(ProjectVersion that) { - SplitVersion thisSplit = assertVersion(); - SplitVersion thatSplit = that.assertVersion(); - int releaseTypeComparison = this.releaseType.compareTo(that.releaseType); - boolean thisReleaseTypeHigher = releaseTypeComparison > 0; - boolean bothGa = this.isReleaseOrServiceRelease() && that.isReleaseOrServiceRelease(); - // 1.0.1.M2 vs 1.0.0.RELEASE (x) - if (thisReleaseTypeHigher && !bothGa) { - return 1; - } - int majorComparison = compare(thisSplit.major, thatSplit.major); - if (majorComparison != 0) { - return majorComparison; - } - int minorComparison = compare(thisSplit.minor, thatSplit.minor); - if (minorComparison != 0) { - return minorComparison; - } - int patchComparison = compare(thisSplit.patch, thatSplit.patch); - if (patchComparison != 0) { - return patchComparison; - } - return releaseTypeComparison; - } - - private int compare(String thisString, String thatString) { - try { - return Integer.valueOf(thisString).compareTo(Integer.valueOf(thatString)); - } - catch (NumberFormatException ex) { - return thisString.compareTo(thatString); - } - } - - boolean isSameWithoutSuffix(ProjectVersion that) { - SplitVersion thisSplit = assertVersion(); - SplitVersion thatSplit = that.assertVersion(); - return thisSplit.major.equals(thatSplit.major) && thisSplit.minor.equals(thatSplit.minor) - && thisSplit.patch.equals(thatSplit.patch); - } - - @Override - public String toString() { - return this.version; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ProjectVersion that = (ProjectVersion) o; - return Objects.equals(this.version, that.version); - } - - @Override - public int hashCode() { - return Objects.hash(this.version); - } - - @Override - public int compareTo(ProjectVersion o) { - return this.version.compareTo(o.version); - } - - private static final class SplitVersion { - - private static final String DOT = "."; - - private static final String HYPHEN = "-"; - - final String major; - - final String minor; - - final String patch; - - final String delimiter; - - final String suffix; - - // 1.0.0.RELEASE - // 1.0.0-RELEASE - private SplitVersion(String major, String minor, String patch, String delimiter, String suffix) { - this.major = major; - this.minor = minor; - this.patch = patch; - this.delimiter = delimiter; - this.suffix = suffix; - assertIfValid(); - } - - // Hoxton.RELEASE - // Hoxton-RELEASE - private SplitVersion(String major, String delimiter, String suffix) { - this(major, "", "", delimiter, suffix); - } - - private SplitVersion(String[] args, String delimiter) { - this.major = orDefault(args, 0); - this.minor = orDefault(args, 1); - this.patch = orDefault(args, 2); - this.delimiter = delimiter; - this.suffix = orDefault(args, 3); - assertIfValid(); - } - - private static String orDefault(String[] args, int argIndex) { - return args.length > argIndex ? args[argIndex] : ""; - } - - static SplitVersion hyphen(String major, String suffix) { - return new SplitVersion(major, HYPHEN, suffix); - } - - static SplitVersion hyphen(String[] args) { - return version(args, HYPHEN); - } - - static SplitVersion dot(String[] args) { - return version(args, DOT); - } - - private static SplitVersion version(String[] args, String delimiter) { - if (args.length == 2) { - return new SplitVersion(args[0], "", "", delimiter, args[1]); - } - else if (args.length == 3) { - return new SplitVersion(args[0], args[1], "", delimiter, args[2]); - } - return new SplitVersion(args, delimiter); - } - - private void assertIfValid() { - if (isInvalid()) { - throw new IllegalStateException( - "Version is invalid. Should be of format [1.2.3.A] / [1.2.3-A] or [A.B] / [A-B]"); - } - } - - private boolean isInvalid() { - return wrongReleaseTrainVersion() || wrongLibraryVersion() || wrongDelimiter() || noSuffix(); - } - - private boolean noSuffix() { - return !StringUtils.hasText(suffix); - } - - private String gav() { - // Finchley - if (!StringUtils.hasText(minor)) { - return String.format("%s", major); - } - // 1.0.1 - return String.format("%s.%s.%s", major, minor, patch); - } - - private boolean isNumeric(String string) { - return string.matches("[0-9]+"); - } - - private boolean wrongDelimiter() { - return !(DOT.equals(this.delimiter) || HYPHEN.equals(this.delimiter)); - } - - private boolean wrongLibraryVersion() { - // GOOD: - // 1.2.3.RELEASE, 1.2.3-RELEASE, Hoxton.BUILD-SNAPSHOT, Hoxton-RELEASE - // must have - // either major and suffix (release train) - // major, minor, patch and suffix - return isNumeric(major) && (!StringUtils.hasText(minor) || !StringUtils.hasText(patch) - || !StringUtils.hasText(suffix) || !StringUtils.hasText(delimiter)); - } - - private boolean wrongReleaseTrainVersion() { - // BAD: 1.EXAMPLE, GOOD: Hoxton.RELEASE - return isNumeric(major) && !StringUtils.hasText(suffix); - } - - } - -} - -enum ReleaseType { - - SNAPSHOT, M, RC, RELEASE, SR - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ResourceResolver.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ResourceResolver.java deleted file mode 100644 index 3d193a6708..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ResourceResolver.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.core.io.DefaultResourceLoader; -import org.springframework.core.io.ProtocolResolver; -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.SpringFactoriesLoader; - -/** - * Uses {@code META-INF/spring.factories} to read {@link ProtocolResolver} list that gets - * added to {@link DefaultResourceLoader}. Each implementor of a new - * {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder}, if one - * uses a new protocol, should register their own {@link ProtocolResolver} so that Stub - * Runner can convert a {@link String} version of a URI to a {@link Resource}. - * - * IMPORTANT! Internal tool. Do not use. - * - * @author Marcin Grzejszczak - * @since 2.0.0 - */ -public final class ResourceResolver { - - private static final Log log = LogFactory.getLog(ResourceResolver.class); - - private static final List RESOLVERS = new ArrayList<>(); - - private static final DefaultResourceLoader LOADER = new DefaultResourceLoader(); - - static { - RESOLVERS.addAll(SpringFactoriesLoader.loadFactories(StubDownloaderBuilder.class, null)); - RESOLVERS.addAll(new StubDownloaderBuilderProvider().defaultStubDownloaderBuilders()); - for (ProtocolResolver resolver : RESOLVERS) { - LOADER.addProtocolResolver(resolver); - } - } - - private ResourceResolver() { - throw new IllegalStateException("Can't instantiate a utility class"); - } - - /** - * @param url - string url - * @return corresponding {@link Resource} - */ - public static Resource resource(String url) { - try { - return LOADER.getResource(url); - } - catch (Exception e) { - log.error("Exception occurred while trying to read the resource [" + url + "]", e); - return null; - } - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ResourceResolvingStubDownloader.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ResourceResolvingStubDownloader.java deleted file mode 100644 index bde851deee..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ResourceResolvingStubDownloader.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.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.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.function.BiFunction; -import java.util.regex.MatchResult; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import shaded.com.google.common.base.Function; - -import org.springframework.core.io.DefaultResourceLoader; -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.PathMatchingResourcePatternResolver; - -class ResourceResolvingStubDownloader implements StubDownloader { - - private static final Log log = LogFactory.getLog(ResourceResolvingStubDownloader.class); - - private final StubRunnerOptions stubRunnerOptions; - - private final BiFunction repoRootFunction; - - private final Function gavPattern; - - private final PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver( - new DefaultResourceLoader()); - - ResourceResolvingStubDownloader(StubRunnerOptions stubRunnerOptions, - BiFunction repoRootFunction, - Function gavPattern) { - this.stubRunnerOptions = stubRunnerOptions; - this.repoRootFunction = repoRootFunction; - this.gavPattern = gavPattern; - } - - @Override - public Map.Entry downloadAndUnpackStubJar(StubConfiguration config) { - registerShutdownHook(); - List repoRoots = repoRootFunction.apply(stubRunnerOptions, config); - List paths = toPaths(repoRoots); - List resources = resolveResources(paths); - if (log.isDebugEnabled()) { - log.debug("For paths " + paths + " found following resources " + resources); - } - if (resources.isEmpty() && this.stubRunnerOptions.isFailOnNoStubs()) { - throw new IllegalStateException("No stubs were found on classpath for [" + config.getGroupId() + ":" - + config.getArtifactId() + "]"); - } - final File tmp = TemporaryFileStorage.createTempDir("classpath-stubs"); - if (stubRunnerOptions.isDeleteStubsAfterTest()) { - tmp.deleteOnExit(); - } - boolean atLeastOneFound = false; - for (Resource resource : resources) { - try { - String relativePath = relativePathPicker(resource, this.gavPattern.apply(config)); - if (log.isDebugEnabled()) { - log.debug("Relative path for resource is [" + relativePath + "]"); - } - if (relativePath == null) { - log.warn("Unable to match the URI [" + resource.getURI() + "]"); - continue; - } - atLeastOneFound = true; - copyTheFoundFiles(tmp, resource, relativePath); - } - catch (IOException e) { - log.error("Exception occurred while trying to create dirs", e); - throw new IllegalStateException(e); - } - } - if (!atLeastOneFound) { - log.warn("Didn't find any matching stubs"); - return null; - } - log.info("Unpacked files for [" + config.getGroupId() + ":" + config.getArtifactId() + ":" + config.getVersion() - + "] to folder [" + tmp + "]"); - return new AbstractMap.SimpleEntry<>(new StubConfiguration(config.getGroupId(), config.getArtifactId(), - config.getVersion(), config.getClassifier()), tmp); - } - - private void registerShutdownHook() { - Runtime.getRuntime().addShutdownHook( - new Thread(() -> TemporaryFileStorage.cleanup(stubRunnerOptions.isDeleteStubsAfterTest()))); - } - - private void copyTheFoundFiles(File tmp, Resource resource, String relativePath) throws IOException { - // the relative path is OS agnostic and contains / only - int lastIndexOf = relativePath.lastIndexOf("/"); - String relativePathWithoutFile = lastIndexOf > -1 ? relativePath.substring(0, lastIndexOf) : relativePath; - if (log.isDebugEnabled()) { - log.debug("Relative path without file name is [" + relativePathWithoutFile + "]"); - } - Path directory = Files.createDirectories(new File(tmp, relativePathWithoutFile).toPath()); - File newFile = new File(directory.toFile(), resource.getFilename()); - if (!newFile.exists() && !isDirectory(resource)) { - try (InputStream stream = resource.getInputStream()) { - Files.copy(stream, newFile.toPath()); - TemporaryFileStorage.add(newFile); - } - } - if (log.isDebugEnabled()) { - log.debug("Stored file [" + newFile + "]"); - } - } - - boolean isDirectory(Resource resource) { - try { - return resource.getFile().isDirectory(); - } - catch (Exception e) { - if (log.isTraceEnabled()) { - log.trace("Exception occurred while trying to convert path to file for resource [" + resource + "]", e); - } - return false; - } - } - - String relativePathPicker(Resource resource, Pattern groupAndArtifactPattern) throws IOException { - Matcher groupAndArtifactMatcher = matcher(resource, groupAndArtifactPattern); - if (groupAndArtifactMatcher.matches() && groupAndArtifactMatcher.groupCount() > 2) { - MatchResult groupAndArtifactResult = groupAndArtifactMatcher.toMatchResult(); - return groupAndArtifactResult.group(2) + groupAndArtifactResult.group(3); - } - else if (groupAndArtifactMatcher.matches()) { - return groupAndArtifactMatcher.group(1); - } - else { - return null; - } - } - - private Matcher matcher(Resource resource, Pattern groupAndArtifactPattern) throws IOException { - try { - String path = resource.getURI().getPath(); - return groupAndArtifactPattern.matcher(path); - } - catch (Exception ex) { - String path = resource.getURI().toString(); - return groupAndArtifactPattern.matcher(path); - } - } - - private List toPaths(List repoRoots) { - List list = new ArrayList<>(); - for (RepoRoot repoRoot : repoRoots) { - list.add(repoRoot.fullPath); - } - return list; - } - - List resolveResources(List paths) { - List resources = new ArrayList<>(); - for (String path : paths) { - try { - List list = Arrays.asList(this.resolver.getResources(path)); - resources.addAll(list); - } - catch (IOException e) { - log.error("Exception occurred while trying to fetch resources from [" + path + "]"); - throw new IllegalStateException(e); - } - } - return resources; - } - -} - -class RepoRoot { - - final String repoRoot; - - final String fullPath; - - RepoRoot(String repoRoot) { - this.repoRoot = repoRoot; - this.fullPath = repoRoot; - } - - RepoRoot(String repoRoot, String suffix) { - this.repoRoot = repoRoot; - this.fullPath = repoRoot + suffix; - } - -} - -class RepoRoots extends LinkedList { - - RepoRoots() { - } - - RepoRoots(Collection c) { - super(c); - } - - static RepoRoots asList(RepoRoot... repoRoots) { - return new RepoRoots(Arrays.asList(repoRoots)); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/RunningStubs.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/RunningStubs.java deleted file mode 100644 index 045f37b707..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/RunningStubs.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -/** - * Structure representing executed stubs. Contains the configuration of each stub together - * with the port on which its executed. - * - * @author Marcin Grzejszczak - */ -public class RunningStubs { - - final private Map namesAndPorts = new LinkedHashMap<>(); - - public RunningStubs(Map map) { - this.namesAndPorts.putAll(map); - } - - public RunningStubs(Collection runningStubs) { - for (RunningStubs it : runningStubs) { - this.namesAndPorts.putAll(it.namesAndPorts); - } - } - - public Integer getPort(String artifactId) { - return getEntry(artifactId) == null ? null : getEntry(artifactId).getValue(); - } - - public Map.Entry getEntry(String artifactId) { - for (Entry it : this.namesAndPorts.entrySet()) { - if (it.getKey().matchesIvyNotation(artifactId)) { - return it; - } - } - return null; - } - - public Integer getPort(String groupId, String artifactId) { - for (Entry it : this.namesAndPorts.entrySet()) { - if (it.getKey().matchesIvyNotation(groupId + ":" + artifactId)) { - return it.getValue(); - } - } - return null; - } - - public boolean isPresent(String artifactId) { - return getEntry(artifactId) != null; - } - - public boolean isPresent(String groupId, String artifactId) { - return getPort(groupId, artifactId) != null; - } - - public Set getAllServices() { - return this.namesAndPorts.keySet(); - } - - public Set getAllServicesNames() { - Set result = new LinkedHashSet<>(); - for (Entry it : this.namesAndPorts.entrySet()) { - result.add(it.getKey().artifactId); - } - return result; - } - - public Map toIvyToPortMapping() { - Map result = new LinkedHashMap<>(); - for (Entry it : this.namesAndPorts.entrySet()) { - result.put(it.getKey().toColonSeparatedDependencyNotation(), it.getValue()); - } - return result; - } - - public Map validNamesAndPorts() { - Map result = new LinkedHashMap<>(); - for (Entry it : this.namesAndPorts.entrySet()) { - if (it.getValue() != null && it.getValue() >= 0) { - result.put(it.getKey(), it.getValue()); - } - } - return result; - } - - @Override - public String toString() { - return "RunningStubs [namesAndPorts=" + this.namesAndPorts + "]"; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((this.namesAndPorts == null) ? 0 : this.namesAndPorts.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - RunningStubs other = (RunningStubs) obj; - if (this.namesAndPorts == null) { - if (other.namesAndPorts != null) { - return false; - } - } - else if (!this.namesAndPorts.equals(other.namesAndPorts)) { - return false; - } - return true; - } - -} 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 deleted file mode 100644 index 7d9e37079f..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ScmStubDownloaderBuilder.java +++ /dev/null @@ -1,411 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.nio.file.FileSystems; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.PathMatcher; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.AbstractMap; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import shaded.org.apache.maven.artifact.versioning.DefaultArtifactVersion; - -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.core.io.AbstractResource; -import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; -import org.springframework.util.StringUtils; - -/** - * Builds a {@link StubDownloader} to work with contracts and stubs from a SCM. - * - * @author Marcin Grzejszczak - * @since 2.0.0 - */ -public final class ScmStubDownloaderBuilder implements StubDownloaderBuilder { - - private static final List ACCEPTABLE_PROTOCOLS = Collections.singletonList("git"); - - /** - * Does any of the accepted protocols matches the URL of the repository. - * @param url - of the repository - * @return {@code true} if the protocol is accepted - */ - public 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 GitResource)) { - return null; - } - return new GitStubDownloader(stubRunnerOptions); - } - - @Override - public Resource resolve(String location, ResourceLoader resourceLoader) { - if (!StringUtils.hasText(location) || !isProtocolAccepted(location)) { - return null; - } - return new GitResource(location); - } - -} - -/** - * Primitive version of a Git {@link Resource}. - */ -class GitResource extends AbstractResource { - - private final String rawLocation; - - GitResource(String location) { - this.rawLocation = location; - } - - @Override - public String getDescription() { - return this.rawLocation; - } - - @Override - public InputStream getInputStream() throws IOException { - return null; - } - - @Override - public URI getURI() throws IOException { - return URI.create(this.rawLocation); - } - -} - -class GitContractsRepo { - - static final Map CACHED_LOCATIONS = new ConcurrentHashMap<>(); - - private static final Log log = LogFactory.getLog(GitContractsRepo.class); - - private static final String TEMP_DIR_PREFIX = "git-contracts"; - - private final StubRunnerOptions options; - - GitContractsRepo(StubRunnerOptions options) { - this.options = options; - } - - File clonedRepo(Resource repo) { - File file = CACHED_LOCATIONS.get(repo); - GitStubDownloaderProperties properties = new GitStubDownloaderProperties(repo, this.options); - if (file == null) { - File tmpDirWhereStubsWillBeUnzipped = TemporaryFileStorage.createTempDir(TEMP_DIR_PREFIX); - GitRepo gitRepo = new GitRepo(tmpDirWhereStubsWillBeUnzipped, properties); - file = gitRepo.cloneProject(properties.url); - gitRepo.checkout(file, properties.branch); - CACHED_LOCATIONS.put(repo, file); - if (log.isDebugEnabled()) { - log.debug("The project hasn't already been cloned. Cloned it to [" + file + "]"); - } - } - else { - if (log.isDebugEnabled()) { - log.debug("The project has already been cloned to [" + file - + "]. Will reset any changes and pull the latest ones."); - } - GitRepo gitRepo = new GitRepo(file, properties); - gitRepo.reset(file); - gitRepo.pull(file); - } - return file; - } - -} - -class GitStubDownloader implements StubDownloader { - - private static final Log log = LogFactory.getLog(GitStubDownloader.class); - - // Preloading class for the shutdown hook not to throw ClassNotFound - private static final Class CLAZZ = TemporaryFileStorage.class; - - private final StubRunnerOptions stubRunnerOptions; - - private final boolean deleteStubsAfterTest; - - private final GitContractsRepo gitContractsRepo; - - GitStubDownloader(StubRunnerOptions stubRunnerOptions) { - this.stubRunnerOptions = stubRunnerOptions; - this.deleteStubsAfterTest = this.stubRunnerOptions.isDeleteStubsAfterTest(); - this.gitContractsRepo = new GitContractsRepo(stubRunnerOptions); - registerShutdownHook(); - } - - @Override - public Map.Entry downloadAndUnpackStubJar(StubConfiguration stubConfiguration) { - try { - if (log.isDebugEnabled()) { - log.debug("Trying to find a contract for [" + stubConfiguration.toColonSeparatedDependencyNotation() - + "]"); - } - Resource repo = this.stubRunnerOptions.getStubRepositoryRoot(); - File clonedRepo = this.gitContractsRepo.clonedRepo(repo); - FileWalker walker = new FileWalker(stubConfiguration); - Files.walkFileTree(clonedRepo.toPath(), walker); - if (walker.foundFile != null) { - return new AbstractMap.SimpleEntry<>(stubConfiguration, walker.foundFile.toFile()); - } - } - catch (IOException e) { - throw new IllegalStateException(e); - } - if (log.isWarnEnabled()) { - log.warn("No matching contracts were found in the repo for [" - + stubConfiguration.toColonSeparatedDependencyNotation() + "]"); - } - return null; - } - - private void registerShutdownHook() { - Runtime.getRuntime().addShutdownHook( - new Thread(() -> TemporaryFileStorage.cleanup(GitStubDownloader.this.deleteStubsAfterTest))); - } - -} - -class GitStubDownloaderProperties { - - private static final Log log = LogFactory.getLog(GitStubDownloaderProperties.class); - - private static final String GIT_BRANCH_PROPERTY = "git.branch"; - - private static final String GIT_USERNAME_PROPERTY = "git.username"; - - private static final String GIT_PASSWORD_PROPERTY = "git.password"; - - private static final String GIT_ENSURE_GIT_SUFFIX_PROPERTY = "git.ensure-git-suffix"; - - final URI url; - - final String username; - - final String password; - - final String branch; - - final Boolean ensureGitSuffix; - - GitStubDownloaderProperties(Resource repo, StubRunnerOptions options) { - String repoUrl; - Map args = options.getProperties(); - try { - repoUrl = schemeSpecificPart(repo.getURI()); - } - catch (IOException e) { - throw new IllegalStateException(e); - } - // if we had git://https://... we want the part starting from https - // if we had git://git@... we want the full address again - // if the URL starts with git@... and ends with .git, we want to remove it - String modifiedRepo = repoUrl.startsWith("git@") ? modifyUrlForGitRepo(repoUrl) : repoUrl; - this.url = URI.create(modifiedRepo); - String username = StubRunnerPropertyUtils.getProperty(args, GIT_USERNAME_PROPERTY); - this.username = StringUtils.hasText(username) ? username : options.getUsername(); - String password = StubRunnerPropertyUtils.getProperty(args, GIT_PASSWORD_PROPERTY); - this.password = StringUtils.hasText(password) ? password : options.getPassword(); - String branch = StubRunnerPropertyUtils.getProperty(args, GIT_BRANCH_PROPERTY); - this.branch = StringUtils.hasText(branch) ? branch : "master"; - String ensureGitSuffix = StubRunnerPropertyUtils.getProperty(args, GIT_ENSURE_GIT_SUFFIX_PROPERTY); - this.ensureGitSuffix = StringUtils.hasText(ensureGitSuffix) ? Boolean.parseBoolean(ensureGitSuffix) : true; - - if (log.isDebugEnabled()) { - log.debug("Repo url is [" + repoUrl + "], modified url string " + "is [" + modifiedRepo + "] URL is [" - + this.url + "] branch is [" + this.branch + "] and ensureGitSuffix is [" + this.ensureGitSuffix - + "]"); - } - } - - private String schemeSpecificPart(URI uri) { - String part = uri.getSchemeSpecificPart(); - if (!StringUtils.hasText(part)) { - return part; - } - return part.startsWith("//") ? part.substring(2) : part; - } - - private String modifyUrlForGitRepo(String gitRepo) { - return "git:" + gitRepo; - } - -} - -class FileWalker extends SimpleFileVisitor { - - private static final Log log = LogFactory.getLog(FileWalker.class); - - private static final List LATEST = Arrays.asList("latest", "+"); - - private static final String RELEASE = "release"; - - private final PathMatcher matcherWithDot; - - private final PathMatcher matcherWithoutDot; - - private final boolean latestSnapshotVersion; - - private final boolean latestReleaseVersion; - - Path foundFile; - - FileWalker(StubConfiguration stubConfiguration) { - this.latestSnapshotVersion = LATEST.stream().anyMatch(s -> s.equals(stubConfiguration.version.toLowerCase())); - this.latestReleaseVersion = RELEASE.equals(stubConfiguration.version.toLowerCase()); - this.matcherWithDot = FileSystems.getDefault().getPathMatcher("glob:" + matcherGlob(stubConfiguration, ".")); - this.matcherWithoutDot = FileSystems.getDefault().getPathMatcher("glob:" + matcherGlob(stubConfiguration, "/")); - } - - private String matcherGlob(StubConfiguration stubConfiguration, String groupArtifactSeparator) { - return "**" + stubConfiguration.groupId + groupArtifactSeparator + stubConfiguration.artifactId + "/" - + (this.latestSnapshotVersion || this.latestReleaseVersion ? "**" : stubConfiguration.version); - } - - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { - if (this.matcherWithDot.matches(dir.toAbsolutePath()) || this.matcherWithoutDot.matches(dir.toAbsolutePath())) { - if (this.latestSnapshotVersion || this.latestReleaseVersion) { - // folders with name latest, release - File[] files = Objects.requireNonNull(dir.getParent().toFile().listFiles(File::isDirectory)); - File file = folderWithPredefinedName(files); - if (file != null) { - if (log.isDebugEnabled()) { - log.debug("Found folder with name corresponding to a latest version [" + file + "] "); - this.foundFile = file.toPath(); - return FileVisitResult.TERMINATE; - } - } - return latestVersionFromFolders(dir, files); - } - else { - this.foundFile = dir; - } - return FileVisitResult.TERMINATE; - } - return FileVisitResult.CONTINUE; - } - - private FileVisitResult latestVersionFromFolders(Path dir, File[] files) { - List versions = pickLatestVersion(files); - if (versions.isEmpty()) { - if (log.isDebugEnabled()) { - log.debug("Not a single version matching semver for path [" + dir.toAbsolutePath().toString() - + "] was found"); - } - return FileVisitResult.CONTINUE; - } - // 2.0.0.RELEASE, 2.0.0.BUILD-SNAPSHOT - // 2.0.0.RELEASE - DefaultArtifactVersionWrapper latestFoundVersion = versions.get(versions.size() - 1); - latestFoundVersion = replaceWithSnapshotIfSameVersions(versions, latestFoundVersion); - this.foundFile = latestFoundVersion.file.toPath(); - return FileVisitResult.TERMINATE; - } - - private DefaultArtifactVersionWrapper replaceWithSnapshotIfSameVersions( - List versions, final DefaultArtifactVersionWrapper latestFoundVersion) { - if (versions.size() > 1 && this.latestSnapshotVersion) { - // 2.0.1.BUILD-SNAPSHOT, 2.0.0.BUILD-SNAPSHOT - // 2.0.0.BUILD-SNAPSHOT, 2.0.0.RELEASE - DefaultArtifactVersionWrapper sameVersionButSnapshot = versions.stream().filter( - w -> w.projectVersion.isSameWithoutSuffix(latestFoundVersion.projectVersion) && w.isSnapshot()) - .findFirst().orElse(latestFoundVersion); - // 2.0.0 vs 2.0.0 - // replace the RELEASE one with SNAPSHOT - if (sameVersionButSnapshot != latestFoundVersion) { - return sameVersionButSnapshot; - } - } - return latestFoundVersion; - } - - private File folderWithPredefinedName(File[] files) { - if (this.latestSnapshotVersion) { - return Arrays.stream(files) - .filter(file -> LATEST.stream().anyMatch(s -> s.equals(file.getName().toLowerCase()))).findFirst() - .orElse(null); - } - return Arrays.stream(files).filter(file -> RELEASE.equals(file.getName().toLowerCase())).findFirst() - .orElse(null); - } - - private List pickLatestVersion(File[] files) { - return Arrays.stream(files).map(DefaultArtifactVersionWrapper::new) - .filter(wrapper -> this.latestSnapshotVersion || wrapper.isNotSnapshot()).sorted() - .collect(Collectors.toList()); - } - -} - -class DefaultArtifactVersionWrapper implements Comparable { - - final DefaultArtifactVersion version; - - final File file; - - final ProjectVersion projectVersion; - - DefaultArtifactVersionWrapper(File file) { - this.version = new DefaultArtifactVersion(file.getName()); - this.file = file; - this.projectVersion = new ProjectVersion(this.version.toString()); - } - - boolean isSnapshot() { - return this.projectVersion.isSnapshot(); - } - - boolean isNotSnapshot() { - return !isSnapshot(); - } - - @Override - public int compareTo(DefaultArtifactVersionWrapper o) { - return this.projectVersion.isMoreMature(o.projectVersion); - } - -} 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 deleted file mode 100644 index a5d1dcd96b..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubConfiguration.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import org.springframework.util.StringUtils; - -/** - * Represents a configuration of a single stub. The stub can be described by - * groupId:artifactId:version:classifier notation - * - * @author Marcin Grzejszczak - */ -public class StubConfiguration { - - /** - * Default classifier for the stubs. - */ - public static final String DEFAULT_CLASSIFIER = "stubs"; - - static final String DEFAULT_VERSION = "+"; - - private static final String STUB_COLON_DELIMITER = ":"; - - final String groupId; - - final String artifactId; - - final String version; - - final String classifier; - - public StubConfiguration(String groupId, String artifactId, String version) { - this.groupId = groupId; - this.artifactId = artifactId; - this.version = version; - this.classifier = DEFAULT_CLASSIFIER; - } - - public StubConfiguration(String groupId, String artifactId, String version, String classifier) { - this.groupId = groupId; - this.artifactId = artifactId; - this.version = version; - this.classifier = classifier; - } - - public StubConfiguration(String stubPath, String defaultClassifier) { - String[] parsedPath = parsedPathEmptyByDefault(stubPath, STUB_COLON_DELIMITER, defaultClassifier); - this.groupId = parsedPath[0]; - this.artifactId = parsedPath[1]; - this.version = parsedPath[2]; - this.classifier = parsedPath[3]; - } - - public StubConfiguration(String stubPath) { - String[] parsedPath = parsedPathEmptyByDefault(stubPath, STUB_COLON_DELIMITER, DEFAULT_CLASSIFIER); - this.groupId = parsedPath[0]; - this.artifactId = parsedPath[1]; - this.version = parsedPath[2]; - this.classifier = parsedPath[3]; - } - - private String[] parsedPathEmptyByDefault(String path, String delimiter, String defaultClassifier) { - String[] splitPath = path.split(delimiter, -1); - String stubsGroupId = ""; - String stubsArtifactId = ""; - String stubsVersion = ""; - String stubsClassifier = ""; - if (splitPath.length >= 2) { - stubsGroupId = splitPath[0]; - stubsArtifactId = splitPath[1]; - stubsVersion = splitPath.length >= 3 ? splitPath[2] : DEFAULT_VERSION; - stubsClassifier = splitPath.length >= 4 ? splitPath[3] : defaultClassifier; - } - return new String[] { stubsGroupId, stubsArtifactId, stubsVersion, stubsClassifier }; - } - - private boolean isDefined() { - return StringUtils.hasText(this.groupId) && StringUtils.hasText(this.artifactId); - } - - /** - * @return a colon separated representation of the stub configuration (e.g. - * groupid:artifactid:version:classifier) - */ - public String toColonSeparatedDependencyNotation() { - if (!isDefined()) { - return ""; - } - return StringUtils.arrayToDelimitedString(new String[] { nullCheck(this.groupId), nullCheck(this.artifactId), - nullCheck(this.version), nullCheck(this.classifier) }, STUB_COLON_DELIMITER); - } - - private String nullCheck(String value) { - return StringUtils.hasText(value) ? value : ""; - } - - /** - * Checks if ivy notation matches group and artifact ids. - * @param ivyNotationAsString - e.g. group:artifact:version:classifier - * @return {@code true} if artifact id matches and there's no group id. Or if both - * group id and artifact id are present and matching - */ - public boolean groupIdAndArtifactMatches(String ivyNotationAsString) { - String[] parts = ivyNotationFrom(ivyNotationAsString); - String groupId = parts[0]; - String artifactId = parts[1]; - if (groupId == null) { - return this.artifactId.equals(artifactId); - } - return this.groupId.equals(groupId) && this.artifactId.equals(artifactId); - } - - /** - * @return {@code true} for a snapshot or a LATEST (+) version. - */ - public boolean isVersionChanging() { - return DEFAULT_VERSION.equals(this.version) || this.version.toLowerCase().contains("snapshot"); - } - - public String getGroupId() { - return this.groupId; - } - - public String getArtifactId() { - return this.artifactId; - } - - public String getClassifier() { - return this.classifier; - } - - public String getVersion() { - return this.version; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((this.artifactId == null) ? 0 : this.artifactId.hashCode()); - result = prime * result + ((this.groupId == null) ? 0 : this.groupId.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - StubConfiguration other = (StubConfiguration) obj; - if (this.artifactId == null) { - if (other.artifactId != null) { - return false; - } - } - else if (!this.artifactId.equals(other.artifactId)) { - return false; - } - if (this.groupId == null) { - if (other.groupId != null) { - return false; - } - } - else if (!this.groupId.equals(other.groupId)) { - return false; - } - return true; - } - - public boolean matchesIvyNotation(String ivyNotationAsString) { - String[] strings = ivyNotationAsString.split(":", -1); - if (strings.length == 1) { - return this.artifactId.equals(ivyNotationAsString); - } - if (strings.length >= 2 && !(this.groupId.equals(strings[0]) && this.artifactId.equals(strings[1]))) { - return false; - } - if (strings.length >= 3 && !(this.version.equals(strings[2]) || DEFAULT_VERSION.equals(strings[2]))) { - return false; - } - if (strings.length == 4 && !(this.classifier.equals(strings[3]) || DEFAULT_CLASSIFIER.equals(strings[3]))) { - return false; - } - return true; - } - - private String[] ivyNotationFrom(String ivyNotation) { - String[] splitString = ivyNotation.split(":"); - if (splitString.length == 1) { - // assuming that ivy notation represents artifactId only - return new String[] { null, splitString[0] }; - } - return new String[] { splitString[0], splitString[1] }; - } - - @Override - public String toString() { - return toColonSeparatedDependencyNotation(); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubDownloader.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubDownloader.java deleted file mode 100644 index c626e93724..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubDownloader.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.util.Map; - -/** - * Contract for providing a tuple containing configuration of a downloaded and unpacked - * stub, together with the file location of that extracted artifact. - * - * Note: Actually the artifact doesn't have to be a JAR. method name contains that suffix - * for historical reasons. - * - * @author Marcin Grzejszczak - * @since 1.0.0 - */ -public interface StubDownloader { - - /** - * Note: Actually the artifact doesn't have to be a JAR. method name contains that - * suffix or historical reasons. - * @param stubConfiguration configuration for which contracts and stubs should be - * resolved - * @return a mapping of updated StubConfiguration (it will contain the resolved - * version) and the location of the downloaded stubs. If there was no artifact this - * method will return {@code null}. - */ - Map.Entry downloadAndUnpackStubJar(StubConfiguration stubConfiguration); - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubDownloaderBuilder.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubDownloaderBuilder.java deleted file mode 100644 index 5f5a813a78..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubDownloaderBuilder.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import org.springframework.core.io.ProtocolResolver; -import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; - -/** - * Builder for a {@link StubDownloader}. Can't allow direct usage of - * {@link StubDownloader} cause in order to register instances of this interface in - * {@link org.springframework.core.io.support.SpringFactoriesLoader} one needs a default - * constructor whereas the {@link StubDownloader} instances need to be constructed from - * stub related options. - * - * Since {@code 2.0.0} extends {@link ProtocolResolver}. Implementations have to tell - * Spring how to parse the repository root String into a resource. - * - * @author Marcin Grzejszczak - * @since 1.1.0 - */ -public interface StubDownloaderBuilder extends ProtocolResolver { - - /** - * @param stubRunnerOptions options of Stub Runner - * @return {@link StubDownloader} instance of {@code null} if current parameters don't - * allow building the instance - */ - StubDownloader build(StubRunnerOptions stubRunnerOptions); - - @Override - default Resource resolve(String location, ResourceLoader resourceLoader) { - return null; - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubDownloaderBuilderProvider.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubDownloaderBuilderProvider.java deleted file mode 100644 index 774e5f37e3..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubDownloaderBuilderProvider.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.springframework.core.io.support.SpringFactoriesLoader; - -/** - * Provider for {@link StubDownloaderBuilder}. It can also pick a default downloader if - * none is provided - * - * @author Marcin Grzejszczak - * @since 1.1.0 - */ -public class StubDownloaderBuilderProvider { - - private final List builders = new ArrayList<>(); - - public StubDownloaderBuilderProvider() { - this.builders.addAll(SpringFactoriesLoader.loadFactories(StubDownloaderBuilder.class, null)); - } - - StubDownloaderBuilderProvider(List builders) { - this.builders.addAll(builders); - } - - /** - * @param stubRunnerOptions options of Stub Runner - * @param additionalBuilders - optional array of {@link StubDownloaderBuilder}s to - * append to the list of builders - * @return composite {@link StubDownloader} that iterates over a list of stub - * downloaders - */ - public StubDownloader get(StubRunnerOptions stubRunnerOptions, StubDownloaderBuilder... additionalBuilders) { - List builders = this.builders; - if (additionalBuilders != null) { - builders.addAll(Arrays.asList(additionalBuilders)); - } - List defaultBuilders = defaultStubDownloaderBuilders(); - builders.addAll(defaultBuilders); - return new CompositeStubDownloader(builders, stubRunnerOptions); - } - - List defaultStubDownloaderBuilders() { - return Arrays.asList(new ScmStubDownloaderBuilder(), new ClasspathStubProvider(), new FileStubDownloader(), - new AetherStubDownloaderBuilder()); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubFinder.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubFinder.java deleted file mode 100644 index ffa06d665a..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubFinder.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.net.URL; -import java.util.Collection; -import java.util.Map; - -import org.springframework.cloud.contract.spec.Contract; - -/** - * Contract for finding registered stubs. - * - * @author Marcin Grzejszczak - */ -public interface StubFinder extends StubTrigger { - - /** - * For the given groupId and artifactId tries to find the matching URL of the running - * stub. - * @param groupId - might be null. In that case a search only via artifactId takes - * place - * @param artifactId - artifact id of the stub - * @return URL of a running stub or throws exception if not found - * @throws StubNotFoundException in case of not finding a stub - */ - URL findStubUrl(String groupId, String artifactId) throws StubNotFoundException; - - /** - * For the given Ivy notation {@code [groupId]:artifactId:[version]:[classifier]} - * tries to find the matching URL of the running stub. You can also pass only - * {@code artifactId}. - * @param ivyNotation - Ivy representation of the Maven artifact - * @return URL of a running stub or throws exception if not found - * @throws StubNotFoundException in case of not finding a stub - */ - URL findStubUrl(String ivyNotation) throws StubNotFoundException; - - /** - * @return all running stubs - */ - RunningStubs findAllRunningStubs(); - - /** - * @return the list of Contracts - */ - Map> getContracts(); - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubNotFoundException.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubNotFoundException.java deleted file mode 100644 index 454dcff656..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubNotFoundException.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -/** - * Exception thrown when a stub was not found. - * - * @author Marcin Grzejszczak - * @since 1.0.1 - */ -public class StubNotFoundException extends RuntimeException { - - public StubNotFoundException(String groupId, String artifactId) { - super("Stub not found for groupid [" + groupId + "] and artifactid [" + artifactId + "]"); - } - - public StubNotFoundException(String ivyNotation) { - super("Stub not found for stub with notation [" + ivyNotation + "]"); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRepository.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRepository.java deleted file mode 100644 index 40595babc8..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRepository.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.ContractConverter; -import org.springframework.cloud.contract.stubrunner.provider.wiremock.WireMockHttpServerStub; -import org.springframework.cloud.contract.verifier.util.ContractScanner; -import org.springframework.core.io.support.SpringFactoriesLoader; - -/** - * Wraps the folder with stub mappings. - */ -class StubRepository { - - private static final Log log = LogFactory.getLog(StubRepository.class); - - final List stubs; - - final Collection contracts; - - private final File path; - - private final List contractConverters; - - private final List httpServerStubs; - - private final StubRunnerOptions options; - - StubRepository(File repository, List httpServerStubs, StubRunnerOptions options) { - if (!repository.isDirectory()) { - throw new IllegalArgumentException("Missing descriptor repository under path [" + repository + "]"); - } - this.contractConverters = SpringFactoriesLoader.loadFactories(ContractConverter.class, null); - if (log.isTraceEnabled()) { - log.trace("Found the following contract converters " + this.contractConverters); - } - this.httpServerStubs = httpServerStubs; - this.path = repository; - this.options = options; - this.stubs = stubs(); - this.contracts = contracts(); - if (log.isTraceEnabled()) { - log.trace("Found the following contracts " + this.contracts); - } - } - - StubRepository(File repository) { - this(repository, new ArrayList<>(), new StubRunnerOptionsBuilder().build()); - } - - public File getPath() { - return this.path; - } - - public List getStubs() { - return this.stubs; - } - - public Collection getContracts() { - return this.contracts; - } - - /** - * @return a list of contracts - */ - private Collection contracts() { - return new ArrayList<>(contractDescriptors()); - } - - /** - * @return the list of stubs - */ - private List stubs() { - return new ArrayList<>(collectedStubs()); - } - - private List collectedStubs() { - return this.path.exists() ? collectMappings(this.path) : Collections.emptyList(); - } - - private List collectMappings(File descriptorsDirectory) { - final List mappingDescriptors = new ArrayList<>(); - try { - Files.walkFileTree(Paths.get(descriptorsDirectory.toURI()), new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException { - File file = path.toFile(); - if (httpServerStubAccepts(file) && isStubPerConsumerPathMatching(file)) { - mappingDescriptors.add(file); - } - return super.visitFile(path, attrs); - } - }); - } - catch (IOException e) { - log.warn("Exception occurred while trying to parse file", e); - } - return mappingDescriptors; - } - - private ContractConverter contractConverter(File file) { - for (ContractConverter converter : this.contractConverters) { - if (converter.isAccepted(file)) { - return converter; - } - } - return null; - } - - private boolean httpServerStubAccepts(File file) { - for (HttpServerStub httpServerStub : this.httpServerStubs) { - if (httpServerStub.isAccepted(file)) { - return true; - } - } - // the default implementation - return new WireMockHttpServerStub().isAccepted(file); - } - - private Collection contractDescriptors() { - return (this.path.exists() - ? ContractScanner.collectContractDescriptors(this.path, this::isStubPerConsumerPathMatching) - : Collections.emptySet()); - } - - private boolean isStubPerConsumerPathMatching(File file) { - if (!this.options.isStubsPerConsumer()) { - return true; - } - String consumerName = this.options.getConsumerName(); - String searchedConsumerName = File.separator + consumerName + File.separator; - String absolutePath = file.getAbsolutePath(); - boolean stubPerConsumerMatching = absolutePath.contains(searchedConsumerName); - if (log.isDebugEnabled()) { - log.debug("Absolute path [" + absolutePath + "] contains [" + searchedConsumerName + "] in its path [" - + stubPerConsumerMatching + "]"); - } - return stubPerConsumerMatching; - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunner.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunner.java deleted file mode 100644 index 54d3c4a5da..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunner.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender; -import org.springframework.cloud.contract.verifier.messaging.noop.NoOpStubMessages; -import org.springframework.core.io.support.SpringFactoriesLoader; -import org.springframework.util.StringUtils; - -/** - * Represents a single instance of ready-to-run stubs. Can run the stubs and then will - * return the name of the collaborator together with its URI. Can also be queried if the - * current groupid and artifactid are matching the corresponding running stub. - * - * @author Marcin Grzejszczak - */ -public class StubRunner implements StubRunning { - - private static final Log log = LogFactory.getLog(StubRunner.class); - - private final StubRepository stubRepository; - - private final StubConfiguration stubsConfiguration; - - private final StubRunnerOptions stubRunnerOptions; - - private final StubRunnerExecutor localStubRunner; - - public StubRunner(StubRunnerOptions stubRunnerOptions, String repositoryPath, - StubConfiguration stubsConfiguration) { - this(stubRunnerOptions, repositoryPath, stubsConfiguration, new NoOpStubMessages<>()); - } - - public StubRunner(StubRunnerOptions stubRunnerOptions, String repositoryPath, StubConfiguration stubsConfiguration, - MessageVerifierSender contractVerifierMessaging) { - this.stubsConfiguration = stubsConfiguration; - this.stubRunnerOptions = stubRunnerOptions; - List serverStubs = SpringFactoriesLoader.loadFactories(HttpServerStub.class, null); - this.stubRepository = new StubRepository(new File(repositoryPath), serverStubs, this.stubRunnerOptions); - AvailablePortScanner portScanner = new AvailablePortScanner(stubRunnerOptions.getMinPortValue(), - stubRunnerOptions.getMaxPortValue()); - this.localStubRunner = new StubRunnerExecutor(portScanner, contractVerifierMessaging, serverStubs); - } - - @Override - public RunningStubs runStubs() { - registerShutdownHook(); - RunningStubs stubs = this.localStubRunner.runStubs(this.stubRunnerOptions, this.stubRepository, - this.stubsConfiguration); - if (this.stubRunnerOptions.hasMappingsOutputFolder()) { - String registeredMappings = this.localStubRunner.registeredMappings(); - if (StringUtils.hasText(registeredMappings)) { - File outputMappings = new File(this.stubRunnerOptions.getMappingsOutputFolder(), - this.stubsConfiguration.artifactId + "_" - + stubs.getPort(this.stubsConfiguration.toColonSeparatedDependencyNotation())); - try { - outputMappings.getParentFile().mkdirs(); - clearOldFiles(outputMappings.getParentFile(), this.stubsConfiguration.artifactId); - outputMappings.createNewFile(); - Files.write(Paths.get(outputMappings.toURI()), registeredMappings.getBytes()); - if (log.isDebugEnabled()) { - log.debug("Stored the mappings for artifactid [" + this.stubsConfiguration.artifactId + "] at [" - + outputMappings + "] location"); - } - } - catch (IOException e) { - log.error("Exception occurred while trying to store the mappings", e); - throw new IllegalStateException(e); - } - } - } - return stubs; - } - - private void clearOldFiles(File outputFolder, final String filename) { - File[] files = outputFolder.listFiles(new FilenameFilter() { - @Override - public boolean accept(final File dir, final String name) { - return name.startsWith(filename); - } - }); - if (files == null) { - if (log.isDebugEnabled()) { - log.debug("Failed to retrieve any mappings"); - } - return; - } - for (final File file : files) { - if (!file.delete()) { - if (log.isDebugEnabled()) { - log.debug("Exception occurred while trying to remove [" + file.getAbsolutePath() + "]"); - } - } - } - } - - @Override - public URL findStubUrl(String groupId, String artifactId) { - return this.localStubRunner.findStubUrl(groupId, artifactId); - } - - @Override - public URL findStubUrl(String ivyNotation) { - return this.localStubRunner.findStubUrl(ivyNotation); - } - - @Override - public RunningStubs findAllRunningStubs() { - return this.localStubRunner.findAllRunningStubs(); - } - - @Override - public Map> getContracts() { - return this.localStubRunner.getContracts(); - } - - @Override - public boolean trigger(String ivyNotation, String labelName) { - return this.localStubRunner.trigger(ivyNotation, labelName); - } - - @Override - public boolean trigger(String labelName) { - return this.localStubRunner.trigger(labelName); - } - - @Override - public boolean trigger() { - return this.localStubRunner.trigger(); - } - - @Override - public Map> labels() { - return this.localStubRunner.labels(); - } - - private void registerShutdownHook() { - Runnable stopAllServers = new Runnable() { - @Override - public void run() { - try { - close(); - } - catch (IOException e) { - } - } - }; - Runtime.getRuntime().addShutdownHook(new Thread(stopAllServers)); - } - - @Override - public void close() throws IOException { - if (this.localStubRunner != null) { - this.localStubRunner.shutdown(); - } - TemporaryFileStorage.cleanup(this.stubRunnerOptions.isDeleteStubsAfterTest()); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerExecutor.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerExecutor.java deleted file mode 100644 index 98b0d90be5..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerExecutor.java +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import groovy.json.JsonOutput; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.beans.BeanUtils; -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.internal.DslProperty; -import org.springframework.cloud.contract.spec.internal.FromFileProperty; -import org.springframework.cloud.contract.spec.internal.Headers; -import org.springframework.cloud.contract.spec.internal.OutputMessage; -import org.springframework.cloud.contract.stubrunner.AvailablePortScanner.PortCallback; -import org.springframework.cloud.contract.stubrunner.provider.wiremock.WireMockHttpServerStub; -import org.springframework.cloud.contract.verifier.converter.YamlContract; -import org.springframework.cloud.contract.verifier.converter.YamlContractConverter; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessageMetadata; -import org.springframework.cloud.contract.verifier.messaging.noop.NoOpStubMessages; -import org.springframework.cloud.contract.verifier.util.BodyExtractor; - -/** - * Runs stubs for a particular {@link StubServer}. - */ -class StubRunnerExecutor implements StubFinder { - - static final Set STUB_SERVERS = Collections.synchronizedSet(new HashSet<>()); - - private static final Log log = LogFactory.getLog(StubRunnerExecutor.class); - - private final AvailablePortScanner portScanner; - - private final MessageVerifierSender messageVerifierSender; - - private final List serverStubs; - - private StubServer stubServer; - - private final YamlContractConverter yamlContractConverter = new YamlContractConverter(); - - StubRunnerExecutor(AvailablePortScanner portScanner, MessageVerifierSender messageVerifierSender, - List serverStubs) { - this.portScanner = portScanner; - this.messageVerifierSender = messageVerifierSender; - this.serverStubs = serverStubs; - } - - StubRunnerExecutor(AvailablePortScanner portScanner, List serverStubs) { - this(portScanner, new NoOpStubMessages(), serverStubs); - } - - StubRunnerExecutor(AvailablePortScanner portScanner) { - this(portScanner, new NoOpStubMessages(), new ArrayList<>()); - } - - public RunningStubs runStubs(StubRunnerOptions stubRunnerOptions, StubRepository repository, - StubConfiguration stubConfiguration) { - if (this.stubServer != null) { - if (log.isDebugEnabled()) { - log.debug("Returning cached version of stubs [" + stubConfiguration.toColonSeparatedDependencyNotation() - + "]"); - } - return runningStubs(); - } - HttpServerStubConfigurer configurer = BeanUtils - .instantiateClass(stubRunnerOptions.getHttpServerStubConfigurer()); - startStubServers(configurer, stubRunnerOptions, stubConfiguration, repository); - RunningStubs runningCollaborators = runningStubs(); - log.info("All stubs are now running " + runningCollaborators.toString()); - return runningCollaborators; - } - - private RunningStubs runningStubs() { - return new RunningStubs( - Collections.singletonMap(this.stubServer.getStubConfiguration(), this.stubServer.getPort())); - } - - public void shutdown() { - if (this.stubServer != null) { - this.stubServer.stop(); - } - } - - String registeredMappings() { - return this.stubServer.registeredMappings(); - } - - @Override - public URL findStubUrl(String groupId, String artifactId) { - URL url = null; - if (groupId == null) { - url = findStubUrl(this.stubServer.stubConfiguration.artifactId.equals(artifactId)); - } - if (url == null) { - url = findStubUrl(this.stubServer.stubConfiguration.artifactId.equals(artifactId) - && this.stubServer.stubConfiguration.groupId.equals(groupId)); - } - if (url == null) { - throw new StubNotFoundException(groupId, artifactId); - } - return url; - } - - @Override - public URL findStubUrl(String ivyNotation) { - String[] splitString = ivyNotation.split(":", -1); - if (splitString.length > 4) { - throw new IllegalArgumentException( - "[" + ivyNotation + "] is an invalid notation. Pass [groupId]:artifactId[:version][:classifier]."); - } - else if (splitString.length == 1) { - return findStubUrl(null, splitString[0]); - } - else if (splitString.length == 2) { - return findStubUrl(splitString[0], splitString[1]); - } - else if (splitString.length == 3) { - return findStubUrl(groupIdArtifactVersionMatches(splitString)); - } - return findStubUrl(groupIdArtifactVersionMatches(splitString) && classifierMatches(splitString)); - } - - private boolean classifierMatches(String[] splitString) { - return this.stubServer.stubConfiguration.classifier.equals(splitString[3]); - } - - private boolean groupIdArtifactVersionMatches(String[] splitString) { - return this.stubServer.stubConfiguration.groupId.equals(splitString[0]) - && this.stubServer.stubConfiguration.artifactId.equals(splitString[1]) - && this.stubServer.stubConfiguration.version.equals(splitString[2]); - } - - private URL findStubUrl(boolean condition) { - return returnStubUrlIfMatches(condition); - } - - @Override - public RunningStubs findAllRunningStubs() { - return new RunningStubs(Collections.singletonMap(this.stubServer.stubConfiguration, this.stubServer.getPort())); - } - - @Override - public Map> getContracts() { - return Collections.singletonMap(this.stubServer.stubConfiguration, this.stubServer.getContracts()); - } - - @Override - public boolean trigger(String ivyNotationAsString, String labelName) { - Collection matchingContracts = new ArrayList<>(); - for (Entry> it : getContracts().entrySet()) { - if (it.getKey().groupIdAndArtifactMatches(ivyNotationAsString)) { - matchingContracts.addAll(it.getValue()); - } - } - return triggerForDsls(matchingContracts, labelName); - } - - @Override - public boolean trigger(String labelName) { - Collection matchingContracts = new ArrayList<>(); - for (Collection it : getContracts().values()) { - matchingContracts.addAll(it); - } - return triggerForDsls(matchingContracts, labelName); - } - - private boolean triggerForDsls(Collection dsls, String labelName) { - Collection matchingDsls = new ArrayList<>(); - for (Contract contract : dsls) { - if (labelName.equals(contract.getLabel()) && contract.getOutputMessage() != null) { - matchingDsls.add(contract); - } - } - if (matchingDsls.isEmpty()) { - return false; - } - for (Contract contract : matchingDsls) { - sendMessage(contract); - } - return true; - } - - @Override - public boolean trigger() { - Collection matchingContracts = new ArrayList<>(); - for (Collection it : getContracts().values()) { - for (Contract contract : it) { - if (contract.getOutputMessage() != null) { - matchingContracts.add(contract); - } - } - } - if (matchingContracts.isEmpty()) { - return false; - } - for (Contract contract : matchingContracts) { - sendMessage(contract); - } - return true; - } - - @Override - public Map> labels() { - Map> labels = new LinkedHashMap<>(); - for (Entry> it : getContracts().entrySet()) { - Collection values = new ArrayList<>(); - for (Contract contract : it.getValue()) { - if (contract.getLabel() != null) { - values.add(contract.getLabel()); - } - } - labels.put(it.getKey().toColonSeparatedDependencyNotation(), values); - } - return labels; - } - - private void sendMessage(Contract groovyDsl) { - OutputMessage outputMessage = groovyDsl.getOutputMessage(); - DslProperty body = outputMessage.getBody(); - Headers headers = outputMessage.getHeaders(); - List yamlContracts = yamlContractConverter.convertTo(Collections.singleton(groovyDsl)); - YamlContract contract = yamlContracts.get(0); - setMessageType(contract, ContractVerifierMessageMetadata.MessageType.OUTPUT); - - Object payload = null; - if (body.getClientValue() instanceof FromFileProperty) { - FromFileProperty fromFile = (FromFileProperty) body.getClientValue(); - if (fromFile.isByte()) { - payload = fromFile.asBytes(); - } - else { - payload = fromFile.asString(); - } - } - else { - payload = JsonOutput - .toJson(BodyExtractor.extractClientValueFromBody(body == null ? null : body.getClientValue())); - } - - this.messageVerifierSender.send(payload, headers == null ? null : headers.asStubSideMap(), - outputMessage.getSentTo().getClientValue(), contract); - } - - private void setMessageType(YamlContract contract, ContractVerifierMessageMetadata.MessageType output) { - contract.metadata.put(ContractVerifierMessageMetadata.METADATA_KEY, - new ContractVerifierMessageMetadata(output)); - } - - private URL returnStubUrlIfMatches(boolean condition) { - return condition ? this.stubServer.getStubUrl() : null; - } - - private StubServer startStubServers(HttpServerStubConfigurer configurer, final StubRunnerOptions stubRunnerOptions, - final StubConfiguration stubConfiguration, StubRepository repository) { - final List mappings = repository.getStubs(); - final Collection contracts = repository.contracts; - Integer port = stubRunnerOptions.port(stubConfiguration); - boolean randomPort = randomPort(port); - HttpServerStubConfiguration configuration = new HttpServerStubConfiguration(configurer, stubRunnerOptions, - stubConfiguration, port, randomPort); - if (!hasRequest(contracts) && mappings.isEmpty()) { - if (log.isDebugEnabled()) { - log.debug("There are no HTTP related contracts. Won't start any servers"); - } - this.stubServer = new StubServer(stubConfiguration, mappings, contracts, new NoOpHttpServerStub()) - .start(configuration); - return this.stubServer; - } - if (!randomPort) { - this.stubServer = new StubServer(stubConfiguration, mappings, contracts, httpServerStub()) - .start(configuration); - } - else { - this.stubServer = this.portScanner.tryToExecuteWithFreePort(new PortCallback() { - @Override - public StubServer call(int availablePort) { - return new StubServer(stubConfiguration, mappings, contracts, httpServerStub()) - .start(new HttpServerStubConfiguration(configurer, stubRunnerOptions, stubConfiguration, - availablePort, true)); - } - }); - } - STUB_SERVERS.add(this.stubServer); - return this.stubServer; - } - - private boolean randomPort(Integer port) { - return port == null || port == 0; - } - - private boolean hasRequest(Collection contracts) { - if (contracts.isEmpty()) { - return false; - } - for (Contract contract : contracts) { - if (contract.getRequest() != null) { - return true; - } - } - return false; - } - - private HttpServerStub httpServerStub() { - // the default impl is the WireMock one - if (this.serverStubs.isEmpty()) { - return new WireMockHttpServerStub(); - } - // first one wins - return this.serverStubs.get(0); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerFactory.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerFactory.java deleted file mode 100644 index 106e77aa11..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerFactory.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.stubrunner.provider.wiremock.WireMockHttpServerStub; -import org.springframework.cloud.contract.verifier.converter.RecursiveFilesConverter; -import org.springframework.cloud.contract.verifier.converter.StubGenerator; -import org.springframework.cloud.contract.verifier.converter.StubGeneratorProvider; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender; -import org.springframework.cloud.contract.verifier.wiremock.DslToWireMockClientConverter; -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.SpringFactoriesLoader; - -/** - * Factory of StubRunners. Basing on the options and passed collaborators downloads the - * stubs and returns a list of corresponding stub runners. - */ -class StubRunnerFactory { - - private static final Log log = LogFactory.getLog(StubRunnerFactory.class); - - private final StubRunnerOptions stubRunnerOptions; - - private final StubDownloader stubDownloader; - - private final MessageVerifierSender contractVerifierMessaging; - - StubRunnerFactory(StubRunnerOptions stubRunnerOptions, StubDownloader stubDownloader, - MessageVerifierSender contractVerifierMessaging) { - this.stubRunnerOptions = stubRunnerOptions; - this.stubDownloader = stubDownloader; - this.contractVerifierMessaging = contractVerifierMessaging; - } - - public Collection createStubsFromServiceConfiguration() { - if (log.isDebugEnabled()) { - log.debug("Will download stubs for dependencies " + this.stubRunnerOptions.getDependencies()); - } - if (this.stubRunnerOptions.getDependencies().isEmpty()) { - log.warn("No stubs to download have been passed. Most likely you have forgotten to pass " - + "them either via annotation or a property"); - } - Collection result = new ArrayList<>(); - for (StubConfiguration stubsConfiguration : this.stubRunnerOptions.getDependencies()) { - Map.Entry entry = this.stubDownloader.downloadAndUnpackStubJar(stubsConfiguration); - if (log.isDebugEnabled()) { - log.debug( - "For stub configuration [" + stubsConfiguration + "] the downloaded entry is [" + entry + "]"); - } - if (entry != null) { - Path path = resolvePath(entry.getValue()); - File unpackedLocation = path.toFile(); - if (this.stubRunnerOptions.isGenerateStubs()) { - if (log.isDebugEnabled()) { - log.debug( - "Flag to generate stubs at runtime was switched on. Will remove the current mappings and will generate new ones."); - } - generateMappingsAtRuntime(path); - } - result.add(createStubRunner(entry.getKey(), unpackedLocation)); - } - } - return result; - } - - private void generateMappingsAtRuntime(Path path) { - removeCurrentMappings(path); - generateNewMappings(path); - } - - private Path resolvePath(File unpackedLocation) { - Resource resource = ResourceResolver.resource(unpackedLocation.toURI().toString()); - Path path = unpackedLocation.toPath(); - if (resource != null) { - try { - return Paths.get(resource.getURI()); - } - catch (IOException ex) { - return unpackedLocation.toPath(); - } - } - return path; - } - - private void removeCurrentMappings(Path path) { - - List httpServerStubs = SpringFactoriesLoader.loadFactories(HttpServerStub.class, null); - if (httpServerStubs.isEmpty()) { - httpServerStubs.add(new WireMockHttpServerStub()); - } - - try { - Files.walkFileTree(path, new SimpleFileVisitor() { - - private final Log log = LogFactory.getLog(StubRunnerFactory.class); - - private final StubGeneratorProvider provider = new StubGeneratorProvider(); - - private final HttpServerStub wireMockHttpServerStub = new WireMockHttpServerStub(); - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { - File potentialStubMapping = file.toFile(); - Collection stubGenerators = this.provider - .allOrDefault(new DslToWireMockClientConverter()); - if (stubGenerators.stream().anyMatch(s -> s.canReadStubMapping(potentialStubMapping))) { - if (log.isDebugEnabled()) { - log.debug("Deleting file [" + file.toString() + "] since it contains a valid mapping."); - } - try { - Files.delete(file); - } - catch (IOException ex) { - log.warn("Failed to delete file [" + file.toString() + "]", ex); - } - } - return FileVisitResult.CONTINUE; - } - }); - } - catch (IOException ex) { - log.warn("Exception occurred while trying to delete mappings", ex); - } - } - - private void generateNewMappings(Path path) { - File unpackedLocation = path.toFile(); - RecursiveFilesConverter converter = new RecursiveFilesConverter( - subfolderIfPresent(unpackedLocation, "mappings"), subfolderIfPresent(unpackedLocation, "contracts"), - new ArrayList<>(), ".*", false); - converter.processFiles(); - } - - private File subfolderIfPresent(File unpackedLocation, String subfolder) { - File subfolderDir = new File(unpackedLocation, subfolder); - if (subfolderDir.exists()) { - return subfolderDir; - } - return unpackedLocation; - } - - private StubRunner createStubRunner(StubConfiguration stubsConfiguration, File unzipedStubDir) { - if (unzipedStubDir == null) { - return null; - } - return createStubRunner(unzipedStubDir, stubsConfiguration, this.stubRunnerOptions); - } - - private StubRunner createStubRunner(File unzippedStubsDir, StubConfiguration stubsConfiguration, - StubRunnerOptions stubRunnerOptions) { - return new StubRunner(stubRunnerOptions, unzippedStubsDir.getPath(), stubsConfiguration, - this.contractVerifierMessaging); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerOptions.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerOptions.java deleted file mode 100644 index 73a54e6728..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerOptions.java +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; -import java.util.Set; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.core.io.Resource; -import org.springframework.util.StringUtils; - -/** - * Technical options related to running StubRunner - * - * Use {@link StubRunnerOptionsBuilder} to build this object. - * - * @author Marcin Grzejszczak - * @author Eddú Meléndez - * @see StubRunnerOptionsBuilder - */ -public class StubRunnerOptions { - - private static final Log log = LogFactory.getLog(StubRunnerOptions.class); - - /** - * min port value of the WireMock instance for the given collaborator. - */ - final Integer minPortValue; - - /** - * max port value of the WireMock instance for the given collaborator. - */ - final Integer maxPortValue; - - /** - * root URL from where the JAR with stub mappings will be downloaded. - */ - final Resource stubRepositoryRoot; - - /** - * stub definition classifier. - */ - final String stubsClassifier; - - final Collection dependencies; - - /** - * colon separated list of ids to the desired port. - */ - final Map stubIdsToPortMapping; - - /** - * Optional username for authorization header. - */ - final String username; - - /** - * Optional password for authorization header. - */ - final String password; - - final StubRunnerProperties.StubsMode stubsMode; - - /** - * Optional proxy settings. - */ - private final StubRunnerProxyOptions stubRunnerProxyOptions; - - /** - * Configuration for an HTTP server stub class that allows to perform additional HTTP - * server stub configuration. - */ - private final Class httpServerStubConfigurer; - - /** - * Should only stubs applicable for the given consumer get registered. - */ - private boolean stubsPerConsumer = false; - - /** - * Name of the consumer. If not set should default to {@code spring.application.name}. - */ - private String consumerName; - - /** - * For debugging purposes you can output the registered mappings to a given folder. - * Each HTTP server stub will have its own subfolder where all the mappings will get - * stored. - */ - private String mappingsOutputFolder; - - /** - * If set to {@code false} will NOT delete stubs from a temporary folder after running - * tests. - */ - private boolean deleteStubsAfterTest; - - /** - * When enabled, this flag will tell stub runner to not load the generated stubs, but - * convert the found contracts at runtime to a stub format and run those stubs. - */ - private boolean generateStubs; - - /** - * When enabled, this flag will tell stub runner to throw an exception when no stubs / - * contracts were found. - */ - private boolean failOnNoStubs = true; - - /** - * Map of properties that can be passed to custom - * {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder}. - */ - private Map properties; - - /** - * - */ - final String serverId; - - StubRunnerOptions(Integer minPortValue, Integer maxPortValue, Resource stubRepositoryRoot, - StubRunnerProperties.StubsMode stubsMode, String stubsClassifier, - Collection dependencies, Map stubIdsToPortMapping, - String username, String password, final StubRunnerProxyOptions stubRunnerProxyOptions, - boolean stubsPerConsumer, String consumerName, String mappingsOutputFolder, boolean deleteStubsAfterTest, - boolean generateStubs, boolean failOnNoStubs, Map properties, - Class httpServerStubConfigurer, String serverId) { - this.minPortValue = minPortValue; - this.maxPortValue = maxPortValue; - this.stubRepositoryRoot = stubRepositoryRoot; - this.stubsMode = stubsMode != null ? stubsMode : StubRunnerProperties.StubsMode.CLASSPATH; - this.stubsClassifier = stubsClassifier; - this.dependencies = dependencies; - this.stubIdsToPortMapping = stubIdsToPortMapping; - this.username = username; - this.password = password; - this.stubRunnerProxyOptions = stubRunnerProxyOptions; - this.stubsPerConsumer = stubsPerConsumer; - this.consumerName = consumerName; - this.mappingsOutputFolder = mappingsOutputFolder; - this.deleteStubsAfterTest = deleteStubsAfterTest; - this.generateStubs = generateStubs; - this.failOnNoStubs = failOnNoStubs; - this.properties = properties; - this.httpServerStubConfigurer = httpServerStubConfigurer; - this.serverId = serverId; - } - - public static StubRunnerOptions fromSystemProps() { - StubRunnerOptionsBuilder builder = new StubRunnerOptionsBuilder() - .withMinPort(Integer.valueOf(System.getProperty("stubrunner.port.range.min", "10000"))) - .withMaxPort(Integer.valueOf(System.getProperty("stubrunner.port.range.max", "15000"))) - .withStubRepositoryRoot(ResourceResolver.resource(System.getProperty("stubrunner.repository.root", ""))) - .withStubsMode(System.getProperty("stubrunner.stubs-mode", "LOCAL")) - .withStubsClassifier(System.getProperty("stubrunner.classifier", "stubs")) - .withStubs(System.getProperty("stubrunner.ids", "")) - .withUsername(System.getProperty("stubrunner.username")) - .withPassword(System.getProperty("stubrunner.password")) - .withStubPerConsumer(Boolean.parseBoolean(System.getProperty("stubrunner.stubs-per-consumer", "false"))) - .withConsumerName(System.getProperty("stubrunner.consumer-name")) - .withMappingsOutputFolder(System.getProperty("stubrunner.mappings-output-folder")) - .withDeleteStubsAfterTest( - Boolean.parseBoolean(System.getProperty("stubrunner.delete-stubs-after-test", "true"))) - .withGenerateStubs(Boolean.parseBoolean(System.getProperty("stubrunner.generate-stubs", "false"))) - .withFailOnNoStubs(Boolean.parseBoolean(System.getProperty("stubrunner.fail-on-no-stubs", "false"))) - .withProperties(stubRunnerProps()).withServerId(System.getProperty("stubrunner.server-id", "")); - builder = httpStubConfigurer(builder); - String proxyHost = System.getProperty("stubrunner.proxy.host"); - if (proxyHost != null) { - builder.withProxy(proxyHost, Integer.parseInt(System.getProperty("stubrunner.proxy.port"))); - } - return builder.build(); - } - - private static StubRunnerOptionsBuilder httpStubConfigurer(StubRunnerOptionsBuilder builder) { - String classProperty = System.getProperty("stubrunner.http-server-stub-configurer", - HttpServerStubConfigurer.NoOpHttpServerStubConfigurer.class.getName()); - try { - Class clazz = Class.forName(classProperty); - return builder.withHttpServerStubConfigurer(clazz); - } - catch (ClassNotFoundException ex) { - throw new IllegalStateException("Class [" + classProperty + "] not found", ex); - } - } - - private static Map stubRunnerProps() { - Map map = new HashMap<>(); - Properties properties = System.getProperties(); - Set propertyNames = properties.stringPropertyNames(); - propertyNames.stream() - // stubrunner.properties.foo.bar=baz - .filter(s -> s.toLowerCase().startsWith("stubrunner.properties")) - // foo.bar=baz - .forEach(s -> map.put(s.substring("stubrunner.properties".length() + 1), System.getProperty(s))); - return map; - } - - public Integer port(StubConfiguration stubConfiguration) { - if (this.stubIdsToPortMapping != null) { - return this.stubIdsToPortMapping.get(stubConfiguration); - } - else { - return null; - } - } - - public Integer getMinPortValue() { - return this.minPortValue; - } - - public Integer getMaxPortValue() { - return this.maxPortValue; - } - - public Collection getDependencies() { - return this.dependencies; - } - - public Map getStubIdsToPortMapping() { - return this.stubIdsToPortMapping; - } - - public Resource getStubRepositoryRoot() { - return this.stubRepositoryRoot; - } - - public String getStubRepositoryRootAsString() { - if (this.stubRepositoryRoot == null) { - return ""; - } - try { - return this.stubRepositoryRoot.getURI().toString(); - } - catch (FileNotFoundException f) { - if (log.isDebugEnabled()) { - log.debug("File not found", f); - } - return ""; - } - catch (IOException e) { - throw new IllegalStateException(e); - } - } - - public StubRunnerProperties.StubsMode getStubsMode() { - return this.stubsMode; - } - - public String getStubsClassifier() { - return this.stubsClassifier; - } - - public String getUsername() { - return this.username; - } - - public String getPassword() { - return this.password; - } - - public StubRunnerProxyOptions getStubRunnerProxyOptions() { - return this.stubRunnerProxyOptions; - } - - public StubRunnerProxyOptions getProxyOptions() { - return this.stubRunnerProxyOptions; - } - - public boolean isStubsPerConsumer() { - return this.stubsPerConsumer; - } - - public String getConsumerName() { - return this.consumerName; - } - - public boolean hasMappingsOutputFolder() { - return StringUtils.hasText(this.mappingsOutputFolder); - } - - public String getMappingsOutputFolder() { - return this.mappingsOutputFolder; - } - - public boolean isDeleteStubsAfterTest() { - return this.deleteStubsAfterTest; - } - - public boolean isGenerateStubs() { - return this.generateStubs; - } - - public boolean isFailOnNoStubs() { - return this.failOnNoStubs; - } - - public Map getProperties() { - return this.properties; - } - - public String getServerId() { - return this.serverId; - } - - public Class getHttpServerStubConfigurer() { - return this.httpServerStubConfigurer; - } - - @Override - public String toString() { - return "StubRunnerOptions{" + "minPortValue=" + this.minPortValue + ", maxPortValue=" + this.maxPortValue - + ", stubRepositoryRoot='" + this.stubRepositoryRoot + '\'' + ", stubsMode='" + this.stubsMode - + "', stubsClassifier='" + this.stubsClassifier + '\'' + ", dependencies=" + this.dependencies - + ", stubIdsToPortMapping=" + this.stubIdsToPortMapping + ", username='" + obfuscate(this.username) - + '\'' + ", password='" + obfuscate(this.password) + '\'' + ", stubRunnerProxyOptions='" - + this.stubRunnerProxyOptions + "', stubsPerConsumer='" + this.stubsPerConsumer + '\'' - + ", httpServerStubConfigurer='" + this.httpServerStubConfigurer + '\'' + ", serverId='" + this.serverId - + '\'' + '}'; - } - - private String obfuscate(String string) { - return StringUtils.hasText(string) ? "****" : ""; - } - - /** - * Options for a proxy. - */ - public static class StubRunnerProxyOptions { - - private final String proxyHost; - - private final int proxyPort; - - public StubRunnerProxyOptions(final String proxyHost, final int proxyPort) { - this.proxyHost = proxyHost; - this.proxyPort = proxyPort; - } - - public String getProxyHost() { - return this.proxyHost; - } - - public int getProxyPort() { - return this.proxyPort; - } - - @Override - public String toString() { - return "StubRunnerProxyOptions{" + "proxyHost='" + this.proxyHost + '\'' + ", proxyPort=" + this.proxyPort - + '}'; - } - - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerOptionsBuilder.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerOptionsBuilder.java deleted file mode 100644 index b43477f7f1..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerOptionsBuilder.java +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.cloud.contract.stubrunner.util.StubsParser; -import org.springframework.core.io.Resource; -import org.springframework.util.StringUtils; - -/** - * A builder object for {@link StubRunnerOptions}. - * - * @author Marcin Grzejszczak - * @author Eddú Meléndez - */ -public class StubRunnerOptionsBuilder { - - private static final String DELIMITER = ":"; - - private LinkedList stubs = new LinkedList<>(); - - private Collection stubConfigurations = new ArrayList<>(); - - private Map stubIdsToPortMapping = new LinkedHashMap<>(); - - private Integer minPortValue = 10000; - - private Integer maxPortValue = 15000; - - private Resource stubRepositoryRoot; - - private String stubsClassifier = "stubs"; - - private String username; - - private String password; - - private StubRunnerOptions.StubRunnerProxyOptions stubRunnerProxyOptions; - - private boolean stubsPerConsumer = false; - - private String consumerName; - - private String mappingsOutputFolder; - - private StubRunnerProperties.StubsMode stubsMode; - - private boolean deleteStubsAfterTest = true; - - private boolean generateStubs; - - private boolean failOnNoStubs = true; - - private Map properties = new HashMap<>(); - - private Class httpServerStubConfigurer = HttpServerStubConfigurer.NoOpHttpServerStubConfigurer.class; - - private String serverId; - - public StubRunnerOptionsBuilder() { - } - - public StubRunnerOptionsBuilder(StubRunnerOptions options) { - withOptions(options); - } - - private static List stubsToList(String[] stubIdsToPortMapping) { - List list = new ArrayList<>(); - if (stubIdsToPortMapping.length == 1 && !containsRange(stubIdsToPortMapping[0])) { - list.addAll(StringUtils.commaDelimitedListToSet(stubIdsToPortMapping[0])); - return list; - } - else if (stubIdsToPortMapping.length == 1 && containsRange(stubIdsToPortMapping[0])) { - LinkedList linkedList = new LinkedList<>(); - String[] split = stubIdsToPortMapping[0].split(","); - for (String string : split) { - if (containsClosingRange(string)) { - String last = linkedList.pop(); - linkedList.push(last + "," + string); - } - else { - linkedList.push(string); - } - } - list.addAll(linkedList); - return list; - } - Collections.addAll(list, stubIdsToPortMapping); - return list; - } - - private static boolean containsRange(String s) { - return s.contains("[") || s.contains("("); - } - - private static boolean containsClosingRange(String s) { - return s.contains("]") || s.contains(")"); - } - - public StubRunnerOptionsBuilder withStubs(String... stubs) { - addStub(stubsToList(stubs)); - return this; - } - - public StubRunnerOptionsBuilder withStubs(List stubs) { - for (String stub : stubs) { - withStubs(stub); - } - return this; - } - - public StubRunnerOptionsBuilder withMinMaxPort(Integer minPortValue, Integer maxPortValue) { - this.minPortValue = minPortValue; - this.maxPortValue = maxPortValue; - return this; - } - - public StubRunnerOptionsBuilder withMinPort(int minPortValue) { - this.minPortValue = minPortValue; - return this; - } - - public StubRunnerOptionsBuilder withMaxPort(int maxPortValue) { - this.maxPortValue = maxPortValue; - return this; - } - - public StubRunnerOptionsBuilder withStubRepositoryRoot(Resource stubRepositoryRoot) { - this.stubRepositoryRoot = stubRepositoryRoot; - return this; - } - - public StubRunnerOptionsBuilder withStubRepositoryRoot(String stubRepositoryRoot) { - if (StringUtils.hasText(stubRepositoryRoot)) { - this.stubRepositoryRoot = ResourceResolver.resource(stubRepositoryRoot); - } - return this; - } - - public StubRunnerOptionsBuilder withStubsMode(StubRunnerProperties.StubsMode stubsMode) { - if (stubsMode == null) { - return this; - } - this.stubsMode = stubsMode; - return this; - } - - public StubRunnerOptionsBuilder withStubsMode(String stubsMode) { - if (stubsMode == null) { - return this; - } - this.stubsMode = StubRunnerProperties.StubsMode.valueOf(stubsMode); - return this; - } - - public StubRunnerOptionsBuilder withStubsClassifier(String stubsClassifier) { - this.stubsClassifier = stubsClassifier; - return this; - } - - public StubRunnerOptionsBuilder withPort(Integer port) { - String lastStub = this.stubs.peekLast(); - addPort(lastStub + DELIMITER + port); - return this; - } - - public StubRunnerOptionsBuilder withOptions(StubRunnerOptions options) { - this.minPortValue = options.minPortValue; - this.maxPortValue = options.maxPortValue; - this.stubRepositoryRoot = options.stubRepositoryRoot; - this.stubsMode = options.stubsMode; - this.stubsClassifier = options.stubsClassifier; - this.username = options.username; - this.password = options.password; - this.stubRunnerProxyOptions = options.getStubRunnerProxyOptions(); - this.stubsPerConsumer = options.isStubsPerConsumer(); - this.consumerName = options.getConsumerName(); - this.mappingsOutputFolder = options.getMappingsOutputFolder(); - this.stubConfigurations = options.dependencies != null ? options.dependencies : new ArrayList<>(); - this.stubIdsToPortMapping = options.stubIdsToPortMapping != null ? options.stubIdsToPortMapping - : new LinkedHashMap<>(); - this.deleteStubsAfterTest = options.isDeleteStubsAfterTest(); - this.generateStubs = options.isGenerateStubs(); - this.failOnNoStubs = options.isFailOnNoStubs(); - this.properties = options.getProperties(); - this.httpServerStubConfigurer = options.getHttpServerStubConfigurer(); - this.serverId = options.getServerId(); - return this; - } - - public StubRunnerOptionsBuilder withMappingsOutputFolder(String mappingsOutputFolder) { - this.mappingsOutputFolder = mappingsOutputFolder; - return this; - } - - public StubRunnerOptionsBuilder withDeleteStubsAfterTest(boolean deleteStubsAfterTest) { - this.deleteStubsAfterTest = deleteStubsAfterTest; - return this; - } - - public StubRunnerOptionsBuilder withGenerateStubs(boolean generateStubs) { - this.generateStubs = generateStubs; - return this; - } - - public StubRunnerOptionsBuilder withFailOnNoStubs(boolean failOnNoStubs) { - this.failOnNoStubs = failOnNoStubs; - return this; - } - - public StubRunnerOptionsBuilder withProperties(Map properties) { - this.properties = properties; - return this; - } - - public StubRunnerOptionsBuilder withHttpServerStubConfigurer(Class httpServerStubConfigurer) { - this.httpServerStubConfigurer = httpServerStubConfigurer; - return this; - } - - public StubRunnerOptionsBuilder withServerId(String serverId) { - this.serverId = serverId; - return this; - } - - public StubRunnerOptions build() { - return new StubRunnerOptions(this.minPortValue, this.maxPortValue, this.stubRepositoryRoot, this.stubsMode, - this.stubsClassifier, buildDependencies(), this.stubIdsToPortMapping, this.username, this.password, - this.stubRunnerProxyOptions, this.stubsPerConsumer, this.consumerName, this.mappingsOutputFolder, - this.deleteStubsAfterTest, this.generateStubs, this.failOnNoStubs, this.properties, - this.httpServerStubConfigurer, this.serverId); - } - - private Collection buildDependencies() { - List stubConfigurations = StubsParser.fromString(this.stubs, this.stubsClassifier); - this.stubConfigurations.addAll(stubConfigurations); - return this.stubConfigurations; - } - - private void addStub(List notations) { - for (String notation : notations) { - addStub(notation); - } - } - - private void addStub(String notation) { - if (StubsParser.hasPort(notation)) { - addPort(notation); - this.stubs.add(StubsParser.ivyFromStringWithPort(notation)); - } - else { - this.stubs.add(notation); - } - } - - private void addPort(String notation) { - putStubIdsToPortMapping(StubsParser.fromStringWithPort(notation)); - } - - private void putStubIdsToPortMapping(Map stubIdsToPortMapping) { - this.stubIdsToPortMapping.putAll(stubIdsToPortMapping); - } - - public StubRunnerOptionsBuilder withUsername(final String username) { - this.username = username; - return this; - } - - public StubRunnerOptionsBuilder withPassword(final String password) { - this.password = password; - return this; - } - - public StubRunnerOptionsBuilder withProxy(final String proxyHost, final int proxyPort) { - this.stubRunnerProxyOptions = new StubRunnerOptions.StubRunnerProxyOptions(proxyHost, proxyPort); - return this; - } - - public StubRunnerOptionsBuilder withStubPerConsumer(boolean stubPerConsumer) { - this.stubsPerConsumer = stubPerConsumer; - return this; - } - - public StubRunnerOptionsBuilder withConsumerName(String consumerName) { - this.consumerName = consumerName; - return this; - } - -} 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 deleted file mode 100644 index 6b9e437e6d..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerPropertyUtils.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.util.StringUtils; - -/** - * Reads property from system prop and from env var. - * - * @author Marcin Grzejszczak - * @since 2.0.0 - */ -public final class StubRunnerPropertyUtils { - - private static final Log log = LogFactory.getLog(StubRunnerPropertyUtils.class); - - private static final String STUBRUNNER_PROPERTIES = "stubrunner.properties"; - - static PropertyFetcher FETCHER = new PropertyFetcher(); - - private StubRunnerPropertyUtils() { - throw new IllegalStateException("Can't instantiate a utility class"); - } - - /** - * @param propName property name - * @return for Env vars takes the prop name, converts dots to underscores and applies - * upper case - */ - public static boolean isPropertySet(String propName) { - String value = getProperty(new HashMap<>(), propName); - return StringUtils.hasText(value) && Boolean.parseBoolean(value); - } - - /** - * @param options map of options - * @param propName property name - * @return For options, system props and env vars returns {@code true} when property - * is set - */ - public static boolean hasProperty(Map options, String propName) { - String value = getProperty(options, propName); - return StringUtils.hasText(value); - } - - /** - * @param options map of options - * @param propName property name - * @return Tries to pick a value from options, for Env vars takes the prop name, - * converts dots to underscores and applies upper case - */ - public static String getProperty(Map options, String propName) { - if (options != null && options.containsKey(propName)) { - String value = options.get(propName); - if (log.isTraceEnabled()) { - log.trace("Options map contains the prop [" + propName + "] with value [" + value + "]"); - } - return value; - } - return doGetProp(appendPrefixIfNecessary(propName)); - } - - private static String appendPrefixIfNecessary(String prop) { - if (prop.toLowerCase().startsWith("stubrunner")) { - return prop; - } - return STUBRUNNER_PROPERTIES + "." + prop; - } - - private static String doGetProp(String stubRunnerProp) { - String systemProp = FETCHER.systemProp(stubRunnerProp); - if (StringUtils.hasText(systemProp)) { - if (log.isTraceEnabled()) { - log.trace("System property [" + stubRunnerProp + "] has value [" + systemProp + "]"); - } - return systemProp; - } - String convertedEnvProp = stubRunnerProp.replaceAll("\\.", "_").replaceAll("-", "_").toUpperCase(); - String envVar = FETCHER.envVar(convertedEnvProp); - if (log.isTraceEnabled()) { - log.trace("Environment variable [" + convertedEnvProp + "] has value [" + envVar + "]"); - } - return envVar; - } - -} - -class PropertyFetcher { - - String systemProp(String prop) { - return System.getProperty(prop); - } - - String envVar(String prop) { - return System.getenv(prop); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunning.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunning.java deleted file mode 100644 index a6f07d2846..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunning.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.Closeable; - -/** - * Contract for running stubs. - * - * @author Marcin Grzejszczak - */ -public interface StubRunning extends Closeable, StubFinder { - - /** - * @return runs the stubs and returns the {@link RunningStubs}. If the stubs were - * already started then a cached version will be returned. - */ - RunningStubs runStubs(); - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubServer.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubServer.java deleted file mode 100644 index fc4982b0c2..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubServer.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Collection; -import java.util.Objects; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.spec.Contract; - -class StubServer { - - private static final Log log = LogFactory.getLog(StubServer.class); - - final StubConfiguration stubConfiguration; - - final Collection mappings; - - final Collection contracts; - - private final HttpServerStub httpServerStub; - - StubServer(StubConfiguration stubConfiguration, Collection mappings, Collection contracts, - HttpServerStub httpServerStub) { - this.stubConfiguration = stubConfiguration; - this.mappings = mappings; - this.httpServerStub = httpServerStub; - this.contracts = contracts; - } - - public StubServer start(HttpServerStubConfiguration configuration) { - this.httpServerStub.start(configuration); - return stubServer(); - } - - private StubServer stubServer() { - this.httpServerStub.registerMappings(this.mappings); - log.info("Started stub server for project [" + this.stubConfiguration.toColonSeparatedDependencyNotation() - + "] on port " + this.httpServerStub.port() + " with [" + this.mappings.size() + "] mappings"); - if (this.mappings.isEmpty() && getPort() != -1) { - log.warn( - "There are no HTTP mappings registered, if your contracts are not messaging based then something went wrong"); - } - return this; - } - - public boolean isRunning() { - return this.httpServerStub.isRunning(); - } - - public void stop() { - if (log.isDebugEnabled()) { - log.debug("Stopping the server at port [" + this.getPort() + "]"); - } - this.httpServerStub.stop(); - } - - public int getPort() { - if (this.httpServerStub.isRunning()) { - int httpsPort = this.httpServerStub.httpsPort(); - int httpPort = this.httpServerStub.port(); - if (log.isDebugEnabled()) { - log.debug("Ports for this server are https [" + httpsPort + "] and http [" + httpPort + "]"); - } - return httpsPort != -1 ? httpsPort : httpPort; - } - if (log.isDebugEnabled()) { - log.debug("The HTTP Server stub is not running... That means that the " - + "artifact is running a messaging module. Returning back -1 value of the port."); - } - return -1; - } - - private boolean hasHttps() { - int httpsPort = this.httpServerStub.httpsPort(); - return httpsPort != -1; - } - - public URL getStubUrl() { - try { - return new URL((hasHttps() ? "https:" : "http:") + "//localhost:" + getPort()); - } - catch (MalformedURLException e) { - throw new IllegalStateException("Cannot parse URL", e); - } - } - - public StubConfiguration getStubConfiguration() { - return this.stubConfiguration; - } - - public Collection getContracts() { - return this.contracts; - } - - String registeredMappings() { - return this.httpServerStub.registeredMappings(); - } - - HttpServerStub httpServerStub() { - return this.httpServerStub; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - StubServer that = (StubServer) o; - return Objects.equals(this.stubConfiguration, that.stubConfiguration) - && Objects.equals(this.contracts, that.contracts); - } - - @Override - public int hashCode() { - return Objects.hash(this.stubConfiguration, this.contracts); - } - - @Override - public String toString() { - return "StubServer{" + "stubConfiguration=" + this.stubConfiguration + ", mappingsSize=" + this.mappings.size() - + '}'; - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubTrigger.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubTrigger.java deleted file mode 100644 index a31eeb9928..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubTrigger.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.util.Collection; -import java.util.Map; - -/** - * Contract for triggering stub messages. - * - * @author Marcin Grzejszczak - */ -public interface StubTrigger { - - /** - * Triggers an event by a given label for a given {@code groupid:artifactid} notation. - * You can use only {@code artifactId} too. - * - * Feature related to messaging. - * @param ivyNotation ivy notation of a stub - * @param labelName name of the label to trigger - * @return true - if managed to run a trigger - */ - boolean trigger(String ivyNotation, String labelName); - - /** - * Triggers an event by a given label. - * - * Feature related to messaging. - * @param labelName name of the label to trigger - * @return true - if managed to run a trigger - */ - boolean trigger(String labelName); - - /** - * Triggers all possible events. - * - * Feature related to messaging. - * @return true - if managed to run a trigger - */ - boolean trigger(); - - /** - * Feature related to messaging. - * @return a mapping of ivy notation of a dependency to all the labels it has. - */ - Map> labels(); - -} 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 deleted file mode 100644 index abb3c892a1..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/TemporaryFileStorage.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Queue; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Stores all generated temporary folders with stubs. - * - * @author Marcin Grzejszczak - * @since 2.0.0 - */ -final class TemporaryFileStorage { - - private static final Log log = LogFactory.getLog(TemporaryFileStorage.class); - - private static final int TEMP_DIR_ATTEMPTS = 10000; - - /** - * There are problems with removal of stubs unpacked to a temporary folder. That's why - * we're creating a bounded in-memory storage of unpacked files and later we register - * a shutdown hook to remove all these files. - */ - private static final BlockingQueue TEMP_FILES_LOG = new LinkedBlockingQueue<>(20_000); - - private TemporaryFileStorage() { - throw new IllegalStateException("Can't instantiate a utility class"); - } - - static void add(File file) { - TEMP_FILES_LOG.offer(file); - } - - static Queue files() { - return TEMP_FILES_LOG; - } - - static void cleanup(boolean deleteStubsAfterTest) { - if (!deleteStubsAfterTest) { - log.info("Will not clear temporary files due to switch"); - return; - } - for (File file : TemporaryFileStorage.files()) { - try { - if (file.isDirectory()) { - Files.walkFileTree(file.toPath(), new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - if (log.isTraceEnabled()) { - log.trace("Removing file [" + file + "]"); - } - Files.delete(file); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { - if (log.isTraceEnabled()) { - log.trace("Removing dir [" + dir + "]"); - } - Files.delete(dir); - return FileVisitResult.CONTINUE; - } - }); - } - else { - Files.delete(file.toPath()); - } - } - catch (NoClassDefFoundError | IOException e) { - // Added NoClassDefFoundError cause sometimes it's visible in the builds - // this error is completely harmless - if (log.isTraceEnabled()) { - log.trace("Failed to remove temporary file", e); - } - } - TemporaryFileStorage.files().clear(); - } - } - - // taken from Guava - static File createTempDir(String tempDirPrefix) { - File baseDir = new File(System.getProperty("java.io.tmpdir")); - String baseName = tempDirPrefix + "-" + System.currentTimeMillis() + "-"; - for (int counter = 0; counter < TEMP_DIR_ATTEMPTS; counter++) { - File tempDir = new File(baseDir, baseName + counter); - if (tempDir.mkdir()) { - return tempDir; - } - } - throw new IllegalStateException("Failed to create directory within " + TEMP_DIR_ATTEMPTS + " attempts (tried " - + baseName + "0 to " + baseName + (TEMP_DIR_ATTEMPTS - 1) + ")"); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/ExceptionThrowingMessageVerifier.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/ExceptionThrowingMessageVerifier.java deleted file mode 100644 index d165e1ca24..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/ExceptionThrowingMessageVerifier.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2018-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.junit; - -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import org.springframework.cloud.contract.verifier.converter.YamlContract; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender; - -/** - * @author Olga Maciaszek-Sharma - * @since 2.1.0 - */ -class ExceptionThrowingMessageVerifier implements MessageVerifierSender, MessageVerifierReceiver { - - private static final String EXCEPTION_MESSAGE = "Please provide a custom MessageVerifier to use this feature"; - - @Override - public void send(Object message, String destination, YamlContract contract) { - throw new UnsupportedOperationException(EXCEPTION_MESSAGE); - } - - @Override - public Object receive(String destination, long timeout, TimeUnit timeUnit, YamlContract contract) { - throw new UnsupportedOperationException(EXCEPTION_MESSAGE); - } - - @Override - public Object receive(String destination, YamlContract contract) { - throw new UnsupportedOperationException(EXCEPTION_MESSAGE); - } - - @Override - public void send(Object payload, Map headers, String destination, YamlContract contract) { - throw new UnsupportedOperationException(EXCEPTION_MESSAGE); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/PortStubRunnerExtensionOptions.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/PortStubRunnerExtensionOptions.java deleted file mode 100644 index f5c78e6091..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/PortStubRunnerExtensionOptions.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2018-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.junit; - -/** - * @author Olga Maciaszek-Sharma - * @since 2.1.0 - */ -interface PortStubRunnerExtensionOptions { - - StubRunnerExtension withPort(Integer port); - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/PortStubRunnerRuleOptions.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/PortStubRunnerRuleOptions.java deleted file mode 100644 index c36ee6efa1..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/PortStubRunnerRuleOptions.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.junit; - -interface PortStubRunnerRuleOptions extends StubRunnerRuleOptions { - - /** - * Appends port to last added stub. - * @param port port at which the stub will be ran - * @return this - */ - StubRunnerRule withPort(Integer port); - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerExtension.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerExtension.java deleted file mode 100644 index 6c552c8ee1..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerExtension.java +++ /dev/null @@ -1,374 +0,0 @@ -/* - * Copyright 2018-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.junit; - -import java.io.IOException; -import java.net.URL; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.junit.jupiter.api.extension.AfterAllCallback; -import org.junit.jupiter.api.extension.AfterEachCallback; -import org.junit.jupiter.api.extension.BeforeAllCallback; -import org.junit.jupiter.api.extension.BeforeEachCallback; -import org.junit.jupiter.api.extension.ExtensionContext; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.stubrunner.BatchStubRunner; -import org.springframework.cloud.contract.stubrunner.BatchStubRunnerFactory; -import org.springframework.cloud.contract.stubrunner.HttpServerStubConfigurer; -import org.springframework.cloud.contract.stubrunner.RunningStubs; -import org.springframework.cloud.contract.stubrunner.StubConfiguration; -import org.springframework.cloud.contract.stubrunner.StubFinder; -import org.springframework.cloud.contract.stubrunner.StubNotFoundException; -import org.springframework.cloud.contract.stubrunner.StubRunnerOptions; -import org.springframework.cloud.contract.stubrunner.StubRunnerOptionsBuilder; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender; - -/** - * JUnit 5 extension that allows to download and run stubs. - * - * @author Olga Maciaszek-Sharma - * @since 2.1.0 - */ -public class StubRunnerExtension implements BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback, - StubFinder, StubRunnerExtensionOptions { - - private static final String DELIMITER = ":"; - - private static final String LATEST_VERSION = "+"; - - private static final Log LOG = LogFactory.getLog(StubRunnerExtension.class); - - StubRunnerExtension delegate = this; - - private AtomicBoolean beforeAllCalled = new AtomicBoolean(); - - private AtomicBoolean afterAllCalled = new AtomicBoolean(); - - private BatchStubRunner stubFinder; - - private StubRunnerOptionsBuilder stubRunnerOptionsBuilder = new StubRunnerOptionsBuilder( - StubRunnerOptions.fromSystemProps()); - - private MessageVerifierSender verifierSender = new ExceptionThrowingMessageVerifier(); - - private MessageVerifierReceiver verifierReceiver = new ExceptionThrowingMessageVerifier(); - - public StubRunnerExtension() { - } - - StubRunnerExtension(StubRunnerExtension delegate) { - this.delegate = delegate; - } - - @Override - public void afterAll(ExtensionContext extensionContext) { - try { - after(); - } - finally { - this.afterAllCalled.set(true); - } - } - - @Override - public void afterEach(ExtensionContext context) throws Exception { - if (extensionOverStaticField()) { - return; - } - after(); - } - - private boolean extensionOverStaticField() { - return this.afterAllCalled.get() || this.beforeAllCalled.get(); - } - - @Override - public void beforeAll(ExtensionContext extensionContext) { - try { - before(); - } - finally { - this.beforeAllCalled.set(true); - } - } - - @Override - public void beforeEach(ExtensionContext context) throws Exception { - if (extensionOverStaticField()) { - return; - } - before(); - } - - private void before() { - stubFinder(new BatchStubRunnerFactory(builder().build(), verifierSender()).buildBatchStubRunner()); - stubFinder().runStubs(); - } - - private void after() { - try { - stubFinder().close(); - } - catch (IOException exception) { - LOG.warn(exception.getMessage(), exception); - } - } - - @Override - public URL findStubUrl(String groupId, String artifactId) throws StubNotFoundException { - return stubFinder().findStubUrl(groupId, artifactId); - } - - @Override - public URL findStubUrl(String ivyNotation) throws StubNotFoundException { - return stubFinder().findStubUrl(ivyNotation); - } - - @Override - public RunningStubs findAllRunningStubs() { - return stubFinder().findAllRunningStubs(); - } - - @Override - public Map> getContracts() { - return stubFinder().getContracts(); - } - - @Override - public boolean trigger(String ivyNotation, String labelName) { - boolean result = stubFinder().trigger(ivyNotation, labelName); - if (!result) { - throw new IllegalStateException( - "Failed to trigger a message with notation [" + ivyNotation + "] and label [" + labelName + "]"); - } - return result; - } - - @Override - public boolean trigger(String labelName) { - boolean result = stubFinder().trigger(labelName); - if (!result) { - throw new IllegalStateException("Failed to trigger a message with label [" + labelName + "]"); - } - return result; - } - - @Override - public boolean trigger() { - boolean result = stubFinder().trigger(); - if (!result) { - throw new IllegalStateException("Failed to trigger a message"); - } - return result; - } - - @Override - public Map> labels() { - return stubFinder().labels(); - } - - @Override - public StubRunnerExtension messageVerifierSender(MessageVerifierSender messageVerifier) { - verifierSender(messageVerifier); - return this.delegate; - } - - @Override - public StubRunnerExtension messageVerifierReceiver(MessageVerifierReceiver messageVerifier) { - verifierReceiver(messageVerifier); - return this.delegate; - } - - @Override - public StubRunnerExtension options(StubRunnerOptions stubRunnerOptions) { - builder().withOptions(stubRunnerOptions); - return this.delegate; - } - - @Override - public StubRunnerExtension minPort(int minPort) { - builder().withMinPort(minPort); - return this.delegate; - } - - @Override - public StubRunnerExtension maxPort(int maxPort) { - builder().withMaxPort(maxPort); - return this.delegate; - } - - @Override - public StubRunnerExtension repoRoot(String repoRoot) { - builder().withStubRepositoryRoot(repoRoot); - return this.delegate; - } - - @Override - public StubRunnerExtension stubsMode(StubRunnerProperties.StubsMode stubsMode) { - builder().withStubsMode(stubsMode); - return this.delegate; - } - - @Override - public PortStubRunnerExtension downloadStub(String groupId, String artifactId, String version, String classifier) { - builder().withStubs(groupId + DELIMITER + artifactId + DELIMITER + version + DELIMITER + classifier); - return new PortStubRunnerExtension(this.delegate); - } - - @Override - public PortStubRunnerExtension downloadLatestStub(String groupId, String artifactId, String classifier) { - builder().withStubs(groupId + DELIMITER + artifactId + DELIMITER + LATEST_VERSION + DELIMITER + classifier); - return new PortStubRunnerExtension(this.delegate); - } - - @Override - public PortStubRunnerExtension downloadStub(String groupId, String artifactId, String version) { - builder().withStubs(groupId + DELIMITER + artifactId + DELIMITER + version); - return new PortStubRunnerExtension(this.delegate); - } - - @Override - public PortStubRunnerExtension downloadStub(String groupId, String artifactId) { - builder().withStubs(groupId + DELIMITER + artifactId); - return new PortStubRunnerExtension(this.delegate); - } - - @Override - public PortStubRunnerExtension downloadStub(String ivyNotation) { - builder().withStubs(ivyNotation); - return new PortStubRunnerExtension(this.delegate); - } - - @Override - public StubRunnerExtension downloadStubs(String... ivyNotations) { - builder().withStubs(Arrays.asList(ivyNotations)); - return new PortStubRunnerExtension(this.delegate); - } - - @Override - public StubRunnerExtension downloadStubs(List ivyNotations) { - builder().withStubs(ivyNotations); - return new PortStubRunnerExtension(this.delegate); - } - - @Override - public StubRunnerExtension withStubPerConsumer(boolean stubPerConsumer) { - builder().withStubPerConsumer(stubPerConsumer); - return new PortStubRunnerExtension(this.delegate); - } - - @Override - public StubRunnerExtension withConsumerName(String consumerName) { - builder().withConsumerName(consumerName); - return new PortStubRunnerExtension(this.delegate); - } - - @Override - public StubRunnerExtension withMappingsOutputFolder(String mappingsOutputFolder) { - builder().withMappingsOutputFolder(mappingsOutputFolder); - return new PortStubRunnerExtension(this.delegate); - } - - @Override - public StubRunnerExtension withDeleteStubsAfterTest(boolean deleteStubsAfterTest) { - builder().withDeleteStubsAfterTest(deleteStubsAfterTest); - return new PortStubRunnerExtension(this.delegate); - } - - @Override - public StubRunnerExtension withGenerateStubs(boolean generateStubs) { - builder().withGenerateStubs(generateStubs); - return new PortStubRunnerExtension(this.delegate); - } - - @Override - public StubRunnerExtension failOnNoStubs(boolean failOnNoStubs) { - builder().withFailOnNoStubs(failOnNoStubs); - return new PortStubRunnerExtension(this.delegate); - } - - @Override - public StubRunnerExtension withProperties(Map properties) { - builder().withProperties(properties); - return new PortStubRunnerExtension(this.delegate); - } - - @Override - public StubRunnerExtension withHttpServerStubConfigurer( - Class httpServerStubConfigurer) { - builder().withHttpServerStubConfigurer(httpServerStubConfigurer); - return new PortStubRunnerExtension(this.delegate); - } - - BatchStubRunner stubFinder() { - return this.delegate.stubFinder; - } - - void stubFinder(BatchStubRunner stubFinder) { - this.delegate.stubFinder = stubFinder; - } - - StubRunnerOptionsBuilder builder() { - return this.delegate.stubRunnerOptionsBuilder; - } - - MessageVerifierSender verifierSender() { - return this.delegate.verifierSender; - } - - MessageVerifierReceiver verifierReceiver() { - return this.delegate.verifierReceiver; - } - - void verifierSender(MessageVerifierSender verifier) { - this.delegate.verifierSender = verifier; - } - - void verifierReceiver(MessageVerifierReceiver verifier) { - this.delegate.verifierReceiver = verifier; - } - - /** - * Helper class with additional port, related methods once you pick a stub to - * download. - * - * @since 1.2.0 - */ - public static class PortStubRunnerExtension extends StubRunnerExtension implements PortStubRunnerExtensionOptions { - - PortStubRunnerExtension(StubRunnerExtension delegate) { - super(delegate); - } - - @Override - public StubRunnerExtension withPort(Integer port) { - builder().withPort(port); - return this.delegate; - } - - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerExtensionOptions.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerExtensionOptions.java deleted file mode 100644 index d37386154e..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerExtensionOptions.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright 2018-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.junit; - -import java.util.List; -import java.util.Map; - -import org.springframework.cloud.contract.stubrunner.HttpServerStubConfigurer; -import org.springframework.cloud.contract.stubrunner.StubRunnerOptions; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender; - -/** - * @author Olga Maciaszek-Sharma - * @since 2.1.0 - */ -interface StubRunnerExtensionOptions { - - /** - * Pass the {@link MessageVerifierSender} that this rule should use. If you don't pass - * anything a {@link ExceptionThrowingMessageVerifier} will be used. That means that - * an exception will be thrown whenever you try to do sth messaging related. - * @param messageVerifier message verifier implementation - * @return the stub runner extension - */ - StubRunnerExtension messageVerifierSender(MessageVerifierSender messageVerifier); - - /** - * Pass the {@link MessageVerifierReceiver} that this rule should use. If you don't - * pass anything a {@link ExceptionThrowingMessageVerifier} will be used. That means - * that an exception will be thrown whenever you try to do sth messaging related. - * @param messageVerifier message verifier implementation - * @return the stub runner extension - */ - StubRunnerExtension messageVerifierReceiver(MessageVerifierReceiver messageVerifier); - - /** - * Override all options. - * @param stubRunnerOptions options of Stub Runner - * @return the stub runner extension - * @see StubRunnerOptions - */ - StubRunnerExtension options(StubRunnerOptions stubRunnerOptions); - - /** - * @param minPort min value of port for WireMock server - * @return the stub runner extension - */ - StubRunnerExtension minPort(int minPort); - - /** - * @param maxPort max value of port for WireMock server - * @return the stub runner extension - */ - StubRunnerExtension maxPort(int maxPort); - - /** - * @param repoRoot String URI of repository containing stubs - * @return the stub runner extension - */ - StubRunnerExtension repoRoot(String repoRoot); - - /** - * @param stubsMode Stubs mode that should be used - * @return the stub runner extension - */ - StubRunnerExtension stubsMode(StubRunnerProperties.StubsMode stubsMode); - - /** - * @param groupId group id of the stub - * @param artifactId artifact id of the stub - * @param version version of the stub - * @param classifier classifier of the stub - * @return the stub runner extension with ports - */ - PortStubRunnerExtensionOptions downloadStub(String groupId, String artifactId, String version, String classifier); - - /** - * @param groupId group id of the stub - * @param artifactId artifact id of the stub - * @param classifier classifier of the stub - * @return the stub runner extension with ports - */ - PortStubRunnerExtensionOptions downloadLatestStub(String groupId, String artifactId, String classifier); - - /** - * @param groupId group id of the stub - * @param artifactId artifact id of the stub - * @param version version of the stub - * @return the stub runner extension with ports - */ - PortStubRunnerExtensionOptions downloadStub(String groupId, String artifactId, String version); - - /** - * @param groupId group id of the stub - * @param artifactId artifact id of the stub - * @return the stub runner extension with ports - */ - PortStubRunnerExtensionOptions downloadStub(String groupId, String artifactId); - - /** - * @param ivyNotation Ivy notation of a single stub to download. - * @return the stub runner extension with ports - */ - PortStubRunnerExtensionOptions downloadStub(String ivyNotation); - - /** - * @param ivyNotations Stubs to download in Ivy notations. - * @return the stub runner extension - */ - StubRunnerExtension downloadStubs(String... ivyNotations); - - /** - * @param ivyNotations Stubs to download in Ivy notations. - * @return the stub runner extension - */ - StubRunnerExtension downloadStubs(List ivyNotations); - - /** - * @param stubPerConsumer Allows stub per consumer. - * @return the stub runner extension - */ - StubRunnerExtension withStubPerConsumer(boolean stubPerConsumer); - - /** - * @param consumerName given consumer name - * @return the stub runner extension - */ - StubRunnerExtension withConsumerName(String consumerName); - - /** - * @param mappingsOutputFolder Allows setting the output folder for mappings - * @return the stub runner extension - */ - StubRunnerExtension withMappingsOutputFolder(String mappingsOutputFolder); - - /** - * @param deleteStubsAfterTest If set to {@code false} will NOT delete stubs from a - * temporary folder after running tests - * @return the stub runner extension - */ - StubRunnerExtension withDeleteStubsAfterTest(boolean deleteStubsAfterTest); - - /** - * @param generateStubs If set to {@code true} will NOT load generated stubs but will - * generate stubs from contract definitions at runtime. - * @return the rule - */ - StubRunnerExtension withGenerateStubs(boolean generateStubs); - - /** - * @param failOnNoStubs when enabled, this flag will tell stub runner to throw an - * exception when no stubs / contracts were found. - * @return the rule - */ - StubRunnerExtension failOnNoStubs(boolean failOnNoStubs); - - /** - * @param properties Map of properties that can be passed to custom - * {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder} - * @return the stub runner extension - */ - StubRunnerExtension withProperties(Map properties); - - /** - * @param httpServerStubConfigurer Configuration for an HTTP server stub - * @return the stub runner extension - */ - StubRunnerExtension withHttpServerStubConfigurer( - Class httpServerStubConfigurer); - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRule.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRule.java deleted file mode 100644 index 43eda0ddf5..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRule.java +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.junit; - -import java.net.URL; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import org.junit.rules.TestRule; -import org.junit.runner.Description; -import org.junit.runners.model.Statement; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.stubrunner.BatchStubRunner; -import org.springframework.cloud.contract.stubrunner.BatchStubRunnerFactory; -import org.springframework.cloud.contract.stubrunner.HttpServerStubConfigurer; -import org.springframework.cloud.contract.stubrunner.RunningStubs; -import org.springframework.cloud.contract.stubrunner.StubConfiguration; -import org.springframework.cloud.contract.stubrunner.StubFinder; -import org.springframework.cloud.contract.stubrunner.StubRunnerOptions; -import org.springframework.cloud.contract.stubrunner.StubRunnerOptionsBuilder; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender; - -/** - * JUnit class rule that allows you to download the provided stubs. - * - * @author Marcin Grzejszczak - */ -public class StubRunnerRule implements TestRule, StubFinder, StubRunnerRuleOptions { - - private static final String DELIMITER = ":"; - - private static final String LATEST_VERSION = "+"; - - StubRunnerOptionsBuilder stubRunnerOptionsBuilder = new StubRunnerOptionsBuilder( - StubRunnerOptions.fromSystemProps()); - - BatchStubRunner stubFinder; - - MessageVerifierSender verifierSender = new ExceptionThrowingMessageVerifier(); - - MessageVerifierReceiver verifierReceiver = new ExceptionThrowingMessageVerifier(); - - StubRunnerRule delegate = this; - - public StubRunnerRule() { - } - - StubRunnerRule(StubRunnerRule delegate) { - this.delegate = delegate; - } - - @Override - public Statement apply(final Statement base, Description description) { - return new Statement() { - @Override - public void evaluate() throws Throwable { - before(); - base.evaluate(); - StubRunnerRule.this.stubFinder().close(); - } - - private void before() { - stubFinder(new BatchStubRunnerFactory(builder().build(), verifierSender()).buildBatchStubRunner()); - StubRunnerRule.this.stubFinder().runStubs(); - } - }; - } - - @Override - public StubRunnerRule messageVerifierSender(MessageVerifierSender messageVerifier) { - verifier(messageVerifier); - return this.delegate; - } - - @Override - public StubRunnerRule messageVerifierReceiver(MessageVerifierReceiver messageVerifier) { - verifier(messageVerifier); - return this.delegate; - } - - @Override - public StubRunnerRule options(StubRunnerOptions stubRunnerOptions) { - builder().withOptions(stubRunnerOptions); - return this.delegate; - } - - @Override - public StubRunnerRule minPort(int minPort) { - builder().withMinPort(minPort); - return this.delegate; - } - - @Override - public StubRunnerRule maxPort(int maxPort) { - builder().withMaxPort(maxPort); - return this.delegate; - } - - @Override - public StubRunnerRule repoRoot(String repoRoot) { - builder().withStubRepositoryRoot(repoRoot); - return this.delegate; - } - - @Override - public StubRunnerRule stubsMode(StubRunnerProperties.StubsMode stubsMode) { - builder().withStubsMode(stubsMode); - return this.delegate; - } - - @Override - public PortStubRunnerRule downloadStub(String groupId, String artifactId, String version, String classifier) { - builder().withStubs(groupId + DELIMITER + artifactId + DELIMITER + version + DELIMITER + classifier); - return new PortStubRunnerRule(this.delegate); - } - - @Override - public PortStubRunnerRule downloadLatestStub(String groupId, String artifactId, String classifier) { - builder().withStubs(groupId + DELIMITER + artifactId + DELIMITER + LATEST_VERSION + DELIMITER + classifier); - return new PortStubRunnerRule(this.delegate); - } - - @Override - public PortStubRunnerRule downloadStub(String groupId, String artifactId, String version) { - builder().withStubs(groupId + DELIMITER + artifactId + DELIMITER + version); - return new PortStubRunnerRule(this.delegate); - } - - @Override - public PortStubRunnerRule downloadStub(String groupId, String artifactId) { - builder().withStubs(groupId + DELIMITER + artifactId); - return new PortStubRunnerRule(this.delegate); - } - - @Override - public PortStubRunnerRule downloadStub(String ivyNotation) { - builder().withStubs(ivyNotation); - return new PortStubRunnerRule(this.delegate); - } - - @Override - public StubRunnerRule downloadStubs(String... ivyNotations) { - builder().withStubs(Arrays.asList(ivyNotations)); - return new PortStubRunnerRule(this.delegate); - } - - @Override - public StubRunnerRule downloadStubs(List ivyNotations) { - builder().withStubs(ivyNotations); - return new PortStubRunnerRule(this.delegate); - } - - @Override - public StubRunnerRule withStubPerConsumer(boolean stubPerConsumer) { - builder().withStubPerConsumer(stubPerConsumer); - return this.delegate; - } - - @Override - public StubRunnerRule withConsumerName(String consumerName) { - builder().withConsumerName(consumerName); - return this.delegate; - } - - @Override - public StubRunnerRule withMappingsOutputFolder(String mappingsOutputFolder) { - builder().withMappingsOutputFolder(mappingsOutputFolder); - return this.delegate; - } - - @Override - public StubRunnerRule withDeleteStubsAfterTest(boolean deleteStubsAfterTest) { - builder().withDeleteStubsAfterTest(deleteStubsAfterTest); - return this.delegate; - } - - @Override - public StubRunnerRule withGenerateStubs(boolean generateStubs) { - builder().withGenerateStubs(generateStubs); - return this.delegate; - } - - @Override - public StubRunnerRule failOnNoStubs(boolean failOnNoStubs) { - builder().withFailOnNoStubs(failOnNoStubs); - return this.delegate; - } - - @Override - public StubRunnerRule withProperties(Map properties) { - builder().withProperties(properties); - return this.delegate; - } - - @Override - public StubRunnerRule withHttpServerStubConfigurer( - Class httpServerStubConfigurer) { - builder().withHttpServerStubConfigurer(httpServerStubConfigurer); - return this.delegate; - } - - @Override - public URL findStubUrl(String groupId, String artifactId) { - return this.stubFinder().findStubUrl(groupId, artifactId); - } - - @Override - public URL findStubUrl(String ivyNotation) { - return this.stubFinder().findStubUrl(ivyNotation); - } - - @Override - public RunningStubs findAllRunningStubs() { - return this.stubFinder().findAllRunningStubs(); - } - - @Override - public Map> getContracts() { - return this.stubFinder().getContracts(); - } - - @Override - public boolean trigger(String ivyNotation, String labelName) { - boolean result = this.stubFinder().trigger(ivyNotation, labelName); - if (!result) { - throw new IllegalStateException( - "Failed to trigger a message with notation [" + ivyNotation + "] and label [" + labelName + "]"); - } - return result; - } - - @Override - public boolean trigger(String labelName) { - boolean result = this.stubFinder().trigger(labelName); - if (!result) { - throw new IllegalStateException("Failed to trigger a message with label [" + labelName + "]"); - } - return result; - } - - @Override - public boolean trigger() { - boolean result = this.stubFinder().trigger(); - if (!result) { - throw new IllegalStateException("Failed to trigger a message"); - } - return result; - } - - @Override - public Map> labels() { - return this.stubFinder().labels(); - } - - BatchStubRunner stubFinder() { - return this.delegate.stubFinder; - } - - void stubFinder(BatchStubRunner stubFinder) { - this.delegate.stubFinder = stubFinder; - } - - MessageVerifierSender verifierSender() { - return this.delegate.verifierSender; - } - - MessageVerifierReceiver verifierReceiver() { - return this.delegate.verifierReceiver; - } - - void verifier(MessageVerifierSender verifier) { - this.delegate.verifierSender = verifier; - } - - void verifier(MessageVerifierReceiver verifier) { - this.delegate.verifierReceiver = verifier; - } - - StubRunnerOptionsBuilder builder() { - return this.delegate.stubRunnerOptionsBuilder; - } - - /** - * Helper class with additional port, related methods once you pick a stub to - * download. - * - * @since 1.2.0 - */ - public static class PortStubRunnerRule extends StubRunnerRule implements PortStubRunnerRuleOptions { - - PortStubRunnerRule(StubRunnerRule delegate) { - super(delegate); - } - - @Override - public StubRunnerRule withPort(Integer port) { - builder().withPort(port); - return this.delegate; - } - - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRuleOptions.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRuleOptions.java deleted file mode 100644 index fcaca8ece4..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRuleOptions.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.junit; - -import java.util.List; -import java.util.Map; - -import org.springframework.cloud.contract.stubrunner.HttpServerStubConfigurer; -import org.springframework.cloud.contract.stubrunner.StubRunnerOptions; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender; - -interface StubRunnerRuleOptions { - - /** - * Pass the {@link MessageVerifierSender} that this rule should use. If you don't pass - * anything a {@link ExceptionThrowingMessageVerifier} will be used. That means that - * an exception will be thrown whenever you try to do sth messaging related. - * @param messageVerifier message verifier implementation - * @return the rule - */ - StubRunnerRule messageVerifierSender(MessageVerifierSender messageVerifier); - - /** - * Pass the {@link MessageVerifierReceiver} that this rule should use. If you don't - * pass anything a {@link ExceptionThrowingMessageVerifier} will be used. That means - * that an exception will be thrown whenever you try to do sth messaging related. - * @param messageVerifier message verifier implementation - * @return the rule - */ - StubRunnerRule messageVerifierReceiver(MessageVerifierReceiver messageVerifier); - - /** - * Override all options. - * @param stubRunnerOptions options of Stub Runner - * @return the rule - * @see StubRunnerOptions - */ - StubRunnerRule options(StubRunnerOptions stubRunnerOptions); - - /** - * @param minPort min value of port for WireMock server - * @return the rule - */ - StubRunnerRule minPort(int minPort); - - /** - * @param maxPort max value of port for WireMock server - * @return the rule - */ - StubRunnerRule maxPort(int maxPort); - - /** - * @param repoRoot String URI of repository containing stubs - * @return the rule - */ - StubRunnerRule repoRoot(String repoRoot); - - /** - * @param stubsMode Stubs mode that should be used - * @return the rule - */ - StubRunnerRule stubsMode(StubRunnerProperties.StubsMode stubsMode); - - /** - * @param groupId group id of the stub - * @param artifactId artifact id of the stub - * @param version version of the stub - * @param classifier classifier of the stub - * @return the rule with port - */ - PortStubRunnerRuleOptions downloadStub(String groupId, String artifactId, String version, String classifier); - - /** - * @param groupId group id of the stub - * @param artifactId artifact id of the stub - * @param classifier classifier of the stub - * @return the rule with port - */ - PortStubRunnerRuleOptions downloadLatestStub(String groupId, String artifactId, String classifier); - - /** - * @param groupId group id of the stub - * @param artifactId artifact id of the stub - * @param version version of the stub - * @return the rule with port - */ - PortStubRunnerRuleOptions downloadStub(String groupId, String artifactId, String version); - - /** - * @param groupId group id of the stub - * @param artifactId artifact id of the stub - * @return the rule with port - */ - PortStubRunnerRuleOptions downloadStub(String groupId, String artifactId); - - /** - * @param ivyNotation Ivy notation of a single stub to download. - * @return the rule with port - */ - PortStubRunnerRuleOptions downloadStub(String ivyNotation); - - /** - * @param ivyNotations Stubs to download in Ivy notations. - * @return the rule - */ - StubRunnerRule downloadStubs(String... ivyNotations); - - /** - * @param ivyNotations Stubs to download in Ivy notations. - * @return the rule - */ - StubRunnerRule downloadStubs(List ivyNotations); - - /** - * @param stubPerConsumer Allows stub per consumer. - * @return the rule - */ - StubRunnerRule withStubPerConsumer(boolean stubPerConsumer); - - /** - * @param consumerName given consumer name - * @return the rule - */ - StubRunnerRule withConsumerName(String consumerName); - - /** - * @param mappingsOutputFolder Allows setting the output folder for mappings - * @return the rule - */ - StubRunnerRule withMappingsOutputFolder(String mappingsOutputFolder); - - /** - * @param deleteStubsAfterTest If set to {@code false} will NOT delete stubs from a - * temporary folder after running tests - * @return the rule - */ - StubRunnerRule withDeleteStubsAfterTest(boolean deleteStubsAfterTest); - - /** - * @param generateStubs If set to {@code true} will NOT load generated stubs but will - * generate stubs from contract definitions at runtime. - * @return the rule - */ - StubRunnerRule withGenerateStubs(boolean generateStubs); - - /** - * @param failOnNoStubs when enabled, this flag will tell stub runner to throw an - * exception when no stubs / contracts were found. - * @return the rule - */ - StubRunnerRule failOnNoStubs(boolean failOnNoStubs); - - /** - * @param properties Map of properties that can be passed to custom - * {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder} - * @return the rule - */ - StubRunnerRule withProperties(Map properties); - - /** - * @param httpServerStubConfigurer Configuration for an HTTP server stub - * @return the rule - */ - StubRunnerRule withHttpServerStubConfigurer(Class httpServerStubConfigurer); - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/provider/wiremock/StubRunnerWireMockTestExecutionListener.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/provider/wiremock/StubRunnerWireMockTestExecutionListener.java deleted file mode 100644 index ddfd8f6911..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/provider/wiremock/StubRunnerWireMockTestExecutionListener.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.provider.wiremock; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.TestContext; -import org.springframework.test.context.support.AbstractTestExecutionListener; - -/** - * Marks context to be restarted if at least one stub has a fixed port. - * - * @author Marcin Grzejszczak - * @since 1.2.6 - */ -public final class StubRunnerWireMockTestExecutionListener extends AbstractTestExecutionListener { - - private static final Log log = LogFactory.getLog(StubRunnerWireMockTestExecutionListener.class); - - @Override - public void afterTestClass(TestContext testContext) { - if (testContext.getTestClass().getAnnotationsByType(AutoConfigureStubRunner.class).length == 0) { - if (log.isDebugEnabled()) { - log.debug("No @AutoConfigureStubRunner annotation found on [" + testContext.getTestClass() - + "]. Skipping"); - } - return; - } - if (!WireMockHttpServerStub.SERVERS.isEmpty() - && WireMockHttpServerStub.SERVERS.values().stream().noneMatch(p -> p.random)) { - if (log.isWarnEnabled()) { - log.warn("You've used fixed ports for WireMock setup - " - + "will mark context as dirty. Please use random ports, as much " - + "as possible. Your tests will be faster and more reliable and this " - + "warning will go away"); - } - testContext.markApplicationContextDirty(DirtiesContext.HierarchyMode.EXHAUSTIVE); - } - // potential race condition - WireMockHttpServerStub.SERVERS.clear(); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStub.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStub.java deleted file mode 100644 index 8ca2223eb1..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStub.java +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.provider.wiremock; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import com.github.tomakehurst.wiremock.common.JsonException; -import com.github.tomakehurst.wiremock.common.Notifier; -import com.github.tomakehurst.wiremock.core.WireMockConfiguration; -import com.github.tomakehurst.wiremock.extension.Extension; -import com.github.tomakehurst.wiremock.security.ClientAuthenticator; -import com.github.tomakehurst.wiremock.security.NoClientAuthenticator; -import com.github.tomakehurst.wiremock.stubbing.StubMapping; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import wiremock.com.github.jknack.handlebars.Helper; - -import org.springframework.cloud.contract.stubrunner.HttpServerStub; -import org.springframework.cloud.contract.stubrunner.HttpServerStubConfiguration; -import org.springframework.cloud.contract.stubrunner.HttpServerStubConfigurer; -import org.springframework.cloud.contract.verifier.builder.handlebars.HandlebarsEscapeHelper; -import org.springframework.cloud.contract.verifier.builder.handlebars.HandlebarsJsonPathHelper; -import org.springframework.cloud.contract.verifier.dsl.wiremock.DefaultResponseTransformer; -import org.springframework.cloud.contract.verifier.dsl.wiremock.SpringCloudContractRequestMatcher; -import org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockExtensions; -import org.springframework.cloud.contract.wiremock.WireMockSpring; -import org.springframework.core.io.support.SpringFactoriesLoader; -import org.springframework.util.ClassUtils; -import org.springframework.util.StreamUtils; -import org.springframework.util.StringUtils; - -/** - * Abstraction over WireMock as a HTTP Server Stub. - * - * @author Marcin Grzejszczak - * @since 1.1.0 - */ -public class WireMockHttpServerStub implements HttpServerStub { - - static final Map SERVERS = new ConcurrentHashMap<>(); - - private static final Log log = LogFactory.getLog(WireMockHttpServerStub.class); - - private static final int INVALID_PORT = -1; - - private WireMockServer wireMockServer; - - private boolean https = false; - - private WireMockConfiguration wireMockConfiguration; - - private WireMockConfiguration config() { - if (ClassUtils.isPresent("org.springframework.cloud.contract.wiremock.WireMockSpring", null)) { - return WireMockSpring.options().extensions(responseTransformers()); - } - return new WireMockConfiguration().extensions(responseTransformers()); - } - - private Extension[] responseTransformers() { - List wireMockExtensions = SpringFactoriesLoader.loadFactories(WireMockExtensions.class, - null); - List extensions = new ArrayList<>(); - if (!wireMockExtensions.isEmpty()) { - for (WireMockExtensions wireMockExtension : wireMockExtensions) { - extensions.addAll(wireMockExtension.extensions()); - } - } - else { - extensions.addAll(Arrays.asList(new DefaultResponseTransformer(false, helpers()), - new SpringCloudContractRequestMatcher())); - } - return extensions.toArray(new Extension[extensions.size()]); - } - - private Map> helpers() { - Map> helpers = new HashMap<>(); - helpers.put(HandlebarsJsonPathHelper.NAME, new HandlebarsJsonPathHelper()); - helpers.put(HandlebarsEscapeHelper.NAME, new HandlebarsEscapeHelper()); - return helpers; - } - - @Override - public int port() { - return isRunning() ? (this.https ? this.wireMockServer.httpsPort() : this.wireMockServer.port()) : INVALID_PORT; - } - - @Override - public boolean isRunning() { - return this.wireMockServer != null && this.wireMockServer.isRunning(); - } - - @Override - public HttpServerStub start(HttpServerStubConfiguration configuration) { - if (isRunning()) { - if (log.isTraceEnabled()) { - log.trace("The server is already running at port [" + port() + "]"); - } - return this; - } - int port = configuration.port; - WireMockConfiguration wireMockConfiguration = config().port(port).notifier(new Slf4jNotifier(true)); - if (configuration.configurer.isAccepted(wireMockConfiguration)) { - @SuppressWarnings("unchecked") - HttpServerStubConfigurer configurer = configuration.configurer; - wireMockConfiguration = configurer.configure(wireMockConfiguration, configuration); - } - this.wireMockConfiguration = wireMockConfiguration; - this.https = wireMockConfiguration.httpsSettings().enabled(); - port = this.https ? wireMockConfiguration.httpsSettings().port() : wireMockConfiguration.portNumber(); - this.wireMockServer = new WireMockServer(wireMockConfiguration); - this.wireMockServer.start(); - if (log.isDebugEnabled()) { - log.debug("For " + configuration.toColonSeparatedDependencyNotation() + " Started WireMock at [" - + (this.https ? "https" : "http") + "] port [" + port + "]"); - } - cacheStubServer(configuration.randomPort, port); - return this; - } - - @Override - public int httpsPort() { - return this.https ? port() : INVALID_PORT; - } - - @Override - public HttpServerStub reset() { - this.wireMockServer.resetAll(); - return this; - } - - private void cacheStubServer(boolean random, int port) { - SERVERS.put(this, new PortAndMappings(random, port, new ArrayList<>())); - } - - @Override - public HttpServerStub stop() { - if (!isRunning()) { - if (log.isTraceEnabled()) { - log.trace("Trying to stop a non started server!"); - } - return this; - } - this.wireMockServer.stop(); - return this; - } - - @Override - public HttpServerStub registerMappings(Collection stubFiles) { - if (!isRunning()) { - throw new IllegalStateException("Server not started!"); - } - registerStubMappings(stubFiles); - return this; - } - - @Override - public String registeredMappings() { - Collection mappings = new ArrayList<>(); - for (StubMapping stubMapping : this.wireMockServer.getStubMappings()) { - mappings.add(stubMapping.toString()); - } - return jsonArrayOfMappings(mappings); - } - - private String jsonArrayOfMappings(Collection mappings) { - return "[" + StringUtils.collectionToDelimitedString(mappings, ",\n") + "]"; - } - - @Override - public boolean isAccepted(File file) { - return file.getName().endsWith(".json") && validMapping(file); - } - - private boolean validMapping(File file) { - try { - getMapping(file); - return true; - } - catch (IllegalStateException e) { - return false; - } - } - - StubMapping getMapping(File file) { - try (InputStream stream = Files.newInputStream(file.toPath())) { - return StubMapping.buildFrom(StreamUtils.copyToString(stream, Charset.forName("UTF-8"))); - } - catch (IOException | JsonException e) { - throw new IllegalStateException("Cannot read file", e); - } - } - - private void registerStubMappings(Collection stubFiles) { - WireMock wireMock = wireMock(); - registerDefaultHealthChecks(wireMock); - registerStubs(stubFiles, wireMock); - } - - private WireMock wireMock() { - String scheme = this.https ? "https" : "http"; - String host = "localhost"; - int port = port(); - String urlPathPrefix = ""; - String hostHeader = ""; - String proxyHost = this.wireMockConfiguration.proxyHostHeader(); - int proxyPort = this.wireMockConfiguration.proxyVia().port(); - ClientAuthenticator authenticator = NoClientAuthenticator.noClientAuthenticator(); - return new WireMock(scheme, host, port, urlPathPrefix, hostHeader, proxyHost, proxyPort, authenticator); - } - - private void registerDefaultHealthChecks(WireMock wireMock) { - registerHealthCheck(wireMock, "/ping"); - registerHealthCheck(wireMock, "/health"); - } - - private void registerStubs(Collection sortedMappings, WireMock wireMock) { - List stubMappings = new ArrayList<>(); - for (File mappingDescriptor : sortedMappings) { - try { - stubMappings.add(registerDescriptor(wireMock, mappingDescriptor)); - if (log.isDebugEnabled()) { - log.debug("Registered stub mappings from [" + mappingDescriptor + "]"); - } - } - catch (Exception e) { - if (log.isDebugEnabled()) { - log.debug("Failed to register the stub mapping [" + mappingDescriptor + "]", e); - } - } - } - PortAndMappings portAndMappings = SERVERS.get(this); - SERVERS.put(this, new PortAndMappings(portAndMappings.random, portAndMappings.port, stubMappings)); - } - - private StubMapping registerDescriptor(WireMock wireMock, File mappingDescriptor) { - StubMapping mapping = getMapping(mappingDescriptor); - wireMock.register(mapping); - return mapping; - } - - private void registerHealthCheck(WireMock wireMock, String url) { - registerHealthCheck(wireMock, url, "OK"); - } - - private void registerHealthCheck(WireMock wireMock, String url, String body) { - wireMock.register( - WireMock.get(WireMock.urlEqualTo(url)).willReturn(WireMock.aResponse().withBody(body).withStatus(200))); - } - - static class Slf4jNotifier implements Notifier { - - private static final Logger log = LoggerFactory.getLogger("WireMock"); - - private final boolean verbose; - - Slf4jNotifier(boolean verbose) { - this.verbose = verbose; - } - - @Override - public void info(String message) { - if (verbose) { - log.info(message); - } - } - - @Override - public void error(String message) { - log.error(message); - } - - @Override - public void error(String message, Throwable t) { - log.error(message, t); - } - - } - -} - -class PortAndMappings { - - final boolean random; - - final Integer port; - - final List mappings; - - PortAndMappings(boolean random, Integer port, List mappings) { - this.random = random; - this.port = port; - this.mappings = mappings; - } - - @Override - public String toString() { - return "PortAndMappings{" + "random=" + this.random + ", port=" + this.port + ", mappings=" + this.mappings - + '}'; - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStubConfigurer.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStubConfigurer.java deleted file mode 100644 index 3fe9e0af1f..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStubConfigurer.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.provider.wiremock; - -import com.github.tomakehurst.wiremock.core.WireMockConfiguration; - -import org.springframework.cloud.contract.stubrunner.HttpServerStubConfigurer; - -/** - * Typed implementation of {@link HttpServerStubConfigurer} for WireMock's - * {@link WireMockConfiguration}. - * - * @author Marcin Grzejszczak - * @since 2.1.0 - */ -public class WireMockHttpServerStubConfigurer implements HttpServerStubConfigurer { - - @Override - public boolean isAccepted(Object httpStubConfiguration) { - return httpStubConfiguration instanceof WireMockConfiguration; - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/EnableStubRunnerServer.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/EnableStubRunnerServer.java deleted file mode 100644 index ea97c7ca49..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/EnableStubRunnerServer.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.server; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration; -import org.springframework.context.annotation.Import; - -/** - * Annotation to enable a Stub runner server. - * @author Dave Syer - * @author Tim Ysewyn - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Inherited -@Import({ HttpStubsController.class, StubRunnerConfiguration.class, StubRunnerServerConfiguration.class }) -public @interface EnableStubRunnerServer { - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/HttpStubsController.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/HttpStubsController.java deleted file mode 100644 index d7e29b1654..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/HttpStubsController.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.server; - -import java.util.Map; - -import org.springframework.cloud.contract.stubrunner.StubRunning; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * @author Marcin Grzejszczak - */ -@RestController -@RequestMapping(value = "/stubs", produces = MediaType.APPLICATION_JSON_VALUE) -public class HttpStubsController { - - private final StubRunning stubRunning; - - public HttpStubsController(StubRunning stubRunning) { - this.stubRunning = stubRunning; - } - - @GetMapping - public Map stubs() { - return this.stubRunning.runStubs().toIvyToPortMapping(); - } - - @GetMapping(path = "/{ivy:.*}") - public ResponseEntity consumer(@PathVariable String ivy) { - Integer port = this.stubRunning.runStubs().getPort(ivy); - if (port != null) { - return ResponseEntity.ok(port); - } - return new ResponseEntity<>(HttpStatus.NOT_FOUND); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/StubRunnerBoot.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/StubRunnerBoot.java deleted file mode 100644 index 9ee94e8a3e..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/StubRunnerBoot.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.server; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.stream.config.BindingServiceConfiguration; - -/** - * @author Marcin Grzejszczak - */ -@SpringBootApplication -@EnableStubRunnerServer -@AutoConfigureBefore(BindingServiceConfiguration.class) -public class StubRunnerBoot { - - public static void main(String[] args) { - SpringApplication.run(StubRunnerBoot.class, args); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/StubRunnerServerConfiguration.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/StubRunnerServerConfiguration.java deleted file mode 100644 index 1bca861356..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/StubRunnerServerConfiguration.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.server; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cloud.contract.verifier.messaging.boot.AutoConfigureMessageVerifier; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; - -/** - * @author Marcin Grzejszczak - * @author Tim Ysewyn - */ -@Configuration(proxyBeanMethods = false) -class StubRunnerServerConfiguration { - - @ConditionalOnProperty(name = "stubrunner.messaging.enabled", havingValue = "true", matchIfMissing = true) - @AutoConfigureMessageVerifier - @Import({ TriggerController.class }) - static class StubRunnerMessagingAutoConfiguration { - - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/TriggerController.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/TriggerController.java deleted file mode 100644 index aeb1dadf42..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/server/TriggerController.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.server; - -import java.util.Collection; -import java.util.Collections; -import java.util.Map; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cloud.contract.stubrunner.StubFinder; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * @author Marcin Grzejszczak - */ -@RestController -@RequestMapping(value = "/triggers", produces = MediaType.APPLICATION_JSON_VALUE) -public class TriggerController { - - private final StubFinder stubFinder; - - @Autowired - public TriggerController(StubFinder stubFinder) { - this.stubFinder = stubFinder; - } - - @PostMapping("/{label:.*}") - public ResponseEntity>> trigger(@PathVariable String label) { - try { - this.stubFinder.trigger(label); - return ResponseEntity.ok().body(Collections.>emptyMap()); - } - catch (Exception e) { - throw new RuntimeException("Exception occurred while trying to return [" + label - + "] label. \n\nAvailable labels are [" + this.stubFinder.labels() + " ]", e); - } - } - - @PostMapping("/{ivyNotation:.*}/{label:.*}") - public ResponseEntity>> triggerByArtifact(@PathVariable String ivyNotation, - @PathVariable String label) { - try { - this.stubFinder.trigger(ivyNotation, label); - return ResponseEntity.ok().body(Collections.>emptyMap()); - } - catch (Exception e) { - throw new RuntimeException("Exception occurred while trying to return [" + label - + "] label. \n\nAvailable labels are [" + this.stubFinder.labels() + " ]", e); - } - } - - @GetMapping - public Map> labels() { - return this.stubFinder.labels(); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/AutoConfigureStubRunner.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/AutoConfigureStubRunner.java deleted file mode 100644 index e5ccb0770f..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/AutoConfigureStubRunner.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.boot.autoconfigure.ImportAutoConfiguration; -import org.springframework.boot.test.autoconfigure.properties.PropertyMapping; -import org.springframework.boot.test.autoconfigure.properties.SkipPropertyMapping; -import org.springframework.cloud.contract.stubrunner.HttpServerStubConfigurer; -import org.springframework.cloud.contract.stubrunner.HttpServerStubConfigurer.NoOpHttpServerStubConfigurer; -import org.springframework.cloud.contract.verifier.messaging.boot.AutoConfigureMessageVerifier; - -/** - * @author Dave Syer - * - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@ImportAutoConfiguration -@AutoConfigureMessageVerifier -@PropertyMapping(value = "stubrunner", skip = SkipPropertyMapping.ON_DEFAULT_VALUE) -public @interface AutoConfigureStubRunner { - - /** - * @return Min value of a port for the automatically started WireMock server. - */ - int minPort() default 10000; - - /** - * @return Max value of a port for the automatically started WireMock server. - */ - int maxPort() default 15000; - - /** - * @return The repository root to use (where the stubs should be downloaded from). - */ - String repositoryRoot() default ""; - - /** - * @return The ids of the stubs to run in "ivy" notation - * ([groupId]:artifactId[:version][:classifier][:port]). {@code groupId}, - * {@code version}, {@code classifier} and {@code port} can be optional. - */ - String[] ids() default {}; - - /** - * @return The classifier to use by default in ivy co-ordinates for a stub. - */ - String classifier() default "stubs"; - - /** - * On the producer side the consumers can have a folder that contains contracts - * related only to them. By setting the flag to {@code true} we no longer register all - * stubs but only those that correspond to the consumer application's name. In other - * words we'll scan the path of every stub and if it contains the name of the consumer - * in the path only then will it get registered. - * - * Let's look at this example. Let's assume that we have a producer called {@code foo} - * and two consumers {@code baz} and {@code bar}. On the {@code foo} producer side the - * contracts would look like this - * {@code src/test/resources/contracts/baz-service/some/contracts/...} and - * {@code src/test/resources/contracts/bar-service/some/contracts/...}. - * - * Then when the consumer with {@code spring.application.name} or the - * {@link AutoConfigureStubRunner#consumerName()} annotation parameter set to - * {@code baz-service} will define the test setup as follows - * {@code @AutoConfigureStubRunner(ids = "com.example:foo:+:stubs:8095", stubsPerConsumer=true)} - * then only the stubs registered under - * {@code src/test/resources/contracts/baz-service/some/contracts/...} will get - * registered and those under - * {@code src/test/resources/contracts/bar-service/some/contracts/...} will get - * ignored. - * - * @see
issue 224 - * @return {@code true} to turn on the feature - */ - boolean stubsPerConsumer() default false; - - /** - * You can override the default {@code spring.application.name} of this field by - * setting a value to this parameter. - * - * @see issue 224 - * @return name of this application - */ - String consumerName() default ""; - - /** - * For debugging purposes you can output the registered mappings to a given folder. - * Each HTTP server stub will have its own subfolder where all the mappings will get - * stored. - * - * @see issue 355 - * @return where the mappings output should be stored - */ - String mappingsOutputFolder() default ""; - - /** - * The way stubs should be found and registered. Defaults to - * {@link StubRunnerProperties.StubsMode#CLASSPATH}. - * @return the type of stubs mode - */ - StubRunnerProperties.StubsMode stubsMode() default StubRunnerProperties.StubsMode.CLASSPATH; - - /** - * Properties in form {@literal key=value}. - * @return the properties to add - */ - String[] properties() default {}; - - /** - * @return If set to {@code false} will NOT delete stubs from a temporary folder after - * running tests - */ - boolean deleteStubsAfterTest() default true; - - /** - * @return When enabled, this flag will tell stub runner to not load the generated - * stubs, but convert the found contracts at runtime to a stub format and run those - * stubs. - */ - boolean generateStubs() default false; - - /** - * @return when enabled, this flag will tell stub runner to throw an exception when no - * stubs / contracts were found. - */ - boolean failOnNoStubs() default true; - - /** - * Configuration for an HTTP server stub. - * @return class that allows to perform additional HTTP server stub configuration - */ - Class httpServerStubConfigurer() default NoOpHttpServerStubConfigurer.class; - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfiguration.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfiguration.java deleted file mode 100644 index 8ac92d0330..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfiguration.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.contract.stubrunner.BatchStubRunner; -import org.springframework.cloud.contract.stubrunner.BatchStubRunnerFactory; -import org.springframework.cloud.contract.stubrunner.RunningStubs; -import org.springframework.cloud.contract.stubrunner.StubConfiguration; -import org.springframework.cloud.contract.stubrunner.StubDownloaderBuilderProvider; -import org.springframework.cloud.contract.stubrunner.StubRunnerOptions; -import org.springframework.cloud.contract.stubrunner.StubRunnerOptionsBuilder; -import org.springframework.cloud.contract.verifier.converter.YamlContract; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender; -import org.springframework.cloud.contract.verifier.messaging.noop.NoOpStubMessages; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.env.MapPropertySource; -import org.springframework.core.env.MutablePropertySources; -import org.springframework.util.StringUtils; - -/** - * Configuration that initializes a {@link BatchStubRunner} that runs - * {@link org.springframework.cloud.contract.stubrunner.StubRunner} instance for each - * stub. - * - * @author Marcin Grzejszczak - * @author Eddú Meléndez - */ -@Configuration(proxyBeanMethods = false) -@EnableConfigurationProperties(StubRunnerProperties.class) -@ConditionalOnMissingBean(type = "org.springframework.cloud.contract.wiremock.WiremockServerConfiguration") -@Import(StubRunnerPortBeanPostProcessor.class) -public class StubRunnerConfiguration { - - static final String STUBRUNNER_PREFIX = "stubrunner.runningstubs"; - - private StubDownloaderBuilderProvider provider = new StubDownloaderBuilderProvider(); - - @Autowired - private ConfigurableEnvironment environment; - - /** - * Bean that initializes stub runners, runs them and on shutdown closes them. Upon its - * instantiation JAR with stubs is downloaded and unpacked to a temporary folder and - * WireMock server are started for each of those stubs - * @param beanFactory bean factory - * @return the batch stub runner bean - */ - @Bean - public BatchStubRunner batchStubRunner(BeanFactory beanFactory) { - StubRunnerProperties props = beanFactory.getBean(StubRunnerProperties.class); - StubRunnerOptionsBuilder builder = builder(props); - if (props.getProxyHost() != null) { - builder.withProxy(props.getProxyHost(), props.getProxyPort()); - } - StubRunnerOptions stubRunnerOptions = stubRunnerOptions(builder); - BatchStubRunner batchStubRunner = new BatchStubRunnerFactory(stubRunnerOptions, - this.provider.get(stubRunnerOptions), new LazyMessageVerifier(beanFactory)).buildBatchStubRunner(); - // TODO: Consider running it in a separate thread - RunningStubs runningStubs = batchStubRunner.runStubs(); - registerPort(runningStubs); - return batchStubRunner; - } - - private StubRunnerOptions stubRunnerOptions(StubRunnerOptionsBuilder builder) { - return builder.build(); - } - - @Bean - public BeanPostProcessor batchStubRunnerBeanPostProcessor(BatchStubRunner runner) { - return new BeanPostProcessor() { - }; - } - - private StubRunnerOptionsBuilder builder(StubRunnerProperties props) { - return new StubRunnerOptionsBuilder() - .withMinMaxPort(Integer.valueOf(resolvePlaceholder(props.getMinPort(), props.getMinPort())), - Integer.valueOf(resolvePlaceholder(props.getMaxPort(), props.getMaxPort()))) - .withStubRepositoryRoot(props.getRepositoryRoot()) - .withStubsMode(resolvePlaceholder(props.getStubsMode())) - .withStubsClassifier(resolvePlaceholder(props.getClassifier())) - .withStubs(resolvePlaceholder(props.getIds())).withUsername(resolvePlaceholder(props.getUsername())) - .withPassword(resolvePlaceholder(props.getPassword())) - .withStubPerConsumer(Boolean.parseBoolean(resolvePlaceholder(props.isStubsPerConsumer()))) - .withConsumerName(consumerName(props)) - .withMappingsOutputFolder(resolvePlaceholder(props.getMappingsOutputFolder())) - .withDeleteStubsAfterTest(Boolean.parseBoolean(resolvePlaceholder(props.isDeleteStubsAfterTest()))) - .withGenerateStubs(Boolean.parseBoolean(resolvePlaceholder(props.isGenerateStubs()))) - .withProperties(props.getProperties()).withHttpServerStubConfigurer(props.getHttpServerStubConfigurer()) - .withServerId(resolvePlaceholder(props.getServerId())).withFailOnNoStubs(props.isFailOnNoStubs()); - } - - private String[] resolvePlaceholder(String[] string) { - return Arrays.stream(string).map(this::resolvePlaceholder).toArray(String[]::new); - } - - private String resolvePlaceholder(Object string) { - return resolvePlaceholder(string, null); - } - - private String resolvePlaceholder(Object string, Object defaultValue) { - if (string == null) { - return defaultValue != null ? defaultValue.toString() : null; - } - return this.environment.resolvePlaceholders(string.toString()); - } - - private String consumerName(StubRunnerProperties props) { - if (StringUtils.hasText(props.getConsumerName())) { - return resolvePlaceholder(props.getConsumerName()); - } - return this.environment.getProperty("spring.application.name"); - } - - private void registerPort(RunningStubs runStubs) { - MutablePropertySources propertySources = this.environment.getPropertySources(); - if (!propertySources.contains(STUBRUNNER_PREFIX)) { - propertySources.addFirst(new MapPropertySource(STUBRUNNER_PREFIX, new HashMap<>())); - } - Map source = ((MapPropertySource) propertySources.get(STUBRUNNER_PREFIX)).getSource(); - for (Map.Entry entry : runStubs.validNamesAndPorts().entrySet()) { - source.put(STUBRUNNER_PREFIX + "." + entry.getKey().getArtifactId() + ".port", entry.getValue()); - // there are projects where artifact id is the same, what differs is the group - // id - source.put(STUBRUNNER_PREFIX + "." + entry.getKey().getGroupId() + "." + entry.getKey().getArtifactId() - + ".port", entry.getValue()); - } - } - -} - -@SuppressWarnings("unchecked") -class LazyMessageVerifier implements MessageVerifierSender, MessageVerifierReceiver { - - private MessageVerifierSender messageVerifierSender; - - private MessageVerifierReceiver messageVerifierReceiver; - - private final BeanFactory beanFactory; - - LazyMessageVerifier(BeanFactory beanFactory) { - this.beanFactory = beanFactory; - } - - private MessageVerifierSender messageVerifierSender() { - if (this.messageVerifierSender == null) { - this.messageVerifierSender = this.beanFactory.getBeanProvider(MessageVerifierSender.class) - .getIfAvailable(NoOpStubMessages::new); - } - return this.messageVerifierSender; - } - - private MessageVerifierReceiver messageVerifierReceiver() { - if (this.messageVerifierReceiver == null) { - this.messageVerifierReceiver = this.beanFactory.getBeanProvider(MessageVerifierReceiver.class) - .getIfAvailable(NoOpStubMessages::new); - } - return this.messageVerifierReceiver; - } - - @Override - public void send(Object message, String destination, YamlContract contract) { - messageVerifierSender().send(message, destination, contract); - } - - @Override - public Object receive(String destination, long timeout, TimeUnit timeUnit, YamlContract contract) { - return messageVerifierReceiver().receive(destination, timeout, timeUnit, contract); - } - - @Override - public Object receive(String destination, YamlContract contract) { - return messageVerifierReceiver().receive(destination, contract); - } - - @Override - public void send(Object payload, Map headers, String destination, YamlContract contract) { - messageVerifierSender().send(payload, headers, destination, contract); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/StubRunnerPort.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/StubRunnerPort.java deleted file mode 100644 index 7d530825b0..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/StubRunnerPort.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * The annotated field with this annotation will have the port of a running stub injected. - * - * @author Marcin Grzejszczak - * @since 2.0.0 - */ -@Target({ ElementType.FIELD }) -@Retention(RetentionPolicy.RUNTIME) -@Documented -public @interface StubRunnerPort { - - /** - * @return the {@code artifactid} or {@code groupid:artifactid} notation of the - * started stub. - */ - String value(); - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/StubRunnerPortBeanPostProcessor.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/StubRunnerPortBeanPostProcessor.java deleted file mode 100644 index 70d01fb32b..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/StubRunnerPortBeanPostProcessor.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring; - -import java.lang.reflect.Field; - -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.core.env.Environment; -import org.springframework.util.ReflectionUtils; - -/** - * Injects {@link StubRunnerPort} ports into fields. - * - * @author Marcin Grzejszczak - * @since 2.0.0 - */ -class StubRunnerPortBeanPostProcessor implements BeanPostProcessor { - - private final Environment environment; - - StubRunnerPortBeanPostProcessor(Environment environment) { - this.environment = environment; - } - - @Override - public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { - injectStubRunnerPort(bean); - return bean; - } - - private void injectStubRunnerPort(Object bean) { - Class clazz = bean.getClass(); - ReflectionUtils.FieldCallback fieldCallback = new StubRunnerPortFieldCallback(this.environment, bean); - ReflectionUtils.doWithFields(clazz, fieldCallback); - } - -} - -class StubRunnerPortFieldCallback implements ReflectionUtils.FieldCallback { - - private final Environment environment; - - private final Object bean; - - StubRunnerPortFieldCallback(Environment environment, Object bean) { - this.environment = environment; - this.bean = bean; - } - - @Override - public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { - if (!field.isAnnotationPresent(StubRunnerPort.class)) { - return; - } - ReflectionUtils.makeAccessible(field); - String stub = field.getDeclaredAnnotation(StubRunnerPort.class).value(); - Integer port = this.environment.getProperty( - StubRunnerConfiguration.STUBRUNNER_PREFIX + "." + stub.replace(":", ".") + ".port", Integer.class); - if (port != null) { - field.set(this.bean, port); - } - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/StubRunnerProperties.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/StubRunnerProperties.java deleted file mode 100644 index 5571903351..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/StubRunnerProperties.java +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.cloud.contract.stubrunner.HttpServerStubConfigurer; -import org.springframework.cloud.contract.stubrunner.HttpServerStubConfigurer.NoOpHttpServerStubConfigurer; -import org.springframework.cloud.contract.stubrunner.ResourceResolver; -import org.springframework.core.io.Resource; -import org.springframework.util.StringUtils; - -/** - * @author Dave Syer - */ -@ConfigurationProperties("stubrunner") -public class StubRunnerProperties { - - /** - * Min value of a port for the automatically started WireMock server. - */ - private int minPort = 10000; - - /** - * Max value of a port for the automatically started WireMock server. - */ - private int maxPort = 15000; - - /** - * The repository root to use (where the stubs should be downloaded from). - */ - private Resource repositoryRoot; - - /** - * The ids of the stubs to run in "ivy" notation - * ([groupId]:artifactId:[version]:[classifier][:port]). {@code groupId}, - * {@code classifier}, {@code version} and {@code port} can be optional. - */ - private String[] ids = new String[0]; - - /** - * The classifier to use by default in ivy co-ordinates for a stub. - */ - private String classifier = "stubs"; - - /** - * Repository username. - */ - private String username; - - /** - * Repository password. - */ - private String password; - - /** - * Repository proxy port. - */ - private Integer proxyPort; - - /** - * Repository proxy host. - */ - private String proxyHost; - - /** - * Should only stubs for this particular consumer get registered in HTTP server stub. - */ - private boolean stubsPerConsumer; - - /** - * You can override the default {@code spring.application.name} of this field by - * setting a value to this parameter. - */ - private String consumerName; - - /** - * Dumps the mappings of each HTTP server to the selected folder. - */ - private String mappingsOutputFolder; - - /** - * Pick where the stubs should come from. - */ - private StubsMode stubsMode; - - /** - * If set to {@code false} will NOT delete stubs from a temporary folder after running - * tests. - */ - private boolean deleteStubsAfterTest = true; - - /** - * When enabled, this flag will tell stub runner to not load the generated stubs, but - * convert the found contracts at runtime to a stub format and run those stubs. - */ - private boolean generateStubs; - - /** - * When enabled, this flag will tell stub runner to throw an exception when no stubs / - * contracts were found. - */ - private boolean failOnNoStubs = true; - - /** - * Map of properties that can be passed to custom - * {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder}. - */ - private Map properties = new HashMap<>(); - - /** - * Configuration for an HTTP server stub. - */ - private Class httpServerStubConfigurer = NoOpHttpServerStubConfigurer.class; - - /** - * - */ - private String serverId; - - public int getMinPort() { - return this.minPort; - } - - public void setMinPort(int minPort) { - this.minPort = minPort; - } - - public int getMaxPort() { - return this.maxPort; - } - - public void setMaxPort(int maxPort) { - this.maxPort = maxPort; - } - - public Resource getRepositoryRoot() { - return this.repositoryRoot; - } - - public void setRepositoryRoot(String repositoryRoot) { - this.repositoryRoot = ResourceResolver.resource(repositoryRoot); - } - - public String getUsername() { - return this.username; - } - - public void setUsername(final String username) { - this.username = username; - } - - public String getPassword() { - return this.password; - } - - public void setPassword(final String password) { - this.password = password; - } - - public Integer getProxyPort() { - return this.proxyPort; - } - - public void setProxyPort(final Integer proxyPort) { - this.proxyPort = proxyPort; - } - - public String getProxyHost() { - return this.proxyHost; - } - - public void setProxyHost(final String proxyHost) { - this.proxyHost = proxyHost; - } - - public String[] getIds() { - return this.ids; - } - - public void setIds(String[] ids) { - this.ids = ids; - } - - public String getClassifier() { - return this.classifier; - } - - public void setClassifier(String classifier) { - this.classifier = classifier; - } - - public boolean isStubsPerConsumer() { - return this.stubsPerConsumer; - } - - public void setStubsPerConsumer(boolean stubsPerConsumer) { - this.stubsPerConsumer = stubsPerConsumer; - } - - public String getConsumerName() { - return this.consumerName; - } - - public void setConsumerName(String consumerName) { - this.consumerName = consumerName; - } - - public String getMappingsOutputFolder() { - return this.mappingsOutputFolder; - } - - public void setMappingsOutputFolder(String mappingsOutputFolder) { - this.mappingsOutputFolder = mappingsOutputFolder; - } - - public StubsMode getStubsMode() { - return this.stubsMode; - } - - public void setStubsMode(StubsMode stubsMode) { - this.stubsMode = stubsMode; - } - - public boolean isDeleteStubsAfterTest() { - return this.deleteStubsAfterTest; - } - - public void setDeleteStubsAfterTest(boolean deleteStubsAfterTest) { - this.deleteStubsAfterTest = deleteStubsAfterTest; - } - - public Map getProperties() { - return this.properties; - } - - public void setProperties(String[] properties) { - Properties elements = StringUtils.splitArrayElementsIntoProperties(properties, "="); - if (elements == null) { - return; - } - for (String key : elements.stringPropertyNames()) { - this.properties.put(key, elements.getProperty(key)); - } - } - - public boolean isGenerateStubs() { - return this.generateStubs; - } - - public void setGenerateStubs(boolean generateStubs) { - this.generateStubs = generateStubs; - } - - public boolean isFailOnNoStubs() { - return this.failOnNoStubs; - } - - public void setFailOnNoStubs(boolean failOnNoStubs) { - this.failOnNoStubs = failOnNoStubs; - } - - public Class getHttpServerStubConfigurer() { - return this.httpServerStubConfigurer; - } - - public void setHttpServerStubConfigurer(Class httpServerStubConfigurer) { - this.httpServerStubConfigurer = httpServerStubConfigurer; - } - - public String getServerId() { - return serverId; - } - - public void setServerId(String serverId) { - this.serverId = serverId; - } - - @Override - public String toString() { - return "StubRunnerProperties{" + "minPort=" + this.minPort + ", maxPort=" + this.maxPort + ", repositoryRoot=" - + this.repositoryRoot + ", ids=" + Arrays.toString(this.ids) + ", classifier='" + this.classifier + '\'' - + ", setStubsPerConsumer='" + this.stubsPerConsumer + "', consumerName='" + this.consumerName + '\'' - + ", stubsMode='" + this.stubsMode + '\'' + ", size of properties=" + this.properties.size() + '}'; - } - - /** - * An enumeration stub modes. - */ - public enum StubsMode { - - /** - * Pick the stubs from classpath. - */ - CLASSPATH, - - /** - * Fetch the stubs from local .m2. - */ - LOCAL, - - /** - * Fetch the stubs from a remote location. - */ - REMOTE, - - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/ConditionalOnStubbedDiscoveryDisabled.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/ConditionalOnStubbedDiscoveryDisabled.java deleted file mode 100644 index ffa4c82c6a..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/ConditionalOnStubbedDiscoveryDisabled.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring.cloud; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; - -/** - * Conditional that checks if the user turned off the stubbed discovery mode. - * - * @author Marcin Grzejszczak - * - * @since 1.0.0 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Documented -@ConditionalOnProperty(value = "stubrunner.cloud.stubbed.discovery.enabled", havingValue = "false") -public @interface ConditionalOnStubbedDiscoveryDisabled { - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/ConditionalOnStubbedDiscoveryEnabled.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/ConditionalOnStubbedDiscoveryEnabled.java deleted file mode 100644 index 05472175b4..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/ConditionalOnStubbedDiscoveryEnabled.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring.cloud; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; - -/** - * Conditional that checks if the user turned on the stubbed discovery mode. The feature - * is turned on by default. - * - * @author Marcin Grzejszczak - * - * @since 1.0.0 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Documented -@ConditionalOnProperty(value = "stubrunner.cloud.stubbed.discovery.enabled", havingValue = "true", - matchIfMissing = true) -public @interface ConditionalOnStubbedDiscoveryEnabled { - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/StubMapperProperties.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/StubMapperProperties.java deleted file mode 100644 index 886435be85..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/StubMapperProperties.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring.cloud; - -import java.util.HashMap; -import java.util.Map; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.cloud.contract.stubrunner.StubConfiguration; -import org.springframework.util.StringUtils; - -/** - * Maps Ivy based ids to service Ids. You might want to name the service you're calling in - * another way than artifact id. If that's the case then this class should be used to - * change do the proper mapping. - * - * Just provide in your properties file for example: - * - * stubrunner.idsToServiceIds: fraudDetectionServer: - * someNameThatShouldMapFraudDetectionServer - * - * @author Marcin Grzejszczak - * @since 1.0.0 - */ -@ConfigurationProperties("stubrunner") -public class StubMapperProperties { - - /** - * Mapping of Ivy notation based ids to serviceIds inside your application. - * - * Example - * - * "a:b" -> "myService" "artifactId" -> "myOtherService" - */ - private Map idsToServiceIds = new HashMap<>(); - - public Map getIdsToServiceIds() { - return this.idsToServiceIds; - } - - public void setIdsToServiceIds(Map idsToServiceIds) { - this.idsToServiceIds = idsToServiceIds; - } - - public String fromIvyNotationToId(String ivyNotation) { - StubConfiguration stubConfiguration = new StubConfiguration(ivyNotation); - String id = this.idsToServiceIds.get(ivyNotation); - if (StringUtils.hasText(id)) { - return id; - } - String groupAndArtifact = this.idsToServiceIds - .get(stubConfiguration.getGroupId() + ":" + stubConfiguration.getArtifactId()); - if (StringUtils.hasText(groupAndArtifact)) { - return groupAndArtifact; - } - return this.idsToServiceIds.get(stubConfiguration.getArtifactId()); - } - - public String fromServiceIdToIvyNotation(String serviceId) { - for (Map.Entry entry : this.idsToServiceIds.entrySet()) { - if (entry.getValue().equals(serviceId)) { - return entry.getKey(); - } - } - return null; - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerDiscoveryClient.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerDiscoveryClient.java deleted file mode 100644 index 4794beda3f..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerDiscoveryClient.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring.cloud; - -import java.net.URI; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.client.ServiceInstance; -import org.springframework.cloud.client.discovery.DiscoveryClient; -import org.springframework.cloud.contract.stubrunner.RunningStubs; -import org.springframework.cloud.contract.stubrunner.StubFinder; -import org.springframework.util.StringUtils; - -/** - * Custom version of {@link DiscoveryClient} that tries to find an instance in one of the - * started WireMock servers. - * - * @author Marcin Grzejszczak - * @since 1.0.0 - */ -class StubRunnerDiscoveryClient implements DiscoveryClient { - - private static final Log log = LogFactory.getLog(StubRunnerDiscoveryClient.class); - - private final DiscoveryClient delegate; - - private final StubFinder stubFinder; - - private final StubMapperProperties stubMapperProperties; - - StubRunnerDiscoveryClient(DiscoveryClient delegate, StubFinder stubFinder, - StubMapperProperties stubMapperProperties) { - this.delegate = delegate instanceof StubRunnerDiscoveryClient ? noOpDiscoveryClient() : delegate; - if (log.isDebugEnabled()) { - log.debug("Will delegate calls to discovery service [" + this.delegate + "] if a stub is not found"); - } - this.stubFinder = stubFinder; - this.stubMapperProperties = stubMapperProperties; - } - - StubRunnerDiscoveryClient(StubFinder stubFinder, StubMapperProperties stubMapperProperties) { - this.delegate = noOpDiscoveryClient(); - if (log.isDebugEnabled()) { - log.debug("Will delegate calls to discovery service [" + this.delegate + "] if a stub is not found"); - } - this.stubFinder = stubFinder; - this.stubMapperProperties = stubMapperProperties; - } - - private StubRunnerNoOpDiscoveryClient noOpDiscoveryClient() { - return new StubRunnerNoOpDiscoveryClient(); - } - - @Override - public String description() { - try { - return this.delegate.description(); - } - catch (Exception e) { - if (log.isDebugEnabled()) { - log.debug("Failed to fetch description from delegate", e); - } - } - return ""; - } - - @Override - public List getInstances(String serviceId) { - String ivyNotation = this.stubMapperProperties.fromServiceIdToIvyNotation(serviceId); - String serviceToFind = StringUtils.hasText(ivyNotation) ? ivyNotation : serviceId; - URL stubUrl = this.stubFinder.findStubUrl(serviceToFind); - log.info("Resolved from ivy [" + ivyNotation + "] service to find [" + serviceToFind - + "]. Found stub is available under URL [" + stubUrl + "]"); - if (stubUrl == null) { - return getInstancesFromDelegate(serviceId); - } - return Collections.singletonList( - new StubRunnerServiceInstance(serviceId, stubUrl.getHost(), stubUrl.getPort(), toUri(stubUrl))); - } - - private List getInstancesFromDelegate(String serviceId) { - try { - return new ArrayList<>(this.delegate.getInstances(serviceId)); - } - catch (Exception e) { - if (log.isDebugEnabled()) { - log.debug("Failed to fetch instances from delegate", e); - } - return new ArrayList<>(); - } - } - - private URI toUri(URL url) { - try { - return url.toURI(); - } - catch (Exception e) { - return null; - } - } - - @Override - public List getServices() { - List list = new ArrayList<>(); - List services = getServicesFromDelegate(); - RunningStubs runningStubs = this.stubFinder.findAllRunningStubs(); - list.addAll(services); - list.addAll(runningStubs.getAllServicesNames()); - return list; - } - - private List getServicesFromDelegate() { - try { - return new ArrayList<>(this.delegate.getServices()); - } - catch (Exception e) { - if (log.isDebugEnabled()) { - log.debug("Failed to fetch services from delegate", e); - } - } - return new ArrayList<>(); - } - - @Override - public int getOrder() { - return this.delegate.getOrder(); - } - -} - -class StubRunnerNoOpDiscoveryClient implements DiscoveryClient { - - @Override - public String description() { - return "Spring Cloud Stub Runner No-op DiscoveryClient"; - } - - @Override - public List getInstances(String serviceId) { - return Collections.emptyList(); - } - - @Override - public List getServices() { - return Collections.emptyList(); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerReactiveDiscoveryClient.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerReactiveDiscoveryClient.java deleted file mode 100644 index ce3b1e5e7a..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerReactiveDiscoveryClient.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring.cloud; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import reactor.core.publisher.Flux; - -import org.springframework.cloud.client.ServiceInstance; -import org.springframework.cloud.client.discovery.DiscoveryClient; -import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient; -import org.springframework.cloud.contract.stubrunner.StubFinder; - -/** - * Custom version of {@link DiscoveryClient} that tries to find an instance in one of the - * started WireMock servers. - * - * @author Marcin Grzejszczak - * @since 2.2.4 - */ -class StubRunnerReactiveDiscoveryClient implements ReactiveDiscoveryClient { - - private static final Log log = LogFactory.getLog(StubRunnerReactiveDiscoveryClient.class); - - private final ReactiveDiscoveryClient delegate; - - private final StubFinder stubFinder; - - private final StubMapperProperties stubMapperProperties; - - StubRunnerReactiveDiscoveryClient(ReactiveDiscoveryClient delegate, StubFinder stubFinder, - StubMapperProperties stubMapperProperties) { - this.delegate = delegate instanceof StubRunnerDiscoveryClient ? noOpDiscoveryClient() : delegate; - if (log.isDebugEnabled()) { - log.debug("Will delegate calls to discovery service [" + this.delegate + "] if a stub is not found"); - } - this.stubFinder = stubFinder; - this.stubMapperProperties = stubMapperProperties; - } - - StubRunnerReactiveDiscoveryClient(StubFinder stubFinder, StubMapperProperties stubMapperProperties) { - this.delegate = noOpDiscoveryClient(); - if (log.isDebugEnabled()) { - log.debug("Will delegate calls to discovery service [" + this.delegate + "] if a stub is not found"); - } - this.stubFinder = stubFinder; - this.stubMapperProperties = stubMapperProperties; - } - - private StubRunnerNoOpReactiveDiscoveryClient noOpDiscoveryClient() { - return new StubRunnerNoOpReactiveDiscoveryClient(); - } - - @Override - public String description() { - try { - return this.delegate.description(); - } - catch (Exception e) { - if (log.isDebugEnabled()) { - log.debug("Failed to fetch description from delegate", e); - } - } - return ""; - } - - @Override - public Flux getInstances(String serviceId) { - return Flux.just(client()).flatMapIterable(c -> c.getInstances(serviceId)); - } - - private StubRunnerDiscoveryClient client() { - return new StubRunnerDiscoveryClient(this.stubFinder, this.stubMapperProperties); - } - - @Override - public Flux getServices() { - return Flux.just(client()).flatMapIterable(StubRunnerDiscoveryClient::getServices); - } - - @Override - public int getOrder() { - return this.delegate.getOrder(); - } - -} - -class StubRunnerNoOpReactiveDiscoveryClient implements ReactiveDiscoveryClient { - - @Override - public String description() { - return "Spring Cloud Stub Runner No-op ReactiveDiscoveryClient"; - } - - @Override - public Flux getInstances(String serviceId) { - return Flux.empty(); - } - - @Override - public Flux getServices() { - return Flux.empty(); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerServiceInstance.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerServiceInstance.java deleted file mode 100644 index 4d50bfe99d..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerServiceInstance.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring.cloud; - -import java.net.URI; -import java.util.HashMap; -import java.util.Map; - -import org.springframework.cloud.client.ServiceInstance; - -/** - * {@link ServiceInstance} with a helpful constructor. - * - * @author Marcin Grzejszczak - * @since 1.0.0 - */ -class StubRunnerServiceInstance implements ServiceInstance { - - private final String serviceId; - - private final String host; - - private final int port; - - private final URI uri; - - StubRunnerServiceInstance(String serviceId, String host, int port, URI uri) { - this.serviceId = serviceId; - this.host = host; - this.port = port; - this.uri = uri; - } - - @Override - public String getServiceId() { - return this.serviceId; - } - - @Override - public String getHost() { - return this.host; - } - - @Override - public int getPort() { - return this.port; - } - - @Override - public boolean isSecure() { - return false; - } - - @Override - public URI getUri() { - return this.uri; - } - - @Override - public Map getMetadata() { - return new HashMap<>(); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerSpringCloudAutoConfiguration.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerSpringCloudAutoConfiguration.java deleted file mode 100644 index 526a33d562..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerSpringCloudAutoConfiguration.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring.cloud; - -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.client.discovery.DiscoveryClient; -import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient; -import org.springframework.cloud.contract.stubrunner.StubFinder; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; -import org.springframework.core.env.Environment; - -/** - * Wraps {@link DiscoveryClient} in a Stub Runner implementation that tries to find a - * corresponding WireMock server for a searched dependency. - * - * @author Marcin Grzejszczak - * @since 1.0.0 - */ -@Configuration(proxyBeanMethods = false) -@EnableConfigurationProperties(StubMapperProperties.class) -@ConditionalOnClass(DiscoveryClient.class) -@ConditionalOnProperty(value = "stubrunner.cloud.enabled", matchIfMissing = true) -public class StubRunnerSpringCloudAutoConfiguration { - - @Bean - public StubRunnerDiscoveryClientWrapper stubRunnerDiscoveryClientWrapper(BeanFactory beanFactory) { - return new StubRunnerDiscoveryClientWrapper(beanFactory); - } - - @Bean - @ConditionalOnStubbedDiscoveryEnabled - @ConditionalOnProperty(value = "stubrunner.cloud.delegate.enabled", havingValue = "false", matchIfMissing = true) - @Order(Ordered.HIGHEST_PRECEDENCE) - public DiscoveryClient noOpStubRunnerDiscoveryClient(StubFinder stubFinder, - StubMapperProperties stubMapperProperties) { - return new StubRunnerDiscoveryClient(stubFinder, stubMapperProperties); - } - - @Bean - @ConditionalOnStubbedDiscoveryEnabled - @ConditionalOnProperty(value = "stubrunner.cloud.delegate.enabled", havingValue = "false", matchIfMissing = true) - @Order(Ordered.HIGHEST_PRECEDENCE) - public ReactiveDiscoveryClient noOpStubRunnerReactiveDiscoveryClient(StubFinder stubFinder, - StubMapperProperties stubMapperProperties) { - return new StubRunnerReactiveDiscoveryClient(stubFinder, stubMapperProperties); - } - -} - -class StubRunnerDiscoveryClientWrapper implements BeanPostProcessor { - - private final BeanFactory beanFactory; - - StubFinder stubFinder; - - StubMapperProperties stubMapperProperties; - - String springAppName; - - Boolean stubbedDiscoveryEnabled; - - Boolean cloudDelegateEnabled; - - StubRunnerDiscoveryClientWrapper(BeanFactory beanFactory) { - this.beanFactory = beanFactory; - } - - @Override - public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { - return bean; - } - - @Override - public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { - if (bean instanceof DiscoveryClient && !(bean instanceof StubRunnerDiscoveryClient)) { - if (!isStubbedDiscoveryEnabled()) { - return bean; - } - if (isCloudDelegateEnabled()) { - return new StubRunnerDiscoveryClient((DiscoveryClient) bean, stubFinder(), stubMapperProperties()); - } - return new StubRunnerDiscoveryClient(stubFinder(), stubMapperProperties()); - } - return bean; - } - - StubFinder stubFinder() { - if (this.stubFinder == null) { - this.stubFinder = this.beanFactory.getBean(StubFinder.class); - } - return this.stubFinder; - } - - StubMapperProperties stubMapperProperties() { - if (this.stubMapperProperties == null) { - this.stubMapperProperties = this.beanFactory.getBean(StubMapperProperties.class); - } - return this.stubMapperProperties; - } - - boolean isStubbedDiscoveryEnabled() { - if (this.stubbedDiscoveryEnabled == null) { - this.stubbedDiscoveryEnabled = Boolean.valueOf(this.beanFactory.getBean(Environment.class) - .getProperty("stubrunner.cloud.stubbed.discovery.enabled", "true")); - } - return this.stubbedDiscoveryEnabled; - } - - boolean isCloudDelegateEnabled() { - if (this.cloudDelegateEnabled == null) { - this.cloudDelegateEnabled = Boolean.valueOf(this.beanFactory.getBean(Environment.class) - .getProperty("stubrunner.cloud.delegate.enabled", "false")); - } - return this.cloudDelegateEnabled; - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/StubsRegistrar.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/StubsRegistrar.java deleted file mode 100644 index b2eee52ff0..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/StubsRegistrar.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring.cloud; - -/** - * Contract for registering stubs in a Service Discovery. - * - * @author Marcin Grzejszczak - * @since 1.0.0 - */ -public interface StubsRegistrar extends AutoCloseable { - - void registerStubs(); - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/consul/ConsulStubsRegistrar.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/consul/ConsulStubsRegistrar.java deleted file mode 100644 index d84e53f636..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/consul/ConsulStubsRegistrar.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring.cloud.consul; - -import java.lang.invoke.MethodHandles; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import com.ecwid.consul.v1.ConsulClient; -import com.ecwid.consul.v1.agent.model.NewService; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.commons.util.InetUtils; -import org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties; -import org.springframework.cloud.contract.stubrunner.StubConfiguration; -import org.springframework.cloud.contract.stubrunner.StubRunning; -import org.springframework.cloud.contract.stubrunner.spring.cloud.StubMapperProperties; -import org.springframework.cloud.contract.stubrunner.spring.cloud.StubsRegistrar; -import org.springframework.util.StringUtils; - -/** - * Registers all stubs in Zookeeper Service Discovery. - * - * @author Marcin Grzejszczak - * @since 1.0.0 - */ -public class ConsulStubsRegistrar implements StubsRegistrar { - - private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass()); - - private final StubRunning stubRunning; - - private final ConsulClient consulClient; - - private final StubMapperProperties stubMapperProperties; - - private final ConsulDiscoveryProperties consulDiscoveryProperties; - - private final InetUtils inetUtils; - - private final List services = new LinkedList<>(); - - public ConsulStubsRegistrar(StubRunning stubRunning, ConsulClient consulClient, - StubMapperProperties stubMapperProperties, ConsulDiscoveryProperties consulDiscoveryProperties, - InetUtils inetUtils) { - this.stubRunning = stubRunning; - this.consulClient = consulClient; - this.stubMapperProperties = stubMapperProperties; - this.consulDiscoveryProperties = consulDiscoveryProperties; - this.inetUtils = inetUtils; - } - - @Override - public void registerStubs() { - Map activeStubs = this.stubRunning.runStubs().validNamesAndPorts(); - for (Map.Entry entry : activeStubs.entrySet()) { - NewService newService = newService(entry.getKey(), entry.getValue()); - this.services.add(newService); - try { - this.consulClient.agentServiceRegister(newService); - if (log.isDebugEnabled()) { - log.debug("Successfully registered stub [" + entry.getKey().toColonSeparatedDependencyNotation() - + "] in Service Discovery"); - } - } - catch (Exception e) { - log.warn("Exception occurred while trying to register a stub [" - + entry.getKey().toColonSeparatedDependencyNotation() + "] in Service Discovery", e); - } - } - } - - protected NewService newService(StubConfiguration stubConfiguration, Integer port) { - NewService newService = new NewService(); - newService.setAddress(StringUtils.hasText(this.consulDiscoveryProperties.getHostname()) - ? this.consulDiscoveryProperties.getHostname() - : this.inetUtils.findFirstNonLoopbackAddress().getHostName()); - newService.setId(stubConfiguration.getArtifactId()); - newService.setName(name(stubConfiguration)); - newService.setPort(port); - return newService; - } - - protected String name(StubConfiguration stubConfiguration) { - String resolvedName = this.stubMapperProperties - .fromIvyNotationToId(stubConfiguration.toColonSeparatedDependencyNotation()); - if (StringUtils.hasText(resolvedName)) { - return resolvedName; - } - return stubConfiguration.getArtifactId(); - } - - @Override - public void close() throws Exception { - for (NewService service : this.services) { - this.consulClient.agentServiceDeregister(service.getId()); - } - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/consul/StubRunnerSpringCloudConsulAutoConfiguration.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/consul/StubRunnerSpringCloudConsulAutoConfiguration.java deleted file mode 100644 index 2569e18fb0..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/consul/StubRunnerSpringCloudConsulAutoConfiguration.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring.cloud.consul; - -import com.ecwid.consul.v1.ConsulClient; - -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cloud.commons.util.InetUtils; -import org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties; -import org.springframework.cloud.consul.serviceregistry.ConsulServiceRegistryAutoConfiguration; -import org.springframework.cloud.contract.stubrunner.StubRunning; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration; -import org.springframework.cloud.contract.stubrunner.spring.cloud.ConditionalOnStubbedDiscoveryDisabled; -import org.springframework.cloud.contract.stubrunner.spring.cloud.StubMapperProperties; -import org.springframework.cloud.contract.stubrunner.spring.cloud.StubsRegistrar; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * Autoconfiguration for registering stubs in a Zookeeper Service discovery. - * - * @author Marcin Grzejszczak - * @since 1.0.0 - */ -@Configuration(proxyBeanMethods = false) -@AutoConfigureAfter({ StubRunnerConfiguration.class, ConsulServiceRegistryAutoConfiguration.class }) -@ConditionalOnClass(ConsulClient.class) -@ConditionalOnStubbedDiscoveryDisabled -@ConditionalOnProperty(value = "stubrunner.cloud.consul.enabled", matchIfMissing = true) -public class StubRunnerSpringCloudConsulAutoConfiguration { - - @Bean(initMethod = "registerStubs") - public StubsRegistrar stubsRegistrar(StubRunning stubRunning, ConsulClient consulClient, - StubMapperProperties stubMapperProperties, ConsulDiscoveryProperties consulDiscoveryProperties, - InetUtils inetUtils) { - return new ConsulStubsRegistrar(stubRunning, consulClient, stubMapperProperties, consulDiscoveryProperties, - inetUtils); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/eureka/ConditionalOnEurekaEnabled.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/eureka/ConditionalOnEurekaEnabled.java deleted file mode 100644 index 2ad62d3eb5..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/eureka/ConditionalOnEurekaEnabled.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring.cloud.eureka; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; - -/** - * Conditional that checks if Eureka is enabled. - * - * @author Marcin Grzejszczak - * - * @since 1.0.0 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Documented -@ConditionalOnProperty(value = "eureka.client.enabled", havingValue = "true", matchIfMissing = true) -@interface ConditionalOnEurekaEnabled { - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/eureka/EurekaStubsRegistrar.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/eureka/EurekaStubsRegistrar.java deleted file mode 100644 index e0c29339d8..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/eureka/EurekaStubsRegistrar.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring.cloud.eureka; - -import java.lang.invoke.MethodHandles; -import java.net.InetAddress; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import com.netflix.appinfo.ApplicationInfoManager; -import com.netflix.appinfo.InstanceInfo; -import com.netflix.discovery.AbstractDiscoveryClientOptionalArgs; -import com.netflix.discovery.EurekaClient; -import com.netflix.discovery.shared.transport.jersey.TransportClientFactories; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.beans.BeansException; -import org.springframework.boot.actuate.health.StatusAggregator; -import org.springframework.cloud.client.serviceregistry.ServiceRegistry; -import org.springframework.cloud.commons.util.InetUtils; -import org.springframework.cloud.contract.stubrunner.StubConfiguration; -import org.springframework.cloud.contract.stubrunner.StubRunning; -import org.springframework.cloud.contract.stubrunner.spring.cloud.StubMapperProperties; -import org.springframework.cloud.contract.stubrunner.spring.cloud.StubsRegistrar; -import org.springframework.cloud.loadbalancer.support.SimpleObjectProvider; -import org.springframework.cloud.netflix.eureka.CloudEurekaClient; -import org.springframework.cloud.netflix.eureka.EurekaClientConfigBean; -import org.springframework.cloud.netflix.eureka.EurekaHealthCheckHandler; -import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean; -import org.springframework.cloud.netflix.eureka.InstanceInfoFactory; -import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaRegistration; -import org.springframework.context.ApplicationContext; -import org.springframework.util.StringUtils; - -/** - * Registers all stubs in Eureka Service Discovery. - * - * @author Marcin Grzejszczak - * @since 1.0.0 - */ -public class EurekaStubsRegistrar implements StubsRegistrar { - - private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass()); - - private final StubRunning stubRunning; - - private final StubMapperProperties stubMapperProperties; - - private final InetUtils inetUtils; - - private final EurekaInstanceConfigBean eurekaInstanceConfigBean; - - private final EurekaClientConfigBean eurekaClientConfigBean; - - private final List registrations = new LinkedList<>(); - - private final ServiceRegistry serviceRegistry; - - private final ApplicationContext context; - - public EurekaStubsRegistrar(StubRunning stubRunning, ServiceRegistry serviceRegistry, - StubMapperProperties stubMapperProperties, InetUtils inetUtils, - EurekaInstanceConfigBean eurekaInstanceConfigBean, EurekaClientConfigBean eurekaClientConfigBean, - ApplicationContext context) { - this.stubRunning = stubRunning; - this.stubMapperProperties = stubMapperProperties; - this.serviceRegistry = serviceRegistry; - this.inetUtils = inetUtils; - this.eurekaInstanceConfigBean = eurekaInstanceConfigBean; - this.eurekaClientConfigBean = eurekaClientConfigBean; - this.context = context; - } - - @Override - public void registerStubs() { - Map activeStubs = this.stubRunning.runStubs().validNamesAndPorts(); - for (Map.Entry entry : activeStubs.entrySet()) { - EurekaInstanceConfigBean instance = registration(entry); - log.info("Will register stub in Eureka " + "[" + instance.getAppname() + ", " + instance.getHostname() - + ", " + instance.getNonSecurePort() + ", " + instance.getInstanceId() + "]"); - InstanceInfo instanceInfo = new InstanceInfoFactory().create(instance); - ApplicationInfoManager applicationInfoManager = new ApplicationInfoManager(instance, instanceInfo); - AbstractDiscoveryClientOptionalArgs args = args(); - TransportClientFactories transportClientFactories = transportClientFactories(); - EurekaClient client = new CloudEurekaClient(applicationInfoManager, this.eurekaClientConfigBean, - transportClientFactories, args, this.context); - EurekaRegistration registration = EurekaRegistration.builder(instance) - .with(this.eurekaClientConfigBean, this.context).with(client).build(); - EurekaHealthCheckHandler eurekaHealthCheckHandler = new EurekaHealthCheckHandler( - StatusAggregator.getDefault()); - eurekaHealthCheckHandler.setApplicationContext(context); - eurekaHealthCheckHandler.afterPropertiesSet(); - registration.setHealthCheckHandler(new SimpleObjectProvider<>(eurekaHealthCheckHandler)); - this.registrations.add(registration); - try { - this.serviceRegistry.register(registration); - log.info("Successfully registered stub " + "[" + entry.getKey().toColonSeparatedDependencyNotation() - + "] in Service Discovery"); - } - catch (Exception e) { - log.warn("Exception occurred while trying to register a stub [" - + entry.getKey().toColonSeparatedDependencyNotation() + "] in Service Discovery", e); - } - } - } - - private AbstractDiscoveryClientOptionalArgs args() { - try { - return this.context.getBean(AbstractDiscoveryClientOptionalArgs.class); - } - catch (BeansException e) { - return null; - } - } - - private TransportClientFactories transportClientFactories() { - try { - return this.context.getBean(TransportClientFactories.class); - } - catch (BeansException e) { - return null; - } - } - - private EurekaInstanceConfigBean registration(Map.Entry entry) { - EurekaInstanceConfigBean config = new EurekaInstanceConfigBean(this.inetUtils); - String appName = name(entry.getKey()); - config.setInstanceEnabledOnit(true); - InetAddress address = this.inetUtils.findFirstNonLoopbackAddress(); - config.setIpAddress(address.getHostAddress()); - config.setHostname(StringUtils.hasText(hostName(entry)) ? hostName(entry) : address.getHostName()); - config.setAppname(appName); - config.setVirtualHostName(appName); - config.setSecureVirtualHostName(appName); - int port = port(entry); - config.setNonSecurePort(port); - config.setInstanceId(address.getHostAddress() + ":" + entry.getKey().getArtifactId() + ":" + port); - config.setLeaseRenewalIntervalInSeconds(1); - return config; - } - - protected String hostName(Map.Entry entry) { - return this.eurekaInstanceConfigBean.getHostname(); - } - - protected int port(Map.Entry entry) { - return entry.getValue(); - } - - private String name(StubConfiguration stubConfiguration) { - String resolvedName = this.stubMapperProperties - .fromIvyNotationToId(stubConfiguration.toColonSeparatedDependencyNotation()); - if (StringUtils.hasText(resolvedName)) { - return resolvedName; - } - return stubConfiguration.getArtifactId(); - } - - @Override - public void close() throws Exception { - for (EurekaRegistration registration : this.registrations) { - this.serviceRegistry.deregister(registration); - } - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/eureka/StubRunnerSpringCloudEurekaAutoConfiguration.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/eureka/StubRunnerSpringCloudEurekaAutoConfiguration.java deleted file mode 100644 index 2b40a56d20..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/eureka/StubRunnerSpringCloudEurekaAutoConfiguration.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring.cloud.eureka; - -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cloud.client.serviceregistry.ServiceRegistry; -import org.springframework.cloud.commons.util.InetUtils; -import org.springframework.cloud.contract.stubrunner.StubConfiguration; -import org.springframework.cloud.contract.stubrunner.StubRunning; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration; -import org.springframework.cloud.contract.stubrunner.spring.cloud.ConditionalOnStubbedDiscoveryDisabled; -import org.springframework.cloud.contract.stubrunner.spring.cloud.StubMapperProperties; -import org.springframework.cloud.contract.stubrunner.spring.cloud.StubsRegistrar; -import org.springframework.cloud.netflix.eureka.CloudEurekaClient; -import org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration; -import org.springframework.cloud.netflix.eureka.EurekaClientConfigBean; -import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean; -import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaRegistration; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import org.springframework.core.env.Environment; - -/** - * Autoconfiguration for registering stubs in a Eureka Service discovery. - * - * @author Marcin Grzejszczak - * @since 1.0.0 - */ -@Configuration(proxyBeanMethods = false) -@AutoConfigureAfter({ StubRunnerConfiguration.class, EurekaClientAutoConfiguration.class }) -@ConditionalOnClass(CloudEurekaClient.class) -@ConditionalOnStubbedDiscoveryDisabled -@ConditionalOnEurekaEnabled -@ConditionalOnProperty(value = "stubrunner.cloud.eureka.enabled", matchIfMissing = true) -public class StubRunnerSpringCloudEurekaAutoConfiguration { - - @Profile("!cloud") - @Configuration(proxyBeanMethods = false) - protected static class NonCloudConfig { - - @Bean(initMethod = "registerStubs") - public StubsRegistrar stubsRegistrar(StubRunning stubRunning, - ServiceRegistry serviceRegistry, ApplicationContext context, - StubMapperProperties stubMapperProperties, InetUtils inetUtils, - EurekaInstanceConfigBean eurekaInstanceConfigBean, EurekaClientConfigBean eurekaClientConfigBean) { - return new EurekaStubsRegistrar(stubRunning, serviceRegistry, stubMapperProperties, inetUtils, - eurekaInstanceConfigBean, eurekaClientConfigBean, context); - } - - } - - @Profile("cloud") - @Configuration(proxyBeanMethods = false) - protected static class CloudConfig { - - private static final int DEFAULT_PORT = 80; - - private static final Log log = LogFactory.getLog(CloudConfig.class); - - @Autowired - Environment environment; - - @Bean(initMethod = "registerStubs") - public StubsRegistrar stubsRegistrar(StubRunning stubRunning, - ServiceRegistry serviceRegistry, ApplicationContext context, - StubMapperProperties stubMapperProperties, InetUtils inetUtils, - EurekaInstanceConfigBean eurekaInstanceConfigBean, EurekaClientConfigBean eurekaClientConfigBean) { - return new EurekaStubsRegistrar(stubRunning, serviceRegistry, stubMapperProperties, inetUtils, - eurekaInstanceConfigBean, eurekaClientConfigBean, context) { - @Override - protected String hostName(Map.Entry entry) { - String hostname = CloudConfig.this.environment.getProperty("application.hostname") + "-" - + entry.getValue() + "." + CloudConfig.this.environment.getProperty("application.domain"); - log.info("Registering stub [" + entry.getKey().getArtifactId() + "] with hostname [" + hostname - + "]"); - return hostname; - } - - @Override - protected int port(Map.Entry entry) { - return DEFAULT_PORT; - } - }; - } - - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/loadbalancer/SpringCloudLoadBalancerAutoConfiguration.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/loadbalancer/SpringCloudLoadBalancerAutoConfiguration.java deleted file mode 100644 index feb5d99e64..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/loadbalancer/SpringCloudLoadBalancerAutoConfiguration.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring.cloud.loadbalancer; - -import java.io.Closeable; -import java.net.URI; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import reactor.core.publisher.Mono; - -import org.springframework.beans.factory.BeanFactory; -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.client.ServiceInstance; -import org.springframework.cloud.client.loadbalancer.CompletionContext; -import org.springframework.cloud.client.loadbalancer.DefaultResponse; -import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; -import org.springframework.cloud.client.loadbalancer.LoadBalancerClientsProperties; -import org.springframework.cloud.client.loadbalancer.LoadBalancerLifecycle; -import org.springframework.cloud.client.loadbalancer.Request; -import org.springframework.cloud.client.loadbalancer.Response; -import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer; -import org.springframework.cloud.contract.stubrunner.RunningStubs; -import org.springframework.cloud.contract.stubrunner.StubConfiguration; -import org.springframework.cloud.contract.stubrunner.StubFinder; -import org.springframework.cloud.contract.stubrunner.spring.cloud.ConditionalOnStubbedDiscoveryEnabled; -import org.springframework.cloud.contract.stubrunner.spring.cloud.StubMapperProperties; -import org.springframework.cloud.contract.stubrunner.spring.cloud.StubRunnerSpringCloudAutoConfiguration; -import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientConfiguration; -import org.springframework.cloud.loadbalancer.config.LoadBalancerAutoConfiguration; -import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer; -import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Primary; -import org.springframework.core.ResolvableType; -import org.springframework.util.StringUtils; - -/** - * Provides autoconfiguraion for the Spring Cloud Load Balancer module. - * - * @author Marcin Grzejszczak - * @since 2.2.3 - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnClass({ LoadBalancerClient.class, LoadBalancerClientFactory.class }) -@ConditionalOnProperty(value = "stubrunner.cloud.loadbalancer.enabled", matchIfMissing = true) -@ConditionalOnBean(StubMapperProperties.class) -@AutoConfigureBefore(LoadBalancerAutoConfiguration.class) -@AutoConfigureAfter({ LoadBalancerClientConfiguration.class, StubRunnerSpringCloudAutoConfiguration.class }) -@ConditionalOnStubbedDiscoveryEnabled -@EnableConfigurationProperties(LoadBalancerClientsProperties.class) -public class SpringCloudLoadBalancerAutoConfiguration { - - @Bean - @Primary - LoadBalancerClientFactory stubRunnerLoadBalancerClientFactory(BeanFactory beanFactory, - LoadBalancerClientsProperties properties) { - return new StubRunnerLoadBalancerClientFactory(beanFactory, properties); - } - -} - -class StubRunnerLoadBalancerClientFactory extends LoadBalancerClientFactory implements Closeable { - - private final BeanFactory beanFactory; - - StubRunnerLoadBalancerClientFactory(BeanFactory beanFactory, LoadBalancerClientsProperties properties) { - super(properties); - this.beanFactory = beanFactory; - } - - @Override - public ReactiveLoadBalancer getInstance(String serviceId) { - return new ContractReactorServiceInstanceLoadBalancer(this.beanFactory, serviceId); - } - - @Override - @SuppressWarnings("unchecked") - public T getInstance(String name, Class type) { - return (T) getInstance(name); - } - - @Override - @SuppressWarnings("unchecked") - public T getInstance(String name, Class clazz, Class... generics) { - return (T) getInstance(name); - } - - @Override - @SuppressWarnings("unchecked") - public T getInstance(String name, ResolvableType type) { - return (T) getInstance(name); - } - - @Override - @SuppressWarnings("unchecked") - public Map getInstances(String name, Class type) { - Map map = new HashMap<>(); - map.put(name, (T) getInstance(name)); - return map; - } - - @Override - public void close() { - StubbedServiceInstance.CACHE.clear(); - } - -} - -class StubbedServiceInstance implements ServiceInstance { - - private final StubFinder stubFinder; - - private final StubMapperProperties stubMapperProperties; - - private final String serviceId; - - static final Map> CACHE = new ConcurrentHashMap<>(); - - StubbedServiceInstance(StubFinder stubFinder, StubMapperProperties stubMapperProperties, String serviceId) { - this.stubFinder = stubFinder; - this.stubMapperProperties = stubMapperProperties; - this.serviceId = serviceId; - } - - private Map.Entry stubEntry() { - Map.Entry entry = CACHE.get(this.serviceId); - if (entry != null) { - return entry; - } - RunningStubs runningStubs = this.stubFinder.findAllRunningStubs(); - String mappedServiceName = StringUtils - .hasText(this.stubMapperProperties.fromServiceIdToIvyNotation(this.serviceId)) - ? this.stubMapperProperties.fromServiceIdToIvyNotation(this.serviceId) : this.serviceId; - entry = runningStubs.getEntry(mappedServiceName); - CACHE.put(this.serviceId, entry); - return entry; - } - - @Override - public String getServiceId() { - return this.serviceId; - } - - @Override - public String getHost() { - return "localhost"; - } - - @Override - public int getPort() { - Map.Entry entry = stubEntry(); - if (entry == null) { - return 0; - } - return entry.getValue(); - } - - @Override - public boolean isSecure() { - // TODO: What if the user marks a stub as secure? - return false; - } - - @Override - public URI getUri() { - return URI.create((isSecure() ? "https://" : "http://") + getHost() + ":" + getPort()); - } - - @Override - public Map getMetadata() { - return null; - } - -} - -class ContractReactorServiceInstanceLoadBalancer implements ReactorServiceInstanceLoadBalancer, LoadBalancerLifecycle { - - private final BeanFactory beanFactory; - - private final String serviceId; - - private StubFinder stubFinder; - - private StubMapperProperties stubMapperProperties; - - ContractReactorServiceInstanceLoadBalancer(BeanFactory beanFactory, String serviceId) { - this.beanFactory = beanFactory; - this.serviceId = serviceId; - } - - @Override - public void onStart(Request request) { - - } - - @Override - public void onStartRequest(Request request, Response lbResponse) { - - } - - @Override - public void onComplete(CompletionContext completionContext) { - - } - - @Override - public Mono> choose(Request request) { - return Mono.just( - new DefaultResponse(new StubbedServiceInstance(stubFinder(), stubMapperProperties(), this.serviceId))); - } - - private StubFinder stubFinder() { - if (this.stubFinder == null) { - this.stubFinder = this.beanFactory.getBean(StubFinder.class); - } - return this.stubFinder; - } - - private StubMapperProperties stubMapperProperties() { - if (this.stubMapperProperties == null) { - this.stubMapperProperties = this.beanFactory.getBean(StubMapperProperties.class); - } - return this.stubMapperProperties; - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/zookeeper/StubRunnerSpringCloudZookeeperAutoConfiguration.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/zookeeper/StubRunnerSpringCloudZookeeperAutoConfiguration.java deleted file mode 100644 index 2f40bf8ca5..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/zookeeper/StubRunnerSpringCloudZookeeperAutoConfiguration.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring.cloud.zookeeper; - -import org.apache.curator.framework.CuratorFramework; - -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cloud.contract.stubrunner.StubRunning; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration; -import org.springframework.cloud.contract.stubrunner.spring.cloud.ConditionalOnStubbedDiscoveryDisabled; -import org.springframework.cloud.contract.stubrunner.spring.cloud.StubMapperProperties; -import org.springframework.cloud.contract.stubrunner.spring.cloud.StubsRegistrar; -import org.springframework.cloud.zookeeper.discovery.ConditionalOnZookeeperDiscoveryEnabled; -import org.springframework.cloud.zookeeper.discovery.ZookeeperDiscoveryProperties; -import org.springframework.cloud.zookeeper.support.CuratorServiceDiscoveryAutoConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * Autoconfiguration for registering stubs in a Zookeeper Service discovery. - * - * @author Marcin Grzejszczak - * @since 1.0.0 - */ -@Configuration(proxyBeanMethods = false) -@AutoConfigureAfter({ StubRunnerConfiguration.class, CuratorServiceDiscoveryAutoConfiguration.class }) -@ConditionalOnClass(org.apache.curator.x.discovery.ServiceInstance.class) -@ConditionalOnStubbedDiscoveryDisabled -@ConditionalOnZookeeperDiscoveryEnabled -@ConditionalOnProperty(value = "stubrunner.cloud.zookeeper.enabled", matchIfMissing = true) -public class StubRunnerSpringCloudZookeeperAutoConfiguration { - - @Bean(initMethod = "registerStubs") - public StubsRegistrar stubsRegistrar(StubRunning stubRunning, CuratorFramework curatorFramework, - StubMapperProperties stubMapperProperties, ZookeeperDiscoveryProperties zookeeperDiscoveryProperties) { - return new ZookeeperStubsRegistrar(stubRunning, curatorFramework, stubMapperProperties, - zookeeperDiscoveryProperties); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/zookeeper/ZookeeperStubsRegistrar.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/zookeeper/ZookeeperStubsRegistrar.java deleted file mode 100644 index 0d697c56a8..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/cloud/zookeeper/ZookeeperStubsRegistrar.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring.cloud.zookeeper; - -import java.lang.invoke.MethodHandles; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.curator.framework.CuratorFramework; -import org.apache.curator.x.discovery.ServiceDiscovery; -import org.apache.curator.x.discovery.ServiceDiscoveryBuilder; -import org.apache.curator.x.discovery.ServiceInstance; -import org.apache.curator.x.discovery.UriSpec; - -import org.springframework.cloud.contract.stubrunner.StubConfiguration; -import org.springframework.cloud.contract.stubrunner.StubRunning; -import org.springframework.cloud.contract.stubrunner.spring.cloud.StubMapperProperties; -import org.springframework.cloud.contract.stubrunner.spring.cloud.StubsRegistrar; -import org.springframework.cloud.zookeeper.discovery.ZookeeperDiscoveryProperties; -import org.springframework.util.StringUtils; - -/** - * Registers all stubs in Zookeeper Service Discovery. - * - * @author Marcin Grzejszczak - * @since 1.0.0 - */ -public class ZookeeperStubsRegistrar implements StubsRegistrar { - - private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass()); - - private final StubRunning stubRunning; - - private final CuratorFramework curatorFramework; - - private final StubMapperProperties stubMapperProperties; - - private final ZookeeperDiscoveryProperties zookeeperDiscoveryProperties; - - private final List discoveryList = new LinkedList<>(); - - public ZookeeperStubsRegistrar(StubRunning stubRunning, CuratorFramework curatorFramework, - StubMapperProperties stubMapperProperties, ZookeeperDiscoveryProperties zookeeperDiscoveryProperties) { - this.stubRunning = stubRunning; - this.curatorFramework = curatorFramework; - this.stubMapperProperties = stubMapperProperties; - this.zookeeperDiscoveryProperties = zookeeperDiscoveryProperties; - } - - @Override - public void registerStubs() { - Map activeStubs = this.stubRunning.runStubs().validNamesAndPorts(); - for (Map.Entry entry : activeStubs.entrySet()) { - ServiceInstance serviceInstance = serviceInstance(entry.getKey(), entry.getValue()); - ServiceDiscovery serviceDiscovery = serviceDiscovery(serviceInstance); - this.discoveryList.add(serviceDiscovery); - try { - serviceDiscovery.start(); - if (log.isDebugEnabled()) { - log.debug("Successfully registered stub [" + entry.getKey().toColonSeparatedDependencyNotation() - + "] in Service Discovery"); - } - } - catch (Exception e) { - log.warn("Exception occurred while trying to register a stub [" - + entry.getKey().toColonSeparatedDependencyNotation() + "] in Service Discovery", e); - } - } - } - - protected ServiceInstance serviceInstance(StubConfiguration stubConfiguration, int port) { - try { - return ServiceInstance.builder().uriSpec(new UriSpec(this.zookeeperDiscoveryProperties.getUriSpec())) - .address("localhost").port(port).name(name(stubConfiguration)).build(); - } - catch (Exception e) { - throw new IllegalStateException(e); - } - } - - private String name(StubConfiguration stubConfiguration) { - String resolvedName = this.stubMapperProperties - .fromIvyNotationToId(stubConfiguration.toColonSeparatedDependencyNotation()); - if (StringUtils.hasText(resolvedName)) { - return resolvedName; - } - return stubConfiguration.getArtifactId(); - } - - protected ServiceDiscovery serviceDiscovery(ServiceInstance serviceInstance) { - return ServiceDiscoveryBuilder.builder(Void.class).basePath(this.zookeeperDiscoveryProperties.getRoot()) - .client(this.curatorFramework).thisInstance(serviceInstance).build(); - } - - @Override - public void close() throws Exception { - for (ServiceDiscovery discovery : this.discoveryList) { - discovery.close(); - } - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/util/StubsParser.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/util/StubsParser.java deleted file mode 100644 index f7bbe3cbc0..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/util/StubsParser.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.util; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import org.springframework.cloud.contract.stubrunner.StubConfiguration; -import org.springframework.util.StringUtils; - -/** - * Utility to parse string into a list of configuration of stubs. - * - * @author Marcin Grzejszczak - */ -public final class StubsParser { - - private StubsParser() { - throw new IllegalStateException("Can't instantiate a utility class"); - } - - /** - * The string is expected to be a map with entry called "stubs" that contains a list - * of Strings in the format - * - *
    - *
  • groupid:artifactid:version:classifier:port
  • - *
  • groupid:artifactid:version:classifier
  • - *
  • groupid:artifactid:version
  • - *
  • groupid:artifactid
  • - *
- * - * In the latter case the provided default stub classifier will be passed. - * - * Example: - * - * "a:b,c:d:e" - * @param collection collection of ids - * @param defaultClassifier default classifier to append if one is missing - * @return parsed stub configurations - */ - public static List fromString(Collection collection, String defaultClassifier) { - List stubs = new ArrayList<>(); - for (String config : collection) { - if (StringUtils.hasText(config)) { - stubs.add(StubSpecification.parse(config, defaultClassifier).stub); - } - } - return stubs; - } - - /** - * @param notation ivy notation of stubs with ports - * @return mapping of parsed stub configurations to ports on which the stub is running - */ - public static Map fromStringWithPort(String notation) { - StubSpecification stub = StubSpecification.parse(notation, StubConfiguration.DEFAULT_CLASSIFIER); - if (!stub.hasPort()) { - return Collections.emptyMap(); - } - return Collections.singletonMap(stub.stub, stub.port); - } - - /** - * @param notation ivy notation of stubs with ports - * @return colon seprated dependency notation with port or empty string if no port is - * present - */ - public static String ivyFromStringWithPort(String notation) { - StubSpecification stub = StubSpecification.parse(notation, StubConfiguration.DEFAULT_CLASSIFIER); - if (!stub.hasPort()) { - return ""; - } - return stub.stub.toColonSeparatedDependencyNotation(); - } - - /** - * @param id string notation of a stub - * @return {@code true} if a port is there in the identifier - */ - public static boolean hasPort(String id) { - String[] splitEntry = id.split(":"); - try { - Integer.valueOf(splitEntry[splitEntry.length - 1]); - return true; - } - catch (NumberFormatException e) { - return false; - } - } - - private static class StubSpecification { - - private final StubConfiguration stub; - - private final Integer port; - - StubSpecification(StubConfiguration stub, Integer port) { - this.stub = stub; - this.port = port; - } - - private static StubSpecification parse(String id, String defaultClassifier) { - String[] splitEntry = id.split(":"); - Integer port = null; - try { - port = Integer.valueOf(splitEntry[splitEntry.length - 1]); - id = id.substring(0, id.lastIndexOf(":")); - } - catch (NumberFormatException e) { - } - return new StubSpecification(new StubConfiguration(id, defaultClassifier), port); - } - - public boolean hasPort() { - return this.port != null; - } - - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/util/ZipCategory.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/util/ZipCategory.java deleted file mode 100644 index 40dba8d898..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/util/ZipCategory.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.util; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.Files; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.zip.ZipEntry; -import java.util.zip.ZipException; -import java.util.zip.ZipInputStream; - -import org.springframework.util.StreamUtils; - -/** - * Based on - * https://github.com/ - * timyates/groovy-common-extensions. - * - * Category for {@link File} that adds a method that allows you to unzip a given file to a - * specified location - * - * @author Marcin Grzejszczak - */ -public final class ZipCategory { - - private ZipCategory() { - throw new IllegalStateException("Can't instantiate a utility class"); - } - - /** - * Unzips this file. If the destination directory is not provided, it will - * fall back to this file's parent directory. - * @param self file - * @param destination (optional), the destination directory where this file's content - * will be unzipped to. - * @return a {@link Collection} of unzipped {@link File} objects. - */ - public static Collection unzipTo(File self, File destination) { - checkUnzipDestination(destination); - // if destination directory is not given, we'll fall back to the parent directory - // of 'self' - if (destination == null) { - destination = new File(self.getParent()); - } - List unzippedFiles = new ArrayList<>(); - try (InputStream fileInputStream = Files.newInputStream(self.toPath())) { - try (ZipInputStream zipInput = new ZipInputStream(fileInputStream)) { - for (ZipEntry entry = zipInput.getNextEntry(); entry != null; entry = zipInput.getNextEntry()) { - if (!entry.isDirectory()) { - final File destinationFile = new File(destination, entry.getName()); - /* - * If we see the relative traversal string of ".." we need to make - * sure that the outputdir + name doesn't leave the outputdir. - */ - String zipEntryName = entry.getName(); - if (!destinationFile.toPath().normalize().startsWith(destination.toPath())) { - throw new ZipException("The file " + zipEntryName - + " is trying to leave the target output directory of " + destination); - } - if (destinationFile.getParentFile() != null) { - destinationFile.getParentFile().mkdirs(); - } - try (OutputStream output = Files.newOutputStream(destinationFile.toPath())) { - StreamUtils.copy(zipInput, output); - } - unzippedFiles.add(destinationFile); - } - else { - final File dir = new File(destination, entry.getName()); - dir.mkdirs(); - unzippedFiles.add(dir); - } - } - } - } - catch (IOException e) { - throw new IllegalStateException("Cannot unzip archive", e); - } - return unzippedFiles; - } - - private static void checkUnzipDestination(File file) { - if (file != null && !file.isDirectory()) { - throw new IllegalArgumentException("'destination' has to be a directory."); - } - } - -} diff --git a/spring-cloud-contract-stub-runner/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-contract-stub-runner/src/main/resources/META-INF/additional-spring-configuration-metadata.json deleted file mode 100644 index 9130066f3f..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "properties": [ - { - "name": "stubrunner.amqp.enabled", - "type": "java.lang.Boolean", - "description": "Whether to enable support for Stub Runner and AMQP.", - "defaultValue": false - }, - { - "name": "stubrunner.amqp.mockCOnnection", - "type": "java.lang.Boolean", - "description": "Whether to enable support for Stub Runner and AMQP mocked connection factory.", - "defaultValue": true - }, - { - "name": "stubrunner.cloud.consul.enabled", - "type": "java.lang.Boolean", - "description": "Whether to enable stubs registration in Consul.", - "defaultValue": true - }, - { - "name": "stubrunner.cloud.delegate.enabled", - "type": "java.lang.Boolean", - "description": "Whether to enable DiscoveryClient's Stub Runner implementation.", - "defaultValue": true - }, - { - "name": "stubrunner.cloud.enabled", - "type": "java.lang.Boolean", - "description": "Whether to enable Spring Cloud support for Stub Runner.", - "defaultValue": true - }, - { - "name": "stubrunner.cloud.eureka.enabled", - "type": "java.lang.Boolean", - "description": "Whether to enable stubs registration in Eureka.", - "defaultValue": true - }, - { - "name": "stubrunner.cloud.loadbalancer.enabled", - "type": "java.lang.Boolean", - "description": "Whether to enable Stub Runner's Spring Cloud Load Balancer integration.", - "defaultValue": true - }, - { - "name": "stubrunner.cloud.stubbed.discovery.enabled", - "type": "java.lang.Boolean", - "description": "Whether Service Discovery should be stubbed for Stub Runner. If set to false, stubs will get registered in real service discovery.", - "defaultValue": true - }, - { - "name": "stubrunner.cloud.zookeeper.enabled", - "type": "java.lang.Boolean", - "description": "Whether to enable stubs registration in Zookeeper.", - "defaultValue": true - }, - { - "name": "stubrunner.integration.enabled", - "type": "java.lang.Boolean", - "description": "Whether to enable Stub Runner integration with Spring Integration.", - "defaultValue": true - }, - { - "name": "stubrunner.stream.enabled", - "type": "java.lang.Boolean", - "description": "Whether to enable Stub Runner integration with Spring Cloud Stream.", - "defaultValue": true - }, - { - "name": "stubrunner.jms.enabled", - "type": "java.lang.Boolean", - "description": "Whether to enable Stub Runner integration with Spring JMS.", - "defaultValue": true - }, - { - "name": "stubrunner.kafka.enabled", - "type": "java.lang.Boolean", - "description": "Whether to enable Stub Runner integration with Spring Kafka.", - "defaultValue": true - }, - { - "name": "stubrunner.kafka.initializer.enabled", - "type": "java.lang.Boolean", - "description": "Whether to allow Stub Runner to take care of polling for messages instead of the KafkaStubMessages component. The latter should be used only on the producer side.", - "defaultValue": true - } - ] -} diff --git a/spring-cloud-contract-stub-runner/src/main/resources/META-INF/spring.factories b/spring-cloud-contract-stub-runner/src/main/resources/META-INF/spring.factories deleted file mode 100644 index ee0ca0f753..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,3 +0,0 @@ -# Test Execution Listeners -org.springframework.test.context.TestExecutionListener=\ -org.springframework.cloud.contract.stubrunner.provider.wiremock.StubRunnerWireMockTestExecutionListener diff --git a/spring-cloud-contract-stub-runner/src/main/resources/META-INF/spring/org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner.imports b/spring-cloud-contract-stub-runner/src/main/resources/META-INF/spring/org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner.imports deleted file mode 100644 index 49fbbe54c1..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/resources/META-INF/spring/org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner.imports +++ /dev/null @@ -1,6 +0,0 @@ -org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration -org.springframework.cloud.contract.stubrunner.spring.cloud.StubRunnerSpringCloudAutoConfiguration -org.springframework.cloud.contract.stubrunner.spring.cloud.loadbalancer.SpringCloudLoadBalancerAutoConfiguration -org.springframework.cloud.contract.stubrunner.spring.cloud.eureka.StubRunnerSpringCloudEurekaAutoConfiguration -org.springframework.cloud.contract.stubrunner.spring.cloud.zookeeper.StubRunnerSpringCloudZookeeperAutoConfiguration -org.springframework.cloud.contract.stubrunner.spring.cloud.consul.StubRunnerSpringCloudConsulAutoConfiguration diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/AetherStubDownloaderSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/AetherStubDownloaderSpec.groovy deleted file mode 100644 index f153eadd4a..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/AetherStubDownloaderSpec.groovy +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner - -import io.specto.hoverfly.junit.HoverflyRule -import org.eclipse.aether.RepositorySystemSession -import org.eclipse.aether.repository.Authentication -import org.junit.Rule -import org.junit.rules.TemporaryFolder -import spock.lang.Specification -import spock.util.environment.RestoreSystemProperties - -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties -import org.springframework.util.ResourceUtils - -class AetherStubDownloaderSpec extends Specification { - - @Rule - HoverflyRule hoverflyRule = HoverflyRule.inSimulationMode("simulation.json") - - @Rule - TemporaryFolder folder = new TemporaryFolder() - - def 'should throw an exception when artifact not found in local m2'() { - given: - StubRunnerOptions stubRunnerOptions = new StubRunnerOptionsBuilder() - .withStubsMode(StubRunnerProperties.StubsMode.LOCAL) - .build() - - AetherStubDownloader aetherStubDownloader = new AetherStubDownloader(stubRunnerOptions) - - when: - def entry = aetherStubDownloader.downloadAndUnpackStubJar(new StubConfiguration("non.existing.group", "missing-artifact-id", "1.0-SNAPSHOT")) - - then: - entry == null - } - - def 'should throw an exception when local m2 gets replaced with a temp dir and a jar is not found in remote'() { - given: - StubRunnerOptions stubRunnerOptions = new StubRunnerOptionsBuilder() - .withStubsMode(StubRunnerProperties.StubsMode.REMOTE) - .withStubRepositoryRoot("file://" + folder.newFolder().absolutePath) - .build() - and: - String localRepo = AetherFactories.localRepositoryDirectory(true) - new File(localRepo, "org/springframework/cloud/spring-cloud-contract-spec" - .replace("/", File.separator)).list().size() > 0 - - and: - AetherStubDownloader aetherStubDownloader = new AetherStubDownloader(stubRunnerOptions) - - when: - def entry = aetherStubDownloader.downloadAndUnpackStubJar(new StubConfiguration("org.springframework.cloud", "spring-cloud-contract-spec", "+", "")) - - then: - entry == null - } - - @RestoreSystemProperties - def 'Should use local repository from settings.xml'() { - given: - File tempSettings = File.createTempFile("settings", ".xml") - def m2repoFolder = 'm2repo' + File.separator + 'repository' - tempSettings.text = '' + - ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX + m2repoFolder).getAbsolutePath() + '' - System.setProperty("org.apache.maven.user-settings", tempSettings.getAbsolutePath()) - RepositorySystemSession repositorySystemSession = - AetherFactories.newSession(AetherFactories.newRepositorySystem(), true) - - and: - StubRunnerOptions stubRunnerOptions = new StubRunnerOptionsBuilder() - .withStubsMode(StubRunnerProperties.StubsMode.LOCAL) - .build() - AetherStubDownloader aetherStubDownloader = new AetherStubDownloader(stubRunnerOptions) - - when: - def jar = aetherStubDownloader.downloadAndUnpackStubJar( - new StubConfiguration("org.springframework.cloud.contract.verifier.stubs", - "bootService", "0.0.1-SNAPSHOT")) - - then: - jar != null - repositorySystemSession.getLocalRepository().getBasedir().getAbsolutePath().endsWith(m2repoFolder) - } - - @RestoreSystemProperties - def 'Should return credentials from settings_xml'() { - given: - File settings = new File(AetherStubDownloaderSpec.getResource("/.m2/settings.xml").getFile()) - System.setProperty("org.apache.maven.user-settings", settings.getAbsolutePath()) - - and: - File configDir = new File(AetherStubDownloaderSpec.getResource("/.m2").getFile()) - System.setProperty("maven.user.config.dir", configDir.getAbsolutePath()) - - and: - StubRunnerOptions stubRunnerOptions = new StubRunnerOptionsBuilder() - .withStubsMode(StubRunnerProperties.StubsMode.REMOTE) - .withStubRepositoryRoot(AetherStubDownloaderSpec.getResource("/m2repo/repository").toString()) - .withServerId("my-server") - .build() - AetherStubDownloader aetherStubDownloader = new AetherStubDownloader(stubRunnerOptions) { - @Override - Authentication buildAuthentication(String stubServerPassword, String username) { - assert username == "admin" - // hashed {ha7QXbuAf9wH5uVeYJGWg+SC8fdkufPVfdtpTK8Yk3E=} - assert stubServerPassword == "mypassword" - return super.buildAuthentication(stubServerPassword, username) - } - } - - when: - def jar = aetherStubDownloader.downloadAndUnpackStubJar( - new StubConfiguration("org.springframework.cloud.contract.verifier.stubs", - "bootService", "0.0.1-SNAPSHOT")) - then: - jar != null - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/AvailablePortScannerSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/AvailablePortScannerSpec.groovy deleted file mode 100644 index d9934a67b6..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/AvailablePortScannerSpec.groovy +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner - -import spock.lang.Specification - -class AvailablePortScannerSpec extends Specification { - - private static final int MIN_PORT = 8989 - private static final int MAX_PORT = 8990 - private static final int MAX_RETRY_COUNT_FOR_NEGATIVE_SCENARIOS = 2 - - def 'should execute given closure with the next available port number'() { - given: - AvailablePortScanner portScanner = new AvailablePortScanner(MIN_PORT, MAX_PORT) - when: - int usedPort = portScanner.tryToExecuteWithFreePort { int port -> port } - then: - noExceptionThrown() - usedPort == MIN_PORT || MAX_PORT - } - - def 'should execute given closure with the available port from specified range'() { - given: - AvailablePortScanner portScanner = new AvailablePortScanner(MIN_PORT, MIN_PORT) - when: - int usedPort = portScanner.tryToExecuteWithFreePort { int port -> port } - then: - noExceptionThrown() - usedPort == MIN_PORT - } - - def 'should throw exception when improper range has been provided'() { - when: - new AvailablePortScanner(minPort, maxPort, MAX_RETRY_COUNT_FOR_NEGATIVE_SCENARIOS) - then: - def ex = thrown(AvailablePortScanner.InvalidPortRange) - ex.message == "Invalid bounds exceptions, min port [$minPort] is greater to max port [$maxPort]" - where: - minPort | maxPort - MAX_PORT | MIN_PORT - - } - - def 'should throw exception when there is no available port'() { - given: - AvailablePortScanner portScanner = new AvailablePortScanner(MIN_PORT, MAX_PORT, MAX_RETRY_COUNT_FOR_NEGATIVE_SCENARIOS) - when: - portScanner.tryToExecuteWithFreePort { - throw new BindException('Bind exception from closure') - } - then: - def ex = thrown(AvailablePortScanner.NoPortAvailableException) - ex.message == "Could not find available port in range $MIN_PORT:$MAX_PORT" - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/BatchStubRunnerSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/BatchStubRunnerSpec.groovy deleted file mode 100644 index 84f5bdb872..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/BatchStubRunnerSpec.groovy +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner - -import spock.lang.Specification - -class BatchStubRunnerSpec extends Specification { - - static final String KNOWN_STUB_PATH = 'group:knownArtifact' - static final String UNKNOWN_STUB_PATH = 'group:unknownArtifact' - static final URL KNOWN_STUB_URL = new URL('http://localhost:8080') - - def 'should provide stub URL from enclosed stub runner'() { - given: - BatchStubRunner batchStubRunner = new BatchStubRunner(runners()) - expect: - batchStubRunner.findStubUrl(KNOWN_STUB_PATH) == KNOWN_STUB_URL - } - - def 'should throw an exception for unknown stub path'() { - given: - BatchStubRunner batchStubRunner = new BatchStubRunner(runners()) - when: - batchStubRunner.findStubUrl(UNKNOWN_STUB_PATH) - then: - thrown(StubNotFoundException) - } - - def 'should throw exception if trying to execute not available trigger'() { - given: - BatchStubRunner batchStubRunner = new BatchStubRunner(runners()) - when: - batchStubRunner.trigger('non existing label') - then: - IllegalArgumentException exception = thrown(IllegalArgumentException) - exception.message == "No label with name [non existing label] was found. Here you have the list of dependencies and their labels [Dependency [a:b:c] has labels [foo]]" - } - - Collection runners() { - StubRunner runner = Mock(StubRunner) - runner.findStubUrl("group", "knownArtifact") >> KNOWN_STUB_URL - runner.findStubUrl("group:knownArtifact") >> KNOWN_STUB_URL - runner.findStubUrl("group:unknownArtifact") >> { throw new StubNotFoundException(UNKNOWN_STUB_PATH) } - runner.labels() >> ['a:b:c': ['foo']] - return [runner] - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/ContractDownloaderSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/ContractDownloaderSpec.groovy deleted file mode 100644 index f62afd0bf3..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/ContractDownloaderSpec.groovy +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner - -import spock.lang.Specification - -/** - * @author Marcin Grzejszczak - */ -class ContractDownloaderSpec extends Specification { - - StubDownloader stubDownloader = Stub() - StubConfiguration stubConfiguration = new StubConfiguration('') - - File file = new File(File.separator + ['some', 'path', 'to', 'somewhere'].join(File.separator)) - - def 'should set inclusion pattern on config when path pattern was explicitly provided with a separator at the beginning'() { - given: - String contractPath = File.separator + ['a', 'b', 'c', 'd'].join(File.separator) - ContractDownloader contractDownloader = new ContractDownloader(stubDownloader, - stubConfiguration, contractPath, '', '', '') - when: - ContractDownloader.InclusionProperties inclusionProperties = contractDownloader.createNewInclusionProperties(file) - then: - inclusionProperties.includedContracts.startsWith('^') - inclusionProperties.includedContracts.endsWith('$') - inclusionProperties.includedContracts.contains(fileSeparated('/some/path/to/somewhere(/)?.*/a/b/c/d/.*')) - inclusionProperties.includedRootFolderAntPattern == "**/a/b/c/d/**/" - } - - def 'should set inclusion pattern on config when path pattern was explicitly provided without a separator at the beginning'() { - given: - String contractPath = ['a', 'b', 'c', 'd'].join(File.separator) - ContractDownloader contractDownloader = new ContractDownloader(stubDownloader, - stubConfiguration, contractPath, '', '', '') - when: - ContractDownloader.InclusionProperties inclusionProperties = - contractDownloader.createNewInclusionProperties(file) - then: - inclusionProperties.includedContracts.startsWith('^') - inclusionProperties.includedContracts.endsWith('$') - inclusionProperties.includedContracts.contains(fileSeparated('/some/path/to/somewhere(/)?.*/a/b/c/d/.*')) - inclusionProperties.includedRootFolderAntPattern == "**/a/b/c/d/**/" - } - - private static String fileSeparated(String string) { - return string.replace('/', File.separator).replace("\\", "\\\\") - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/GitStubDownloaderPropertiesSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/GitStubDownloaderPropertiesSpec.groovy deleted file mode 100644 index 31cf88e585..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/GitStubDownloaderPropertiesSpec.groovy +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner - -import spock.lang.Specification - -import org.springframework.core.io.AbstractResource -import org.springframework.core.io.Resource - -/** - * @author Marcin Grzejszczak - */ -class GitStubDownloaderPropertiesSpec extends Specification { - - def "should parse only the URL after protocol if it doesn't start with git"() { - given: - Resource resource = resource("git://https://foo.com") - when: - GitStubDownloaderProperties props = new GitStubDownloaderProperties(resource, new StubRunnerOptionsBuilder().build()) - then: - props.url == URI.create("https://foo.com") - } - - def "should return the whole address if it starts with git@ but doesn't finish with dot git"() { - given: - Resource resource = resource("git://git@foo.com/foo") - when: - GitStubDownloaderProperties props = new GitStubDownloaderProperties(resource, new StubRunnerOptionsBuilder().build()) - then: - props.url == URI.create("git:git@foo.com/foo") - } - - Resource resource(String resourceUri) { - return new AbstractResource() { - @Override - String getDescription() { - return null - } - - @Override - InputStream getInputStream() throws IOException { - return null - } - - @Override - URI getURI() throws IOException { - // Groovy resolves URI to getURI() and StackOverFlow is thrown - return java.net.URI.create(resourceUri) - } - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/RunningStubsSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/RunningStubsSpec.groovy deleted file mode 100644 index 50c0825307..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/RunningStubsSpec.groovy +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner - -import spock.lang.Specification - -/** - * @author Marcin Grzejszczak - */ -class RunningStubsSpec extends Specification { - RunningStubs runningStubs = new RunningStubs([(new StubConfiguration('group', 'artifact', 'version', 'classifier')): 100]) - - def "should get port by group and artifact id"() { - expect: - runningStubs.getPort('group', 'artifact') == 100 - } - - def "should get port by artifact id"() { - expect: - runningStubs.getPort('artifact') == 100 - } - - def "should get port by group and artifact id in Ivy notation"() { - expect: - runningStubs.getPort('group:artifact') == 100 - } - - def "should get port by group, artifact id and version in Ivy notation"() { - expect: - runningStubs.getPort('group:artifact:version') == 100 - } - - def "should get port by group, artifact id, version and classifier in Ivy notation"() { - expect: - runningStubs.getPort('group:artifact:version:classifier') == 100 - } - - def "should return null if no stub has been found"() { - expect: - runningStubs.getPort('missing artifact id') == null - } - - def "should find stub by group and artifact id"() { - expect: - runningStubs.isPresent('group', 'artifact') - } - - def "should find stub by artifact id"() { - expect: - runningStubs.isPresent('artifact') - } - - def "should find stub by group and artifact id in Ivy notation"() { - expect: - runningStubs.isPresent('group:artifact') - } - - def "should find stub by group, artifact id and version in Ivy notation"() { - expect: - runningStubs.isPresent('group:artifact:version') - } - - def "should find stub by group, artifact id, version and classifier in Ivy notation"() { - expect: - runningStubs.isPresent('group:artifact:version:classifier') - } - - def "should return false if no stub has been found"() { - expect: - runningStubs.isPresent('missing artifact id') == false - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubConfigurationSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubConfigurationSpec.groovy deleted file mode 100644 index 46948b0d54..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubConfigurationSpec.groovy +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner - -import spock.lang.Specification -import spock.lang.Unroll - -/** - * @author Marcin Grzejszczak - */ -class StubConfigurationSpec extends Specification { - - @Unroll - def 'should parse (#ivy) and match ivy notation'() { - when: - StubConfiguration stubConfiguration = new StubConfiguration(ivy) - then: - stubConfiguration.artifactId == artifactId - stubConfiguration.groupId == groupId - stubConfiguration.classifier == classifier - stubConfiguration.version == version - and: - stubConfiguration.toColonSeparatedDependencyNotation() == ivyNotation - and: - stubConfiguration.matchesIvyNotation(ivy) - where: - ivy || ivyNotation | artifactId | groupId | classifier | version - 'group:artifact:version:classifier' || 'group:artifact:version:classifier' | 'artifact' | 'group' | 'classifier' | 'version' - 'group:artifact:version:' || 'group:artifact:version:' | 'artifact' | 'group' | '' | 'version' - 'group:artifact:version' || 'group:artifact:version:stubs' | 'artifact' | 'group' | 'stubs' | 'version' - - } - - @Unroll - def 'should resolve [#ivy] as a changing version [#result]'() { - given: - StubConfiguration stubConfiguration = new StubConfiguration(ivy) - expect: - result == stubConfiguration.isVersionChanging() - where: - ivy || result - 'group:artifact:1.0.0.RELEASE:classifier' || false - 'group:artifact:1.0.0.BUILD-SNAPSHOT:' || true - 'group:artifact:1.0.0.SNAPSHOT' || true - 'group:artifact:+:' || true - - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRepositorySpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRepositorySpec.groovy deleted file mode 100644 index 290eba00ab..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRepositorySpec.groovy +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner - -import spock.lang.Specification - -class StubRepositorySpec extends Specification { - public static - final File REPOSITORY_LOCATION = new File('src/test/resources/repository') - - def 'should retrieve all descriptors for given project'() { - given: - StubRepository repository = new StubRepository(REPOSITORY_LOCATION, - [], new StubRunnerOptionsBuilder().build()) - int expectedDescriptorsSize = 8 - when: - List descriptors = repository.getStubs() - then: - descriptors.size() == expectedDescriptorsSize - } - - def 'should return empty list if files are missing'() { - given: - StubRepository repository = new StubRepository(new File('src/test/resources/emptyrepo'), - [], new StubRunnerOptionsBuilder().build()) - when: - List descriptors = repository.getStubs() - then: - descriptors.empty - } - - def 'should throw an exception if directory with mappings is missing'() { - when: - new StubRepository(new File('src/test/resources/nonexistingrepo'), [], - new StubRunnerOptionsBuilder().build()) - then: - thrown(IllegalArgumentException) - } - - def 'should retrieve only those mappings that contain the consumer name'() { - given: - StubRepository repository = new StubRepository(REPOSITORY_LOCATION, - [], new StubRunnerOptionsBuilder() - .withStubPerConsumer(true) - .withConsumerName("ping").build()) - int expectedDescriptorsSize = 1 - when: - List descriptors = repository.stubs - then: - descriptors.size() == expectedDescriptorsSize - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerExecutorSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerExecutorSpec.groovy deleted file mode 100644 index b76f97787b..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerExecutorSpec.groovy +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner - -import java.util.concurrent.TimeUnit - -import groovy.json.JsonOutput -import spock.lang.Specification - -import org.springframework.cloud.contract.stubrunner.util.StubsParser -import org.springframework.cloud.contract.verifier.converter.YamlContract -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender -import org.springframework.cloud.test.TestSocketUtils - -class StubRunnerExecutorSpec extends Specification { - - static final int MIN_PORT = 18999 - static final int MAX_PORT = 19999 - - private AvailablePortScanner portScanner - private StubRepository repository - private StubConfiguration stub = new StubConfiguration("group:artifact", "stubs") - private StubRunnerOptions stubRunnerOptions = new StubRunnerOptionsBuilder().build() - - def setup() { - portScanner = new AvailablePortScanner(MIN_PORT, MAX_PORT) - repository = new StubRepository(new File('src/test/resources/repository'), - [], new StubRunnerOptionsBuilder().build()) - } - - def 'should provide URL for given relative path of stub'() { - given: - StubRunnerExecutor executor = new StubRunnerExecutor(portScanner) - when: - executor.runStubs(stubRunnerOptions, repository, stub) - then: - URL url = executor.findStubUrl("group", "artifact") - url.port >= MIN_PORT - url.port <= MAX_PORT - and: - executor.findAllRunningStubs().isPresent('artifact') - executor.findAllRunningStubs().isPresent('group', 'artifact') - executor.findAllRunningStubs().isPresent('group:artifact') - cleanup: - executor.shutdown() - } - - def 'should provide no URL for unknown dependency path'() { - given: - StubRunnerExecutor executor = new StubRunnerExecutor(portScanner) - when: - executor.runStubs(stubRunnerOptions, repository, stub) - and: - executor.findStubUrl("unkowngroup", "unknownartifact") - then: - thrown(StubNotFoundException) - cleanup: - executor.shutdown() - } - - def 'should start a stub on a given port'() { - given: - int port = TestSocketUtils.findAvailableTcpPort() - StubRunnerExecutor executor = new StubRunnerExecutor(portScanner) - stubRunnerOptions = new StubRunnerOptionsBuilder(stubIdsToPortMapping: - stubIdsWithPortsFromString("group:artifact:${port},someotherartifact:${TestSocketUtils.findAvailableTcpPort()}")) - .build() - when: - executor.runStubs(stubRunnerOptions, repository, stub) - then: - executor.findStubUrl("group", "artifact") == "http://localhost:${port}".toURL() - cleanup: - executor.shutdown() - } - - def 'should ensure that triggered contracts have properly parsed message body when a message is sent'() { - given: - StubRunnerExecutor executor = new StubRunnerExecutor(portScanner, new AssertingStubMessages(), []) - executor.runStubs(stubRunnerOptions, repository, stub) - when: - executor.trigger('send_order') - then: - noExceptionThrown() - cleanup: - executor.shutdown() - } - - def 'should ensure that triggered contracts have properly parsed message body from file as bytes when a message is sent'() { - given: - StubRunnerExecutor executor = new StubRunnerExecutor(portScanner, new AssertingStubMessages(), []) - executor.runStubs(stubRunnerOptions, repository, stub) - when: - executor.trigger('send_order_bin') - then: - noExceptionThrown() - cleanup: - executor.shutdown() - } - - def 'should ensure that triggered contracts have properly parsed message body from file as json when a message is sent'() { - given: - StubRunnerExecutor executor = new StubRunnerExecutor(portScanner, new AssertingStubMessages(), []) - executor.runStubs(stubRunnerOptions, repository, stub) - when: - executor.trigger('send_order_json') - then: - noExceptionThrown() - cleanup: - executor.shutdown() - } - - def 'should ensure that triggered contracts have properly parsed message body from file as xml when a message is sent'() { - given: - StubRunnerExecutor executor = new StubRunnerExecutor(portScanner, new AssertingStubMessages(), []) - executor.runStubs(stubRunnerOptions, repository, stub) - when: - executor.trigger('send_order_xml') - then: - noExceptionThrown() - cleanup: - executor.shutdown() - } - - def 'should ensure that triggered contracts have properly parsed message body from file as text when a message is sent'() { - given: - StubRunnerExecutor executor = new StubRunnerExecutor(portScanner, new AssertingStubMessages(), []) - executor.runStubs(stubRunnerOptions, repository, stub) - when: - executor.trigger('send_order_csv') - then: - noExceptionThrown() - cleanup: - executor.shutdown() - } - - def 'should match stub with empty classifier'() { - given: - def stubConf = new StubConfiguration('groupX', 'artifactX', 'versionX', '') - StubRunnerExecutor executor = new StubRunnerExecutor(portScanner) - when: - executor.runStubs(stubRunnerOptions, repository, stubConf) - then: - URL url = executor.findStubUrl('groupX:artifactX:versionX:') - url.port >= MIN_PORT - url.port <= MAX_PORT - and: - executor.findAllRunningStubs().isPresent('artifactX') - executor.findAllRunningStubs().isPresent('groupX', 'artifactX') - executor.findAllRunningStubs().isPresent('groupX:artifactX') - cleanup: - executor.shutdown() - } - - def 'should return false if no messages are found'() { - given: - def stubConf = new StubConfiguration('asd', 'asd', 'asd', '') - StubRunnerExecutor executor = new StubRunnerExecutor(portScanner) - when: - executor.runStubs(stubRunnerOptions, - new StubRepository(new File('src/test/resources/repository/httpcontract'), - [], new StubRunnerOptionsBuilder().build()), stubConf) - then: - !executor.trigger() - !executor.trigger("missing", "label") - !executor.trigger("label") - cleanup: - executor.shutdown() - } - - def 'should not start http server if no contracts or mappings are found'() { - given: - def stubConf = new StubConfiguration('asd', 'asd', 'asd', '') - StubRunnerExecutor executor = new StubRunnerExecutor(portScanner) - when: - RunningStubs stubs = executor.runStubs(stubRunnerOptions, - new StubRepository(new File('src/test/resources/emptyrepo'), - [], new StubRunnerOptionsBuilder().build()), stubConf) - then: - stubs.getPort('asd') == -1 - cleanup: - executor.shutdown() - } - - def 'should generate regex values when message is to be set and it contains regex'() { - given: - MockMessageVerifier messageVerifier = new MockMessageVerifier() - StubRunnerExecutor executor = new StubRunnerExecutor(portScanner, messageVerifier, []) - when: - def stubConf = new StubConfiguration('asd', 'asd', 'asd', '') - executor.runStubs(stubRunnerOptions, - new StubRepository(new File('src/test/resources/messages'), - [], new StubRunnerOptionsBuilder().build()), stubConf) - boolean triggered = executor.trigger("trigger") - then: - triggered - messageVerifier.called - cleanup: - executor.shutdown() - } - - class MockMessageVerifier implements MessageVerifierSender, MessageVerifierReceiver { - - boolean called - - @Override - void send(Object message, String destination, YamlContract contract) { - - } - - @Override - Object receive(String destination, long timeout, TimeUnit timeUnit, YamlContract contract) { - return null - } - - @Override - Object receive(String destination, YamlContract contract) { - return null - } - - @Override - void send(Object payload, Map headers, String destination, YamlContract contract) { - this.called = true - println "Body <${payload}>" - assert !payload.toString().contains("cursor") - println "Headers <${headers}>" - assert headers.values().every { !it.toString().contains("cursor") } - } - } - - Map stubIdsWithPortsFromString(String stubIdsToPortMapping) { - return stubIdsToPortMapping.split(',').collectEntries { String entry -> - return StubsParser.fromStringWithPort(entry) - } - } - - private class AssertingStubMessages implements MessageVerifierSender, MessageVerifierReceiver { - - @Override - void send(Object message, String destination, YamlContract contract) { - throw new UnsupportedOperationException() - } - - @Override - void send(T payload, Map headers, String destination, YamlContract contract) { - if(payload instanceof String) { - assert !(JsonOutput.toJson(payload).contains("serverValue")) - } - assert headers.entrySet().every { !(it.value.toString().contains("serverValue")) } - } - - @Override - Object receive(String destination, long timeout, TimeUnit timeUnit, YamlContract contract) { - throw new UnsupportedOperationException() - } - - @Override - Object receive(String destination, YamlContract contract) { - throw new UnsupportedOperationException() - } - - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerFactorySpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerFactorySpec.groovy deleted file mode 100644 index 46fa8a08b3..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerFactorySpec.groovy +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner - -import org.junit.Rule -import org.junit.rules.TemporaryFolder -import spock.lang.Specification - -import org.springframework.cloud.contract.verifier.messaging.noop.NoOpStubMessages - -class StubRunnerFactorySpec extends Specification { - - @Rule - TemporaryFolder folder = new TemporaryFolder() - - String stubs = "a:b,c:d" - StubDownloader downloader = Mock(StubDownloader) - StubRunnerOptions stubRunnerOptions - StubRunnerFactory factory - - void setup() { - stubRunnerOptions = new StubRunnerOptionsBuilder() - .withStubRepositoryRoot(folder.root.absolutePath) // FIXME: not used - .withStubs(stubs).build() - factory = new StubRunnerFactory(stubRunnerOptions, downloader, new NoOpStubMessages()) - } - - def "Should download stub definitions many times"() { - given: - folder.newFolder("mappings") - 1 * downloader.downloadAndUnpackStubJar(_) >> new AbstractMap.SimpleEntry(new StubConfiguration('a:b'), folder.root) - 1 * downloader.downloadAndUnpackStubJar(_) >> new AbstractMap.SimpleEntry(new StubConfiguration('c:d'), folder.root) - when: - Collection stubRunners = collectOnlyPresentValues(factory.createStubsFromServiceConfiguration()) - then: - stubRunners.size() == 2 - } - - private List collectOnlyPresentValues(Collection stubRunners) { - return stubRunners.findAll { it != null } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerOptionsBuilderSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerOptionsBuilderSpec.groovy deleted file mode 100644 index 9e6cc0d56c..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerOptionsBuilderSpec.groovy +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner - -import spock.lang.Issue -import spock.lang.Specification -import spock.util.environment.RestoreSystemProperties - -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties -import org.springframework.core.io.ClassPathResource -import org.springframework.core.io.FileSystemResource - -class StubRunnerOptionsBuilderSpec extends Specification { - - private StubRunnerOptionsBuilder builder = new StubRunnerOptionsBuilder() - - def shouldReturnURIOfAResourceFromString() { - - given: - builder.withStubRepositoryRoot("classpath:/logback.xml") - - when: - StubRunnerOptions options = builder.build() - - then: - options.getStubRepositoryRootAsString().startsWith("file:/") - options.getStubRepositoryRootAsString().endsWith("logback.xml") - } - - def shouldReturnURIOfAResourceFromResource() { - - given: - builder.withStubRepositoryRoot(new ClassPathResource("logback.xml")) - - when: - StubRunnerOptions options = builder.build() - - then: - options.getStubRepositoryRootAsString().startsWith("file:/") - options.getStubRepositoryRootAsString().endsWith("logback.xml") - } - - def shouldReturnEmptyStringWhenFileNotFound() { - - given: - builder.withStubRepositoryRoot(new ClassPathResource("fileThatDoesNotExist.xml")) - - when: - StubRunnerOptions options = builder.build() - - then: - options.getStubRepositoryRootAsString() == "" - } - - def shouldCreateDependenciesForStub() { - - given: - builder.withStubs('foo:bar') - - when: - StubRunnerOptions options = builder.build() - - then: - options.getDependencies().toString() == '[foo:bar:+:stubs]' - } - - def shouldCreateDependenciesForStubWithSameGroupAndArtifactId() { - - given: - builder.withStubs('foo:bar:1.0', 'foo:bar:2.0') - - when: - StubRunnerOptions options = builder.build() - - then: - options.getDependencies().toString() == '[foo:bar:1.0:stubs, foo:bar:2.0:stubs]' - } - - def shouldCreateDependenciesForMultipleStubsWithSameGroup() { - - given: - builder.withStubs('foo:bar', 'foo:baz', 'foo:baz2') - - when: - StubRunnerOptions options = builder.build() - - then: - options.getDependencies().toString() == '[foo:bar:+:stubs, foo:baz:+:stubs, foo:baz2:+:stubs]' - } - - def shouldCreateDependenciesForMultipleStubsWithSameArtifactId() { - - given: - builder.withStubs('bar:foo', 'baz:foo', 'baz2:foo') - - when: - StubRunnerOptions options = builder.build() - - then: - options.getDependencies().toString() == '[bar:foo:+:stubs, baz:foo:+:stubs, baz2:foo:+:stubs]' - } - - def shouldCreateDependenciesForCommaSeparatedStubs() { - - given: - builder.withStubs('foo:bar,bar:foo,foo:baz') - - when: - StubRunnerOptions options = builder.build() - - then: - options.getDependencies().size() == 3 - } - - def shouldCreateDependenciesForCommaSeparatedStubsWithSameArtifact() { - - given: - builder.withStubs('bar:foo,baz:foo,baz2:foo') - - when: - StubRunnerOptions options = builder.build() - - then: - options.getDependencies().toString() == '[bar:foo:+:stubs, baz:foo:+:stubs, baz2:foo:+:stubs]' - } - - def shouldMapStubsWithPort() { - - given: - builder.withStubs('foo:bar:8080') - - when: - StubRunnerOptions options = builder.build() - - then: - options.getStubIdsToPortMapping().toString() == '[foo:bar:+:stubs:8080]' - } - - def shouldCreateDependenciesWithVersion() { - - given: - builder.withStubs('foo:1.2.3:bar') - - when: - StubRunnerOptions options = builder.build() - - then: - options.getDependencies().toString() == '[foo:1.2.3:bar:stubs]' - } - - def shouldCreateDependenciesWithClassifier() { - - given: - builder.withStubs('foo:bar').withStubsClassifier('xxx') - - when: - StubRunnerOptions options = builder.build() - - then: - options.getDependencies().toString() == '[foo:bar:+:xxx]' - } - - @Issue("#176") - def shouldCreateDependenciesWithEmptyPort() { - - given: - builder.withStubs('groupId:artifactId:version:classifier:') - - when: - StubRunnerOptions options = builder.build() - - then: - options.getDependencies().toString() == '[groupId:artifactId:version:classifier]' - } - - @Issue("#210") - def shouldCreateDependenciesWithVersionRange() { - - given: - builder.withStubs('groupId:artifactId:[,0.0.1]:classifier', 'groupId2:artifactId2:[,0.0.2]:classifier2') - - when: - StubRunnerOptions options = builder.build() - - then: - options.getDependencies().toString() == '[groupId:artifactId:[,0.0.1]:classifier, groupId2:artifactId2:[,0.0.2]:classifier2]' - } - - @Issue("#210") - def shouldCreateDependenciesWithVersionRangeWhenSingleOneWasPassed() { - - given: - builder.withStubs('groupId:artifactId:[,0.0.1]:classifier') - - when: - StubRunnerOptions options = builder.build() - - then: - options.getDependencies().toString() == '[groupId:artifactId:[,0.0.1]:classifier]' - } - - @Issue("#210") - def shouldCreateDependenciesWithVersionRangeWhenManyWerePassedInASingleLine() { - - given: - builder.withStubs('groupId:artifactId:[,0.0.1]:classifier,groupId2:artifactId2:[,0.0.2]:classifier2') - - when: - StubRunnerOptions options = builder.build() - - then: - options.getDependencies().toString() == '[groupId2:artifactId2:[,0.0.2]:classifier2, groupId:artifactId:[,0.0.1]:classifier]' - } - - @Issue("#466") - def shouldSetAllDependenciesFromOptions() { - given: - StubRunnerOptionsBuilder builder = builder.withOptions(new StubRunnerOptions(1, 2, new FileSystemResource("root"), StubRunnerProperties.StubsMode.LOCAL, - "classifier", [new StubConfiguration("a:b:c")], [(new StubConfiguration("a:b:c")): 3], "foo", "bar", - new StubRunnerOptions.StubRunnerProxyOptions("host", 4), true, "consumer", "folder", false, true, false, [foo: "bar"], Foo, "server")) - builder.withStubs("foo:bar:baz") - when: - StubRunnerOptions options = builder.build() - then: - options.minPortValue == 1 - options.maxPortValue == 2 - options.stubRepositoryRoot == new FileSystemResource("root") - options.stubsMode == StubRunnerProperties.StubsMode.LOCAL - options.stubsClassifier == "classifier" - options.dependencies == [new StubConfiguration("a:b:c"), new StubConfiguration("foo:bar:baz:classifier")] - options.stubIdsToPortMapping == [(new StubConfiguration("a:b:c")): 3] - options.username == "foo" - options.password == "bar" - options.proxyOptions.proxyHost == "host" - options.proxyOptions.proxyPort == 4 - options.stubsPerConsumer == true - options.consumerName == "consumer" - options.mappingsOutputFolder == "folder" - options.deleteStubsAfterTest == false - options.generateStubs == true - options.failOnNoStubs == false - options.properties == [foo: "bar"] - options.httpServerStubConfigurer == Foo - options.serverId == "server" - } - - def shouldNotPrintUsernameAndPassword() { - given: - StubRunnerOptionsBuilder builder = builder.withOptions(new StubRunnerOptions(1, 2, new FileSystemResource("root"), - StubRunnerProperties.StubsMode.CLASSPATH, "classifier", - [new StubConfiguration("a:b:c")], [(new StubConfiguration("a:b:c")): 3], "username123", "password123", - new StubRunnerOptions.StubRunnerProxyOptions("host", 4), true, "consumer", "folder", false, true, true, [:], Foo, "server")) - builder.withStubs("foo:bar:baz") - when: - String options = builder.build().toString() - then: - !options.contains("username123") - !options.contains("password123") - options.contains("****") - } - - @Issue("#462") - @RestoreSystemProperties - def shouldSetAllPropsFromSystemProps() { - given: - System.setProperty("stubrunner.port.range.min", "1") - System.setProperty("stubrunner.port.range.max", "2") - System.setProperty("stubrunner.repository.root", "root") - System.setProperty("stubrunner.stubs-mode", "LOCAL") - System.setProperty("stubrunner.classifier", "classifier") - System.setProperty("stubrunner.ids", "a:b:c,foo:bar:baz:classifier") - System.setProperty("stubrunner.username", "foo") - System.setProperty("stubrunner.password", "bar") - System.setProperty("stubrunner.stubs-per-consumer", "true") - System.setProperty("stubrunner.consumer-name", "consumer") - System.setProperty("stubrunner.proxy.host", "host") - System.setProperty("stubrunner.proxy.port", "4") - System.setProperty("stubrunner.mappings-output-folder", "folder") - System.setProperty("stubrunner.properties.foo-bar", "bar") - System.setProperty("stubrunner.properties.foo-baz", "baz") - System.setProperty("stubrunner.properties.bar.bar", "foo") - System.setProperty("stubrunner.delete-stubs-after-test", "false") - System.setProperty("stubrunner.generate-stubs", "true") - System.setProperty("stubrunner.fail-on-no-stubs", "false") - System.setProperty("stubrunner.http-server-stub-configurer", "org.springframework.cloud.contract.stubrunner.Foo") - when: - StubRunnerOptions options = StubRunnerOptions.fromSystemProps() - then: - options.minPortValue == 1 - options.maxPortValue == 2 - options.stubRepositoryRoot == new ClassPathResource("root") - options.stubsMode == StubRunnerProperties.StubsMode.LOCAL - options.stubsClassifier == "classifier" - options.dependencies == [new StubConfiguration("a:b:c"), new StubConfiguration("foo:bar:baz:classifier")] - options.username == "foo" - options.password == "bar" - options.proxyOptions.proxyHost == "host" - options.proxyOptions.proxyPort == 4 - options.stubsPerConsumer == true - options.deleteStubsAfterTest == false - options.generateStubs == true - options.failOnNoStubs == false - options.consumerName == "consumer" - options.mappingsOutputFolder == "folder" - options.properties == ["foo-bar": "bar", "foo-baz": "baz", "bar.bar": "foo"] - options.httpServerStubConfigurer == Foo - } -} - -class Foo implements HttpServerStubConfigurer { - - @Override - boolean isAccepted(Object httpStubConfiguration) { - return true - } -} 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 deleted file mode 100644 index 9ba6cf50ea..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerPropertyUtilsSpec.groovy +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner - -import spock.lang.Specification -import spock.util.environment.RestoreSystemProperties - -class StubRunnerPropertyUtilsSpec extends Specification { - - @RestoreSystemProperties - def "should return #expectedResult when checking if queried prop is set, and system is #systemProperty and env #envVariable"() { - given: - def sysProp = systemProperty - def envVar = envVariable - def expectedEnv = expectedEnvVar - PropertyFetcher fetcher = new PropertyFetcher() { - @Override - String systemProp(String prop) { - return sysProp - } - - @Override - String envVar(String prop) { - assert prop == expectedEnv || prop == "STUBRUNNER_PROPERTIES_" + expectedEnv - return envVar - } - } - StubRunnerPropertyUtils.FETCHER = fetcher - expect: - expectedResult == StubRunnerPropertyUtils.isPropertySet(queriedProp) - where: - queriedProp | systemProperty | envVariable | expectedEnvVar | expectedResult - "foo.bar-baz" | null | null | "FOO_BAR_BAZ" | false - "foo.bar-baz" | null | "true" | "FOO_BAR_BAZ" | true - "foo.bar-baz" | null | "false" | "FOO_BAR_BAZ" | false - "foo.bar-baz" | "false" | "true" | "FOO_BAR_BAZ" | false - "foo.bar-baz" | "true" | "true" | "FOO_BAR_BAZ" | true - } - - @RestoreSystemProperties - def "should return #expectedResult when queried for queried prop and system is #systemProperty and env #envVariable"() { - given: - def sysProp = systemProperty - def envVar = envVariable - def checkedSysProp = assertedSystemProp - def checkedEnvVar = assertedEnvVar - PropertyFetcher fetcher = new PropertyFetcher() { - @Override - String systemProp(String prop) { - assert prop == checkedSysProp || prop == checkedSysProp - "stubrunner.properties." - return sysProp - } - - @Override - String envVar(String prop) { - assert prop == checkedEnvVar || prop == checkedEnvVar - "STUBRUNNER_PROPERTIES_" - return envVar - } - } - StubRunnerPropertyUtils.FETCHER = fetcher - expect: - expectedResult == StubRunnerPropertyUtils.getProperty(map, queriedProp) - where: - queriedProp | map | systemProperty | envVariable | expectedResult | assertedSystemProp | assertedEnvVar - "foo.bar-baz" | ["foo.bar-baz": "faz"] | "ab" | "bc" | "faz" | "stubrunner.properties.foo.bar-baz" | "STUBRUNNER_PROPERTIES_FOO_BAR_BAZ" - "foo.bar-baz" | [:] | "ab" | "bc" | "ab" | "stubrunner.properties.foo.bar-baz" | "STUBRUNNER_PROPERTIES_FOO_BAR_BAZ" - "foo.bar-baz" | [:] | "" | "bc" | "bc" | "stubrunner.properties.foo.bar-baz" | "STUBRUNNER_PROPERTIES_FOO_BAR_BAZ" - "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 queried prop 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-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerSpec.groovy deleted file mode 100644 index c157c6a57c..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerSpec.groovy +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner - - -import spock.lang.Specification - -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties -import org.springframework.cloud.contract.verifier.messaging.noop.NoOpStubMessages -import org.springframework.cloud.test.TestSocketUtils - -class StubRunnerSpec extends Specification { - - private static final int MIN_PORT = TestSocketUtils.findAvailableTcpPort() - private static final int MAX_PORT = MIN_PORT - private static final URL EXPECTED_STUB_URL = new URL("http://localhost:$MIN_PORT") - - private static final URL generateStubs = StubRunnerSpec.getResource('/generateStubs/') - - def 'should provide stub URL for provided groupid and artifactId'() { - given: - Arguments args = argumentsWithProjectDefinition() - StubRunner runner = new StubRunner(args.stubRunnerOptions, - args.repositoryPath, args.stub) - when: - runner.runStubs() - then: - runner.findStubUrl("groupId", "artifactId") == EXPECTED_STUB_URL - cleanup: - runner.close() - } - - def 'should provide stub URL if only artifactId was passed'() { - given: - Arguments args = argumentsWithProjectDefinition() - StubRunner runner = new StubRunner(args.stubRunnerOptions, - args.repositoryPath, args.stub) - when: - runner.runStubs() - then: - runner.findStubUrl(null, "artifactId") == EXPECTED_STUB_URL - cleanup: - runner.close() - } - - def 'should generate stubs at runtime'() { - given: - Arguments args = argumentsWithGenerateStubs() - StubDownloader downloader = new FileStubDownloader().build(args.stubRunnerOptions) - StubRunner runner = new StubRunnerFactory(args.stubRunnerOptions, - downloader, new NoOpStubMessages()).createStubsFromServiceConfiguration().first() - when: - runner.runStubs() - then: - URL url = runner.findStubUrl("groupId2", "artifactId2") - "Goodbye World!" == new URL(url.toString() + "/goodbye").text - cleanup: - runner.close() - } - - def 'should override existing mappings when generating stubs at runtime'() { - given: - Arguments args = argumentsWithGenerateStubs() - StubDownloader downloader = new FileStubDownloader().build(args.stubRunnerOptions) - StubRunner runner = new StubRunnerFactory(args.stubRunnerOptions, - downloader, new NoOpStubMessages()).createStubsFromServiceConfiguration().first() - when: - runner.runStubs() - then: - URL url = runner.findStubUrl("groupId2", "artifactId2") - // don't return the response defined in hello.json, but the one defined in the contract - "Hello New World!" == new URL(url.toString() + "/hello").text - cleanup: - runner.close() - } - - def 'should handle contracts with body contents loaded from external file when generating stubs at runtime'() { - given: - Arguments args = argumentsWithGenerateStubs() - StubDownloader downloader = new FileStubDownloader().build(args.stubRunnerOptions) - StubRunner runner = new StubRunnerFactory(args.stubRunnerOptions, - downloader, new NoOpStubMessages()).createStubsFromServiceConfiguration().first() - when: - runner.runStubs() - then: - URL url = runner.findStubUrl("groupId2", "artifactId2") - "Goodbye from file!" == new URL(url.toString() + "/goodbye_from_file").text - cleanup: - runner.close() - } - - Arguments argumentsWithProjectDefinition() { - StubConfiguration stubConfiguration = new StubConfiguration("groupId", "artifactId", "classifier") - StubRunnerOptions stubRunnerOptions = new StubRunnerOptionsBuilder().withMinMaxPort(MIN_PORT, MAX_PORT).build() - return new Arguments(stubRunnerOptions, 'src/test/resources/repository', stubConfiguration) - } - - Arguments argumentsWithGenerateStubs() { - StubConfiguration stubConfiguration = new StubConfiguration("groupId2", "artifactId2", "classifier2") - StubRunnerOptions stubRunnerOptions = new StubRunnerOptionsBuilder() - .withMinMaxPort(MIN_PORT, MAX_PORT) - .withGenerateStubs(true) - .withStubs(stubConfiguration.toString()) - .withStubsMode(StubRunnerProperties.StubsMode.REMOTE) - .withStubRepositoryRoot("stubs://file://" + generateStubs.path) - .build() - return new Arguments(stubRunnerOptions, 'src/test/resources/generateStubs', stubConfiguration) - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubServerSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubServerSpec.groovy deleted file mode 100644 index a1483b1e73..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubServerSpec.groovy +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner - -import spock.lang.Specification - -import org.springframework.cloud.contract.stubrunner.provider.wiremock.WireMockHttpServerStub -import org.springframework.cloud.test.TestSocketUtils - -class StubServerSpec extends Specification { - static final int STUB_SERVER_PORT = TestSocketUtils.findAvailableTcpPort() - static final URL EXPECTED_URL = new URL("http://localhost:$STUB_SERVER_PORT") - - File repository = new File('src/test/resources/repository/mappings/spring/cloud/bye') - StubConfiguration stubConfiguration = new StubConfiguration("a:b") - - def 'should register stub mappings upon server start'() { - given: - List mappingDescriptors = new StubRepository(repository).getStubs() - StubServer pingStubServer = new StubServer(stubConfiguration, mappingDescriptors, [], - new WireMockHttpServerStub()).start(new HttpServerStubConfiguration(new HttpServerStubConfigurer.NoOpHttpServerStubConfigurer(), StubRunnerOptions.fromSystemProps(), new StubConfiguration("a:b:c:d"), STUB_SERVER_PORT)) - when: - pingStubServer.start() - then: - "http://localhost:$pingStubServer.port/bye".toURL().text == 'Goodbye world!' - cleanup: - pingStubServer.stop() - } - - def 'should provide stub server URL'() { - given: - List mappingDescriptors = new StubRepository(repository).getStubs() - StubServer pingStubServer = new StubServer(stubConfiguration, mappingDescriptors, [], - new WireMockHttpServerStub()).start(new HttpServerStubConfiguration(new HttpServerStubConfigurer.NoOpHttpServerStubConfigurer(), StubRunnerOptions.fromSystemProps(), new StubConfiguration("a:b:c:d"), STUB_SERVER_PORT)) - when: - pingStubServer.start() - then: - pingStubServer.stubUrl == EXPECTED_URL - cleanup: - pingStubServer.stop() - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleCustomMsgVerifierSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleCustomMsgVerifierSpec.groovy deleted file mode 100644 index 8b553e51cf..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleCustomMsgVerifierSpec.groovy +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.junit4 - -import java.util.concurrent.TimeUnit - -import org.junit.AfterClass -import org.junit.BeforeClass -import org.junit.ClassRule -import spock.lang.Shared -import spock.lang.Specification - -import org.springframework.cloud.contract.stubrunner.junit.StubRunnerRule -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties -import org.springframework.cloud.contract.verifier.converter.YamlContract -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender -/** - * @author Marcin Grzejszczak - */ -class StubRunnerRuleCustomMsgVerifierSpec extends Specification { - - @BeforeClass - @AfterClass - void setupProps() { - System.clearProperty("stubrunner.repository.root") - System.clearProperty("stubrunner.classifier") - } - - @ClassRule - @Shared - StubRunnerRule rule = new StubRunnerRule() - .stubsMode(StubRunnerProperties.StubsMode.REMOTE) - .repoRoot(StubRunnerRuleCustomMsgVerifierSpec.getResource("/m2repo/repository").toURI().toString()) - .downloadStub("org.springframework.cloud.contract.verifier.stubs", "bootService") - .messageVerifierSender(new MyMessageVerifier()) - .messageVerifierReceiver(new MyMessageVerifier()) - - def 'should use the provided message verifier in the junit rule'() { - when: - rule.trigger() - then: - IllegalStateException e = thrown(IllegalStateException) - e.message.contains("Failed to send a message with headers") - when: - rule.trigger("return_book_1") - then: - e = thrown(IllegalStateException) - e.message.contains("Failed to send a message with headers") - when: - rule.trigger("bootService", "return_book_1") - then: - e = thrown(IllegalStateException) - e.message.contains("Failed to send a message with headers") - } - - static class MyMessageVerifier implements MessageVerifierSender, MessageVerifierReceiver { - - @Override - void send(Object message, String destination, YamlContract contract) { - throw new IllegalStateException("Failed to send a message") - } - - @Override - Object receive(String destination, long timeout, TimeUnit timeUnit, YamlContract contract) { - throw new IllegalStateException("Failed to receive a message with timeout") - } - - @Override - Object receive(String destination, YamlContract contract) { - throw new IllegalStateException("Failed to receive a message") - } - - @Override - void send(Object payload, Map headers, String destination, YamlContract contract) { - throw new IllegalStateException("Failed to send a message with headers") - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleCustomPortJUnitTest.java b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleCustomPortJUnitTest.java deleted file mode 100644 index 5c58ea4862..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleCustomPortJUnitTest.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.junit4; - -import java.io.InputStream; -import java.net.URI; -import java.nio.charset.Charset; - -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; - -import org.springframework.cloud.contract.stubrunner.junit.StubRunnerRule; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.util.StreamUtils; - -import static org.assertj.core.api.BDDAssertions.then; - -/** - * @author Marcin Grzejszczak - */ -public class StubRunnerRuleCustomPortJUnitTest { - - // tag::classrule_with_port[] - @ClassRule - public static StubRunnerRule rule = new StubRunnerRule().repoRoot(repoRoot()) - .stubsMode(StubRunnerProperties.StubsMode.REMOTE) - .downloadStub("org.springframework.cloud.contract.verifier.stubs", "loanIssuance").withPort(35465) - .downloadStub("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer:35466"); - - @BeforeClass - @AfterClass - public static void setupProps() { - System.clearProperty("stubrunner.repository.root"); - System.clearProperty("stubrunner.classifier"); - } - - // end::classrule_with_port[] - - private static String repoRoot() { - try { - return StubRunnerRuleCustomPortJUnitTest.class.getResource("/m2repo/repository/").toURI().toString(); - } - catch (Exception e) { - return ""; - } - } - - @Test - public void should_start_wiremock_servers() throws Exception { - // expect: 'WireMocks are running' - then(rule.findStubUrl("org.springframework.cloud.contract.verifier.stubs", "loanIssuance")).isNotNull(); - then(rule.findStubUrl("loanIssuance")).isNotNull(); - then(rule.findStubUrl("loanIssuance")) - .isEqualTo(rule.findStubUrl("org.springframework.cloud.contract.verifier.stubs", "loanIssuance")); - then(rule.findStubUrl("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer")).isNotNull(); - // and: - then(rule.findAllRunningStubs().isPresent("loanIssuance")).isTrue(); - then(rule.findAllRunningStubs().isPresent("org.springframework.cloud.contract.verifier.stubs", - "fraudDetectionServer")).isTrue(); - then(rule.findAllRunningStubs() - .isPresent("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer")).isTrue(); - // and: 'Stubs were registered' - then(httpGet(rule.findStubUrl("loanIssuance").toString() + "/name")).isEqualTo("loanIssuance"); - then(httpGet(rule.findStubUrl("fraudDetectionServer").toString() + "/name")).isEqualTo("fraudDetectionServer"); - // and: 'The port is fixed' - // tag::test_with_port[] - then(rule.findStubUrl("loanIssuance")).isEqualTo(URI.create("http://localhost:35465").toURL()); - then(rule.findStubUrl("fraudDetectionServer")).isEqualTo(URI.create("http://localhost:35466").toURL()); - // end::test_with_port[] - } - - private String httpGet(String url) throws Exception { - try (InputStream stream = URI.create(url).toURL().openStream()) { - return StreamUtils.copyToString(stream, Charset.forName("UTF-8")); - } - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleExceptionThrowingSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleExceptionThrowingSpec.groovy deleted file mode 100644 index ff45ab8fee..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleExceptionThrowingSpec.groovy +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.junit4 - -import org.junit.AfterClass -import org.junit.BeforeClass -import org.junit.ClassRule -import spock.lang.Shared -import spock.lang.Specification - -import org.springframework.cloud.contract.stubrunner.junit.StubRunnerRule -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties - -/** - * @author Marcin Grzejszczak - */ -class StubRunnerRuleExceptionThrowingSpec extends Specification { - - @BeforeClass - @AfterClass - void setupProps() { - System.clearProperty("stubrunner.repository.root") - System.clearProperty("stubrunner.classifier") - } - - @ClassRule - @Shared - StubRunnerRule rule = new StubRunnerRule() - .stubsMode(StubRunnerProperties.StubsMode.REMOTE) - .repoRoot(StubRunnerRuleExceptionThrowingSpec.getResource("/m2repo/repository").toURI().toString()) - .downloadStub("org.springframework.cloud.contract.verifier.stubs", "bootService") - - def 'should throw exception when no message verifier was passed and message related method was triggered'() { - when: - rule.trigger() - then: - thrown(UnsupportedOperationException) - when: - rule.trigger("return_book_1") - then: - thrown(UnsupportedOperationException) - when: - rule.trigger("bootService", "return_book_1") - then: - thrown(UnsupportedOperationException) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleJUnitTest.java b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleJUnitTest.java deleted file mode 100644 index 534004f01f..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleJUnitTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.junit4; - -import java.io.InputStream; -import java.net.URI; -import java.nio.charset.Charset; - -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; - -import org.springframework.cloud.contract.stubrunner.junit.StubRunnerRule; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.util.StreamUtils; - -import static org.assertj.core.api.BDDAssertions.then; - -/** - * @author Marcin Grzejszczak - */ -public class StubRunnerRuleJUnitTest { - - // tag::classrule[] - @ClassRule - public static StubRunnerRule rule = new StubRunnerRule().repoRoot(repoRoot()) - .stubsMode(StubRunnerProperties.StubsMode.REMOTE) - .downloadStub("org.springframework.cloud.contract.verifier.stubs", "loanIssuance") - .downloadStub("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer"); - - @BeforeClass - @AfterClass - public static void setupProps() { - System.clearProperty("stubrunner.repository.root"); - System.clearProperty("stubrunner.classifier"); - } - - // end::classrule[] - - private static String repoRoot() { - try { - return StubRunnerRuleJUnitTest.class.getResource("/m2repo/repository/").toURI().toString(); - } - catch (Exception e) { - return ""; - } - } - - // tag::test[] - @Test - public void should_start_wiremock_servers() throws Exception { - // expect: 'WireMocks are running' - then(rule.findStubUrl("org.springframework.cloud.contract.verifier.stubs", "loanIssuance")).isNotNull(); - then(rule.findStubUrl("loanIssuance")).isNotNull(); - then(rule.findStubUrl("loanIssuance")) - .isEqualTo(rule.findStubUrl("org.springframework.cloud.contract.verifier.stubs", "loanIssuance")); - then(rule.findStubUrl("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer")).isNotNull(); - // and: - then(rule.findAllRunningStubs().isPresent("loanIssuance")).isTrue(); - then(rule.findAllRunningStubs().isPresent("org.springframework.cloud.contract.verifier.stubs", - "fraudDetectionServer")).isTrue(); - then(rule.findAllRunningStubs() - .isPresent("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer")).isTrue(); - // and: 'Stubs were registered' - then(httpGet(rule.findStubUrl("loanIssuance").toString() + "/name")).isEqualTo("loanIssuance"); - then(httpGet(rule.findStubUrl("fraudDetectionServer").toString() + "/name")).isEqualTo("fraudDetectionServer"); - } - // end::test[] - - private String httpGet(String url) throws Exception { - try (InputStream stream = URI.create(url).toURL().openStream()) { - return StreamUtils.copyToString(stream, Charset.forName("UTF-8")); - } - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleSpec.groovy deleted file mode 100644 index a1f0128162..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleSpec.groovy +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.junit4 - -import org.junit.AfterClass -import org.junit.BeforeClass -import org.junit.ClassRule -import spock.lang.Shared -import spock.lang.Specification - -import org.springframework.cloud.contract.stubrunner.junit.StubRunnerRule -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties - -/** - * @author Marcin Grzejszczak - */ -class StubRunnerRuleSpec extends Specification { - - @BeforeClass - @AfterClass - void setupProps() { - System.clearProperty("stubrunner.repository.root") - System.clearProperty("stubrunner.classifier") - } - - // tag::classrule[] - @ClassRule - @Shared - StubRunnerRule rule = new StubRunnerRule() - .stubsMode(StubRunnerProperties.StubsMode.REMOTE) - .repoRoot(StubRunnerRuleSpec.getResource("/m2repo/repository").toURI().toString()) - .downloadStub("org.springframework.cloud.contract.verifier.stubs", "loanIssuance") - .downloadStub("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer") - .withMappingsOutputFolder("target/outputmappingsforrule") - - - def 'should start WireMock servers'() { - expect: 'WireMocks are running' - rule.findStubUrl('org.springframework.cloud.contract.verifier.stubs', 'loanIssuance') != null - rule.findStubUrl('loanIssuance') != null - rule.findStubUrl('loanIssuance') == rule.findStubUrl('org.springframework.cloud.contract.verifier.stubs', 'loanIssuance') - rule.findStubUrl('org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer') != null - and: - rule.findAllRunningStubs().isPresent('loanIssuance') - rule.findAllRunningStubs().isPresent('org.springframework.cloud.contract.verifier.stubs', 'fraudDetectionServer') - rule.findAllRunningStubs().isPresent('org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer') - and: 'Stubs were registered' - "${rule.findStubUrl('loanIssuance').toString()}/name".toURL().text == 'loanIssuance' - "${rule.findStubUrl('fraudDetectionServer').toString()}/name".toURL().text == 'fraudDetectionServer' - } - - def 'should output mappings to output folder'() { - when: - def url = rule.findStubUrl('fraudDetectionServer') - then: - new File("target/outputmappingsforrule", "fraudDetectionServer_${url.port}").exists() - } - // end::classrule[] -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/wiremock/TestWireMockExtensions.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/wiremock/TestWireMockExtensions.groovy deleted file mode 100644 index aa7b2ef9ab..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/wiremock/TestWireMockExtensions.groovy +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.provider.wiremock - -import com.github.tomakehurst.wiremock.common.FileSource -import com.github.tomakehurst.wiremock.extension.Extension -import com.github.tomakehurst.wiremock.extension.Parameters -import com.github.tomakehurst.wiremock.extension.ResponseTransformer -import com.github.tomakehurst.wiremock.http.ChunkedDribbleDelay -import com.github.tomakehurst.wiremock.http.HttpHeader -import com.github.tomakehurst.wiremock.http.HttpHeaders -import com.github.tomakehurst.wiremock.http.Request -import com.github.tomakehurst.wiremock.http.Response -import groovy.transform.CompileStatic - -import org.springframework.cloud.contract.verifier.dsl.wiremock.DefaultResponseTransformer -import org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockExtensions - -/** - * Extension that registers the default response transformer and a custom one too - */ -@CompileStatic -class TestWireMockExtensions implements WireMockExtensions { - @Override - List extensions() { - return [ new DefaultResponseTransformer(), new CustomExtension() ] as List - } -} - -@CompileStatic -class CustomExtension extends ResponseTransformer { - - /** - * We expect the mapping to contain "foo-transformer" in the list - * of "response-transformers" in the stub mapping - */ - @Override - String getName() { - return "foo-transformer" - } - - /** - * Transformer adds a X-My-Header with value "surprise!" to the response - */ - @Override - Response transform(Request request, Response response, FileSource files, Parameters parameters) { - HttpHeaders headers = response.headers + new HttpHeader("X-My-Header", "surprise!") - return Response.response() - .status(response.status) - .statusMessage(response.statusMessage) - .body(response.body) - .headers(headers) - .configured(response.wasConfigured()) - .fault(response.fault) - .incrementInitialDelay(response.initialDelay) - .chunkedDribbleDelay(response.chunkedDribbleDelay) - .fromProxy(response.fromProxy) - .build() - } - - /** - * We don't want this extension to be applied to every single mapping. - * We just want this to take place when a mapping explicitly expresses that in the - * "response-transformers" section - */ - @Override - boolean applyGlobally() { - return false - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStubAccessor.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStubAccessor.groovy deleted file mode 100644 index cfd402d28c..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStubAccessor.groovy +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.provider.wiremock - -class WireMockHttpServerStubAccessor { - - static boolean everyPortRandom() { - assert WireMockHttpServerStub.SERVERS.every { it.value.random } - return true - } - - static void clear() { - WireMockHttpServerStub.SERVERS.clear() - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStubSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStubSpec.groovy deleted file mode 100644 index 1e701e656b..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStubSpec.groovy +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.provider.wiremock - -import com.github.tomakehurst.wiremock.http.RequestMethod -import com.github.tomakehurst.wiremock.stubbing.StubMapping -import org.junit.Rule -import spock.lang.Ignore -import spock.lang.Specification - -import org.springframework.boot.test.system.OutputCaptureRule -import org.springframework.boot.test.web.client.TestRestTemplate -import org.springframework.cloud.contract.stubrunner.HttpServerStubConfiguration -import org.springframework.cloud.contract.stubrunner.HttpServerStubConfigurer -import org.springframework.cloud.test.TestSocketUtils -import org.springframework.http.HttpEntity -import org.springframework.http.HttpMethod -import org.springframework.web.client.RestTemplate - -class WireMockHttpServerStubSpec extends Specification { - public static - final File MAPPING_DESCRIPTOR = new File('src/test/resources/transformers.json') - public static final File ARBITRARY_JSON = new File('src/test/resources/sample_response.json') - public static final File PDF = new File('src/test/resources/request.pdf') - public static final File BROKEN_MAPPING = new File('src/test/resources/broken.json') - - @Rule - OutputCaptureRule capture = new OutputCaptureRule() - - def 'should describe stub mapping'() { - given: - WireMockHttpServerStub mappingDescriptor = new WireMockHttpServerStub().start(new HttpServerStubConfiguration(HttpServerStubConfigurer.NoOpHttpServerStubConfigurer.INSTANCE, null, - null, TestSocketUtils.findAvailableTcpPort())) as WireMockHttpServerStub - when: - StubMapping mapping = mappingDescriptor.getMapping(MAPPING_DESCRIPTOR) - then: - with(mapping) { - assert request.method == RequestMethod.GET - assert request.url == '/ping' - assert response.status == 200 - assert response.body == 'pong' - assert response.headers.contentTypeHeader.mimeTypePart() == 'text/plain' - } - when: - mappingDescriptor.registerMappings([MAPPING_DESCRIPTOR]) - then: - noExceptionThrown() - expect: - URI uri = new URI("http://localhost:" + mappingDescriptor.port() + "/ping") - "surprise!" == new RestTemplate().exchange(uri, HttpMethod.GET, (HttpEntity)null, String.class) - .getHeaders().getFirst("X-My-Header") - cleanup: - mappingDescriptor?.stop() - } - - @Ignore("There's sth wrong with SLF4J versions") - def 'should make WireMock print out logs on INFO'() { - given: - WireMockHttpServerStub mappingDescriptor = new WireMockHttpServerStub().start(new HttpServerStubConfiguration(HttpServerStubConfigurer.NoOpHttpServerStubConfigurer.INSTANCE, null, - null, TestSocketUtils.findAvailableTcpPort())) as WireMockHttpServerStub - mappingDescriptor.registerMappings([ - new File(WireMockHttpServerStubSpec.classLoader.getResource("simple.json").toURI()) - ]) - - when: - String response = new TestRestTemplate().getForObject("http://localhost:${mappingDescriptor.port()}/foobar", String) - - then: - response == "foo" - capture.toString().contains("Matched response definition") - - cleanup: - mappingDescriptor?.stop() - } - - def 'should accept a valid mapping'() { - given: - WireMockHttpServerStub httpServerStub = new WireMockHttpServerStub() - when: - boolean accepted = httpServerStub.isAccepted(MAPPING_DESCRIPTOR) - then: - accepted - } - - def 'should not accept an arbitrary JSON file'() { - given: - WireMockHttpServerStub httpServerStub = new WireMockHttpServerStub() - when: - boolean accepted = httpServerStub.isAccepted(ARBITRARY_JSON) - then: - !accepted - } - - def 'should not accept a broken mapping file'() { - given: - WireMockHttpServerStub httpServerStub = new WireMockHttpServerStub() - when: - boolean accepted = httpServerStub.isAccepted(BROKEN_MAPPING) - then: - !accepted - } - - def 'should not accept a non-JSON file'() { - given: - WireMockHttpServerStub httpServerStub = new WireMockHttpServerStub() - when: - boolean accepted = httpServerStub.isAccepted(PDF) - then: - !accepted - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/server/StubRunnerBootSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/server/StubRunnerBootSpec.groovy deleted file mode 100644 index 201a533d50..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/server/StubRunnerBootSpec.groovy +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.server - -import groovy.json.JsonSlurper -import io.restassured.module.mockmvc.RestAssuredMockMvc -import org.assertj.core.api.BDDAssertions -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.mockito.Mockito - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.cloud.contract.stubrunner.StubRunning -import org.springframework.test.context.ActiveProfiles - -/** - * @author Marcin Grzejszczak - */ -// tag::boot_usage[] -@SpringBootTest(classes = StubRunnerBoot, properties = "spring.cloud.zookeeper.enabled=false") -@ActiveProfiles("test") -class StubRunnerBootSpec { - - @Autowired - StubRunning stubRunning - - @BeforeEach - void setup() { - RestAssuredMockMvc.standaloneSetup(new HttpStubsController(stubRunning), - new TriggerController(stubRunning)) - } - - @Test - void 'should return a list of running stub servers in "full ivy port" notation'() { - when: - String response = RestAssuredMockMvc.get('/stubs').body.asString() - then: - def root = new JsonSlurper().parseText(response) - assert root.'org.springframework.cloud.contract.verifier.stubs:bootService:0.0.1-SNAPSHOT:stubs' instanceof Integer - } - - @Test - void 'should return a port on which a #stubId stub is running'() { - given: - def stubIds = ['org.springframework.cloud.contract.verifier.stubs:bootService:+:stubs', - 'org.springframework.cloud.contract.verifier.stubs:bootService:0.0.1-SNAPSHOT:stubs', - 'org.springframework.cloud.contract.verifier.stubs:bootService:+', - 'org.springframework.cloud.contract.verifier.stubs:bootService', - 'bootService'] - stubIds.each { - when: - def response = RestAssuredMockMvc.get("/stubs/${it}") - then: - assert response.statusCode == 200 - assert Integer.valueOf(response.body.asString()) > 0 - } - } - - @Test - void 'should return 404 when missing stub was called'() { - when: - def response = RestAssuredMockMvc.get("/stubs/a:b:c:d") - then: - assert response.statusCode == 404 - } - - @Test - void 'should return a list of messaging labels that can be triggered when version and classifier are passed'() { - when: - String response = RestAssuredMockMvc.get('/triggers').body.asString() - then: - def root = new JsonSlurper().parseText(response) - assert root.'org.springframework.cloud.contract.verifier.stubs:bootService:0.0.1-SNAPSHOT:stubs'?.containsAll(["return_book_1"]) - } - - @Test - void 'should trigger a messaging label'() { - given: - StubRunning stubRunning = Mockito.mock(StubRunning) - RestAssuredMockMvc.standaloneSetup(new HttpStubsController(stubRunning), new TriggerController(stubRunning)) - when: - def response = RestAssuredMockMvc.post("/triggers/delete_book") - then: - response.statusCode == 200 - and: - Mockito.verify(stubRunning).trigger('delete_book') - } - - @Test - void 'should trigger a messaging label for a stub with #stubId ivy notation'() { - given: - StubRunning stubRunning = Mockito.mock(StubRunning) - RestAssuredMockMvc.standaloneSetup(new HttpStubsController(stubRunning), new TriggerController(stubRunning)) - and: - def stubIds = ['org.springframework.cloud.contract.verifier.stubs:bootService:stubs', 'org.springframework.cloud.contract.verifier.stubs:bootService', 'bootService'] - stubIds.each { - when: - def response = RestAssuredMockMvc.post("/triggers/$it/delete_book") - then: - assert response.statusCode == 200 - and: - Mockito.verify(stubRunning).trigger(it, 'delete_book') - } - - } - - @Test - void 'should throw exception when trigger is missing'() { - when: - BDDAssertions.thenThrownBy(() -> RestAssuredMockMvc.post("/triggers/missing_label")) - .hasMessageContaining("Exception occurred while trying to return [missing_label] label.") - .hasMessageContaining("Available labels are") - .hasMessageContaining("org.springframework.cloud.contract.verifier.stubs:loanIssuance:0.0.1-SNAPSHOT:stubs=[]") - .hasMessageContaining("org.springframework.cloud.contract.verifier.stubs:bootService:0.0.1-SNAPSHOT:stubs=") - } - -} -// end::boot_usage[] diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/serverexamples/StubRunnerBootConsulExample.java b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/serverexamples/StubRunnerBootConsulExample.java deleted file mode 100644 index 5eb5db38d8..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/serverexamples/StubRunnerBootConsulExample.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.serverexamples; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.client.discovery.EnableDiscoveryClient; -import org.springframework.cloud.contract.stubrunner.server.EnableStubRunnerServer; -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner; - -/** - * @author Marcin Grzejszczak - */ -@SpringBootApplication -@EnableStubRunnerServer -@EnableDiscoveryClient -@AutoConfigureStubRunner -public class StubRunnerBootConsulExample { - - public static void main(String[] args) { - SpringApplication.run(StubRunnerBootConsulExample.class, args); - } - -} -/* - * - * -Dstubrunner.repositoryRoot=classpath:m2repo/repository/ - * -Dstubrunner.cloud.stubbed.discovery.enabled=false - * -Dstubrunner.ids=org.springframework.cloud.contract.verifier.stubs:loanIssuance,org. - * springframework.cloud.contract.verifier.stubs:fraudDetectionServer,org.springframework. - * cloud.contract.verifier.stubs:bootService - * -Dstubrunner.idsToServiceIds.fraudDetectionServer= - * someNameThatShouldMapFraudDetectionServer -Dstubrunner.cloud.consul.enabled=true - * -Dstubrunner.camel.enabled=false -Dspring.cloud.zookeeper.enabled=false - * -Deureka.client.enabled=false -Dspring.cloud.zookeeper.discovery.enabled=false - * -Ddebug=true -Dspring.cloud.consul.host=192.168.99.100 - * - */ diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/serverexamples/StubRunnerBootEurekaExample.java b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/serverexamples/StubRunnerBootEurekaExample.java deleted file mode 100644 index 1c33b26645..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/serverexamples/StubRunnerBootEurekaExample.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.serverexamples; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.contract.stubrunner.server.EnableStubRunnerServer; -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner; - -/** - * @author Marcin Grzejszczak - */ -// tag::stubrunnereureka[] -@SpringBootApplication -@EnableStubRunnerServer -@AutoConfigureStubRunner -public class StubRunnerBootEurekaExample { - - public static void main(String[] args) { - SpringApplication.run(StubRunnerBootEurekaExample.class, args); - } - -} -// end::stubrunnereureka[] - -/* - * - * // tag::stubrunnereureka_args[] - * -Dstubrunner.repositoryRoot=https://repo.spring.io/snapshot (1) - * -Dstubrunner.cloud.stubbed.discovery.enabled=false (2) - * -Dstubrunner.ids=org.springframework.cloud.contract.verifier.stubs:loanIssuance,org. - * springframework.cloud.contract.verifier.stubs:fraudDetectionServer,org.springframework. - * cloud.contract.verifier.stubs:bootService (3) - * -Dstubrunner.idsToServiceIds.fraudDetectionServer= - * someNameThatShouldMapFraudDetectionServer (4) - * - * (1) - we tell Stub Runner where all the stubs reside (2) - we don't want the default - * behaviour where the discovery service is stubbed. That's why the stub registration will - * be picked (3) - we provide a list of stubs to download (4) - we provide a list of - * artifactId to serviceId mapping // end::stubrunnereureka_args[] - * - * - * -Dstubrunner.cloud.eureka.enabled=true - * -Dstubrunner.repositoryRoot=classpath:m2repo/repository/ - * -Dstubrunner.camel.enabled=false -Dspring.cloud.zookeeper.enabled=false - * -Dspring.cloud.zookeeper.discovery.enabled=false -Ddebug=true - * - */ diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/serverexamples/StubRunnerBootZookeeperExample.java b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/serverexamples/StubRunnerBootZookeeperExample.java deleted file mode 100644 index 9ab0a3dee1..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/serverexamples/StubRunnerBootZookeeperExample.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.serverexamples; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.client.discovery.EnableDiscoveryClient; -import org.springframework.cloud.contract.stubrunner.server.EnableStubRunnerServer; -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner; - -/** - * @author Marcin Grzejszczak - */ -@SpringBootApplication -@EnableStubRunnerServer -@EnableDiscoveryClient -@AutoConfigureStubRunner -public class StubRunnerBootZookeeperExample { - - public static void main(String[] args) { - SpringApplication.run(StubRunnerBootZookeeperExample.class, args); - } - -} -/* - * - * -Dstubrunner.ids=org.springframework.cloud.contract.verifier.stubs:loanIssuance,org. - * springframework.cloud.contract.verifier.stubs:fraudDetectionServer,org.springframework. - * cloud.contract.verifier.stubs:bootService - * -Dstubrunner.idsToServiceIds.fraudDetectionServer= - * someNameThatShouldMapFraudDetectionServer - * -Dstubrunner.cloud.stubbed.discovery.enabled=false - * -Dstubrunner.cloud.zookeepr.enabled=true -Dstubrunner.camel.enabled=false - * -Dstubrunner.repositoryRoot=classpath:m2repo/repository/ -Deureka.client.enabled=false - * -Ddebug=true - * - */ diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfigurationSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfigurationSpec.groovy deleted file mode 100644 index b971b2e508..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfigurationSpec.groovy +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring - -import com.github.tomakehurst.wiremock.core.WireMockConfiguration -import groovy.transform.CompileStatic -import org.apache.commons.logging.Log -import org.apache.commons.logging.LogFactory -import org.assertj.core.api.BDDAssertions -import org.junit.jupiter.api.AfterAll -import org.junit.jupiter.api.BeforeAll -import org.junit.jupiter.api.Test - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.beans.factory.annotation.Value -import org.springframework.boot.autoconfigure.EnableAutoConfiguration -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.cloud.contract.stubrunner.HttpServerStubConfiguration -import org.springframework.cloud.contract.stubrunner.StubFinder -import org.springframework.cloud.contract.stubrunner.StubNotFoundException -import org.springframework.cloud.contract.stubrunner.provider.wiremock.WireMockHttpServerStubAccessor -import org.springframework.cloud.contract.stubrunner.provider.wiremock.WireMockHttpServerStubConfigurer -import org.springframework.cloud.test.TestSocketUtils -import org.springframework.context.annotation.Configuration -import org.springframework.core.env.Environment -import org.springframework.test.context.ActiveProfiles - -/** - * @author Marcin Grzejszczak - */ - -// Not necessary if Spring Cloud is used. TODO: make it work without this. -// tag::test[] -@SpringBootTest(classes = Config, properties = [" stubrunner.cloud.enabled=false", - 'foo=${stubrunner.runningstubs.fraudDetectionServer.port}', - 'fooWithGroup=${stubrunner.runningstubs.org.springframework.cloud.contract.verifier.stubs.fraudDetectionServer.port}']) -// tag::annotation[] -@AutoConfigureStubRunner(mappingsOutputFolder = "target/outputmappings/", - httpServerStubConfigurer = HttpsForFraudDetection) -// end::annotation[] -@ActiveProfiles("test") -class StubRunnerConfigurationSpec { - - @Autowired - StubFinder stubFinder - @Autowired - Environment environment - @StubRunnerPort("fraudDetectionServer") - int fraudDetectionServerPort - @StubRunnerPort("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer") - int fraudDetectionServerPortWithGroupId - @Value('${foo}') - Integer foo - - @BeforeAll - static void setupSpec() { - System.clearProperty("stubrunner.repository.root") - System.clearProperty("stubrunner.classifier") - WireMockHttpServerStubAccessor.clear() - } - - @AfterAll - static void cleanupSpec() { - setupSpec() - } - - @Test - void 'should mark all ports as random'() { - expect: - WireMockHttpServerStubAccessor.everyPortRandom() - } - - @Test - void 'should start WireMock servers'() { - expect: 'WireMocks are running' - assert stubFinder.findStubUrl('org.springframework.cloud.contract.verifier.stubs', 'loanIssuance') != null - assert stubFinder.findStubUrl('loanIssuance') != null - assert stubFinder.findStubUrl('loanIssuance') == stubFinder.findStubUrl('org.springframework.cloud.contract.verifier.stubs', 'loanIssuance') - assert stubFinder.findStubUrl('loanIssuance') == stubFinder.findStubUrl('org.springframework.cloud.contract.verifier.stubs:loanIssuance') - assert stubFinder.findStubUrl('org.springframework.cloud.contract.verifier.stubs:loanIssuance:0.0.1-SNAPSHOT') == stubFinder.findStubUrl('org.springframework.cloud.contract.verifier.stubs:loanIssuance:0.0.1-SNAPSHOT:stubs') - assert stubFinder.findStubUrl('org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer') != null - and: - assert stubFinder.findAllRunningStubs().isPresent('loanIssuance') - assert stubFinder.findAllRunningStubs().isPresent('org.springframework.cloud.contract.verifier.stubs', 'fraudDetectionServer') - assert stubFinder.findAllRunningStubs().isPresent('org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer') - and: 'Stubs were registered' - assert "${stubFinder.findStubUrl('loanIssuance').toString()}/name".toURL().text == 'loanIssuance' - assert "${stubFinder.findStubUrl('fraudDetectionServer').toString()}/name".toURL().text == 'fraudDetectionServer' - and: 'Fraud Detection is an HTTPS endpoint' - assert stubFinder.findStubUrl('fraudDetectionServer').toString().startsWith("https") - } - - @Test - void 'should throw an exception when stub is not found'() { - when: - BDDAssertions.thenThrownBy(() -> stubFinder.findStubUrl('nonExistingService')).isInstanceOf(StubNotFoundException) - when: - BDDAssertions.thenThrownBy(() -> stubFinder.findStubUrl('nonExistingGroupId', 'nonExistingArtifactId')) - .isInstanceOf(StubNotFoundException) - } - - @Test - void 'should register started servers as environment variables'() { - expect: - assert environment.getProperty("stubrunner.runningstubs.loanIssuance.port") != null - assert stubFinder.findAllRunningStubs().getPort("loanIssuance") == (environment.getProperty("stubrunner.runningstubs.loanIssuance.port") as Integer) - and: - assert environment.getProperty("stubrunner.runningstubs.fraudDetectionServer.port") != null - assert stubFinder.findAllRunningStubs().getPort("fraudDetectionServer") == (environment.getProperty("stubrunner.runningstubs.fraudDetectionServer.port") as Integer) - and: - assert environment.getProperty("stubrunner.runningstubs.fraudDetectionServer.port") != null - assert stubFinder.findAllRunningStubs().getPort("fraudDetectionServer") == (environment.getProperty("stubrunner.runningstubs.org.springframework.cloud.contract.verifier.stubs.fraudDetectionServer.port") as Integer) - } - - @Test - void 'should be able to interpolate a running stub in the passed test property'() { - given: - int fraudPort = stubFinder.findAllRunningStubs().getPort("fraudDetectionServer") - expect: - assert fraudPort > 0 - assert environment.getProperty("foo", Integer) == fraudPort - assert environment.getProperty("fooWithGroup", Integer) == fraudPort - assert foo == fraudPort - } - -// @Issue("#573") - @Test - void 'should be able to retrieve the port of a running stub via an annotation'() { - given: - int fraudPort = stubFinder.findAllRunningStubs().getPort("fraudDetectionServer") - expect: - assert fraudPort > 0 - assert fraudDetectionServerPort == fraudPort - assert fraudDetectionServerPortWithGroupId == fraudPort - } - - @Test - void 'should dump all mappings to a file'() { - when: - def url = stubFinder.findStubUrl("fraudDetectionServer") - then: - assert new File("target/outputmappings/", "fraudDetectionServer_${url.port}").exists() - } - - @Configuration - @EnableAutoConfiguration - static class Config {} - - // tag::wireMockHttpServerStubConfigurer[] - @CompileStatic - static class HttpsForFraudDetection extends WireMockHttpServerStubConfigurer { - - private static final Log log = LogFactory.getLog(HttpsForFraudDetection) - - @Override - WireMockConfiguration configure(WireMockConfiguration httpStubConfiguration, HttpServerStubConfiguration httpServerStubConfiguration) { - if (httpServerStubConfiguration.stubConfiguration.artifactId == "fraudDetectionServer") { - int httpsPort = TestSocketUtils.findAvailableTcpPort() - log.info("Will set HTTPs port [" + httpsPort + "] for fraud detection server") - return httpStubConfiguration - .httpsPort(httpsPort) - } - return httpStubConfiguration - } - } - // end::wireMockHttpServerStubConfigurer[] -} -// end::test[] diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerOptionsBuilderSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerOptionsBuilderSpec.groovy deleted file mode 100644 index 4425280dd2..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerOptionsBuilderSpec.groovy +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring - -import org.junit.jupiter.api.Test - -import org.springframework.beans.factory.annotation.Value -import org.springframework.boot.autoconfigure.EnableAutoConfiguration -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.context.annotation.Configuration -import org.springframework.test.context.ActiveProfiles -/** - * @author Marcin Grzejszczak - */ - -@SpringBootTest(classes = Config, properties = ['some.property1=org.springframework.cloud.contract.verifier.stubs:loanIssuance']) -@AutoConfigureStubRunner -@ActiveProfiles("test-with-placeholders") -class StubRunnerOptionsBuilderSpec { - - @StubRunnerPort("fraudDetectionServer") - int fraudDetectionServerPort - - @StubRunnerPort("loanIssuance") - int loanIssuancePort - - @Value('${stub.port}') - int stubPort - - @Test - void 'should resolve placeholders'() { - expect: - assert fraudDetectionServerPort > 1000 - assert loanIssuancePort > 1000 - and: - assert stubPort == fraudDetectionServerPort - } - - @Configuration - @EnableAutoConfiguration - static class Config {} -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubMapperPropertiesSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubMapperPropertiesSpec.groovy deleted file mode 100644 index 1a071d5a9c..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubMapperPropertiesSpec.groovy +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring.cloud - -import spock.lang.Specification - -/** - * @author Marcin Grzejszczak - */ -class StubMapperPropertiesSpec extends Specification { - - def "should convert ivy notation to serviceId by fallbacking to artifactId if nothing else matches"() { - given: - Map idsToServiceIds = [ - fraudDetectionServer: 'someNameThatShouldMapFraudDetectionServer' - ] - StubMapperProperties properties = new StubMapperProperties(idsToServiceIds: idsToServiceIds) - expect: - 'someNameThatShouldMapFraudDetectionServer' == properties.fromIvyNotationToId('fraudDetectionServer') - 'someNameThatShouldMapFraudDetectionServer' == properties.fromIvyNotationToId('groupid:fraudDetectionServer') - 'someNameThatShouldMapFraudDetectionServer' == properties.fromIvyNotationToId('groupid:fraudDetectionServer:+:classifier') - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerSpringCloudAutoConfigurationSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerSpringCloudAutoConfigurationSpec.groovy deleted file mode 100644 index 5183c14507..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerSpringCloudAutoConfigurationSpec.groovy +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring.cloud - -import org.junit.jupiter.api.AfterAll -import org.junit.jupiter.api.BeforeAll -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.autoconfigure.EnableAutoConfiguration -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.cloud.client.loadbalancer.LoadBalanced -import org.springframework.cloud.consul.ConsulAutoConfiguration -import org.springframework.cloud.contract.stubrunner.StubFinder -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties -import org.springframework.cloud.contract.stubrunner.spring.cloud.loadbalancer.StubRunnerLoadBalancerClientFactory -import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory -import org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration -import org.springframework.cloud.zookeeper.ZookeeperAutoConfiguration -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.test.context.ActiveProfiles -import org.springframework.web.client.RestTemplate - -/** - * @author Marcin Grzejszczak - */ -@SpringBootTest(classes = Config) -@ActiveProfiles("cloudtest") -// tag::autoconfigure[] -@AutoConfigureStubRunner( - ids = ["org.springframework.cloud.contract.verifier.stubs:loanIssuance", - "org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer", - "org.springframework.cloud.contract.verifier.stubs:bootService"], - stubsMode = StubRunnerProperties.StubsMode.REMOTE, - repositoryRoot = "classpath:m2repo/repository/") -// end::autoconfigure[] -class StubRunnerSpringCloudAutoConfigurationSpec { - - @Autowired - StubFinder stubFinder - @Autowired - @LoadBalanced - RestTemplate restTemplate - @Autowired - LoadBalancerClientFactory loadBalancerClientFactory; - - @BeforeAll - static void setupSpec() { - System.clearProperty("stubrunner.repository.root") - System.clearProperty("stubrunner.classifier") - } - - @AfterAll - static void cleanupSpec() { - setupSpec() - } - - @BeforeEach - void setup() { - assert loadBalancerClientFactory.getClass().getSimpleName() == "StubRunnerLoadBalancerClientFactory" - } - - // tag::test[] - @Test - void 'should make service discovery work'() { - expect: 'WireMocks are running' - assert "${stubFinder.findStubUrl('loanIssuance').toString()}/name".toURL().text == 'loanIssuance' - assert "${stubFinder.findStubUrl('fraudDetectionServer').toString()}/name".toURL().text == 'fraudDetectionServer' - and: 'Stubs can be reached via load service discovery' - assert restTemplate.getForObject('http://loanIssuance/name', String) == 'loanIssuance' - assert restTemplate.getForObject('http://someNameThatShouldMapFraudDetectionServer/name', String) == 'fraudDetectionServer' - } - // end::test[] - - @Configuration - @EnableAutoConfiguration(exclude = [EurekaClientAutoConfiguration, - ConsulAutoConfiguration, ZookeeperAutoConfiguration]) - static class Config { - - @Bean - @LoadBalanced - RestTemplate restTemplate() { - return new RestTemplate() - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerSpringCloudReactiveAutoConfigurationSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerSpringCloudReactiveAutoConfigurationSpec.groovy deleted file mode 100644 index 6466928c58..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerSpringCloudReactiveAutoConfigurationSpec.groovy +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring.cloud - -import org.junit.AfterClass -import org.junit.BeforeClass -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.autoconfigure.EnableAutoConfiguration -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.cloud.client.ServiceInstance -import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient -import org.springframework.cloud.client.loadbalancer.LoadBalanced -import org.springframework.cloud.consul.ConsulAutoConfiguration -import org.springframework.cloud.contract.stubrunner.StubFinder -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties -import org.springframework.cloud.contract.stubrunner.spring.cloud.loadbalancer.StubRunnerLoadBalancerClientFactory -import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory -import org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration -import org.springframework.cloud.zookeeper.ZookeeperAutoConfiguration -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.test.context.ActiveProfiles -import org.springframework.web.client.RestTemplate - -/** - * @author Marcin Grzejszczak - */ -@SpringBootTest(classes = Config) -@ActiveProfiles("cloudtest") -@AutoConfigureStubRunner( - ids = ["org.springframework.cloud.contract.verifier.stubs:loanIssuance", - "org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer", - "org.springframework.cloud.contract.verifier.stubs:bootService"], - stubsMode = StubRunnerProperties.StubsMode.REMOTE, - repositoryRoot = "classpath:m2repo/repository/") -class StubRunnerSpringCloudReactiveAutoConfigurationSpec { - @Autowired - StubFinder stubFinder - @Autowired - ReactiveDiscoveryClient reactiveDiscoveryClient; - @Autowired - LoadBalancerClientFactory loadBalancerClientFactory; - RestTemplate restTemplate = new RestTemplate() - - @BeforeClass - @AfterClass - static void setupProps() { - System.clearProperty("stubrunner.repository.root") - System.clearProperty("stubrunner.classifier") - } - - @BeforeEach - void setup() { - assert loadBalancerClientFactory.getClass().getSimpleName() == "StubRunnerLoadBalancerClientFactory" - } - - // tag::test[] - @Test - void 'should make service discovery work'() { - expect: 'WireMocks are running' - assert "${stubFinder.findStubUrl('loanIssuance').toString()}/name".toURL().text == 'loanIssuance' - assert "${stubFinder.findStubUrl('fraudDetectionServer').toString()}/name".toURL().text == 'fraudDetectionServer' - and: 'Stubs can be reached via load service discovery' - ServiceInstance loanIssuance = reactiveDiscoveryClient.getInstances('loanIssuance').blockFirst() - assert restTemplate.getForObject(loanIssuance.uri.toString() + '/name', String) == 'loanIssuance' - ServiceInstance fraudDetection = reactiveDiscoveryClient.getInstances('someNameThatShouldMapFraudDetectionServer').blockFirst() - assert restTemplate.getForObject(fraudDetection.uri.toString() + '/name', String) == 'fraudDetectionServer' - } - // end::test[] - - @Configuration - @EnableAutoConfiguration(exclude = [EurekaClientAutoConfiguration, - ConsulAutoConfiguration, ZookeeperAutoConfiguration]) - static class Config { - - @Bean - @LoadBalanced - RestTemplate restTemplate() { - return new RestTemplate() - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerStubsPerConsumerSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerStubsPerConsumerSpec.groovy deleted file mode 100644 index 912c607f43..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerStubsPerConsumerSpec.groovy +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring.cloud - -import java.util.function.Function - -import org.assertj.core.api.BDDAssertions -import org.junit.jupiter.api.Test - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.autoconfigure.EnableAutoConfiguration -import org.springframework.boot.autoconfigure.ImportAutoConfiguration -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.boot.test.web.client.TestRestTemplate -import org.springframework.cloud.contract.stubrunner.StubFinder -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver -import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.core.env.Environment -import org.springframework.http.ResponseEntity -import org.springframework.messaging.Message -import org.springframework.test.context.ActiveProfiles -/** - * @author Marcin Grzejszczak - */ -// tag::test[] -@SpringBootTest(classes = Config, properties = ["spring.application.name=bar-consumer"]) -@AutoConfigureStubRunner(ids = "org.springframework.cloud.contract.verifier.stubs:producerWithMultipleConsumers", - repositoryRoot = "classpath:m2repo/repository/", - stubsMode = StubRunnerProperties.StubsMode.REMOTE, - stubsPerConsumer = true) -@ActiveProfiles("streamconsumer") -class StubRunnerStubsPerConsumerSpec { -// end::test[] - - @Autowired - StubFinder stubFinder - @Autowired - Environment environment - @Autowired - MessageVerifierReceiver> messaging - TestRestTemplate template = new TestRestTemplate() - - @Test - void 'should start http stub servers for bar-consumer only'() { - given: - URL stubUrl = stubFinder.findStubUrl('producerWithMultipleConsumers') - when: - ResponseEntity entity = template.getForEntity("${stubUrl}/bar-consumer", String) - then: - assert entity.statusCode.value() == 200 - when: - entity = template.getForEntity("${stubUrl}/foo-consumer", String) - then: - assert entity.statusCode.value() == 404 - } - - @Test - void 'should trigger a message by label from proper consumer'() { - when: - stubFinder.trigger('return_book_for_bar') - then: - Message receivedMessage = messaging.receive('output') - and: - assert receivedMessage != null - assert receivedMessage.payload == '''{"bookName":"foo_for_bar"}'''.bytes - assert receivedMessage.headers.get('BOOK-NAME') == 'foo_for_bar' - } - - @Test - void 'should not trigger a message by the not matching consumer'() { - when: - BDDAssertions.thenThrownBy(() -> stubFinder.trigger('return_book_for_foo')).isInstanceOf(IllegalArgumentException).hasMessageContaining("No label with name [return_book_for_foo] was found") - } - - @Configuration - @EnableAutoConfiguration - @ImportAutoConfiguration(TestChannelBinderConfiguration.class) - static class Config { - @Bean - Function output() { - return { Object o -> - println(o) - return o - } - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerStubsPerConsumerWithConsumerNameSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerStubsPerConsumerWithConsumerNameSpec.groovy deleted file mode 100644 index f39fdf111a..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerStubsPerConsumerWithConsumerNameSpec.groovy +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring.cloud - -import java.util.function.Function - -import org.assertj.core.api.BDDAssertions -import org.junit.jupiter.api.Test - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.autoconfigure.EnableAutoConfiguration -import org.springframework.boot.autoconfigure.ImportAutoConfiguration -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.boot.test.web.client.TestRestTemplate -import org.springframework.cloud.contract.stubrunner.StubFinder -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver -import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.core.env.Environment -import org.springframework.http.ResponseEntity -import org.springframework.messaging.Message -import org.springframework.test.context.ActiveProfiles -/** - * @author Marcin Grzejszczak - */ -// tag::test[] -@SpringBootTest(classes = Config) -@AutoConfigureStubRunner(ids = "org.springframework.cloud.contract.verifier.stubs:producerWithMultipleConsumers", - repositoryRoot = "classpath:m2repo/repository/", - consumerName = "foo-consumer", - stubsMode = StubRunnerProperties.StubsMode.REMOTE, - stubsPerConsumer = true) -@ActiveProfiles("streamconsumer") -class StubRunnerStubsPerConsumerWithConsumerNameSpec { -// end::test[] - - @Autowired - StubFinder stubFinder - @Autowired - Environment environment - @Autowired - MessageVerifierReceiver> messaging - - TestRestTemplate template = new TestRestTemplate() - - @Test - void 'should start http stub servers for foo-consumer only'() { - given: - URL stubUrl = stubFinder.findStubUrl('producerWithMultipleConsumers') - when: - ResponseEntity entity = template.getForEntity("${stubUrl}/foo-consumer", String) - then: - assert entity.statusCode.value() == 200 - when: - entity = template.getForEntity("${stubUrl}/bar-consumer", String) - then: - assert entity.statusCode.value() == 404 - } - - @Test - void 'should trigger a message by label from proper consumer'() { - when: - stubFinder.trigger('return_book_for_foo') - then: - Message receivedMessage = messaging.receive('output') - and: - assert receivedMessage != null - assert receivedMessage.payload == '''{"bookName":"foo_for_foo"}'''.bytes - assert receivedMessage.headers.get('BOOK-NAME') == 'foo_for_foo' - } - - @Test - void 'should not trigger a message by the not matching consumer'() { - when: - BDDAssertions.thenThrownBy(() -> stubFinder.trigger('return_book_for_bar')).isInstanceOf(IllegalArgumentException) - .hasMessageContaining("No label with name [return_book_for_bar] was found") - } - - @Configuration - @EnableAutoConfiguration - @ImportAutoConfiguration(TestChannelBinderConfiguration.class) - static class Config { - @Bean - Function output() { - return { Object o -> - println(o) - return o - } - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/consul/StubRunnerSpringCloudConsulAutoConfigurationSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/consul/StubRunnerSpringCloudConsulAutoConfigurationSpec.groovy deleted file mode 100644 index 663a8cf34f..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/consul/StubRunnerSpringCloudConsulAutoConfigurationSpec.groovy +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring.cloud.consul - -import com.ecwid.consul.v1.ConsulClient -import com.ecwid.consul.v1.agent.model.NewService -import groovy.transform.CompileStatic -import org.junit.jupiter.api.AfterAll -import org.junit.jupiter.api.BeforeAll -import org.junit.jupiter.api.Test -import org.mockito.ArgumentMatcher - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.autoconfigure.EnableAutoConfiguration -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.cloud.client.discovery.EnableDiscoveryClient -import org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration - -import static org.mockito.BDDMockito.then -import static org.mockito.Matchers.argThat -import static org.mockito.Mockito.mock -/** - * @author Marcin Grzejszczak - */ -@SpringBootTest(classes = Config, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - properties = ["eureka.client.enabled=false", - "spring.cloud.zookeeper.enabled=false", - "stubrunner.cloud.stubbed.discovery.enabled=false", - "stubrunner.cloud.eureka.enabled=false", - "spring.cloud.zookeeper.discovery.enabled=false", - "stubrunner.cloud.consul.enabled=true", - "stubrunner.cloud.zookeeper.enabled=false", - "debug=true"]) -// tag::autoconfigure[] -@AutoConfigureStubRunner(ids = ["org.springframework.cloud.contract.verifier.stubs:loanIssuance", - "org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer", - "org.springframework.cloud.contract.verifier.stubs:bootService"] , -stubsMode = StubRunnerProperties.StubsMode.REMOTE , -repositoryRoot = "classpath:m2repo/repository/" ) -// end::autoconfigure[] -class StubRunnerSpringCloudConsulAutoConfigurationSpec { - - @Autowired - ConsulClient client - - @BeforeAll - static void setupSpec() { - System.clearProperty("stubrunner.stubs.repository.root") - System.clearProperty("stubrunner.stubs.classifier") - } - - @AfterAll - static void cleanupSpec() { - setupSpec() - } - - @Test - void 'should make service discovery work for #serviceName'() { - - given: - def serviceName = ['loanIssuance:loanIssuance', 'bootService:bootService', 'fraudDetectionServer:someNameThatShouldMapFraudDetectionServer'] - when: - serviceName.each { - and: - final String expectedId = it.split(':')[0] - final String expectedName = it.split(':')[1] - then: 'Consul registration took place for 3 stubs' - then(client).should().agentServiceRegister(argThat(new NewServiceMatcher(expectedId, expectedName))) - } - } - - private static class NewServiceMatcher implements ArgumentMatcher { - - private final String expectedId - private final String expectedName - - NewServiceMatcher(String expectedId, String expectedName) { - this.expectedId = expectedId - this.expectedName = expectedName - } - - @Override - boolean matches(NewService item) { - return item.id == expectedId && item.name == expectedName - } - } - - @CompileStatic - @Configuration - @EnableAutoConfiguration - @EnableDiscoveryClient - static class Config { - - @Bean - ConsulClient mockedConsulClient() { - return mock(ConsulClient) - } - - @Bean - ConsulDiscoveryProperties consulDiscoveryProperties() { - return mock(ConsulDiscoveryProperties) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/util/ZipCategorySpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/util/ZipCategorySpec.groovy deleted file mode 100644 index 9544779d7e..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/util/ZipCategorySpec.groovy +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.util - - -import spock.lang.Specification - -class ZipCategorySpec extends Specification { - - def 'should unzip a file to the specified location'() { - given: - File zipFile = new File(ZipCategorySpec.classLoader.getResource('file.zip').toURI()) - File tempDir = File.createTempDir() - tempDir.deleteOnExit() - when: - use(ZipCategory) { - zipFile.unzipTo(tempDir) - } - then: - tempDir.listFiles().find { - it.name == 'file.txt' - }?.text?.trim() == 'test' - } - - def 'should not allow malicious traversal'() throws Exception { - given: - File zipFile = new File(ZipCategorySpec.classLoader.getResource('zip/zip-malicious-traversal.zip').toURI()) - File tempDir = File.createTempDir() - tempDir.deleteOnExit() - when: - use(ZipCategory) { - zipFile.unzipTo(tempDir) - } - then: - Exception e = thrown() - e.getCause().getMessage().contains("is trying to leave the target output directory") - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/AbstractGitTest.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/AbstractGitTest.java deleted file mode 100644 index 1229dd1afe..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/AbstractGitTest.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.net.URISyntaxException; - -import org.eclipse.jgit.api.Git; -import org.eclipse.jgit.api.RemoteRemoveCommand; -import org.eclipse.jgit.api.RemoteSetUrlCommand; -import org.eclipse.jgit.api.errors.GitAPIException; -import org.eclipse.jgit.lib.StoredConfig; -import org.eclipse.jgit.transport.RefSpec; -import org.eclipse.jgit.transport.RemoteConfig; -import org.eclipse.jgit.transport.URIish; -import org.junit.Before; -import org.junit.Rule; -import org.junit.rules.TemporaryFolder; - -/** - * @author Marcin Grzejszczak - */ -public abstract class AbstractGitTest { - - @Rule - public TemporaryFolder tmp = new TemporaryFolder(); - - File tmpFolder; - - @Before - public void setupTemp() throws IOException { - this.tmpFolder = this.tmp.newFolder(); - } - - File createNewFile(File project) throws Exception { - File newFile = new File(project, "newFile"); - newFile.createNewFile(); - try (PrintStream out = new PrintStream(new FileOutputStream(newFile))) { - out.print("foo"); - } - try (Git git = openGitProject(project)) { - git.add().addFilepattern("newFile").call(); - } - return newFile; - } - - void setOriginOnProjectToTmp(File origin, File project, boolean push) - throws GitAPIException, IOException, URISyntaxException { - try (Git git = openGitProject(project)) { - RemoteRemoveCommand remove = git.remoteRemove(); - remove.setRemoteName("origin"); - remove.call(); - RemoteSetUrlCommand command = git.remoteSetUrl(); - command.setRemoteUri(new URIish(origin.toURI().toURL())); - command.setRemoteName("origin"); - command.setUriType(RemoteSetUrlCommand.UriType.PUSH); - command.call(); - StoredConfig config = git.getRepository().getConfig(); - RemoteConfig originConfig = new RemoteConfig(config, "origin"); - originConfig.addFetchRefSpec(new RefSpec("+refs/heads/*:refs/remotes/origin/*")); - originConfig.update(config); - config.save(); - } - } - - Git openGitProject(File project) { - return new GitRepo.JGitFactory().open(project); - } - - File clonedProject(File baseDir, File projectToClone) { - GitRepo projectRepo = new GitRepo(baseDir); - projectRepo.cloneProject(projectToClone.toURI()); - return baseDir; - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/ClasspathStubProviderTest.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/ClasspathStubProviderTest.java deleted file mode 100644 index a44c36ccec..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/ClasspathStubProviderTest.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import org.junit.Test; - -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; - -import static org.assertj.core.api.BDDAssertions.then; - -/** - * @author Marcin Grzejszczak - */ -public class ClasspathStubProviderTest { - - @Test - public void should_return_null_if_stub_mode_is_not_classpath() { - StubDownloader stubDownloader = new ClasspathStubProvider() - .build(new StubRunnerOptionsBuilder().withStubsMode(StubRunnerProperties.StubsMode.REMOTE).build()); - - then(stubDownloader).isNull(); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/CompositeStubDownloaderBuilderTests.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/CompositeStubDownloaderBuilderTests.java deleted file mode 100644 index 798a536b8a..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/CompositeStubDownloaderBuilderTests.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.util.AbstractMap; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import org.assertj.core.api.BDDAssertions; -import org.junit.Test; - -/** - * @author Marcin Grzejszczak - */ -public class CompositeStubDownloaderBuilderTests { - - @Test - public void should_delegate_work_to_other_stub_downloaders() { - EmptyStubDownloaderBuilder emptyStubDownloaderBuilder = new EmptyStubDownloaderBuilder(); - ImpossibleToBuildStubDownloaderBuilder impossible = new ImpossibleToBuildStubDownloaderBuilder(); - List builders = Arrays.asList(emptyStubDownloaderBuilder, impossible, - new SomeStubDownloaderBuilder()); - CompositeStubDownloaderBuilder builder = new CompositeStubDownloaderBuilder(builders); - StubDownloader downloader = builder.build(new StubRunnerOptionsBuilder().build()); - - Map.Entry entry = downloader.downloadAndUnpackStubJar(new StubConfiguration("a:b:v")); - - BDDAssertions.then(entry).isNotNull(); - BDDAssertions.then(emptyStubDownloaderBuilder.downloaderCalled()).isTrue(); - BDDAssertions.then(impossible.called).isTrue(); - } - - @Test - public void should_return_null_if_no_builders_were_passed() { - CompositeStubDownloaderBuilder builder = new CompositeStubDownloaderBuilder(null); - - StubDownloader downloader = builder.build(new StubRunnerOptionsBuilder().build()); - - BDDAssertions.then(downloader).isNull(); - } - - @Test - public void should_return_null_when_no_entries_were_found() { - EmptyStubDownloaderBuilder emptyStubDownloaderBuilder = new EmptyStubDownloaderBuilder(); - CompositeStubDownloaderBuilder builder = new CompositeStubDownloaderBuilder( - Collections.singletonList(emptyStubDownloaderBuilder)); - StubDownloader downloader = builder.build(new StubRunnerOptionsBuilder().withFailOnNoStubs(false).build()); - - Map.Entry entry = downloader.downloadAndUnpackStubJar(new StubConfiguration("a:b:v")); - - BDDAssertions.then(entry).isNull(); - } - - @Test - public void should_throw_exception_when_no_entries_were_found_and_a_switch_to_throw_exception_was_set() { - EmptyStubDownloaderBuilder emptyStubDownloaderBuilder = new EmptyStubDownloaderBuilder(); - CompositeStubDownloaderBuilder builder = new CompositeStubDownloaderBuilder( - Collections.singletonList(emptyStubDownloaderBuilder)); - StubDownloader downloader = builder.build(new StubRunnerOptionsBuilder().withFailOnNoStubs(true).build()); - - BDDAssertions.thenThrownBy(() -> downloader.downloadAndUnpackStubJar(new StubConfiguration("a:b:v"))) - .isInstanceOf(IllegalArgumentException.class); - } - -} - -class EmptyStubDownloaderBuilder implements StubDownloaderBuilder { - - EmptyStubDownloader emptyStubDownloader; - - @Override - public StubDownloader build(StubRunnerOptions stubRunnerOptions) { - this.emptyStubDownloader = new EmptyStubDownloader(); - return this.emptyStubDownloader; - } - - boolean downloaderCalled() { - return this.emptyStubDownloader.called; - } - -} - -class ImpossibleToBuildStubDownloaderBuilder implements StubDownloaderBuilder { - - boolean called; - - @Override - public StubDownloader build(StubRunnerOptions stubRunnerOptions) { - this.called = true; - return null; - } - -} - -class EmptyStubDownloader implements StubDownloader { - - boolean called; - - @Override - public Map.Entry downloadAndUnpackStubJar(StubConfiguration stubConfiguration) { - this.called = true; - return null; - } - -} - -class SomeStubDownloaderBuilder implements StubDownloaderBuilder { - - @Override - public StubDownloader build(StubRunnerOptions stubRunnerOptions) { - return new SomeStubDownloader(); - } - -} - -class SomeStubDownloader implements StubDownloader { - - @Override - public Map.Entry downloadAndUnpackStubJar(StubConfiguration stubConfiguration) { - return new AbstractMap.SimpleEntry<>(stubConfiguration, new File(".")); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/ContractProjectUpdaterTest.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/ContractProjectUpdaterTest.java deleted file mode 100644 index 1d9615dbf6..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/ContractProjectUpdaterTest.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.util.HashMap; - -import org.assertj.core.api.BDDAssertions; -import org.eclipse.jgit.api.Git; -import org.eclipse.jgit.api.ResetCommand; -import org.eclipse.jgit.revwalk.RevCommit; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; - -import org.springframework.boot.test.system.OutputCaptureRule; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; - -import static org.assertj.core.api.BDDAssertions.then; - -/** - * @author Marcin Grzejszczak - */ -public class ContractProjectUpdaterTest extends AbstractGitTest { - - @Rule - public OutputCaptureRule outputCapture = new OutputCaptureRule(); - - File originalProject; - - File project; - - ContractProjectUpdater updater; - - GitRepo gitRepo; - - File origin; - - @Before - public void setup() throws Exception { - GitContractsRepo.CACHED_LOCATIONS.clear(); - this.originalProject = new File(GitRepoTests.class.getResource("/git_samples/contract-git").toURI()); - TestUtils.prepareLocalRepo(); - this.gitRepo = new GitRepo(this.tmpFolder); - this.origin = clonedProject(this.tmp.newFolder(), this.originalProject); - this.project = this.gitRepo.cloneProject(this.originalProject.toURI()); - this.gitRepo.checkout(this.project, "master"); - setOriginOnProjectToTmp(this.origin, this.project, true); - StubRunnerOptions options = new StubRunnerOptionsBuilder() - .withStubRepositoryRoot("file://" + this.project.getAbsolutePath() + "/") - .withStubsMode(StubRunnerProperties.StubsMode.REMOTE).build(); - this.updater = new ContractProjectUpdater(options); - } - - @Test - public void should_push_changes_to_current_branch() throws Exception { - File stubs = new File(GitRepoTests.class.getResource("/git_samples/sample_stubs").toURI()); - - this.updater.updateContractProject("hello-world", stubs.toPath()); - - // project, not origin, cause we're making one more clone of the local copy - try (Git git = openGitProject(this.project)) { - RevCommit revCommit = git.log().call().iterator().next(); - then(revCommit.getShortMessage()).isEqualTo("Updating project [hello-world] with stubs"); - // I have no idea but the file gets deleted after pushing - git.reset().setMode(ResetCommand.ResetType.HARD).call(); - } - BDDAssertions.then(new File(this.project, "META-INF/com.example/hello-world/0.0.2/mappings/someMapping.json")) - .exists(); - BDDAssertions.then(this.gitRepo.gitFactory.provider).isNull(); - BDDAssertions.then(this.outputCapture.toString()).contains("No custom credentials provider will be set"); - } - - @Test - public void should_push_changes_to_current_branch_using_credentials() throws Exception { - StubRunnerOptions options = new StubRunnerOptionsBuilder() - .withStubRepositoryRoot("file://" + this.project.getAbsolutePath() + "/") - .withStubsMode(StubRunnerProperties.StubsMode.REMOTE).withProperties(new HashMap() { - { - put("git.username", "foo"); - put("git.password", "bar"); - } - }).build(); - ContractProjectUpdater updater = new ContractProjectUpdater(options); - File stubs = new File(GitRepoTests.class.getResource("/git_samples/sample_stubs").toURI()); - - updater.updateContractProject("hello-world", stubs.toPath()); - - // project, not origin, cause we're making one more clone of the local copy - try (Git git = openGitProject(this.project)) { - RevCommit revCommit = git.log().call().iterator().next(); - then(revCommit.getShortMessage()).isEqualTo("Updating project [hello-world] with stubs"); - // I have no idea but the file gets deleted after pushing - git.reset().setMode(ResetCommand.ResetType.HARD).call(); - } - BDDAssertions.then(new File(this.project, "META-INF/com.example/hello-world/0.0.2/mappings/someMapping.json")) - .exists(); - BDDAssertions.then(this.outputCapture.toString()) - .contains("Passed username and password - will set a custom credentials provider"); - } - - @Test - public void should_push_changes_to_current_branch_using_root_credentials() throws Exception { - StubRunnerOptions options = new StubRunnerOptionsBuilder() - .withStubRepositoryRoot("file://" + this.project.getAbsolutePath() + "/") - .withStubsMode(StubRunnerProperties.StubsMode.REMOTE).withUsername("foo").withPassword("bar").build(); - ContractProjectUpdater updater = new ContractProjectUpdater(options); - File stubs = new File(GitRepoTests.class.getResource("/git_samples/sample_stubs").toURI()); - - updater.updateContractProject("hello-world", stubs.toPath()); - - // project, not origin, cause we're making one more clone of the local copy - try (Git git = openGitProject(this.project)) { - RevCommit revCommit = git.log().call().iterator().next(); - then(revCommit.getShortMessage()).isEqualTo("Updating project [hello-world] with stubs"); - // I have no idea but the file gets deleted after pushing - git.reset().setMode(ResetCommand.ResetType.HARD).call(); - } - BDDAssertions.then(new File(this.project, "META-INF/com.example/hello-world/0.0.2/mappings/someMapping.json")) - .exists(); - BDDAssertions.then(this.outputCapture.toString()) - .contains("Passed username and password - will set a custom credentials provider"); - } - - @Test - public void should_not_push_changes_to_current_branch_when_no_changes_were_made() throws Exception { - String initialCommit; - try (Git git = openGitProject(this.origin)) { - RevCommit revCommit = git.log().call().iterator().next(); - initialCommit = revCommit.getShortMessage(); - } - - this.updater.updateContractProject("hello-world", this.origin.toPath()); - - try (Git git = openGitProject(this.project)) { - RevCommit revCommit = git.log().call().iterator().next(); - then(revCommit.getShortMessage()).isEqualTo(initialCommit); - } - BDDAssertions.then(new File(this.project, "META-INF/com.example/hello-world/0.0.2/mappings/someMapping.json")) - .doesNotExist(); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/FileStubDownloaderTests.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/FileStubDownloaderTests.java deleted file mode 100644 index 48da145b99..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/FileStubDownloaderTests.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import org.assertj.core.api.Assertions; -import org.junit.Test; - -import org.springframework.core.io.Resource; - -/** - * @author Matty A - */ -public class FileStubDownloaderTests { - - @Test - public void resolve() { - final FileStubDownloader fileStubDownloader = new FileStubDownloader(); - Resource expectedUnixResource = new StubsResource("stubs://file:///User/A/B/C"); - Resource expectedWindowsResource = new StubsResource("stubs://file:///C:/Users/A/B/C"); - String unixFileFormat = "stubs://file:///User/A/B/C"; - String windowsFileFormat = "stubs://file://C:\\Users\\A\\B\\C"; - String windowsFileFormatCorrectPathStart = "stubs://file:///C:\\Users\\A\\B\\C"; - Assertions.assertThat(expectedUnixResource).isEqualTo(fileStubDownloader.resolve(unixFileFormat, null)); - Assertions.assertThat(expectedWindowsResource).isEqualTo(fileStubDownloader.resolve(windowsFileFormat, null)); - Assertions.assertThat(expectedWindowsResource) - .isEqualTo(fileStubDownloader.resolve(windowsFileFormatCorrectPathStart, null)); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/GitRepoTests.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/GitRepoTests.java deleted file mode 100644 index 34edef8835..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/GitRepoTests.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; - -import org.eclipse.jgit.api.CloneCommand; -import org.eclipse.jgit.api.Git; -import org.eclipse.jgit.revwalk.RevCommit; -import org.junit.Before; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; -import static org.assertj.core.api.BDDAssertions.then; -import static org.assertj.core.api.BDDAssertions.thenThrownBy; - -/** - * @author Marcin Grzejszczak taken from: - * https://github.com/spring-cloud/spring-cloud-release-tools - */ -public class GitRepoTests extends AbstractGitTest { - - File project; - - GitRepo gitRepo; - - @Before - public void setup() throws IOException, URISyntaxException { - this.project = new File(GitRepoTests.class.getResource("/git_samples/contract-git").toURI()); - TestUtils.prepareLocalRepo(); - this.gitRepo = new GitRepo(this.tmpFolder); - } - - @Test - public void should_clone_the_project_from_a_given_location() throws IOException { - this.gitRepo.cloneProject(this.project.toURI()); - - then(new File(this.tmpFolder, ".git")).exists(); - } - - @Test - public void should_throw_exception_when_there_is_no_repo() throws IOException, URISyntaxException { - thenThrownBy(() -> this.gitRepo.cloneProject(GitRepoTests.class.getResource("/git_samples/").toURI())) - .isInstanceOf(IllegalStateException.class) - .hasMessageContaining("Exception occurred while cloning repo"); - } - - @Test - public void should_throw_an_exception_when_failed_to_initialize_the_repo() throws IOException { - thenThrownBy(() -> new GitRepo(this.tmpFolder, new ExceptionThrowingJGitFactory()) - .cloneProject(this.project.toURI())).isInstanceOf(IllegalStateException.class) - .hasMessageContaining("Exception occurred while cloning repo") - .hasCauseInstanceOf(CustomException.class); - } - - @Test - public void should_check_out_a_branch_on_cloned_repo() throws IOException { - File project = this.gitRepo.cloneProject(this.project.toURI()); - this.gitRepo.checkout(project, "master"); - - File pom = new File(this.tmpFolder, "README.adoc"); - then(pom).exists(); - } - - @Test - public void should_throw_an_exception_when_checking_out_nonexisting_branch() throws IOException { - File project = this.gitRepo.cloneProject(this.project.toURI()); - try { - this.gitRepo.checkout(project, "nonExistingBranch"); - fail("should throw an exception"); - } - catch (IllegalStateException e) { - then(e).hasMessageContaining("Ref nonExistingBranch cannot be resolved"); - } - } - - @Test - public void should_commit_changes() throws Exception { - File project = this.gitRepo.cloneProject(this.project.toURI()); - createNewFile(project); - - this.gitRepo.commit(project, "some message"); - - try (Git git = openGitProject(project)) { - RevCommit revCommit = git.log().call().iterator().next(); - then(revCommit.getShortMessage()).isEqualTo("some message"); - } - } - - @Test - public void should_reset_any_changes() throws Exception { - File project = this.gitRepo.cloneProject(this.project.toURI()); - File file = createNewFile(project); - - this.gitRepo.reset(project); - - then(file).doesNotExist(); - } - - @Test - public void should_not_commit_empty_changes() throws Exception { - File project = this.gitRepo.cloneProject(this.project.toURI()); - createNewFile(project); - this.gitRepo.commit(project, "some message"); - - this.gitRepo.commit(project, "empty commit"); - - try (Git git = openGitProject(project)) { - RevCommit revCommit = git.log().call().iterator().next(); - then(revCommit.getShortMessage()).isNotEqualTo("empty commit"); - } - } - - @Test - public void should_push_changes_to_current_branch() throws Exception { - File origin = clonedProject(this.tmp.newFolder(), this.project); - File project = this.gitRepo.cloneProject(this.project.toURI()); - setOriginOnProjectToTmp(origin, project, true); - createNewFile(project); - this.gitRepo.commit(project, "some message"); - - this.gitRepo.pushCurrentBranch(project); - - try (Git git = openGitProject(origin)) { - RevCommit revCommit = git.log().call().iterator().next(); - then(revCommit.getShortMessage()).isEqualTo("some message"); - } - } - - @Test - public void should_pull_changes_to_current_branch() throws Exception { - File origin = clonedProject(this.tmp.newFolder(), this.project); - File project = this.gitRepo.cloneProject(this.project.toURI()); - setOriginOnProjectToTmp(origin, project, false); - createNewFile(origin); - this.gitRepo.commit(origin, "some message"); - - this.gitRepo.pull(project); - - try (Git git = openGitProject(project)) { - RevCommit revCommit = git.log().call().iterator().next(); - then(revCommit.getShortMessage()).isEqualTo("some message"); - } - } - - @Test - public void should_add_git_suffix_to_url_if_not_present() throws Exception { - this.gitRepo = new GitRepo(this.tmpFolder, true); - String url = this.gitRepo.sanitizeGitUrl(new URI("git://example.com/repo")); - assertThat(url).isEqualTo("git://example.com/repo.git"); - } - - @Test - public void should_not_add_git_suffix_to_url_if_already_present() throws Exception { - this.gitRepo = new GitRepo(this.tmpFolder, true); - String url = this.gitRepo.sanitizeGitUrl(new URI("git://example.com/repo.git")); - assertThat(url).isEqualTo("git://example.com/repo.git"); - } - - @Test - public void should_not_add_git_suffix_to_url_if_disabled() throws Exception { - this.gitRepo = new GitRepo(this.tmpFolder, false); - String url = this.gitRepo.sanitizeGitUrl(new URI("git://example.com/repo")); - assertThat(url).isEqualTo("git://example.com/repo"); - } - - @Test - public void should_not_remove_git_suffix_from_url_if_disabled() throws Exception { - this.gitRepo = new GitRepo(this.tmpFolder, false); - String url = this.gitRepo.sanitizeGitUrl(new URI("git://example.com/repo.git")); - assertThat(url).isEqualTo("git://example.com/repo.git"); - } - -} - -class ExceptionThrowingJGitFactory extends GitRepo.JGitFactory { - - @Override - CloneCommand getCloneCommandByCloneRepository() { - throw new CustomException("foo"); - } - -} - -class CustomException extends RuntimeException { - - CustomException(String message) { - super(message); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/GitStubDownloaderTests.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/GitStubDownloaderTests.java deleted file mode 100644 index 9703bab87a..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/GitStubDownloaderTests.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.net.URISyntaxException; -import java.util.HashMap; -import java.util.Map; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.util.FileSystemUtils; - -import static org.assertj.core.api.BDDAssertions.then; - -public class GitStubDownloaderTests { - - @Rule - public TemporaryFolder tmp = new TemporaryFolder(); - - File temporaryFolder; - - @Before - public void setup() throws Exception { - this.temporaryFolder = this.tmp.newFolder(); - TestUtils.prepareLocalRepo(); - FileSystemUtils.copyRecursively(file("/git_samples/"), this.temporaryFolder); - } - - @Test - public void should_return_a_null_downloader_for_a_classptath_mode() { - StubDownloaderBuilder stubDownloaderBuilder = new ScmStubDownloaderBuilder(); - - StubDownloader stubDownloader = stubDownloaderBuilder.build(new StubRunnerOptionsBuilder() - .withStubsMode(StubRunnerProperties.StubsMode.CLASSPATH).withProperties(props()).build()); - - then(stubDownloader).isNull(); - } - - @Test - public void should_return_a_null_downloader_for_a_empty_repo() { - StubDownloaderBuilder stubDownloaderBuilder = new ScmStubDownloaderBuilder(); - - StubDownloader stubDownloader = stubDownloaderBuilder.build(new StubRunnerOptionsBuilder() - .withStubsMode(StubRunnerProperties.StubsMode.REMOTE).withProperties(props()).build()); - - then(stubDownloader).isNull(); - } - - @Test - public void should_return_a_null_downloader_for_a_non_git_repo() { - StubDownloaderBuilder stubDownloaderBuilder = new ScmStubDownloaderBuilder(); - - StubDownloader stubDownloader = stubDownloaderBuilder - .build(new StubRunnerOptionsBuilder().withStubsMode(StubRunnerProperties.StubsMode.REMOTE) - .withStubRepositoryRoot("http://www.foo.com/").withProperties(props()).build()); - - then(stubDownloader).isNull(); - } - - @Test - public void should_pick_stubs_for_group_and_artifact_with_version_from_a_git_repo() throws Exception { - StubDownloaderBuilder stubDownloaderBuilder = new ScmStubDownloaderBuilder(); - String contractFolderLocation = (file("/git_samples/contract-git/").getAbsolutePath() + "/") - .replace(File.separator, "/"); - StubDownloader stubDownloader = stubDownloaderBuilder - .build(new StubRunnerOptionsBuilder().withStubsMode(StubRunnerProperties.StubsMode.REMOTE) - .withStubRepositoryRoot("git://" + contractFolderLocation).withProperties(props()).build()); - - Map.Entry entry = stubDownloader - .downloadAndUnpackStubJar(new StubConfiguration("foo.bar:bazService:0.0.1-SNAPSHOT")); - - then(entry).isNotNull(); - then(entry.getValue().getAbsolutePath()) - .contains("foo.bar" + File.separator + "bazService" + File.separator + "0.0.1-SNAPSHOT"); - } - - @Test - public void should_pick_latest_build_snapshot_stubs_when_latest_version_set() throws URISyntaxException { - StubDownloaderBuilder stubDownloaderBuilder = new ScmStubDownloaderBuilder(); - String contractFolderLocation = (file("/git_samples/contract-git/").getAbsolutePath() + "/") - .replace(File.separator, "/"); - StubDownloader stubDownloader = stubDownloaderBuilder - .build(new StubRunnerOptionsBuilder().withStubsMode(StubRunnerProperties.StubsMode.REMOTE) - .withStubRepositoryRoot("git://" + contractFolderLocation).withProperties(props()).build()); - - Map.Entry entry = stubDownloader - .downloadAndUnpackStubJar(new StubConfiguration("com.example:beer-api-producer-external:+")); - - then(entry).isNotNull(); - then(entry.getValue().getAbsolutePath()).contains("com.example" + File.separator + "beer-api-producer-external" - + File.separator + "1.0.0.BUILD-SNAPSHOT"); - - entry = stubDownloader - .downloadAndUnpackStubJar(new StubConfiguration("com.example:beer-api-producer-external:latest")); - - then(entry).isNotNull(); - then(entry.getValue().getAbsolutePath()).contains("com.example" + File.separator + "beer-api-producer-external" - + File.separator + "1.0.0.BUILD-SNAPSHOT"); - - entry = stubDownloader - .downloadAndUnpackStubJar(new StubConfiguration("com.example:beer-api-producer-external:LATEST")); - - then(entry).isNotNull(); - then(entry.getValue().getAbsolutePath()).contains("com.example" + File.separator + "beer-api-producer-external" - + File.separator + "1.0.0.BUILD-SNAPSHOT"); - - entry = stubDownloader - .downloadAndUnpackStubJar(new StubConfiguration("com.issue1305:beer-api-producer-external:+")); - - then(entry).isNotNull(); - then(entry.getValue().getAbsolutePath()).contains( - "com.issue1305" + File.separator + "beer-api-producer-external" + File.separator + "0.0.11-SNAPSHOT"); - } - - @Test - public void should_pick_latest_release_stubs_when_release_version_set() throws URISyntaxException { - StubDownloaderBuilder stubDownloaderBuilder = new ScmStubDownloaderBuilder(); - String contractFolderLocation = (file("/git_samples/contract-git/").getAbsolutePath() + "/") - .replace(File.separator, "/"); - StubDownloader stubDownloader = stubDownloaderBuilder - .build(new StubRunnerOptionsBuilder().withStubsMode(StubRunnerProperties.StubsMode.REMOTE) - .withStubRepositoryRoot("git://" + contractFolderLocation).withProperties(props()).build()); - - Map.Entry entry = stubDownloader - .downloadAndUnpackStubJar(new StubConfiguration("com.example:beer-api-producer-external:release")); - - then(entry).isNotNull(); - then(entry.getValue().getAbsolutePath()).contains( - "com.example" + File.separator + "beer-api-producer-external" + File.separator + "1.0.0.RELEASE"); - - entry = stubDownloader - .downloadAndUnpackStubJar(new StubConfiguration("com.example:beer-api-producer-external:RELEASE")); - - then(entry).isNotNull(); - then(entry.getValue().getAbsolutePath()).contains( - "com.example" + File.separator + "beer-api-producer-external" + File.separator + "1.0.0.RELEASE"); - } - - @Test - public void should_pick_latest_build_snapshot_stubs_when_latest_version_set_and_latest_folder_exists() - throws URISyntaxException { - StubDownloaderBuilder stubDownloaderBuilder = new ScmStubDownloaderBuilder(); - String contractFolderLocation = (file("/git_samples/contract-predefined-names-git/").getAbsolutePath() - .replace("/", File.separator) + "/").replace(File.separator, "/"); - StubDownloader stubDownloader = stubDownloaderBuilder - .build(new StubRunnerOptionsBuilder().withStubsMode(StubRunnerProperties.StubsMode.REMOTE) - .withStubRepositoryRoot("git://" + contractFolderLocation).withProperties(props()).build()); - - Map.Entry entry = stubDownloader - .downloadAndUnpackStubJar(new StubConfiguration("com.example:beer-api-producer-external:+")); - - then(entry).isNotNull(); - then(entry.getValue().getAbsolutePath()) - .contains("com.example" + File.separator + "beer-api-producer-external" + File.separator + "latest"); - - entry = stubDownloader - .downloadAndUnpackStubJar(new StubConfiguration("com.example:beer-api-producer-external:latest")); - - then(entry).isNotNull(); - then(entry.getValue().getAbsolutePath()) - .contains("com.example" + File.separator + "beer-api-producer-external" + File.separator + "latest"); - - entry = stubDownloader - .downloadAndUnpackStubJar(new StubConfiguration("com.example:beer-api-producer-external:LATEST")); - - then(entry).isNotNull(); - then(entry.getValue().getAbsolutePath()) - .contains("com.example" + File.separator + "beer-api-producer-external" + File.separator + "latest"); - } - - @Test - public void should_pick_release_folder_when_release_version_set() throws URISyntaxException { - StubDownloaderBuilder stubDownloaderBuilder = new ScmStubDownloaderBuilder(); - String contractFolderLocation = (file("/git_samples/contract-predefined-names-git/").getAbsolutePath() + "/") - .replace(File.separator, "/"); - StubDownloader stubDownloader = stubDownloaderBuilder - .build(new StubRunnerOptionsBuilder().withStubsMode(StubRunnerProperties.StubsMode.REMOTE) - .withStubRepositoryRoot("git://" + contractFolderLocation).withProperties(props()).build()); - - Map.Entry entry = stubDownloader - .downloadAndUnpackStubJar(new StubConfiguration("com.example:beer-api-producer-external:release")); - - then(entry).isNotNull(); - then(entry.getValue().getAbsolutePath()) - .contains("com.example" + File.separator + "beer-api-producer-external" + File.separator + "release"); - - entry = stubDownloader - .downloadAndUnpackStubJar(new StubConfiguration("com.example:beer-api-producer-external:RELEASE")); - - then(entry).isNotNull(); - then(entry.getValue().getAbsolutePath()) - .contains("com.example" + File.separator + "beer-api-producer-external" + File.separator + "release"); - } - - @Test - public void should_fail_to_fetch_stubs_when_concrete_version_was_not_specified() throws URISyntaxException { - StubDownloaderBuilder stubDownloaderBuilder = new ScmStubDownloaderBuilder(); - String contractFolderLocation = (file("/git_samples/contract-git/").getAbsolutePath() + "/") - .replace(File.separator, "/"); - StubDownloader stubDownloader = stubDownloaderBuilder - .build(new StubRunnerOptionsBuilder().withStubsMode(StubRunnerProperties.StubsMode.REMOTE) - .withStubRepositoryRoot("git://" + contractFolderLocation).withProperties(props()).build()); - - try { - stubDownloader.downloadAndUnpackStubJar(new StubConfiguration("foo.bar", "bazService", "")); - } - catch (IllegalStateException e) { - then(e).hasMessageContaining("Concrete version wasn't passed for [foo.bar:bazService::stubs]"); - } - } - - private Map props() { - Map map = new HashMap<>(); - map.put("git.branch", "master"); - return map; - } - - private File file(String relativePath) throws URISyntaxException { - return new File(GitStubDownloaderTests.class.getResource(relativePath).toURI()); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/StubDownloaderBuilderProviderTests.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/StubDownloaderBuilderProviderTests.java deleted file mode 100644 index d78ec49fd5..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/StubDownloaderBuilderProviderTests.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.util.Collections; -import java.util.List; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.BDDMockito; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -/** - * @author Marcin Grzejszczak - */ -@RunWith(MockitoJUnitRunner.class) -public class StubDownloaderBuilderProviderTests { - - @Mock - StubDownloaderBuilder one; - - @Mock - StubDownloaderBuilder two; - - @Mock - StubDownloaderBuilder three; - - @Test - public void should_get_providers_from_factories_default_and_additional_ones() { - StubDownloaderBuilderProvider provider = new StubDownloaderBuilderProvider( - Collections.singletonList(this.one)) { - @Override - List defaultStubDownloaderBuilders() { - return Collections.singletonList(StubDownloaderBuilderProviderTests.this.two); - } - }; - StubRunnerOptions options = new StubRunnerOptionsBuilder().withFailOnNoStubs(false).build(); - - provider.get(options, this.three).downloadAndUnpackStubJar(new StubConfiguration("a:b:c")); - - BDDMockito.then(this.one).should().build(options); - BDDMockito.then(this.two).should().build(options); - BDDMockito.then(this.three).should().build(options); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/StubRepositoryTest.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/StubRepositoryTest.java deleted file mode 100644 index 09f4c66b4a..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/StubRepositoryTest.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.util.ArrayList; -import java.util.Collection; - -import org.assertj.core.api.BDDAssertions; -import org.junit.Test; - -import org.springframework.cloud.contract.spec.Contract; - -/** - * @author Sven Bayer - */ -public class StubRepositoryTest { - - private static final File YAML_REPOSITORY_LOCATION = new File("src/test/resources/customYamlRepository"); - - @Test - public void should_prefer_custom_yaml_converter_over_standard() { - // given: - StubRepository repository = new StubRepository(YAML_REPOSITORY_LOCATION, new ArrayList<>(), - new StubRunnerOptionsBuilder().build()); - int expectedDescriptorsSize = 1; - - // when: - Collection descriptors = repository.getContracts(); - - // then: - BDDAssertions.then(descriptors).hasSize(expectedDescriptorsSize); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/StubRunnerSliceTests.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/StubRunnerSliceTests.java deleted file mode 100644 index cd161a3fc1..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/StubRunnerSliceTests.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.SpringBootConfiguration; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests that stub runner specific auto-configuration can be loaded up in combination with - * other slice tests - * - * @author Biju Kunjummen - */ -@RunWith(SpringRunner.class) -@WebMvcTest -@AutoConfigureStubRunner( - ids = { "org.springframework.cloud.contract.verifier.stubs:loanIssuance:+:stubs", - "org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer:+:stubs" }, - minPort = 10001, maxPort = 10020, mappingsOutputFolder = "target/outputmappings/", - properties = { "hello=world", "foo=bar" }) -@ActiveProfiles("test") -public class StubRunnerSliceTests { - - @Autowired - private StubFinder stubFinder; - - @Autowired - private StubRunnerProperties properties; - - @Value("${stubrunner.runningstubs.fraudDetectionServer.port}") - private Integer fraudDetectionServerPort; - - @Value("${stubrunner.runningstubs.loanIssuance.port}") - private Integer loanIssuancePort; - - @Test - public void testThatListedStubsAreRunning() { - - assertThat(this.fraudDetectionServerPort).isBetween(10001, 10020); - assertThat(this.loanIssuancePort).isBetween(10001, 10020); - - assertThat(this.stubFinder.findStubUrl("org.springframework.cloud.contract.verifier.stubs", "loanIssuance")) - .isNotNull(); - assertThat(this.stubFinder.findStubUrl("loanIssuance")).isNotNull(); - assertThat(this.stubFinder.findStubUrl("loanIssuance")).isEqualTo( - this.stubFinder.findStubUrl("org.springframework.cloud.contract.verifier.stubs", "loanIssuance")); - assertThat(this.stubFinder.findStubUrl("loanIssuance")).isEqualTo( - this.stubFinder.findStubUrl("org.springframework.cloud.contract.verifier.stubs:loanIssuance")); - assertThat(this.stubFinder - .findStubUrl("org.springframework.cloud.contract.verifier.stubs:loanIssuance:0.0.1-SNAPSHOT")) - .isEqualTo(this.stubFinder.findStubUrl( - "org.springframework.cloud.contract.verifier.stubs:loanIssuance:0.0.1-SNAPSHOT:stubs")); - assertThat( - this.stubFinder.findStubUrl("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer")) - .isNotNull(); - assertThat(this.properties.getProperties()).containsEntry("hello", "world").containsEntry("foo", "bar"); - } - - @SpringBootConfiguration - static class Config { - - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/StubsStubDownloaderTests.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/StubsStubDownloaderTests.java deleted file mode 100644 index a0b192f158..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/StubsStubDownloaderTests.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.net.URL; -import java.util.HashMap; -import java.util.Map; - -import org.assertj.core.api.BDDAssertions; -import org.junit.Test; - -public class StubsStubDownloaderTests { - - URL url = StubsStubDownloaderTests.class.getResource("/repository/mappings"); - - @Test - public void should_pick_stubs_from_a_given_location() { - String path = url.getPath(); - StubRunnerOptions options = new StubRunnerOptionsBuilder().withStubRepositoryRoot("stubs://file://" + path) - .build(); - StubsStubDownloader downloader = new StubsStubDownloader(options); - - Map.Entry entry = downloader - .downloadAndUnpackStubJar(new StubConfiguration("lv.spring.cloud:bye")); - - BDDAssertions.then(entry).isNotNull(); - BDDAssertions.then(entry.getValue()).exists(); - BDDAssertions.then(new File(entry.getValue(), "pl/spring/cloud/bye/pl_bye.json")).exists(); - BDDAssertions.then(new File(entry.getValue(), "lv/spring/cloud/bye/lv_bye.json")).exists(); - } - - @Test - public void should_pick_stubs_from_a_given_location_for_a_find_producer_with_ga() { - String path = url.getPath(); - StubRunnerOptions options = new StubRunnerOptionsBuilder().withStubRepositoryRoot("stubs://file://" + path) - .withProperties(propsWithFindProducer()).build(); - StubsStubDownloader downloader = new StubsStubDownloader(options); - - Map.Entry entry = downloader - .downloadAndUnpackStubJar(new StubConfiguration("lv.spring.cloud:bye")); - - BDDAssertions.then(entry).isNotNull(); - File stub = new File(entry.getValue().getPath(), "lv/spring/cloud/bye/lv_bye.json"); - BDDAssertions.then(stub).exists(); - } - - @Test - public void should_pick_stubs_from_a_given_location_for_a_find_producer_with_gav() { - String path = url.getPath(); - StubRunnerOptions options = new StubRunnerOptionsBuilder().withStubRepositoryRoot("stubs://file://" + path) - .withProperties(propsWithFindProducer()).build(); - StubsStubDownloader downloader = new StubsStubDownloader(options); - - Map.Entry entry = downloader - .downloadAndUnpackStubJar(new StubConfiguration("lv.spring:cloud:bye")); - - BDDAssertions.then(entry).isNotNull(); - File stub = new File(entry.getValue().getPath(), "lv/spring/cloud/bye/lv_bye.json"); - BDDAssertions.then(stub).exists(); - } - - private Map propsWithFindProducer() { - Map map = new HashMap<>(); - map.put("stubs.find-producer", "true"); - return map; - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/TestCustomYamlContractConverter.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/TestCustomYamlContractConverter.java deleted file mode 100644 index 140db82118..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/TestCustomYamlContractConverter.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.util.Collection; -import java.util.Collections; -import java.util.Optional; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.ContractConverter; - -/** - * @author Sven Bayer - */ -public class TestCustomYamlContractConverter implements ContractConverter { - - @Override - public boolean isAccepted(File file) { - if (!file.getName().endsWith(".yml") && !file.getName().endsWith(".yaml")) { - return false; - } - Optional line; - try { - line = Files.lines(file.toPath()).findFirst(); - } - catch (IOException e) { - throw new IllegalStateException(e); - } - return line.isPresent() && line.get().startsWith("custom_format: 1.0"); - } - - @Override - public Collection convertFrom(File file) { - return Collections.singleton(new Contract()); - } - - @Override - public Object convertTo(Collection contract) { - return new Object(); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/TestUtils.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/TestUtils.java deleted file mode 100644 index 7faa54e995..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/TestUtils.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.io.IOException; - -import org.eclipse.jgit.util.FileUtils; - -class TestUtils { - - public static void prepareLocalRepo() throws IOException { - prepareLocalRepo("target/test-classes/git_samples/", "contract-git"); - prepareLocalRepo("target/test-classes/git_samples/", "contract-predefined-names-git"); - } - - private static void prepareLocalRepo(String buildDir, String repoPath) throws IOException { - File dotGit = new File(buildDir + repoPath + "/.git"); - File git = new File(buildDir + repoPath + "/git"); - if (git.exists()) { - if (dotGit.exists()) { - FileUtils.delete(dotGit, FileUtils.RECURSIVE); - } - } - git.renameTo(dotGit); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/issue1225/Issue1225Tests.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/issue1225/Issue1225Tests.java deleted file mode 100644 index 82b6989137..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/issue1225/Issue1225Tests.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.issue1225; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.SpringBootConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerPort; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.web.bind.annotation.RestController; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests that stub runner specific auto-configuration can be loaded up in combination with - * other slice tests - * - * @author Biju Kunjummen - */ -@RunWith(SpringRunner.class) -@SpringBootTest(properties = { "ping.url=http://localhost:${stubrunner.runningstubs.loanIssuance.port}" }) -@AutoConfigureStubRunner(ids = { "org.springframework.cloud.contract.verifier.stubs:loanIssuance:+:stubs", - "org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer:+:stubs" }) -@ActiveProfiles("test") -public class Issue1225Tests { - - @StubRunnerPort("loanIssuance") - private int stubRunnerLoanIssuancePort; - - @Autowired - private PingProxyController pingProxyController; - - @Test - public void shouldInjectTheStubPortsAsEarlyAsPossible() { - assertThat(this.stubRunnerLoanIssuancePort).isPositive(); - assertThat(this.pingProxyController.pingUrl).contains(":" + this.stubRunnerLoanIssuancePort); - } - - @ComponentScan - @SpringBootConfiguration - static class Config { - - } - -} - -@RestController -class PingProxyController { - - String pingUrl; - - PingProxyController(@Value("${ping.url}") String pingUrl) { - this.pingUrl = pingUrl; - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionCustomMessageVerifierTests.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionCustomMessageVerifierTests.java deleted file mode 100644 index 7f1491f826..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionCustomMessageVerifierTests.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2018-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.junit; - -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import org.springframework.cloud.contract.stubrunner.junit4.StubRunnerRuleCustomPortJUnitTest; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.cloud.contract.verifier.converter.YamlContract; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; - -/** - * @author Olga Maciaszek-Sharma - * @since 2.1.0 - */ -class StubRunnerJUnit5ExtensionCustomMessageVerifierTests { - - // Visible for testing - @RegisterExtension - static StubRunnerExtension stubRunnerExtension = new StubRunnerExtension() - .stubsMode(StubRunnerProperties.StubsMode.REMOTE).repoRoot(repoRoot()) - .downloadStub("org.springframework.cloud.contract.verifier.stubs", "bootService") - .messageVerifierSender(new MyMessageVerifier()).messageVerifierReceiver(new MyMessageVerifier()); - - @BeforeAll - @AfterAll - static void setupProps() { - System.clearProperty("stubrunner.repository.root"); - System.clearProperty("stubrunner.classifier"); - } - - private static String repoRoot() { - try { - return StubRunnerRuleCustomPortJUnitTest.class.getResource("/m2repo/repository/").toURI().toString(); - } - catch (Exception e) { - return ""; - } - } - - @Test - void should_use_provided_message_verifier_in_junit5_extension() { - IllegalStateException emptyTriggerException = assertThrows(IllegalStateException.class, - () -> stubRunnerExtension.trigger()); - assertThat(emptyTriggerException.getMessage()).contains("Failed to send a message with headers"); - IllegalStateException wrongLabelException = assertThrows(IllegalStateException.class, - () -> stubRunnerExtension.trigger("return_book_1")); - assertThat(wrongLabelException.getMessage()).contains("Failed to send a message with headers"); - IllegalStateException wrongLabelWithIvyNotation = assertThrows(IllegalStateException.class, - () -> stubRunnerExtension.trigger("bootService", "return_book_1")); - assertThat(wrongLabelWithIvyNotation.getMessage()).contains("Failed to send a message with headers"); - } - - static class MyMessageVerifier implements MessageVerifierSender, MessageVerifierReceiver { - - @Override - public void send(Object message, String destination, YamlContract contract) { - throw new IllegalStateException("Failed to send a message"); - } - - @Override - public Object receive(String destination, long timeout, TimeUnit timeUnit, YamlContract contract) { - throw new IllegalStateException("Failed to receive a message with timeout"); - } - - @Override - public Object receive(String destination, YamlContract contract) { - throw new IllegalStateException("Failed to receive a message"); - } - - @Override - public void send(Object payload, Map headers, String destination, YamlContract contract) { - throw new IllegalStateException("Failed to send a message with headers"); - } - - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionCustomPortTests.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionCustomPortTests.java deleted file mode 100644 index 314e11e4eb..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionCustomPortTests.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2018-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.junit; - -import java.io.InputStream; -import java.net.URI; -import java.nio.charset.Charset; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.util.StreamUtils; - -import static org.assertj.core.api.BDDAssertions.then; - -/** - * @author Olga Maciaszek-Sharma - * @since 2.1.0 - */ -class StubRunnerJUnit5ExtensionCustomPortTests { - - @RegisterExtension - static StubRunnerExtension stubRunnerExtension = new StubRunnerExtension().repoRoot(repoRoot()) - .stubsMode(StubRunnerProperties.StubsMode.REMOTE) - .downloadStub("org.springframework.cloud.contract.verifier.stubs", "loanIssuance").withPort(22345) - .downloadStub("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer:22346"); - - @BeforeAll - @AfterAll - static void setupProps() { - System.clearProperty("stubrunner.repository.root"); - System.clearProperty("stubrunner.classifier"); - } - - private static String repoRoot() { - try { - return StubRunnerJUnit5ExtensionCustomPortTests.class.getResource("/m2repo/repository/").toURI().toString(); - } - catch (Exception e) { - return ""; - } - } - - @Test - void should_start_wiremock_servers() throws Exception { - then(stubRunnerExtension.findStubUrl("org.springframework.cloud.contract.verifier.stubs", "loanIssuance")) - .isNotNull(); - then(stubRunnerExtension.findStubUrl("loanIssuance")).isNotNull(); - then(stubRunnerExtension.findStubUrl("loanIssuance")).isEqualTo( - stubRunnerExtension.findStubUrl("org.springframework.cloud.contract.verifier.stubs", "loanIssuance")); - then(stubRunnerExtension.findStubUrl("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer")) - .isNotNull(); - then(stubRunnerExtension.findAllRunningStubs().isPresent("loanIssuance")).isTrue(); - then(stubRunnerExtension.findAllRunningStubs().isPresent("org.springframework.cloud.contract.verifier.stubs", - "fraudDetectionServer")).isTrue(); - then(stubRunnerExtension.findAllRunningStubs() - .isPresent("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer")).isTrue(); - then(httpGet(stubRunnerExtension.findStubUrl("loanIssuance").toString() + "/name")).isEqualTo("loanIssuance"); - then(httpGet(stubRunnerExtension.findStubUrl("fraudDetectionServer").toString() + "/name")) - .isEqualTo("fraudDetectionServer"); - then(stubRunnerExtension.findStubUrl("loanIssuance")).isEqualTo(URI.create("http://localhost:22345").toURL()); - then(stubRunnerExtension.findStubUrl("fraudDetectionServer")) - .isEqualTo(URI.create("http://localhost:22346").toURL()); - } - - private String httpGet(String url) throws Exception { - try (InputStream stream = URI.create(url).toURL().openStream()) { - return StreamUtils.copyToString(stream, Charset.forName("UTF-8")); - } - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionExceptionThrowingTests.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionExceptionThrowingTests.java deleted file mode 100644 index 1a823c1fa3..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionExceptionThrowingTests.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2018-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.junit; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import org.springframework.cloud.contract.stubrunner.junit4.StubRunnerRuleCustomPortJUnitTest; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; - -import static org.junit.jupiter.api.Assertions.assertThrows; - -/** - * @author Olga Maciaszek-Sharma - * @since 2.1.0 - */ -public class StubRunnerJUnit5ExtensionExceptionThrowingTests { - - @RegisterExtension - static StubRunnerExtension stubRunnerExtension = new StubRunnerExtension() - .stubsMode(StubRunnerProperties.StubsMode.REMOTE).repoRoot(repoRoot()) - .downloadStub("org.springframework.cloud.contract.verifier.stubs", "bootService"); - - @BeforeAll - @AfterAll - static void setupProps() { - System.clearProperty("stubrunner.repository.root"); - System.clearProperty("stubrunner.classifier"); - } - - private static String repoRoot() { - try { - return StubRunnerRuleCustomPortJUnitTest.class.getResource("/m2repo/repository/").toURI().toString(); - } - catch (Exception e) { - return ""; - } - } - - @Test - void should_throw_exception_when_no_message_verifier_was_passed_and_message_related_method_was_triggered() { - UnsupportedOperationException emptyTriggerException = assertThrows(UnsupportedOperationException.class, - () -> stubRunnerExtension.trigger()); - UnsupportedOperationException wrongLabelException = assertThrows(UnsupportedOperationException.class, - () -> stubRunnerExtension.trigger("return_book_1")); - UnsupportedOperationException wrongLabelWithIvyNotation = assertThrows(UnsupportedOperationException.class, - () -> stubRunnerExtension.trigger("bootService", "return_book_1")); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionTests.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionTests.java deleted file mode 100644 index 3ad4384d9f..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionTests.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2018-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.junit; - -import java.io.File; -import java.net.URL; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import org.springframework.cloud.contract.stubrunner.junit4.StubRunnerRuleJUnitTest; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Olga Maciaszek-Sharma - * @since 2.1.0 - */ -class StubRunnerJUnit5ExtensionTests { - - // tag::extension[] - // Visible for Junit - @RegisterExtension - static StubRunnerExtension stubRunnerExtension = new StubRunnerExtension().repoRoot(repoRoot()) - .stubsMode(StubRunnerProperties.StubsMode.REMOTE) - .downloadStub("org.springframework.cloud.contract.verifier.stubs", "loanIssuance") - .downloadStub("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer") - .withMappingsOutputFolder("target/outputmappingsforrule"); - - @BeforeAll - @AfterAll - static void setupProps() { - System.clearProperty("stubrunner.repository.root"); - System.clearProperty("stubrunner.classifier"); - } - - private static String repoRoot() { - try { - return StubRunnerRuleJUnitTest.class.getResource("/m2repo/repository/").toURI().toString(); - } - catch (Exception e) { - return ""; - } - } - // end::extension[] - - @Test - void should_start_WireMock_servers() { - assertThat(stubRunnerExtension.findStubUrl("org.springframework.cloud.contract.verifier.stubs", "loanIssuance")) - .isNotNull(); - assertThat(stubRunnerExtension.findStubUrl("loanIssuance")).isNotNull(); - assertThat(stubRunnerExtension.findStubUrl("loanIssuance")).isEqualTo( - stubRunnerExtension.findStubUrl("org.springframework.cloud.contract.verifier.stubs", "loanIssuance")); - assertThat(stubRunnerExtension - .findStubUrl("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer")).isNotNull(); - } - - @Test - void should_output_mappings_to_output_folder() { - // when - URL url = stubRunnerExtension.findStubUrl("fraudDetectionServer"); - - // then - assertThat(new File("target/outputmappingsforrule", "fraudDetectionServer_" + url.getPort())).exists(); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5MethodExtensionTests.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5MethodExtensionTests.java deleted file mode 100644 index 7becd25503..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5MethodExtensionTests.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2018-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.junit; - -import java.io.File; -import java.net.URL; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import org.springframework.cloud.contract.stubrunner.junit4.StubRunnerRuleJUnitTest; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Olga Maciaszek-Sharma - * @since 2.1.0 - */ -class StubRunnerJUnit5MethodExtensionTests { - - // tag::extension[] - // Visible for Junit - @RegisterExtension - StubRunnerExtension stubRunnerExtension = new StubRunnerExtension().repoRoot(repoRoot()) - .stubsMode(StubRunnerProperties.StubsMode.REMOTE) - .downloadStub("org.springframework.cloud.contract.verifier.stubs", "loanIssuance") - .downloadStub("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer") - .withMappingsOutputFolder("target/outputmappingsforrule"); - - @BeforeEach - @AfterEach - void setupProps() { - System.clearProperty("stubrunner.repository.root"); - System.clearProperty("stubrunner.classifier"); - } - - private static String repoRoot() { - try { - return StubRunnerRuleJUnitTest.class.getResource("/m2repo/repository/").toURI().toString(); - } - catch (Exception e) { - return ""; - } - } - // end::extension[] - - @Test - void should_start_WireMock_servers() { - assertThat(stubRunnerExtension.findStubUrl("org.springframework.cloud.contract.verifier.stubs", "loanIssuance")) - .isNotNull(); - assertThat(stubRunnerExtension.findStubUrl("loanIssuance")).isNotNull(); - assertThat(stubRunnerExtension.findStubUrl("loanIssuance")).isEqualTo( - stubRunnerExtension.findStubUrl("org.springframework.cloud.contract.verifier.stubs", "loanIssuance")); - assertThat(stubRunnerExtension - .findStubUrl("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer")).isNotNull(); - } - - @Test - void should_output_mappings_to_output_folder() { - // when - URL url = stubRunnerExtension.findStubUrl("fraudDetectionServer"); - - // then - assertThat(new File("target/outputmappingsforrule", "fraudDetectionServer_" + url.getPort())).exists(); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/server/StubRunnerServerConfigurationTests.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/server/StubRunnerServerConfigurationTests.java deleted file mode 100644 index ecb35bc633..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/server/StubRunnerServerConfigurationTests.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2020-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.server; - -import org.junit.Test; - -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Tim Ysewyn - */ -public class StubRunnerServerConfigurationTests { - - private ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration( - AutoConfigurations.of(StubRunnerConfiguration.class, StubRunnerServerConfiguration.class)); - - @Test - public void shouldCreateBeansByDefault() { - this.contextRunner.run((context) -> { - assertThat(context.getBeansOfType(ContractVerifierMessaging.class)).hasSize(1); - assertThat(context.getBeansOfType(TriggerController.class)).hasSize(1); - }); - } - - @Test - public void shouldNotCreateBeansWhenDisabled() { - this.contextRunner.withPropertyValues("stubrunner.messaging.enabled=false").run((context) -> { - assertThat(context.getBeansOfType(ContractVerifierMessaging.class)).hasSize(0); - assertThat(context.getBeansOfType(TriggerController.class)).hasSize(0); - }); - } - - @Test - public void shouldCreateBeansWhenExplicitlyEnabled() { - this.contextRunner.withPropertyValues("stubrunner.messaging.enabled=true").run((context) -> { - assertThat(context.getBeansOfType(ContractVerifierMessaging.class)).hasSize(1); - assertThat(context.getBeansOfType(TriggerController.class)).hasSize(1); - }); - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/.m2/settings-security.xml b/spring-cloud-contract-stub-runner/src/test/resources/.m2/settings-security.xml deleted file mode 100644 index 14ab72842c..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/.m2/settings-security.xml +++ /dev/null @@ -1,3 +0,0 @@ - - {HUkK5nexvfwH3iCznPbiCNTL7S1owi59hR79vLMH2wc=} - diff --git a/spring-cloud-contract-stub-runner/src/test/resources/.m2/settings.xml b/spring-cloud-contract-stub-runner/src/test/resources/.m2/settings.xml deleted file mode 100644 index 3bbf4ccd61..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/.m2/settings.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - my-server - admin - {ha7QXbuAf9wH5uVeYJGWg+SC8fdkufPVfdtpTK8Yk3E=} - - - diff --git a/spring-cloud-contract-stub-runner/src/test/resources/META-INF/spring.factories b/spring-cloud-contract-stub-runner/src/test/resources/META-INF/spring.factories deleted file mode 100644 index d1a9007fa8..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/META-INF/spring.factories +++ /dev/null @@ -1,4 +0,0 @@ -org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockExtensions=\ -org.springframework.cloud.contract.stubrunner.provider.wiremock.TestWireMockExtensions -org.springframework.cloud.contract.spec.ContractConverter=\ -org.springframework.cloud.contract.stubrunner.TestCustomYamlContractConverter diff --git a/spring-cloud-contract-stub-runner/src/test/resources/anotherRepository/mappings/spring/cloud/bar/bar.json b/spring-cloud-contract-stub-runner/src/test/resources/anotherRepository/mappings/spring/cloud/bar/bar.json deleted file mode 100644 index ed74e468ae..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/anotherRepository/mappings/spring/cloud/bar/bar.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "request": { - "method": "GET", - "url": "/bar" - }, - "response": { - "status": 200, - "body": "bar", - "headers": { - "Content-Type": "text/plain" - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/anotherRepository/mappings/spring/cloud/foo/bar/foobar.json b/spring-cloud-contract-stub-runner/src/test/resources/anotherRepository/mappings/spring/cloud/foo/bar/foobar.json deleted file mode 100644 index 7a50958518..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/anotherRepository/mappings/spring/cloud/foo/bar/foobar.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "request": { - "method": "GET", - "url": "/foobar" - }, - "response": { - "status": 200, - "body": "foobar", - "headers": { - "Content-Type": "text/plain" - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/anotherRepository/mappings/spring/cloud/foo/foo.json b/spring-cloud-contract-stub-runner/src/test/resources/anotherRepository/mappings/spring/cloud/foo/foo.json deleted file mode 100644 index c5e5d5eecd..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/anotherRepository/mappings/spring/cloud/foo/foo.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "request": { - "method": "GET", - "url": "/foo" - }, - "response": { - "status": 200, - "body": "foo", - "headers": { - "Content-Type": "text/plain" - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/anotherRepository/projects/brokers/brokers.json b/spring-cloud-contract-stub-runner/src/test/resources/anotherRepository/projects/brokers/brokers.json deleted file mode 100644 index f164f29c49..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/anotherRepository/projects/brokers/brokers.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "pl": [ - "spring/cloud/bar" - ] -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/anotherRepository/projects/brokers/nested/anotherDescriptor.json b/spring-cloud-contract-stub-runner/src/test/resources/anotherRepository/projects/brokers/nested/anotherDescriptor.json deleted file mode 100644 index 65c5cde2b5..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/anotherRepository/projects/brokers/nested/anotherDescriptor.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "pl": [ - "spring/cloud/foo/bar" - ] -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/anotherRepository/projects/descriptor.json b/spring-cloud-contract-stub-runner/src/test/resources/anotherRepository/projects/descriptor.json deleted file mode 100644 index e83e99310f..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/anotherRepository/projects/descriptor.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "pl": [ - "spring/cloud/foo" - ] -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/application-cloudtest.yml b/spring-cloud-contract-stub-runner/src/test/resources/application-cloudtest.yml deleted file mode 100644 index e58fa3a04f..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/application-cloudtest.yml +++ /dev/null @@ -1,17 +0,0 @@ -stubrunner: - cloud.stubbed.discovery.enabled: true -spring.cloud: - zookeeper: - enabled: false - discovery.enabled: false - consul: - enabled: false - discovery.enabled: false - service-registry.enabled: false -eureka.client.enabled: false -ribbon.eureka.enabled: false -spring: - cloud: - loadbalancer: - retry: - enabled: false \ No newline at end of file diff --git a/spring-cloud-contract-stub-runner/src/test/resources/application-eureka.yml b/spring-cloud-contract-stub-runner/src/test/resources/application-eureka.yml deleted file mode 100644 index f014420403..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/application-eureka.yml +++ /dev/null @@ -1,9 +0,0 @@ -eureka: - enableSelfPreservation: false - client: - fetchRegistry: false - initialInstanceInfoReplicationIntervalSeconds: 1 - instance: - registryFetchIntervalSeconds: 5 - leaseRenewalIntervalInSeconds: 5 - leaseExpirationDurationInSeconds: 5 diff --git a/spring-cloud-contract-stub-runner/src/test/resources/application-streamconsumer.yml b/spring-cloud-contract-stub-runner/src/test/resources/application-streamconsumer.yml deleted file mode 100644 index cd98425cb2..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/application-streamconsumer.yml +++ /dev/null @@ -1,5 +0,0 @@ -spring.cloud.function.definition: output -spring.cloud.stream.bindings.output-in-0.destination: output -spring.cloud.stream.bindings.output-in-0.contentType: application/json -spring.cloud.stream.bindings.output-out-0.destination: output -spring.cloud.stream.bindings.output-out-0.contentType: application/json \ No newline at end of file diff --git a/spring-cloud-contract-stub-runner/src/test/resources/application-test-with-placeholders.yml b/spring-cloud-contract-stub-runner/src/test/resources/application-test-with-placeholders.yml deleted file mode 100644 index f146989f96..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/application-test-with-placeholders.yml +++ /dev/null @@ -1,23 +0,0 @@ -provider.stub.artifact.id: fraudDetectionServer - -stubrunner: - repositoryRoot: classpath:m2repo/repository/ - ids: - - ${some.property1} - - 'org.springframework.cloud.contract.verifier.stubs:${provider.stub.artifact.id}' - stubs-mode: ${some.stubsmode:remote} - min-port: ${some.minport:1000} - max-port: ${some.maxport:20000} - classifier: ${some.classifier:stubs} - username: ${some.username:user} - password: ${some.password:pass} - stubs-per-consumer: ${some.stubsperconsumer:false} - consumer-name: ${some.consumername:name} - mappings-output-folder: ${some.mappingsoutputfolder:target} - delete-stubs-after-test: ${some.deletestubsaftertest:true} - generate-stubs: ${some.generatestubs:false} -spring: - main: - allow-bean-definition-overriding: true - -stub.port: ${stubrunner.runningstubs.${provider.stub.artifact.id}.port} \ No newline at end of file diff --git a/spring-cloud-contract-stub-runner/src/test/resources/application-test.yml b/spring-cloud-contract-stub-runner/src/test/resources/application-test.yml deleted file mode 100644 index b442108385..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/application-test.yml +++ /dev/null @@ -1,15 +0,0 @@ -# tag::test[] -stubrunner: - repositoryRoot: classpath:m2repo/repository/ - ids: - - org.springframework.cloud.contract.verifier.stubs:loanIssuance - - org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer - - org.springframework.cloud.contract.verifier.stubs:bootService - stubs-mode: remote - # end::test[] - cloud: - enabled: false - -spring.cloud: - consul.enabled: false - service-registry.enabled: false diff --git a/spring-cloud-contract-stub-runner/src/test/resources/application.yml b/spring-cloud-contract-stub-runner/src/test/resources/application.yml deleted file mode 100644 index e9169ba808..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/application.yml +++ /dev/null @@ -1,11 +0,0 @@ -spring.cloud: - zookeeper.enabled: false - consul.enabled: false -eureka.client.enabled: false -stubrunner.camel.enabled: false -# tag::ids[] -stubrunner: - idsToServiceIds: - ivyNotation: someValueInsideYourCode - fraudDetectionServer: someNameThatShouldMapFraudDetectionServer -# end::ids[] diff --git a/spring-cloud-contract-stub-runner/src/test/resources/arbitrary.json b/spring-cloud-contract-stub-runner/src/test/resources/arbitrary.json deleted file mode 100644 index 35ecab0f56..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/arbitrary.json +++ /dev/null @@ -1,12 +0,0 @@ -[ - { - "id": "1", - "firstname": "John", - "name": "Doe" - }, - { - "id": "2", - "firstname": "Lisa", - "name": "Smith" - } -] \ No newline at end of file diff --git a/spring-cloud-contract-stub-runner/src/test/resources/broken.json b/spring-cloud-contract-stub-runner/src/test/resources/broken.json deleted file mode 100644 index 3ac85b61ad..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/broken.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "request": { - "method": "GET", - "url": "/ping" - }, - "response": { - "status": 200, diff --git a/spring-cloud-contract-stub-runner/src/test/resources/customYamlRepository/contracts/custom.yml b/spring-cloud-contract-stub-runner/src/test/resources/customYamlRepository/contracts/custom.yml deleted file mode 100644 index b2a12da7f3..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/customYamlRepository/contracts/custom.yml +++ /dev/null @@ -1,16 +0,0 @@ -custom_format: 1.0 -outbound: - request: - url: /foo - method: PUT - headers: - foo: bar - body: - foo: bar -inbound: - response: - status: 200 - headers: - foo2: bar - body: - foo2: bar diff --git a/spring-cloud-contract-stub-runner/src/test/resources/file.zip b/spring-cloud-contract-stub-runner/src/test/resources/file.zip deleted file mode 100644 index 3da3a912405f9967ebedebe02f41ce44b66ddd5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 171 zcmWIWW@h1H0D)76LW?TkIfXruL1mY!)AQr+{R*11^Mh1AZvVqhw0-+y}b_a17 E0OX(`8~^|S diff --git a/spring-cloud-contract-stub-runner/src/test/resources/generateStubs/contracts/goodbye.groovy b/spring-cloud-contract-stub-runner/src/test/resources/generateStubs/contracts/goodbye.groovy deleted file mode 100644 index c432ed21e9..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/generateStubs/contracts/goodbye.groovy +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - request { - url("/goodbye") - method(GET()) - } - response { - status(OK()) - body("Goodbye World!") - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/generateStubs/contracts/goodbye_from_file.groovy b/spring-cloud-contract-stub-runner/src/test/resources/generateStubs/contracts/goodbye_from_file.groovy deleted file mode 100644 index 67c5325eed..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/generateStubs/contracts/goodbye_from_file.groovy +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - request { - url("/goodbye_from_file") - method(GET()) - } - response { - status(OK()) - body(file("goodbye_response.txt")) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/generateStubs/contracts/goodbye_response.txt b/spring-cloud-contract-stub-runner/src/test/resources/generateStubs/contracts/goodbye_response.txt deleted file mode 100644 index 02e35ff340..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/generateStubs/contracts/goodbye_response.txt +++ /dev/null @@ -1 +0,0 @@ -Goodbye from file! \ No newline at end of file diff --git a/spring-cloud-contract-stub-runner/src/test/resources/generateStubs/contracts/hello.groovy b/spring-cloud-contract-stub-runner/src/test/resources/generateStubs/contracts/hello.groovy deleted file mode 100644 index cb971a69ee..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/generateStubs/contracts/hello.groovy +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - request { - url("/hello") - method(GET()) - } - response { - status(OK()) - body("Hello New World!") - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/generateStubs/contracts/hello.json b/spring-cloud-contract-stub-runner/src/test/resources/generateStubs/contracts/hello.json deleted file mode 100644 index 13d165d71d..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/generateStubs/contracts/hello.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "request": { - "method": "GET", - "url": "/hello" - }, - "response": { - "status": 200, - "body": "Hello world!", - "headers": { - "Content-Type": "text/plain" - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/LICENSE.txt b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/LICENSE.txt deleted file mode 100644 index 62589edd12..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/LICENSE.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy deleted file mode 100644 index 4676a127dc..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a positive verification message when person is eligible to get the beer - -``` -given: - client is old enough -when: - he applies for a beer -then: - we'll send a message with a positive verification -``` - -""") - // Label by means of which the output message can be triggered - label 'accepted_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsOldEnough()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: true - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy deleted file mode 100644 index d3dd5b3834..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a negative verification message when person is not eligible to get the beer - -``` -given: - client is too young -when: - he applies for a beer -then: - we'll send a message with a negative verification -``` - -""") - // Label by means of which the output message can be triggered - label 'rejected_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsTooYoung()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: false - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy deleted file mode 100644 index 2cb715928b..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a successful scenario of getting a beer - -given: - client is old enough -when: - he applies for a beer -then: - we'll grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[2-9][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy deleted file mode 100644 index 0183b0fba3..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a unsuccessful scenario of getting a beer - -given: - client is not old enough -when: - he applies for a beer -then: - we'll NOT grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[0-1][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "NOT_OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json deleted file mode 100644 index 5f25f6f934..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[2-9][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json deleted file mode 100644 index 9a4d31b7e5..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[0-1][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"NOT_OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy deleted file mode 100644 index 4676a127dc..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a positive verification message when person is eligible to get the beer - -``` -given: - client is old enough -when: - he applies for a beer -then: - we'll send a message with a positive verification -``` - -""") - // Label by means of which the output message can be triggered - label 'accepted_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsOldEnough()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: true - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy deleted file mode 100644 index d3dd5b3834..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a negative verification message when person is not eligible to get the beer - -``` -given: - client is too young -when: - he applies for a beer -then: - we'll send a message with a negative verification -``` - -""") - // Label by means of which the output message can be triggered - label 'rejected_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsTooYoung()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: false - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy deleted file mode 100644 index 2cb715928b..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a successful scenario of getting a beer - -given: - client is old enough -when: - he applies for a beer -then: - we'll grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[2-9][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy deleted file mode 100644 index 0183b0fba3..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a unsuccessful scenario of getting a beer - -given: - client is not old enough -when: - he applies for a beer -then: - we'll NOT grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[0-1][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "NOT_OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json deleted file mode 100644 index 5f25f6f934..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[2-9][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json deleted file mode 100644 index 9a4d31b7e5..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[0-1][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"NOT_OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy deleted file mode 100644 index 4676a127dc..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a positive verification message when person is eligible to get the beer - -``` -given: - client is old enough -when: - he applies for a beer -then: - we'll send a message with a positive verification -``` - -""") - // Label by means of which the output message can be triggered - label 'accepted_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsOldEnough()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: true - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy deleted file mode 100644 index d3dd5b3834..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a negative verification message when person is not eligible to get the beer - -``` -given: - client is too young -when: - he applies for a beer -then: - we'll send a message with a negative verification -``` - -""") - // Label by means of which the output message can be triggered - label 'rejected_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsTooYoung()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: false - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy deleted file mode 100644 index 2cb715928b..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a successful scenario of getting a beer - -given: - client is old enough -when: - he applies for a beer -then: - we'll grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[2-9][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy deleted file mode 100644 index 0183b0fba3..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a unsuccessful scenario of getting a beer - -given: - client is not old enough -when: - he applies for a beer -then: - we'll NOT grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[0-1][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "NOT_OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json deleted file mode 100644 index 5f25f6f934..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[2-9][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json deleted file mode 100644 index 9a4d31b7e5..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[0-1][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"NOT_OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy deleted file mode 100644 index 4676a127dc..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a positive verification message when person is eligible to get the beer - -``` -given: - client is old enough -when: - he applies for a beer -then: - we'll send a message with a positive verification -``` - -""") - // Label by means of which the output message can be triggered - label 'accepted_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsOldEnough()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: true - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy deleted file mode 100644 index d3dd5b3834..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a negative verification message when person is not eligible to get the beer - -``` -given: - client is too young -when: - he applies for a beer -then: - we'll send a message with a negative verification -``` - -""") - // Label by means of which the output message can be triggered - label 'rejected_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsTooYoung()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: false - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy deleted file mode 100644 index 2cb715928b..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a successful scenario of getting a beer - -given: - client is old enough -when: - he applies for a beer -then: - we'll grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[2-9][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy deleted file mode 100644 index 0183b0fba3..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a unsuccessful scenario of getting a beer - -given: - client is not old enough -when: - he applies for a beer -then: - we'll NOT grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[0-1][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "NOT_OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json deleted file mode 100644 index 5f25f6f934..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[2-9][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json deleted file mode 100644 index 9a4d31b7e5..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[0-1][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"NOT_OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy deleted file mode 100644 index 4676a127dc..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a positive verification message when person is eligible to get the beer - -``` -given: - client is old enough -when: - he applies for a beer -then: - we'll send a message with a positive verification -``` - -""") - // Label by means of which the output message can be triggered - label 'accepted_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsOldEnough()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: true - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy deleted file mode 100644 index d3dd5b3834..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a negative verification message when person is not eligible to get the beer - -``` -given: - client is too young -when: - he applies for a beer -then: - we'll send a message with a negative verification -``` - -""") - // Label by means of which the output message can be triggered - label 'rejected_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsTooYoung()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: false - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy deleted file mode 100644 index 2cb715928b..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a successful scenario of getting a beer - -given: - client is old enough -when: - he applies for a beer -then: - we'll grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[2-9][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy deleted file mode 100644 index 0183b0fba3..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a unsuccessful scenario of getting a beer - -given: - client is not old enough -when: - he applies for a beer -then: - we'll NOT grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[0-1][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "NOT_OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json deleted file mode 100644 index 5f25f6f934..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[2-9][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json deleted file mode 100644 index 9a4d31b7e5..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[0-1][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"NOT_OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.10-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.10-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy deleted file mode 100644 index 4676a127dc..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.10-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a positive verification message when person is eligible to get the beer - -``` -given: - client is old enough -when: - he applies for a beer -then: - we'll send a message with a positive verification -``` - -""") - // Label by means of which the output message can be triggered - label 'accepted_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsOldEnough()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: true - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.10-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.10-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy deleted file mode 100644 index d3dd5b3834..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.10-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a negative verification message when person is not eligible to get the beer - -``` -given: - client is too young -when: - he applies for a beer -then: - we'll send a message with a negative verification -``` - -""") - // Label by means of which the output message can be triggered - label 'rejected_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsTooYoung()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: false - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.10-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.10-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy deleted file mode 100644 index 2cb715928b..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.10-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a successful scenario of getting a beer - -given: - client is old enough -when: - he applies for a beer -then: - we'll grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[2-9][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.10-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.10-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy deleted file mode 100644 index 0183b0fba3..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.10-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a unsuccessful scenario of getting a beer - -given: - client is not old enough -when: - he applies for a beer -then: - we'll NOT grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[0-1][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "NOT_OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.10-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.10-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json deleted file mode 100644 index 5f25f6f934..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.10-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[2-9][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.10-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.10-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json deleted file mode 100644 index 9a4d31b7e5..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.10-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[0-1][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"NOT_OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.11-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.11-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy deleted file mode 100644 index 4676a127dc..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.11-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a positive verification message when person is eligible to get the beer - -``` -given: - client is old enough -when: - he applies for a beer -then: - we'll send a message with a positive verification -``` - -""") - // Label by means of which the output message can be triggered - label 'accepted_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsOldEnough()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: true - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.11-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.11-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy deleted file mode 100644 index d3dd5b3834..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.11-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a negative verification message when person is not eligible to get the beer - -``` -given: - client is too young -when: - he applies for a beer -then: - we'll send a message with a negative verification -``` - -""") - // Label by means of which the output message can be triggered - label 'rejected_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsTooYoung()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: false - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.11-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.11-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy deleted file mode 100644 index 2cb715928b..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.11-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a successful scenario of getting a beer - -given: - client is old enough -when: - he applies for a beer -then: - we'll grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[2-9][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.11-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.11-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy deleted file mode 100644 index 0183b0fba3..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.11-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a unsuccessful scenario of getting a beer - -given: - client is not old enough -when: - he applies for a beer -then: - we'll NOT grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[0-1][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "NOT_OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.11-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.11-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json deleted file mode 100644 index 5f25f6f934..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.11-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[2-9][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.11-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.11-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json deleted file mode 100644 index 9a4d31b7e5..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.11-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[0-1][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"NOT_OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.5-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.5-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy deleted file mode 100644 index 4676a127dc..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.5-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a positive verification message when person is eligible to get the beer - -``` -given: - client is old enough -when: - he applies for a beer -then: - we'll send a message with a positive verification -``` - -""") - // Label by means of which the output message can be triggered - label 'accepted_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsOldEnough()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: true - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.5-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.5-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy deleted file mode 100644 index d3dd5b3834..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.5-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a negative verification message when person is not eligible to get the beer - -``` -given: - client is too young -when: - he applies for a beer -then: - we'll send a message with a negative verification -``` - -""") - // Label by means of which the output message can be triggered - label 'rejected_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsTooYoung()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: false - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.5-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.5-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy deleted file mode 100644 index 2cb715928b..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.5-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a successful scenario of getting a beer - -given: - client is old enough -when: - he applies for a beer -then: - we'll grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[2-9][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.5-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.5-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy deleted file mode 100644 index 0183b0fba3..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.5-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a unsuccessful scenario of getting a beer - -given: - client is not old enough -when: - he applies for a beer -then: - we'll NOT grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[0-1][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "NOT_OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.5-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.5-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json deleted file mode 100644 index 5f25f6f934..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.5-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[2-9][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.5-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.5-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json deleted file mode 100644 index 9a4d31b7e5..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.5-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[0-1][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"NOT_OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.6-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.6-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy deleted file mode 100644 index 4676a127dc..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.6-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a positive verification message when person is eligible to get the beer - -``` -given: - client is old enough -when: - he applies for a beer -then: - we'll send a message with a positive verification -``` - -""") - // Label by means of which the output message can be triggered - label 'accepted_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsOldEnough()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: true - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.6-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.6-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy deleted file mode 100644 index d3dd5b3834..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.6-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a negative verification message when person is not eligible to get the beer - -``` -given: - client is too young -when: - he applies for a beer -then: - we'll send a message with a negative verification -``` - -""") - // Label by means of which the output message can be triggered - label 'rejected_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsTooYoung()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: false - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.6-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.6-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy deleted file mode 100644 index 2cb715928b..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.6-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a successful scenario of getting a beer - -given: - client is old enough -when: - he applies for a beer -then: - we'll grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[2-9][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.6-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.6-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy deleted file mode 100644 index 0183b0fba3..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.6-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a unsuccessful scenario of getting a beer - -given: - client is not old enough -when: - he applies for a beer -then: - we'll NOT grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[0-1][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "NOT_OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.6-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.6-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json deleted file mode 100644 index 5f25f6f934..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.6-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[2-9][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.6-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.6-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json deleted file mode 100644 index 9a4d31b7e5..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.6-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[0-1][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"NOT_OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.7-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.7-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy deleted file mode 100644 index 4676a127dc..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.7-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a positive verification message when person is eligible to get the beer - -``` -given: - client is old enough -when: - he applies for a beer -then: - we'll send a message with a positive verification -``` - -""") - // Label by means of which the output message can be triggered - label 'accepted_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsOldEnough()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: true - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.7-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.7-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy deleted file mode 100644 index d3dd5b3834..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.7-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a negative verification message when person is not eligible to get the beer - -``` -given: - client is too young -when: - he applies for a beer -then: - we'll send a message with a negative verification -``` - -""") - // Label by means of which the output message can be triggered - label 'rejected_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsTooYoung()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: false - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.7-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.7-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy deleted file mode 100644 index 2cb715928b..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.7-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a successful scenario of getting a beer - -given: - client is old enough -when: - he applies for a beer -then: - we'll grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[2-9][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.7-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.7-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy deleted file mode 100644 index 0183b0fba3..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.7-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a unsuccessful scenario of getting a beer - -given: - client is not old enough -when: - he applies for a beer -then: - we'll NOT grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[0-1][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "NOT_OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.7-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.7-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json deleted file mode 100644 index 5f25f6f934..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.7-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[2-9][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.7-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.7-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json deleted file mode 100644 index 9a4d31b7e5..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.7-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[0-1][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"NOT_OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.8-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.8-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy deleted file mode 100644 index 4676a127dc..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.8-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a positive verification message when person is eligible to get the beer - -``` -given: - client is old enough -when: - he applies for a beer -then: - we'll send a message with a positive verification -``` - -""") - // Label by means of which the output message can be triggered - label 'accepted_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsOldEnough()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: true - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.8-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.8-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy deleted file mode 100644 index d3dd5b3834..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.8-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a negative verification message when person is not eligible to get the beer - -``` -given: - client is too young -when: - he applies for a beer -then: - we'll send a message with a negative verification -``` - -""") - // Label by means of which the output message can be triggered - label 'rejected_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsTooYoung()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: false - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.8-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.8-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy deleted file mode 100644 index 2cb715928b..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.8-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a successful scenario of getting a beer - -given: - client is old enough -when: - he applies for a beer -then: - we'll grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[2-9][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.8-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.8-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy deleted file mode 100644 index 0183b0fba3..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.8-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a unsuccessful scenario of getting a beer - -given: - client is not old enough -when: - he applies for a beer -then: - we'll NOT grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[0-1][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "NOT_OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.8-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.8-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json deleted file mode 100644 index 5f25f6f934..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.8-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[2-9][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.8-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.8-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json deleted file mode 100644 index 9a4d31b7e5..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/com.issue1305/beer-api-producer-external/0.0.8-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[0-1][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"NOT_OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/foo.bar/bazService/0.0.1-SNAPSHOT/contracts/bazConsumer1/rest/shouldSayHello.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/foo.bar/bazService/0.0.1-SNAPSHOT/contracts/bazConsumer1/rest/shouldSayHello.groovy deleted file mode 100644 index 13fb9dc178..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/foo.bar/bazService/0.0.1-SNAPSHOT/contracts/bazConsumer1/rest/shouldSayHello.groovy +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.foo.bar.bazService.bazConsumer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - method 'GET' - url '/hello' - } - response { - status 200 - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/foo.bar/bazService/0.0.1-SNAPSHOT/mappings/bazConsumer1/rest/shouldSayHello.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/foo.bar/bazService/0.0.1-SNAPSHOT/mappings/bazConsumer1/rest/shouldSayHello.json deleted file mode 100644 index d25d733109..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/META-INF/foo.bar/bazService/0.0.1-SNAPSHOT/mappings/bazConsumer1/rest/shouldSayHello.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "id": "f4080f7d-4cb2-4301-81d6-492570316aae", - "request": { - "url": "/hello", - "method": "GET" - }, - "response": { - "status": 200, - "transformers": [ - "response-template" - ] - }, - "uuid": "f4080f7d-4cb2-4301-81d6-492570316aae" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/README.adoc b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/README.adoc deleted file mode 100644 index 98908bc72f..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/README.adoc +++ /dev/null @@ -1,70 +0,0 @@ -= Common contracts repo - -This repo contains all contracts for apps in the system. - -== As a consumer - -You are working offline in order to play around with the API of the producer. -What you need to do is to have the producer's stubs installed locally. To do that -you have to (from the root of the repo) - -[source,bash] ----- -cd src/main/resources/contracts/com/example/beer-api-producer-external/1.0.0 -mvn clean install -DskipTests ----- - -Then if you do `ls ./target` you'll see `beer-api-producer-external-0.0.1-SNAPSHOT-stubs.jar`. This jar will - contain the stubs generated from your contracts. That way you -can reference the `com.example:server:+:stubs` dependency in your consumer tests. - -TIP: Don't mind that there's a version mismatch in the stubs and the folder structure. -The version number is there in the folder name for tests related to dealing with -non-Java friendly naming of packages. - -== As a producer - -Assuming that the consumers have filed a PR with the proposed contract the producers -can work offline to generate tests and stubs. To work offline, as a producer you just have -to go to the root folder of the contracts and: - -[source,bash] ----- -./mvnw clean install -DskipTests ----- - -Then if you do `ls ./target` you'll see `contracts-0.0.1-SNAPSHOT.jar`. This file contains -all DSL contracts, for all applications. - -Now the producer can include the `contracts-0.0.1-SNAPSHOT.jar` from your local maven repository. -You can achieve that by setting the proper flag in plugin properties. - -Example for Maven - -[source,xml] ----- - - org.springframework.cloud - spring-cloud-contract-maven-plugin - - - true - - com.example - beer-contracts - - - ----- - -and for Gradle: - -[source,groovy] ----- -contracts { - contractsWorkOffline = true - contractDependency { - stringNotation = "com.example:beer-contracts" - } -} ----- diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/COMMIT_EDITMSG b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/COMMIT_EDITMSG deleted file mode 100644 index 4907586b9a..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/COMMIT_EDITMSG +++ /dev/null @@ -1 +0,0 @@ -Issue 1305 diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/HEAD b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/HEAD deleted file mode 100644 index cb089cd89a..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/HEAD +++ /dev/null @@ -1 +0,0 @@ -ref: refs/heads/master diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/config b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/config deleted file mode 100644 index 1bc26be514..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/config +++ /dev/null @@ -1,10 +0,0 @@ -[core] - repositoryformatversion = 0 - filemode = true - bare = false - logallrefupdates = true - ignorecase = true - precomposeunicode = true -[branch "master"] - remote = origin - merge = refs/heads/master diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/description b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/description deleted file mode 100644 index 498b267a8c..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/description +++ /dev/null @@ -1 +0,0 @@ -Unnamed repository; edit this file 'description' to name the repository. diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/applypatch-msg.sample b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/applypatch-msg.sample deleted file mode 100755 index a5d7b84a67..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/applypatch-msg.sample +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh -# -# An example hook script to check the commit log message taken by -# applypatch from an e-mail message. -# -# The hook should exit with non-zero status after issuing an -# appropriate message if it wants to stop the commit. The hook is -# allowed to edit the commit message file. -# -# To enable this hook, rename this file to "applypatch-msg". - -. git-sh-setup -commitmsg="$(git rev-parse --git-path hooks/commit-msg)" -test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} -: diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/commit-msg.sample b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/commit-msg.sample deleted file mode 100755 index b58d1184a9..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/commit-msg.sample +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -# -# An example hook script to check the commit log message. -# Called by "git commit" with one argument, the name of the file -# that has the commit message. The hook should exit with non-zero -# status after issuing an appropriate message if it wants to stop the -# commit. The hook is allowed to edit the commit message file. -# -# To enable this hook, rename this file to "commit-msg". - -# Uncomment the below to add a Signed-off-by line to the message. -# Doing this in a hook is a bad idea in general, but the prepare-commit-msg -# hook is more suited to it. -# -# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') -# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" - -# This example catches duplicate Signed-off-by lines. - -test "" = "$(grep '^Signed-off-by: ' "$1" | - sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { - echo >&2 Duplicate Signed-off-by lines. - exit 1 -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/post-update.sample b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/post-update.sample deleted file mode 100755 index ec17ec1939..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/post-update.sample +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -# -# An example hook script to prepare a packed repository for use over -# dumb transports. -# -# To enable this hook, rename this file to "post-update". - -exec git update-server-info diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/pre-applypatch.sample b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/pre-applypatch.sample deleted file mode 100755 index 4142082bcb..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/pre-applypatch.sample +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh -# -# An example hook script to verify what is about to be committed -# by applypatch from an e-mail message. -# -# The hook should exit with non-zero status after issuing an -# appropriate message if it wants to stop the commit. -# -# To enable this hook, rename this file to "pre-applypatch". - -. git-sh-setup -precommit="$(git rev-parse --git-path hooks/pre-commit)" -test -x "$precommit" && exec "$precommit" ${1+"$@"} -: diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/pre-commit.sample b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/pre-commit.sample deleted file mode 100755 index 68d62d5446..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/pre-commit.sample +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh -# -# An example hook script to verify what is about to be committed. -# Called by "git commit" with no arguments. The hook should -# exit with non-zero status after issuing an appropriate message if -# it wants to stop the commit. -# -# To enable this hook, rename this file to "pre-commit". - -if git rev-parse --verify HEAD >/dev/null 2>&1 -then - against=HEAD -else - # Initial commit: diff against an empty tree object - against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 -fi - -# If you want to allow non-ASCII filenames set this variable to true. -allownonascii=$(git config --bool hooks.allownonascii) - -# Redirect output to stderr. -exec 1>&2 - -# Cross platform projects tend to avoid non-ASCII filenames; prevent -# them from being added to the repository. We exploit the fact that the -# printable range starts at the space character and ends with tilde. -if [ "$allownonascii" != "true" ] && - # Note that the use of brackets around a tr range is ok here, (it's - # even required, for portability to Solaris 10's /usr/bin/tr), since - # the square bracket bytes happen to fall in the designated range. - test $(git diff --cached --name-only --diff-filter=A -z $against | - LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 -then - cat <<\EOF -Error: Attempt to add a non-ASCII file name. - -This can cause problems if you want to work with people on other platforms. - -To be portable it is advisable to rename the file. - -If you know what you are doing you can disable this check using: - - git config hooks.allownonascii true -EOF - exit 1 -fi - -# If there are whitespace errors, print the offending file names and fail. -exec git diff-index --check --cached $against -- diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/pre-push.sample b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/pre-push.sample deleted file mode 100755 index 6187dbf439..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/pre-push.sample +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/sh - -# An example hook script to verify what is about to be pushed. Called by "git -# push" after it has checked the remote status, but before anything has been -# pushed. If this script exits with a non-zero status nothing will be pushed. -# -# This hook is called with the following parameters: -# -# $1 -- Name of the remote to which the push is being done -# $2 -- URL to which the push is being done -# -# If pushing without using a named remote those arguments will be equal. -# -# Information about the commits which are being pushed is supplied as lines to -# the standard input in the form: -# -# -# -# This sample shows how to prevent push of commits where the log message starts -# with "WIP" (work in progress). - -remote="$1" -url="$2" - -z40=0000000000000000000000000000000000000000 - -while read local_ref local_sha remote_ref remote_sha -do - if [ "$local_sha" = $z40 ] - then - # Handle delete - : - else - if [ "$remote_sha" = $z40 ] - then - # New branch, examine all commits - range="$local_sha" - else - # Update to existing branch, examine new commits - range="$remote_sha..$local_sha" - fi - - # Check for WIP commit - commit=`git rev-list -n 1 --grep '^WIP' "$range"` - if [ -n "$commit" ] - then - echo >&2 "Found WIP commit in $local_ref, not pushing" - exit 1 - fi - fi -done - -exit 0 diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/pre-rebase.sample b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/pre-rebase.sample deleted file mode 100755 index 33730ca647..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/pre-rebase.sample +++ /dev/null @@ -1,169 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2006, 2008 Junio C Hamano -# -# The "pre-rebase" hook is run just before "git rebase" starts doing -# its job, and can prevent the command from running by exiting with -# non-zero status. -# -# The hook is called with the following parameters: -# -# $1 -- the upstream the series was forked from. -# $2 -- the branch being rebased (or empty when rebasing the current branch). -# -# This sample shows how to prevent topic branches that are already -# merged to 'next' branch from getting rebased, because allowing it -# would result in rebasing already published history. - -publish=next -basebranch="$1" -if test "$#" = 2 -then - topic="refs/heads/$2" -else - topic=`git symbolic-ref HEAD` || - exit 0 ;# we do not interrupt rebasing detached HEAD -fi - -case "$topic" in -refs/heads/??/*) - ;; -*) - exit 0 ;# we do not interrupt others. - ;; -esac - -# Now we are dealing with a topic branch being rebased -# on top of master. Is it OK to rebase it? - -# Does the topic really exist? -git show-ref -q "$topic" || { - echo >&2 "No such branch $topic" - exit 1 -} - -# Is topic fully merged to master? -not_in_master=`git rev-list --pretty=oneline ^master "$topic"` -if test -z "$not_in_master" -then - echo >&2 "$topic is fully merged to master; better remove it." - exit 1 ;# we could allow it, but there is no point. -fi - -# Is topic ever merged to next? If so you should not be rebasing it. -only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` -only_next_2=`git rev-list ^master ${publish} | sort` -if test "$only_next_1" = "$only_next_2" -then - not_in_topic=`git rev-list "^$topic" master` - if test -z "$not_in_topic" - then - echo >&2 "$topic is already up-to-date with master" - exit 1 ;# we could allow it, but there is no point. - else - exit 0 - fi -else - not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` - /usr/bin/perl -e ' - my $topic = $ARGV[0]; - my $msg = "* $topic has commits already merged to public branch:\n"; - my (%not_in_next) = map { - /^([0-9a-f]+) /; - ($1 => 1); - } split(/\n/, $ARGV[1]); - for my $elem (map { - /^([0-9a-f]+) (.*)$/; - [$1 => $2]; - } split(/\n/, $ARGV[2])) { - if (!exists $not_in_next{$elem->[0]}) { - if ($msg) { - print STDERR $msg; - undef $msg; - } - print STDERR " $elem->[1]\n"; - } - } - ' "$topic" "$not_in_next" "$not_in_master" - exit 1 -fi - -<<\DOC_END - -This sample hook safeguards topic branches that have been -published from being rewound. - -The workflow assumed here is: - - * Once a topic branch forks from "master", "master" is never - merged into it again (either directly or indirectly). - - * Once a topic branch is fully cooked and merged into "master", - it is deleted. If you need to build on top of it to correct - earlier mistakes, a new topic branch is created by forking at - the tip of the "master". This is not strictly necessary, but - it makes it easier to keep your history simple. - - * Whenever you need to test or publish your changes to topic - branches, merge them into "next" branch. - -The script, being an example, hardcodes the publish branch name -to be "next", but it is trivial to make it configurable via -$GIT_DIR/config mechanism. - -With this workflow, you would want to know: - -(1) ... if a topic branch has ever been merged to "next". Young - topic branches can have stupid mistakes you would rather - clean up before publishing, and things that have not been - merged into other branches can be easily rebased without - affecting other people. But once it is published, you would - not want to rewind it. - -(2) ... if a topic branch has been fully merged to "master". - Then you can delete it. More importantly, you should not - build on top of it -- other people may already want to - change things related to the topic as patches against your - "master", so if you need further changes, it is better to - fork the topic (perhaps with the same name) afresh from the - tip of "master". - -Let's look at this example: - - o---o---o---o---o---o---o---o---o---o "next" - / / / / - / a---a---b A / / - / / / / - / / c---c---c---c B / - / / / \ / - / / / b---b C \ / - / / / / \ / - ---o---o---o---o---o---o---o---o---o---o---o "master" - - -A, B and C are topic branches. - - * A has one fix since it was merged up to "next". - - * B has finished. It has been fully merged up to "master" and "next", - and is ready to be deleted. - - * C has not merged to "next" at all. - -We would want to allow C to be rebased, refuse A, and encourage -B to be deleted. - -To compute (1): - - git rev-list ^master ^topic next - git rev-list ^master next - - if these match, topic has not merged in next at all. - -To compute (2): - - git rev-list master..topic - - if this is empty, it is fully merged to "master". - -DOC_END diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/pre-receive.sample b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/pre-receive.sample deleted file mode 100755 index a1fd29ec14..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/pre-receive.sample +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -# -# An example hook script to make use of push options. -# The example simply echoes all push options that start with 'echoback=' -# and rejects all pushes when the "reject" push option is used. -# -# To enable this hook, rename this file to "pre-receive". - -if test -n "$GIT_PUSH_OPTION_COUNT" -then - i=0 - while test "$i" -lt "$GIT_PUSH_OPTION_COUNT" - do - eval "value=\$GIT_PUSH_OPTION_$i" - case "$value" in - echoback=*) - echo "echo from the pre-receive-hook: ${value#*=}" >&2 - ;; - reject) - exit 1 - esac - i=$((i + 1)) - done -fi diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/prepare-commit-msg.sample b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/prepare-commit-msg.sample deleted file mode 100755 index f093a02ec4..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/prepare-commit-msg.sample +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh -# -# An example hook script to prepare the commit log message. -# Called by "git commit" with the name of the file that has the -# commit message, followed by the description of the commit -# message's source. The hook's purpose is to edit the commit -# message file. If the hook fails with a non-zero status, -# the commit is aborted. -# -# To enable this hook, rename this file to "prepare-commit-msg". - -# This hook includes three examples. The first comments out the -# "Conflicts:" part of a merge commit. -# -# The second includes the output of "git diff --name-status -r" -# into the message, just before the "git status" output. It is -# commented because it doesn't cope with --amend or with squashed -# commits. -# -# The third example adds a Signed-off-by line to the message, that can -# still be edited. This is rarely a good idea. - -case "$2,$3" in - merge,) - /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; - -# ,|template,) -# /usr/bin/perl -i.bak -pe ' -# print "\n" . `git diff --cached --name-status -r` -# if /^#/ && $first++ == 0' "$1" ;; - - *) ;; -esac - -# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') -# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/update.sample b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/update.sample deleted file mode 100755 index 80ba94135c..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/hooks/update.sample +++ /dev/null @@ -1,128 +0,0 @@ -#!/bin/sh -# -# An example hook script to block unannotated tags from entering. -# Called by "git receive-pack" with arguments: refname sha1-old sha1-new -# -# To enable this hook, rename this file to "update". -# -# Config -# ------ -# hooks.allowunannotated -# This boolean sets whether unannotated tags will be allowed into the -# repository. By default they won't be. -# hooks.allowdeletetag -# This boolean sets whether deleting tags will be allowed in the -# repository. By default they won't be. -# hooks.allowmodifytag -# This boolean sets whether a tag may be modified after creation. By default -# it won't be. -# hooks.allowdeletebranch -# This boolean sets whether deleting branches will be allowed in the -# repository. By default they won't be. -# hooks.denycreatebranch -# This boolean sets whether remotely creating branches will be denied -# in the repository. By default this is allowed. -# - -# --- Command line -refname="$1" -oldrev="$2" -newrev="$3" - -# --- Safety check -if [ -z "$GIT_DIR" ]; then - echo "Don't run this script from the command line." >&2 - echo " (if you want, you could supply GIT_DIR then run" >&2 - echo " $0 )" >&2 - exit 1 -fi - -if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then - echo "usage: $0 " >&2 - exit 1 -fi - -# --- Config -allowunannotated=$(git config --bool hooks.allowunannotated) -allowdeletebranch=$(git config --bool hooks.allowdeletebranch) -denycreatebranch=$(git config --bool hooks.denycreatebranch) -allowdeletetag=$(git config --bool hooks.allowdeletetag) -allowmodifytag=$(git config --bool hooks.allowmodifytag) - -# check for no description -projectdesc=$(sed -e '1q' "$GIT_DIR/description") -case "$projectdesc" in -"Unnamed repository"* | "") - echo "*** Project description file hasn't been set" >&2 - exit 1 - ;; -esac - -# --- Check types -# if $newrev is 0000...0000, it's a commit to delete a ref. -zero="0000000000000000000000000000000000000000" -if [ "$newrev" = "$zero" ]; then - newrev_type=delete -else - newrev_type=$(git cat-file -t $newrev) -fi - -case "$refname","$newrev_type" in - refs/tags/*,commit) - # un-annotated tag - short_refname=${refname##refs/tags/} - if [ "$allowunannotated" != "true" ]; then - echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 - echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 - exit 1 - fi - ;; - refs/tags/*,delete) - # delete tag - if [ "$allowdeletetag" != "true" ]; then - echo "*** Deleting a tag is not allowed in this repository" >&2 - exit 1 - fi - ;; - refs/tags/*,tag) - # annotated tag - if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 - then - echo "*** Tag '$refname' already exists." >&2 - echo "*** Modifying a tag is not allowed in this repository." >&2 - exit 1 - fi - ;; - refs/heads/*,commit) - # branch - if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then - echo "*** Creating a branch is not allowed in this repository" >&2 - exit 1 - fi - ;; - refs/heads/*,delete) - # delete branch - if [ "$allowdeletebranch" != "true" ]; then - echo "*** Deleting a branch is not allowed in this repository" >&2 - exit 1 - fi - ;; - refs/remotes/*,commit) - # tracking branch - ;; - refs/remotes/*,delete) - # delete tracking branch - if [ "$allowdeletebranch" != "true" ]; then - echo "*** Deleting a tracking branch is not allowed in this repository" >&2 - exit 1 - fi - ;; - *) - # Anything else (is there anything else?) - echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 - exit 1 - ;; -esac - -# --- Finished -exit 0 diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/index b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/index deleted file mode 100644 index 4953b4eea548172df738df3fdbc10d7ebfc162c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17291 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 Wq?P=ttPhswg!!fn&pp|4t@;0Jx(#js diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/info/exclude b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/info/exclude deleted file mode 100644 index a5196d1be8..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/info/exclude +++ /dev/null @@ -1,6 +0,0 @@ -# git ls-files --others --exclude-from=.git/info/exclude -# Lines that start with '#' are comments. -# For a project mostly in C, the following would be a good set of -# exclude patterns (uncomment them if you want to use them): -# *.[oa] -# *~ diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/logs/HEAD b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/logs/HEAD deleted file mode 100644 index ce0663ddbc..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/logs/HEAD +++ /dev/null @@ -1,3 +0,0 @@ -0000000000000000000000000000000000000000 0b36113e5fa9713025d50f046e8fd209fc8d9597 Marcin Grzejszczak 1522062299 +0200 clone: from git@github.com:marcingrzejszczak/contract-git.git -0b36113e5fa9713025d50f046e8fd209fc8d9597 3bd42890d5105a30abd82d0205b63cbf20a59e83 Marcin Grzejszczak 1547107982 +0100 commit: Added more versions -3bd42890d5105a30abd82d0205b63cbf20a59e83 49c8705a4409b1a4bd0f767665632c6ae11b5b90 Marcin Grzejszczak 1581521766 +0100 commit: Issue 1305 diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/logs/refs/heads/master b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/logs/refs/heads/master deleted file mode 100644 index ce0663ddbc..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/logs/refs/heads/master +++ /dev/null @@ -1,3 +0,0 @@ -0000000000000000000000000000000000000000 0b36113e5fa9713025d50f046e8fd209fc8d9597 Marcin Grzejszczak 1522062299 +0200 clone: from git@github.com:marcingrzejszczak/contract-git.git -0b36113e5fa9713025d50f046e8fd209fc8d9597 3bd42890d5105a30abd82d0205b63cbf20a59e83 Marcin Grzejszczak 1547107982 +0100 commit: Added more versions -3bd42890d5105a30abd82d0205b63cbf20a59e83 49c8705a4409b1a4bd0f767665632c6ae11b5b90 Marcin Grzejszczak 1581521766 +0100 commit: Issue 1305 diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/logs/refs/remotes/origin/HEAD b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/logs/refs/remotes/origin/HEAD deleted file mode 100644 index 91006b3a8e..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/logs/refs/remotes/origin/HEAD +++ /dev/null @@ -1 +0,0 @@ -0000000000000000000000000000000000000000 0b36113e5fa9713025d50f046e8fd209fc8d9597 Marcin Grzejszczak 1522062299 +0200 clone: from git@github.com:marcingrzejszczak/contract-git.git diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/04/f59ff38f1c76629d41d71f38dcb87afecdf9ab b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/04/f59ff38f1c76629d41d71f38dcb87afecdf9ab deleted file mode 100644 index b0dfc0b00fdbf5ff005c3573c54d867a84343346..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 67 zcmV-J0KETr0V^p=O;s>8W-u`T0)?d1)FR!)f=u0lqWqN7WFRNCq9nB_FENK|h7PT$t>GPK_9!(w#dQ6wL**aaV13i24^!XXSUQt*xSsZF3 zYm#kPTZi}l$!AE5nKxRo@mx}CN_Ht}+DL`mK5|MQ*?DaZJsb+8rsuJ*G&9VaT7=zQg+kSS{lXF>99_H`YI6#eeP@6B1l}9NNBcXSH~Ag zh8{G<&pL$0pHC)T*JUz6&aA5@^^TCA+~k+nv&HopVE1VsOwHbtQ8Hh`sM z0kE~~l0KDV#Da~mJEwy-)hT(q3Y~Nuv6k8gr;9c`P_1V};C_4ox=BOB>4NgbkS?Z+ zd~q6!e9D(^=O32zX?lA*oh|e01LDMeWrK$?CO*lnqfNpvvH9D z#;Bv7Tqf}r97R7&j8=%pci*tmE3H7yRIRL-D*J<-0V8VIZM2Vb^#E8#NVVSRAVWI( z>xQE#O@x5X_py+&COD~r&kAOjZGcL`X_XL|LFOBW=arKi?yS4dRBhWb+vgz6D!c3} zWE*+U^h*p%_R8rd_8$+2L$P2}0vk2fV+cQ(06nrv2x-?5Zd$X6WITk1^jyR6ahjN4 z#UaTM5ejj4cPA>8G3R2SAf16Pp=4bW8{1ZE5i21E-I6I79**lmDIIdgV8^4nCJ$r? z93VtP{|9GkD?sN&3?>u0kp-v9{%puTJ6@swxMamp{jyy3h=-NR}8m`L7kFE zQpKg>^4qZ>}tKcS$<|4EVP|$HAfd#dbW}sh0bB zU0x^2#wR1t`kh+;gTCL~zZiD$_sJ(|+z|^#j`i9N6sZ5J#U3Vv4?q=vmX=1x0(dB} mr&rkW@Za$e7w*L1_zNBegS}bKp>oSO`kLtc7JmRO;>voQfq4r6 diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/0b/b008b1d235cb760e13408f10662dda01027d1d b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/0b/b008b1d235cb760e13408f10662dda01027d1d deleted file mode 100644 index 9fef1219069ed046b12997646012a2be9aca719e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 64 zcmV-G0Kflu0V^p=O;s>4XD~D{Ff%bxD9*?)%}EJPtn^6D$;sEtD$dVixD;D#$hquZ W+@dL>{$fI_zMh`-AR7SuG!*hvZ5_M- diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/0f/c31c163430ef5913e1a85b3a6c4e36bcbf32e1 b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/0f/c31c163430ef5913e1a85b3a6c4e36bcbf32e1 deleted file mode 100644 index 659754a79577cde194dcb5e8cee1f80c7226e162..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 759 zcmVH?#N3A8p16Mxg(MlzPP+qR8SRx|Y`Zc?A2iXfp6Lk(9(h3g6l?T*~~ z^dhM^fF}8DVr;|ZY}WUEt`g+j`Fhsu35D5Bado{|UOxuxA?>YgI0W+ir86Fs%N?l} zu(T=xwo!f3r}m6kbOO8gCK_9xQ*i6pE6;+pG9h|XcJU|G1~vrlrx&1`vNWDAsaTHb z<$PHz&!x!wV)f?s?TX&d@9yS{RdKzf+dI0tUA!t*#q9!buW7#cKz|pDSLejg4AbFn ztrrFuqY*v1O5!b9L_bc9)`-h{Xjz-J(V%AQPSs4c`^w&e5w+~MCdga^09FF2FYz(DrC@R68Crv{E z;1D>X5KsRGYU-MS(OEW{&FDsz+=%tIte`zC-fxWFZ-nb&+r?v54d;}gfhDdPhRsGz zN}hQB%o_Il_f(QeDsQY*0CO?GLGf&~KZeQz;WUJG1fA0^X)S;Oe;DXEI(C1#n@;wk z6=CHZHrCeDvk6#zPn~}OKkV)g2>bXy$th{z0tG|Ig6&5N(7%=9fD*b#fRdk;qsb}% p009o{N>?5KJ$}Z8I})6J#KUNGu*xN^RTCIzpAw(%+5e@E%Y=2fearv= diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/1e/bb28e0982e1e497fe57311c4f8f34bae6f382f b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/1e/bb28e0982e1e497fe57311c4f8f34bae6f382f deleted file mode 100644 index 46cdecb6093d1a63531187e968ed0e50371fd6c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 79 zcmV-V0I>gf0V^p=O;s>6XD~4U0)^bv;^M^g%)E34UymzSbG?7CGkEr%*1W8CV72LK lNr;-F)Z!9`d2uH_zc@Z@>Q>xd#{0JH;1#`8W-u`T0)?d1)FR!)f=u0lqWqN7WFRNCq9nB_FENLqS*osB ZEnszt#y8%;UA6NT+XS9h0|08q77VU!9IF5T diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/2b/42d52aec21936e5578be5ea0e2fdb9c539ce88 b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/2b/42d52aec21936e5578be5ea0e2fdb9c539ce88 deleted file mode 100644 index 91e89ac31180fd797d0d6093769f9dd318a26c5c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 84 zcmV-a0IUCa0V^p=O;s>AVlXiP0)^!KT)ota#N2|MR0g>NElNB=mOU@d>NlA(Hb@3I q7<_`LO3TmJOG+$aD6qMvn!G~$>XZE{@iXkwgdX!tJ_G<3WgG&k@FS@J diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/35/c8489a4e3d4761ae82a8606ea82e0e52b05376 b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/35/c8489a4e3d4761ae82a8606ea82e0e52b05376 deleted file mode 100644 index 660b0fba8e7cbc198be92c1167b8b61980e65bf2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66 zcmV-I0KNZs0V^p=O;s?lWH2-^Ff%bxD9*?)%}EJPtn^6D$;sDCFUrp^t7LF{RsMU2 Y^x0(Kr? z=MbPoO62q1eg3}hoKl$*u2rbwTkO1*0=35qdR?I#n=;D<^-h^3d`IV{(Qw69@H(Q-r_}t-#|UvUJ#_p8+63r5 z5{C3pOND?>0&M`PL72`e$+bWjWN628CX~no9wrP^22SOi8te&7eO?GWOr#+`Z3xzX zNYh~$7#}G!ukGJOQ^vOYoA&Dn5+7eTR+_-;g9U80M{`gKNh-9E>|Mp-f+~KR}d5!KiJ7 zWgR~v{7hzXR)i3jvkvJFSFrf9IV>pboq|Q$qEd#!mssm99Xs~TJSpit{SK>`dr5u) H-WLp>O&|F~ diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/49/c8705a4409b1a4bd0f767665632c6ae11b5b90 b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/49/c8705a4409b1a4bd0f767665632c6ae11b5b90 deleted file mode 100644 index f684debe0e..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/49/c8705a4409b1a4bd0f767665632c6ae11b5b90 +++ /dev/null @@ -1,2 +0,0 @@ -x­Î1N1…ajŸbz¤hlïØ^ ¡t‡{Æa Î"¯ÓìéYÑpÚï—ž^Y[[8ŠO£«edE$‹j E%Ôë”gJ‘«„ŒGJæ›»Þø,“K3 -Y$öÈY’tH9ø’«C¦Y“7ük‡wîe¹Ã¥ïú¹íeç¼´_;]ÿì|m¼|ÊÚ^ÁR²äl žÑ"šCËCÿe̼mÛCÁz$ó›)Tz \ No newline at end of file diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/4d/48d4d56d4bf80700498dcb29d326c0ab35cb19 b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/4d/48d4d56d4bf80700498dcb29d326c0ab35cb19 deleted file mode 100644 index c1cbce1fd003cd6192c46bec0bd2219b14b624a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 113 zcmV-%0FM870V^p=O;s>7HefI`FfcPQQ7F#HFU?5_PR&bkOioTMC`nBTOD)Pw%S=uz z$;{8wOE1dLFRNtW67o4R#WVYJxSRL~y@1Hl7uWn^FboJv%}PziVF3SO88H)s_mRR6 TS43Oo_?hk5Z}boVi7qq%%O)@X diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/4e/5ffb7085c01081f98321985b6663f64939cdb2 b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/4e/5ffb7085c01081f98321985b6663f64939cdb2 deleted file mode 100644 index e064506abc04e96e7390dd1fcd40b795572cbe77..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 118 zcmV-+0Ez#20V^p=O;s>7GGH(?FfcPQQ7F#HFU?7DFG|cSadb*eE%HqB&q;C3%P&pO z(90^$&tr&J{r1!3!1Jef4)#gkFubeLzie$6ir%2qtkh(f=8*jS$o$g0bco(rzJ}YM Yo?_asP-o4u$x!cQMBLK^08kb(@({W{YXATM diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/57/4590052afef4af132f7b8c5b92682401635807 b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/57/4590052afef4af132f7b8c5b92682401635807 deleted file mode 100644 index 5308a6f92effd7c536087700373cba866b5c9441..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54 zcmV-60LlM&0V^p=O;s?qWH2!R0)?c+D(C#X;?msIB14Aj`n&%xy0GyTJNtd_V0)|k MnHF}d0EN*KM7Q%BNdN!< diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/5b/0ae7cddbd14fc6ced6f87f4b9587afd6b0bd18 b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/5b/0ae7cddbd14fc6ced6f87f4b9587afd6b0bd18 deleted file mode 100644 index 81af1360ef3167083f48c521fb4973cbf0034a97..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 127 zcmV-_0D%8^0V^p=O;s>7G-fa~FfcPQQSk9}cJ&K()hnqeVMvOYcUNd}?WOMQ{I_zt zMO`O9#PpgN0D*$9Ylx$+r=J@`9^1FFle=6Z5B}S!bg%Cj^Q-LF=b$D9xjMS|y6PpS h%Cn9zM(-@E9+!qq!Z{S$swnmIx70|2ceF-_T=KLh{( diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/5f/25f6f934c0e7e5dcc18e1bd831dd288fa6ad8a b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/5f/25f6f934c0e7e5dcc18e1bd831dd288fa6ad8a deleted file mode 100644 index b36fe165e7..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/5f/25f6f934c0e7e5dcc18e1bd831dd288fa6ad8a +++ /dev/null @@ -1,4 +0,0 @@ -x•QÉNÃ0åܯ°,¤‚„Iº¤›„@â‡VjoIN2!ÄñäPUáÛ§+$¸ØÒó›·Œ£BGÌó¦W»c4VK6ZO0)?d1)FR!)f=u1y{Ji4Q+|(ilx!oEMX6VUz);}#4 RJo4kS_qu!weE`7)6JHQu8=e3F diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/61/9c03cba4276c76c43b9a307ed00f39dc44616e b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/61/9c03cba4276c76c43b9a307ed00f39dc44616e deleted file mode 100644 index 9b672595dbf948602d708f6983de10d85a371cb2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmV-K0K5Nq0V^p=O;s>8W-u`T0)?d1)FR!)f=u0lqWqN7WFRNCq9nB_FENMV(wVpG amhUK@C3vuAVwlXKH4hf7oCyG#1R0s>O&#O_ diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/61/fcad6942801c44ad275671c7d125efb564f799 b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/61/fcad6942801c44ad275671c7d125efb564f799 deleted file mode 100644 index 922f3ca3fcf1b263091416047fe313c5a133dc8d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 83 zcmV-Z0IdIb0V^p=O;s>AWH2!R0)^!Kypp2C|^S<;|^mv$&d?+pE{NH!t2?^6RNQ^zBBC_A4)veu7=t*{X@Ol z?nJRwyE}B{X4{)~-?+{|CA?Vn2V;kR+jix@rjm%=z!B>07h12s)orRl=Xd1D&aDV>gb$CSa1x!#<8^XyM}0LQg(PjGw`H1xhl@-YTT;?DUf z5h9naffH6GLU|-T({l{@yLOnEGaNF(zq-kJUK1z_`sBVW2FmKpt1LfM6ZZkymY#}0 z@4ECv0?o5f1d{A0skXprD>q?z)%lqc)XuG4*Wq>fD=Vu-S3%RUJgW13V1)(o(NJ)!UM?AQ2*<4Gj#HIgr#yBeB3Pm zi7Yu)-8P4yFv2lZQXlKCt&w)Ct!!?6)NV z2U@Bm1gl36K#6wl9;Jx-V-~|Tl2G{I;NdnTa{vkrb6!mj#};;^nt&GEnhllDsV7R|ubpexW7IF%v9!lO8u4R)WF@PP z;Cab`T5t;KqaIA3BZQM2E|iHxNwf+bRkTMod`$TMwW0i|_>)DK#biaI_69vF2(mn)IW8zi*vAuVfJP)#_K@dw|#+Q&R5grnyU zfWXeKq(|x#Axqf#0$X8Wh_SiTnIsWLl5xxe23xrmoehq=8qnIIo19n+UgA?skf}lM zRSVsR*shLkjaUa${H|OL?ch&e&h;RJG5ydAs$!4EIYqKJPbBgl7W3m1u%2#%e|GJ`R{i10x^wtc zg4o@+D*}0{h&bI;Vg4g>$7u_1pdkVI-6_(w>!`dG7|#yRTiMv$XkT!|35ls2&&tmu)M*@!Hyw`iS+Tn zQgoGbvkSIn(F0va;IIFaKNCNPTh+1Sa7?pvCeu;E17# zf-q%~(sS^Nr`p}F;<(v1NCT+>%!N_4Rb@+z_Tkwq^^oHtBm;*LHyc#1_qHpgI@cZ0 z2i6DtDdR|&-h?O4{5i(pwqdL1bAUfElEmr(Z)G=@S$IKfKqp)!B~U+*ykq6`h&@9Q z`}fSu*9O(8a>~YIFEI4U@(QTA2`bnP$dpGU0dgb+7&XtvhLyN=*Lwd%97Z!%?Lht% zJ|pthRCe!&vZtw)10!S;03V5+Ko!BO$58x9fMa`8#nIGd3LoX*Z-IQZSSx9+l}(5T zXK-m^&pzTO)FCRBUGda4phY{Hxq7cZHBrx|w@zBq)JQgDj=fpOE6iXh#_x%4hb>t&b z8H(&Vic?_-}mv**Fm0hzYpm_+r$yn%LD!o&v5 zNj<6NX`Hx`Jb_$`Q+AM`TQddJALzVv<}y1oEN;XnGTtEWGQTtWE88)JFg{>I2Xqe8 zV@wksPl!t?&1B)|&a!8Ei=5+=SJ}y(>rr4Nf%0@V!c%){^w7A>?&xfGu#oKlP;Ms^ zu<3z<~V?pxc7N-Q3MDuO?W^ph}DR*{Gaui@O zgMf!e2jv;c^a7d^vNIE<8bE>0*+OQ_G3k)OkGPef1UI-M6Qit6Ksy*BCSd+fjQFE| z&BQ$JVe!{P<0RP-o61>~8#+%WMoVn0RuCgJwC@EQ2pdLq9DO}{C^svMz~ix1yZOhX zq>nw4sdc=7GUa;28Me$#-0?n^J8hRIsh(yd*E8dmEA-}*?1PtBf4NOUATR+27)LMY ziYH7n><(n3$~ z9cK)8o3V(;wvmYu*pO;~9GTMLhD`P3>y>P)Ff-A?fWP6Wte{G8OaSJzA57~R7B@TV zk&6;;2HGmi`al4%5&7n0^Of4p*q>e*kxiun17@)) zNI;LY;fS7zA;gLYPlCw+#qC^b*&>fetB5#7k*7H z@zs?Y0BB&EAOmPhP#6ITR1b+4Ng;;8$8G^rhs$YWpj)6>NFm9-m@q*E#E&kUsUFvD zPq(Jq8)}2)Y#5n2^lxPN20jPX{D5|V-LT9Qp$xK+=s|&9gas+6X-rYO!Ne_zf6xk% zi40dZD@+Ix4yn%QkPcToUAR}`bd~#FuRy*96h;DqaNhAQQxgCvk2X%0Ae1}15u)Su zLM_l2HG-R3Y`PMo;nvG__uT1|;NT;?i1g;YtE_bsb&Mg5nKF*49d;@hA>{Um4c%k& z$qNR~me^wTEhHaA8+aMKV};~YXi=@grk1&z%7ZV*YKl07=*p0<&t)wjK+|7v|BS^M zXHRq*JoOg*6APR}DuSdc(o+Ul*^6+*8eu@9D8mcX)h*a`44BqFH|9D$;%cKXT6nCH=<5j;%V zG4%058_9=TCfrJ=;F-p4suJvL<<6% z%5AuhNcR@;NGQJQnX_OjM7fjt2iLTGJ`JADAoXdmB>KM5Fr z9N>2tW5*RJ9!Ei87zkGhzy#gt@gdj>!At1hmk``*{n%9|`3C2nRcl#9r z)%XQdsz>M$+{zSI^Rd_tJ3f;3;wc`HUkiB_r3d`5&;?4!UeqXU*)#Jqeg}g|h)1b9 zbeQxW%K;9n`goKRN+j5pr9q&r zveiYBki$vA)4%GQb@C0a12L|IH*jwqy5QL6;1?8NE%cMQ&yq}DR5eh}gZ%VFZ_9LZ z3{1w}1KFobRM36tlu(KdfhzZXzNcwQ9#$8%VR&$8I?*n=VyK=G3vY-RX!*0xoMAQfuGAAsi{bSoV8 ze*Az@erDd{#me)7Dm=~AAT}@&#knJ7SdljXR?=I+#6UBFMPcrXSF6w}v>W1@Xr-EX zzBmD=0K+V>0NdcFQkeLt_BhxEhl`qExur`yi~T75PAcwuQ2S}gVY}59yIE!Qm+3O` zw*&tB-TWqc169Yfuj4O5%^4p^zqvgBffgdjGO-f~!dRf| zbFRvG+k_CY<)9)6jf!1yZgVnBy;B+OQudMgo;W>-)QwAG^SR%gzQW@1dU5pxzhael zbWZ&QWg&z-PCoQUXEZg@Kg2PTwNXEqoj-sac$9+wkNn#x^A^7?(0dq?II|H6`B``k leq4v?quC6|IB){=1>w3m;{>|Xu92|&Q@dtg{0BJF@DN=;kJtbJ diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/63/201c9f9cfbe294f3f314df8b9c94cfee88e622 b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/63/201c9f9cfbe294f3f314df8b9c94cfee88e622 deleted file mode 100644 index e5b6e05c8d97fa66aefe9590ea8b2dc37548d76a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56 zcmb7G-5C@00M>N{9L`%ip1Q4oKyyuuk%0m%akR}b-XTbac4)> zzq3DABUEJ;7ni0Q8XK50B+g+zy+l2y?1=R&gSrd+mUmnd^C0Td^7HkQ5{nq7{xJS^ ZW=(tP)}TI%&xg4um|Z<;0RY?BFtL&5II#c# diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/78/3688df3e22c6b8e1d8f58167baf4f511d369c5 b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/78/3688df3e22c6b8e1d8f58167baf4f511d369c5 deleted file mode 100644 index 6123d79f37ddfc7fe252cb25660f4d455929144c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54 zcmV-60LlM&0V^p=O;s?qWH2!R0)?c+D(C#X;?msIB149Mx=cE@sy;DQQK=PnnPtC@ M%)EIF09>^ZGIFCAfB*mh diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/83/1a7e732650ab7428f60d51ba7d9ea33c51cf26 b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/83/1a7e732650ab7428f60d51ba7d9ea33c51cf26 deleted file mode 100644 index bb8bb0630cea408888a7e55a019fdc6fb722258f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 88 zcmV-e0H^ElAYa$iG&CI&eZp~lt6)iKx=t62ai|3cQ1ha>9% diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/90/126ac925d26698516838a646e286e037acd55e b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/90/126ac925d26698516838a646e286e037acd55e deleted file mode 100644 index 8f25538fb03cdb6d9fe5e4f3dbca2e8e04744e61..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46 zcmb9XD~4U0)?c+s^HY3vdrXEhGYeq`E!0hn)3Ox$o=j)Q_jEZ Lc%}pZXtfiGcug7z diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/9a/4d31b7e5ca02bf207e3b04b2312ee9585ee560 b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/9a/4d31b7e5ca02bf207e3b04b2312ee9585ee560 deleted file mode 100644 index e5a0b4f6688307acb2bb83d5419554964b613d90..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 306 zcmV-20nPq+0hLi(OT#b}_IbY|1YruscBLC`APT-IxPg6Zi=4KncG@PjNgu|jzul8| zHy;FjN#M(OJ10r05;mPp&bA}Q_&VbY#*?Y% zW%&($wx|t>tek+hDXoK(7MOnY90Dseh3cJG%a>q}76=(O`k*D^gOUcN5y7U$6P#Ws z2g*QMZ>Z~Xoq|~_>AY(td7sQ!*WaD(MS?_Sn-v&?jkFQrjx^Nl85J06sUOLLh=sL2 z5AQDSufs9C;W%cuU(5+zF^TDz$IfN^Gbtv^K8?1ZYbEuuGS>!7YjZu<2duNS&*u8g{!M{7_ODtm+aB4$~Z`Xxo4M{-_&$1H|H% ErQWHLi2wiq diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/9e/5ec949f441e1828b21b7760ded76c1d42ea9bc b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/9e/5ec949f441e1828b21b7760ded76c1d42ea9bc deleted file mode 100644 index f414071fef1f4d858c944466fe56aea490ed0056..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 121 zcmV-<0EYi~0V^p=O;s>7GGQ<@FfcPQQ7F#HFU?7DFG|cSadb*eE%HqB&q;C3%P&pO z&`U4M&o8TFxVbv~ElAYa$iG&CI&eZp~lt6)iKx=t62c^%0a52!X%{t diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/b0/cdfa5512c23af490d213948c7bdcd76d59a93e b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/b0/cdfa5512c23af490d213948c7bdcd76d59a93e deleted file mode 100644 index 407c78baaada42090e24e41346b8f5bc20691eef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 741 zcmVFs%Z$6D>n%LX+!U6OY8sY==-y z{P*3t*-j3;V0=`5r^iXM0 zfoOecEXDnu%czViFO@{?Fo#y>XhYGg5t3^A%m}`qb;@Ws&JJO~s7aqnhVL0-XIiMm z4z%&mIwTC`V5=$we3aODP#UDEn@R~S5jy3|uuqS|OyIW1FdHvuxuAk(2WI!*PoWxYq*(RUCkEj`S}W#S8%#qoXyws<$|J*Fk9Th#e8u#0wm9?h{IycM$Pe>w(R%5&@*lxnLaNz+9u3WUNupw*-Z8nm@?+*d~gbEZ_OT6y8aqvvUO z(WOZolh5}IB#rh~Nbj-@qRohvk7KewbB!hVtrazP#@=VLGHssyUQTJ0*=b*#)#4uE zXB=@y2!U^-9G$ePVH$%ZN#ZMH&8R)`q#<>!lw`rSt-#Ub3abo{Nr9dlMN61Z92e>V z^)!wonWSj~U6@W&<$&6>MHzQx$dgN91dt|{568Zo%;Vw?)2f2Sat(zQgi@+H_!_n# zZbPD5BOR<9($CA)I;FU^6{Hh7Kk}Z#jmdWd`i~-VZ3+*fYH>hrxVA<+uvp;ZApLqc zKDwjJ$z3`eGARE_6m%e6@T3nQW#>rGc)e>d9YNZUFPk;_?u_OwpJM)!XANx=?2R0? zwRQAvIHY`_#Lf~aHav=weLk5&LSnxyFG7w$D79DlA2NGY(JM*;FM1{OUz)=aG}h#; Xd^X{=l7G-fa~FfcPQQSk9}cJ&K()hnqeVYud+8CGmE&(i(H({)b9 zx?G3Fe6E`q0D*$9Ylx$+r=J^xw$oLuH;R+4VK6ZO0)?d1)FR!)f=u1y{Ji4Q+|(k52|`&XRWGH@2+Xip R=Ju%Vf%%%NaR97j?_4vQY}?Ht`M~0X#-2=`jdS zr-t1GTHDOT&;U+0H=mAY8o~7=`^C;4ezr%2!N*x}o{;FGQ?nnfGvLzVlGA+oEi(kO WXoZk^3AujTL-^yFVl7_K&qHD>*;DcW diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/d2/ccedaea7b8739a11c17c91561cc2ace0a0a999 b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/d2/ccedaea7b8739a11c17c91561cc2ace0a0a999 deleted file mode 100644 index 0b1fea88e1fa84170f6a96e2752e732247994336..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 77 zcmV-T0J8sh0V^p=O;s>5v0yMU00IRAJp(;M1KnUh$ADlD{}6^hi?4SEIeQq$CMmm| jFpurr!rvW>q|%UBm8QfhG$U4_Ik5^Y@GArW?`~11`z0NW diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/d7/2fbbffa2d0b1ea0707df4b533f3adf69383eaa b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/d7/2fbbffa2d0b1ea0707df4b533f3adf69383eaa deleted file mode 100644 index 3467337ffbe6cbc3ab79f9da26a4a205df20217e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46 zcmV+}0MY+=0V^p=O;s>9WH2!R0)?W~;t~ea6CShtY~2&rHLXa~_*0P*4t EZh!w0bpQYW diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/d9/ab57c99263dac1e164883dcb7e06c542b89906 b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/d9/ab57c99263dac1e164883dcb7e06c542b89906 deleted file mode 100644 index 12e2653df7..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/d9/ab57c99263dac1e164883dcb7e06c542b89906 +++ /dev/null @@ -1,6 +0,0 @@ -xm”QOÛ0Ç÷š|ŠS^Ò¢6¶‡ÁžºÂ´ -ÔN´ !´×¹&‰Ù¡šøî»s³Áت6}¾Ëÿÿ;;›ÊlàèøÝû7“ƒ`fšUEéáøðèí˜.'àKC“J‹ -DëKciÜß¹ŒÒ8óRIÔshuŽ6$M!)·Œà+Z§Œ†ãì\5éCÉð—Ø™j±m<´©†r°U>Jl<( ÒÔM¥„–òexN_…•Àm_Ãl¼ å‚š˜íË… |/øSz߸ÓɤëºLÉ™±Å¤Úr“Ëùì|±:“ì>íZWèXüÑ*K–7; É’bCb+Ñ>…EŠyò;«¼ÒÅœÙúNXd­¹rÞªMëÿ¢Ö»òþrq’é -æ«>NWóÕˆ‹ÜÌן—×k¸™^]Mëùù -–W0[.ÎæëùrA£O0]ÜÂÅ|q6$fÔ|l,; 6*æ‰y€·B†þ§c°¥8]ƒRm•$kºhEP˜´šAƒ¶VŽûêH`Î’*U+/|˜zÞ /º4‰câ|Ï…¤ÑÞ -é]¶A´©òqLø3×X*¿µ¢ÆÎØûLV¦Í³ßË)Œ2›õÉY-î~Æw„*ðm”£“V5,c$I|…ìµ'àZ) À¶­ÀѾVÞ$zn-`5q\¨Ô§q$ ‘¦ýGĪP›¶(ã® 1âš´WùXìS 'v˜VVPv©ê@3”&ECY#§Ò/ËÕ:¥qk+H'tjä=7&ß è?ŠˆÕ)<ˆªÅ1pmv`±ÀÇAzw<>ùvwH—t8ä¢ü+QÐ1tD?€”y‘ñz×`:‚´ß´ŒhòÝÍ|ŠùK¤zL€9jfëèpHñ ‰y’(ÆEÉ>žœB²¼óT€¦÷ÿ#dï(z%'ÔŠ^YüWâp5y+Ÿ¼¶‘ô ‰`è)þ‚”Œ2 \ No newline at end of file diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/fc/a3d789524348301d622344c8375d89b40f8b5d b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/fc/a3d789524348301d622344c8375d89b40f8b5d deleted file mode 100644 index b5c4d4136d821adb619c9c106e9a0cef139ee535..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 83 zcmV-Z0IdIb0V^p=O;s>AWH2!R0)^!Kypp2C3zxkR_qe?G=!p<*ZieTI+-Ct| CX%O51 diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/pack/pack-36eb4e6b44a393bca412489cd42ac7cc572b42d3.idx b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/pack/pack-36eb4e6b44a393bca412489cd42ac7cc572b42d3.idx deleted file mode 100644 index ef612d3f04d4bf2e00f85f03762a8516091f0026..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1968 zcmexg;-AdGz`z8=qyUh5QZO@6J*k)#sE1t42Gom;*@1i*<^ZyhF(;6ZjJbe(QZP4A zJr5M~0%;KD!-M&Oa-?7Zpn77kAW$8-SO};W84CmX#9|SkT68Q56hp>hK)yJQu_VxZ zY*-2?j*g{)V${YmKr^vnS)e$ru^iA2c`~sAP@e*~nV?<#%0dIxtNbi^{g*iZ^iG}5 z-J@1{;#dQV;aTsZ&jJE}{`?J65dZSiKZ`x*M7e1~M)C_@_SJjS?yJ-!?RvS<|A**% zmFrW2O`7uT^B1Z##n!XE)f2UOVygNeV+ZHNXGb<0UoBmmypKVN{Km-yQw1yyJoXDjv-p$FskB@?PgCefT}nJ6$pOP*Kdfo3e{? z-#hJz*s=QcKhdd|qGn$I@US~r~+;$~HEm;CAB zyP|?y8c)6mO3>MQC>IaXc<^n#wtu!DZh~FyX8yNy{eZJ!z=_f z`;=v-^ULLo{mu8XH*^?G#)t|e;zeE1l#W?m$meHZ+Gj?XqeC1WVEzaXWMEHH)MSu3kU(v3( z(kORl!tScwcl+aVZ&!TV%dGm+E64fc^dA?js=hbty1bIlAZ zHkoJX{^IF6Cu3c%!(u+y-?yw>+PCn@HL0Sdul?I|y;ksRaeOH7Z2zrkz-qU%dC$6H zjTdJw>3IFi?l$Q!|Nk}S%+;xunaZMmQ2FP9olwS$Nfk1uTKpI#NN>wv3Faqlw zkpn<6AeOjj_S!GoW%1-aON2b;T+upyCS2R;^65?dGdvD|-*2|yg`}8jlam>TsyYC1 Crno`? diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/pack/pack-36eb4e6b44a393bca412489cd42ac7cc572b42d3.pack b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/objects/pack/pack-36eb4e6b44a393bca412489cd42ac7cc572b42d3.pack deleted file mode 100644 index fb8e35c7d121e3cef73384dfff5428d05b9ecf9d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8048 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 OpvAW%lX`5D3;zQ)q;;zR diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/packed-refs b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/packed-refs deleted file mode 100644 index 5a69e4592d..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/packed-refs +++ /dev/null @@ -1,2 +0,0 @@ -# pack-refs with: peeled fully-peeled -0b36113e5fa9713025d50f046e8fd209fc8d9597 refs/remotes/origin/master diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/refs/heads/master b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/refs/heads/master deleted file mode 100644 index 73fc07ed64..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/refs/heads/master +++ /dev/null @@ -1 +0,0 @@ -49c8705a4409b1a4bd0f767665632c6ae11b5b90 diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/refs/remotes/origin/HEAD b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/refs/remotes/origin/HEAD deleted file mode 100644 index 6efe28fff8..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-git/git/refs/remotes/origin/HEAD +++ /dev/null @@ -1 +0,0 @@ -ref: refs/remotes/origin/master diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/LICENSE.txt b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/LICENSE.txt deleted file mode 100644 index 62589edd12..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/LICENSE.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy deleted file mode 100644 index 4676a127dc..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a positive verification message when person is eligible to get the beer - -``` -given: - client is old enough -when: - he applies for a beer -then: - we'll send a message with a positive verification -``` - -""") - // Label by means of which the output message can be triggered - label 'accepted_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsOldEnough()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: true - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy deleted file mode 100644 index d3dd5b3834..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a negative verification message when person is not eligible to get the beer - -``` -given: - client is too young -when: - he applies for a beer -then: - we'll send a message with a negative verification -``` - -""") - // Label by means of which the output message can be triggered - label 'rejected_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsTooYoung()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: false - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy deleted file mode 100644 index 2cb715928b..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a successful scenario of getting a beer - -given: - client is old enough -when: - he applies for a beer -then: - we'll grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[2-9][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy deleted file mode 100644 index 0183b0fba3..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a unsuccessful scenario of getting a beer - -given: - client is not old enough -when: - he applies for a beer -then: - we'll NOT grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[0-1][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "NOT_OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json deleted file mode 100644 index 5f25f6f934..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[2-9][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json deleted file mode 100644 index 9a4d31b7e5..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/0.0.1-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[0-1][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"NOT_OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy deleted file mode 100644 index 4676a127dc..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a positive verification message when person is eligible to get the beer - -``` -given: - client is old enough -when: - he applies for a beer -then: - we'll send a message with a positive verification -``` - -""") - // Label by means of which the output message can be triggered - label 'accepted_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsOldEnough()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: true - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy deleted file mode 100644 index d3dd5b3834..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a negative verification message when person is not eligible to get the beer - -``` -given: - client is too young -when: - he applies for a beer -then: - we'll send a message with a negative verification -``` - -""") - // Label by means of which the output message can be triggered - label 'rejected_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsTooYoung()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: false - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy deleted file mode 100644 index 2cb715928b..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a successful scenario of getting a beer - -given: - client is old enough -when: - he applies for a beer -then: - we'll grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[2-9][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy deleted file mode 100644 index 0183b0fba3..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a unsuccessful scenario of getting a beer - -given: - client is not old enough -when: - he applies for a beer -then: - we'll NOT grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[0-1][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "NOT_OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json deleted file mode 100644 index 5f25f6f934..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[2-9][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json deleted file mode 100644 index 9a4d31b7e5..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.BUILD-SNAPSHOT/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[0-1][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"NOT_OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy deleted file mode 100644 index 4676a127dc..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a positive verification message when person is eligible to get the beer - -``` -given: - client is old enough -when: - he applies for a beer -then: - we'll send a message with a positive verification -``` - -""") - // Label by means of which the output message can be triggered - label 'accepted_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsOldEnough()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: true - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy deleted file mode 100644 index d3dd5b3834..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a negative verification message when person is not eligible to get the beer - -``` -given: - client is too young -when: - he applies for a beer -then: - we'll send a message with a negative verification -``` - -""") - // Label by means of which the output message can be triggered - label 'rejected_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsTooYoung()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: false - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy deleted file mode 100644 index 2cb715928b..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a successful scenario of getting a beer - -given: - client is old enough -when: - he applies for a beer -then: - we'll grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[2-9][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy deleted file mode 100644 index 0183b0fba3..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a unsuccessful scenario of getting a beer - -given: - client is not old enough -when: - he applies for a beer -then: - we'll NOT grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[0-1][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "NOT_OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json deleted file mode 100644 index 5f25f6f934..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[2-9][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json deleted file mode 100644 index 9a4d31b7e5..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.M1/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[0-1][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"NOT_OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy deleted file mode 100644 index 4676a127dc..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a positive verification message when person is eligible to get the beer - -``` -given: - client is old enough -when: - he applies for a beer -then: - we'll send a message with a positive verification -``` - -""") - // Label by means of which the output message can be triggered - label 'accepted_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsOldEnough()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: true - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy deleted file mode 100644 index d3dd5b3834..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a negative verification message when person is not eligible to get the beer - -``` -given: - client is too young -when: - he applies for a beer -then: - we'll send a message with a negative verification -``` - -""") - // Label by means of which the output message can be triggered - label 'rejected_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsTooYoung()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: false - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy deleted file mode 100644 index 2cb715928b..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a successful scenario of getting a beer - -given: - client is old enough -when: - he applies for a beer -then: - we'll grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[2-9][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy deleted file mode 100644 index 0183b0fba3..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a unsuccessful scenario of getting a beer - -given: - client is not old enough -when: - he applies for a beer -then: - we'll NOT grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[0-1][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "NOT_OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json deleted file mode 100644 index 5f25f6f934..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[2-9][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json deleted file mode 100644 index 9a4d31b7e5..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RC1/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[0-1][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"NOT_OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy deleted file mode 100644 index 4676a127dc..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a positive verification message when person is eligible to get the beer - -``` -given: - client is old enough -when: - he applies for a beer -then: - we'll send a message with a positive verification -``` - -""") - // Label by means of which the output message can be triggered - label 'accepted_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsOldEnough()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: true - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy deleted file mode 100644 index d3dd5b3834..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a negative verification message when person is not eligible to get the beer - -``` -given: - client is too young -when: - he applies for a beer -then: - we'll send a message with a negative verification -``` - -""") - // Label by means of which the output message can be triggered - label 'rejected_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsTooYoung()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: false - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy deleted file mode 100644 index 2cb715928b..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a successful scenario of getting a beer - -given: - client is old enough -when: - he applies for a beer -then: - we'll grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[2-9][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy deleted file mode 100644 index 0183b0fba3..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a unsuccessful scenario of getting a beer - -given: - client is not old enough -when: - he applies for a beer -then: - we'll NOT grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[0-1][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "NOT_OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json deleted file mode 100644 index 5f25f6f934..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[2-9][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json deleted file mode 100644 index 9a4d31b7e5..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/1.0.0.RELEASE/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[0-1][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"NOT_OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/latest/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/latest/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy deleted file mode 100644 index 4676a127dc..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/latest/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a positive verification message when person is eligible to get the beer - -``` -given: - client is old enough -when: - he applies for a beer -then: - we'll send a message with a positive verification -``` - -""") - // Label by means of which the output message can be triggered - label 'accepted_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsOldEnough()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: true - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/latest/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/latest/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy deleted file mode 100644 index d3dd5b3834..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/latest/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a negative verification message when person is not eligible to get the beer - -``` -given: - client is too young -when: - he applies for a beer -then: - we'll send a message with a negative verification -``` - -""") - // Label by means of which the output message can be triggered - label 'rejected_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsTooYoung()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: false - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/latest/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/latest/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy deleted file mode 100644 index 2cb715928b..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/latest/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a successful scenario of getting a beer - -given: - client is old enough -when: - he applies for a beer -then: - we'll grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[2-9][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/latest/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/latest/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy deleted file mode 100644 index 0183b0fba3..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/latest/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a unsuccessful scenario of getting a beer - -given: - client is not old enough -when: - he applies for a beer -then: - we'll NOT grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[0-1][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "NOT_OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/latest/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/latest/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json deleted file mode 100644 index 5f25f6f934..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/latest/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[2-9][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/latest/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/latest/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json deleted file mode 100644 index 9a4d31b7e5..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/latest/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[0-1][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"NOT_OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/release/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/release/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy deleted file mode 100644 index 4676a127dc..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/release/contracts/beer-api-consumer/messaging/shouldSendAcceptedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a positive verification message when person is eligible to get the beer - -``` -given: - client is old enough -when: - he applies for a beer -then: - we'll send a message with a positive verification -``` - -""") - // Label by means of which the output message can be triggered - label 'accepted_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsOldEnough()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: true - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/release/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/release/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy deleted file mode 100644 index d3dd5b3834..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/release/contracts/beer-api-consumer/messaging/shouldSendRejectedVerification.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.messaging - -org.springframework.cloud.contract.spec.Contract.make { - description(""" -Sends a negative verification message when person is not eligible to get the beer - -``` -given: - client is too young -when: - he applies for a beer -then: - we'll send a message with a negative verification -``` - -""") - // Label by means of which the output message can be triggered - label 'rejected_verification' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('clientIsTooYoung()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'verifications' - // the body of the output message - body([ - eligible: false - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/release/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/release/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy deleted file mode 100644 index 2cb715928b..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/release/contracts/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a successful scenario of getting a beer - -given: - client is old enough -when: - he applies for a beer -then: - we'll grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[2-9][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/release/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/release/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy deleted file mode 100644 index 0183b0fba3..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/release/contracts/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.beer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - description(""" -Represents a unsuccessful scenario of getting a beer - -given: - client is not old enough -when: - he applies for a beer -then: - we'll NOT grant him the beer -""") - method 'POST' - url '/check' - body( - age: value(consumer(regex('[0-1][0-9]'))) - ) - headers { - header 'Content-Type', 'application/json' - } - } - response { - status 200 - body(""" - { - "status": "NOT_OK" - } - """) - headers { - header( - 'Content-Type', - value(consumer('application/json'), producer(regex('application/json.*'))) - ) - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/release/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/release/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json deleted file mode 100644 index 5f25f6f934..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/release/mappings/beer-api-consumer/rest/shouldGrantABeerIfOldEnough.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[2-9][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "e5413ef6-0f3e-4b81-9e78-7a90b53c6ed1" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/release/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/release/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json deleted file mode 100644 index 9a4d31b7e5..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/com.example/beer-api-producer-external/release/mappings/beer-api-consumer/rest/shouldRejectABeerIfTooYoung.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08", - "request": { - "url": "/check", - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - }, - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.['age'] =~ /[0-1][0-9]/)]" - } - ] - }, - "response": { - "status": 200, - "body": "{\"status\":\"NOT_OK\"}", - "headers": { - "Content-Type": "application/json" - }, - "transformers": [ - "response-template" - ] - }, - "uuid": "b54426aa-b2ef-4b12-adc9-a05fcf6a4e08" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/foo.bar/bazService/0.0.1-SNAPSHOT/contracts/bazConsumer1/rest/shouldSayHello.groovy b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/foo.bar/bazService/0.0.1-SNAPSHOT/contracts/bazConsumer1/rest/shouldSayHello.groovy deleted file mode 100644 index 13fb9dc178..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/foo.bar/bazService/0.0.1-SNAPSHOT/contracts/bazConsumer1/rest/shouldSayHello.groovy +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts.foo.bar.bazService.bazConsumer.rest - -org.springframework.cloud.contract.spec.Contract.make { - request { - method 'GET' - url '/hello' - } - response { - status 200 - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/foo.bar/bazService/0.0.1-SNAPSHOT/mappings/bazConsumer1/rest/shouldSayHello.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/foo.bar/bazService/0.0.1-SNAPSHOT/mappings/bazConsumer1/rest/shouldSayHello.json deleted file mode 100644 index d25d733109..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/META-INF/foo.bar/bazService/0.0.1-SNAPSHOT/mappings/bazConsumer1/rest/shouldSayHello.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "id": "f4080f7d-4cb2-4301-81d6-492570316aae", - "request": { - "url": "/hello", - "method": "GET" - }, - "response": { - "status": 200, - "transformers": [ - "response-template" - ] - }, - "uuid": "f4080f7d-4cb2-4301-81d6-492570316aae" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/README.adoc b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/README.adoc deleted file mode 100644 index 98908bc72f..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/README.adoc +++ /dev/null @@ -1,70 +0,0 @@ -= Common contracts repo - -This repo contains all contracts for apps in the system. - -== As a consumer - -You are working offline in order to play around with the API of the producer. -What you need to do is to have the producer's stubs installed locally. To do that -you have to (from the root of the repo) - -[source,bash] ----- -cd src/main/resources/contracts/com/example/beer-api-producer-external/1.0.0 -mvn clean install -DskipTests ----- - -Then if you do `ls ./target` you'll see `beer-api-producer-external-0.0.1-SNAPSHOT-stubs.jar`. This jar will - contain the stubs generated from your contracts. That way you -can reference the `com.example:server:+:stubs` dependency in your consumer tests. - -TIP: Don't mind that there's a version mismatch in the stubs and the folder structure. -The version number is there in the folder name for tests related to dealing with -non-Java friendly naming of packages. - -== As a producer - -Assuming that the consumers have filed a PR with the proposed contract the producers -can work offline to generate tests and stubs. To work offline, as a producer you just have -to go to the root folder of the contracts and: - -[source,bash] ----- -./mvnw clean install -DskipTests ----- - -Then if you do `ls ./target` you'll see `contracts-0.0.1-SNAPSHOT.jar`. This file contains -all DSL contracts, for all applications. - -Now the producer can include the `contracts-0.0.1-SNAPSHOT.jar` from your local maven repository. -You can achieve that by setting the proper flag in plugin properties. - -Example for Maven - -[source,xml] ----- - - org.springframework.cloud - spring-cloud-contract-maven-plugin - - - true - - com.example - beer-contracts - - - ----- - -and for Gradle: - -[source,groovy] ----- -contracts { - contractsWorkOffline = true - contractDependency { - stringNotation = "com.example:beer-contracts" - } -} ----- diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/COMMIT_EDITMSG b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/COMMIT_EDITMSG deleted file mode 100644 index 44b23e0481..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/COMMIT_EDITMSG +++ /dev/null @@ -1 +0,0 @@ -New names diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/HEAD b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/HEAD deleted file mode 100644 index cb089cd89a..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/HEAD +++ /dev/null @@ -1 +0,0 @@ -ref: refs/heads/master diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/config b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/config deleted file mode 100644 index 1bc26be514..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/config +++ /dev/null @@ -1,10 +0,0 @@ -[core] - repositoryformatversion = 0 - filemode = true - bare = false - logallrefupdates = true - ignorecase = true - precomposeunicode = true -[branch "master"] - remote = origin - merge = refs/heads/master diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/description b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/description deleted file mode 100644 index 498b267a8c..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/description +++ /dev/null @@ -1 +0,0 @@ -Unnamed repository; edit this file 'description' to name the repository. diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/applypatch-msg.sample b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/applypatch-msg.sample deleted file mode 100755 index a5d7b84a67..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/applypatch-msg.sample +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh -# -# An example hook script to check the commit log message taken by -# applypatch from an e-mail message. -# -# The hook should exit with non-zero status after issuing an -# appropriate message if it wants to stop the commit. The hook is -# allowed to edit the commit message file. -# -# To enable this hook, rename this file to "applypatch-msg". - -. git-sh-setup -commitmsg="$(git rev-parse --git-path hooks/commit-msg)" -test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} -: diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/commit-msg.sample b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/commit-msg.sample deleted file mode 100755 index b58d1184a9..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/commit-msg.sample +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -# -# An example hook script to check the commit log message. -# Called by "git commit" with one argument, the name of the file -# that has the commit message. The hook should exit with non-zero -# status after issuing an appropriate message if it wants to stop the -# commit. The hook is allowed to edit the commit message file. -# -# To enable this hook, rename this file to "commit-msg". - -# Uncomment the below to add a Signed-off-by line to the message. -# Doing this in a hook is a bad idea in general, but the prepare-commit-msg -# hook is more suited to it. -# -# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') -# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" - -# This example catches duplicate Signed-off-by lines. - -test "" = "$(grep '^Signed-off-by: ' "$1" | - sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { - echo >&2 Duplicate Signed-off-by lines. - exit 1 -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/post-update.sample b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/post-update.sample deleted file mode 100755 index ec17ec1939..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/post-update.sample +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -# -# An example hook script to prepare a packed repository for use over -# dumb transports. -# -# To enable this hook, rename this file to "post-update". - -exec git update-server-info diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/pre-applypatch.sample b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/pre-applypatch.sample deleted file mode 100755 index 4142082bcb..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/pre-applypatch.sample +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh -# -# An example hook script to verify what is about to be committed -# by applypatch from an e-mail message. -# -# The hook should exit with non-zero status after issuing an -# appropriate message if it wants to stop the commit. -# -# To enable this hook, rename this file to "pre-applypatch". - -. git-sh-setup -precommit="$(git rev-parse --git-path hooks/pre-commit)" -test -x "$precommit" && exec "$precommit" ${1+"$@"} -: diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/pre-commit.sample b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/pre-commit.sample deleted file mode 100755 index 68d62d5446..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/pre-commit.sample +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh -# -# An example hook script to verify what is about to be committed. -# Called by "git commit" with no arguments. The hook should -# exit with non-zero status after issuing an appropriate message if -# it wants to stop the commit. -# -# To enable this hook, rename this file to "pre-commit". - -if git rev-parse --verify HEAD >/dev/null 2>&1 -then - against=HEAD -else - # Initial commit: diff against an empty tree object - against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 -fi - -# If you want to allow non-ASCII filenames set this variable to true. -allownonascii=$(git config --bool hooks.allownonascii) - -# Redirect output to stderr. -exec 1>&2 - -# Cross platform projects tend to avoid non-ASCII filenames; prevent -# them from being added to the repository. We exploit the fact that the -# printable range starts at the space character and ends with tilde. -if [ "$allownonascii" != "true" ] && - # Note that the use of brackets around a tr range is ok here, (it's - # even required, for portability to Solaris 10's /usr/bin/tr), since - # the square bracket bytes happen to fall in the designated range. - test $(git diff --cached --name-only --diff-filter=A -z $against | - LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 -then - cat <<\EOF -Error: Attempt to add a non-ASCII file name. - -This can cause problems if you want to work with people on other platforms. - -To be portable it is advisable to rename the file. - -If you know what you are doing you can disable this check using: - - git config hooks.allownonascii true -EOF - exit 1 -fi - -# If there are whitespace errors, print the offending file names and fail. -exec git diff-index --check --cached $against -- diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/pre-push.sample b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/pre-push.sample deleted file mode 100755 index 6187dbf439..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/pre-push.sample +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/sh - -# An example hook script to verify what is about to be pushed. Called by "git -# push" after it has checked the remote status, but before anything has been -# pushed. If this script exits with a non-zero status nothing will be pushed. -# -# This hook is called with the following parameters: -# -# $1 -- Name of the remote to which the push is being done -# $2 -- URL to which the push is being done -# -# If pushing without using a named remote those arguments will be equal. -# -# Information about the commits which are being pushed is supplied as lines to -# the standard input in the form: -# -# -# -# This sample shows how to prevent push of commits where the log message starts -# with "WIP" (work in progress). - -remote="$1" -url="$2" - -z40=0000000000000000000000000000000000000000 - -while read local_ref local_sha remote_ref remote_sha -do - if [ "$local_sha" = $z40 ] - then - # Handle delete - : - else - if [ "$remote_sha" = $z40 ] - then - # New branch, examine all commits - range="$local_sha" - else - # Update to existing branch, examine new commits - range="$remote_sha..$local_sha" - fi - - # Check for WIP commit - commit=`git rev-list -n 1 --grep '^WIP' "$range"` - if [ -n "$commit" ] - then - echo >&2 "Found WIP commit in $local_ref, not pushing" - exit 1 - fi - fi -done - -exit 0 diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/pre-rebase.sample b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/pre-rebase.sample deleted file mode 100755 index 33730ca647..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/pre-rebase.sample +++ /dev/null @@ -1,169 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2006, 2008 Junio C Hamano -# -# The "pre-rebase" hook is run just before "git rebase" starts doing -# its job, and can prevent the command from running by exiting with -# non-zero status. -# -# The hook is called with the following parameters: -# -# $1 -- the upstream the series was forked from. -# $2 -- the branch being rebased (or empty when rebasing the current branch). -# -# This sample shows how to prevent topic branches that are already -# merged to 'next' branch from getting rebased, because allowing it -# would result in rebasing already published history. - -publish=next -basebranch="$1" -if test "$#" = 2 -then - topic="refs/heads/$2" -else - topic=`git symbolic-ref HEAD` || - exit 0 ;# we do not interrupt rebasing detached HEAD -fi - -case "$topic" in -refs/heads/??/*) - ;; -*) - exit 0 ;# we do not interrupt others. - ;; -esac - -# Now we are dealing with a topic branch being rebased -# on top of master. Is it OK to rebase it? - -# Does the topic really exist? -git show-ref -q "$topic" || { - echo >&2 "No such branch $topic" - exit 1 -} - -# Is topic fully merged to master? -not_in_master=`git rev-list --pretty=oneline ^master "$topic"` -if test -z "$not_in_master" -then - echo >&2 "$topic is fully merged to master; better remove it." - exit 1 ;# we could allow it, but there is no point. -fi - -# Is topic ever merged to next? If so you should not be rebasing it. -only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` -only_next_2=`git rev-list ^master ${publish} | sort` -if test "$only_next_1" = "$only_next_2" -then - not_in_topic=`git rev-list "^$topic" master` - if test -z "$not_in_topic" - then - echo >&2 "$topic is already up-to-date with master" - exit 1 ;# we could allow it, but there is no point. - else - exit 0 - fi -else - not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` - /usr/bin/perl -e ' - my $topic = $ARGV[0]; - my $msg = "* $topic has commits already merged to public branch:\n"; - my (%not_in_next) = map { - /^([0-9a-f]+) /; - ($1 => 1); - } split(/\n/, $ARGV[1]); - for my $elem (map { - /^([0-9a-f]+) (.*)$/; - [$1 => $2]; - } split(/\n/, $ARGV[2])) { - if (!exists $not_in_next{$elem->[0]}) { - if ($msg) { - print STDERR $msg; - undef $msg; - } - print STDERR " $elem->[1]\n"; - } - } - ' "$topic" "$not_in_next" "$not_in_master" - exit 1 -fi - -<<\DOC_END - -This sample hook safeguards topic branches that have been -published from being rewound. - -The workflow assumed here is: - - * Once a topic branch forks from "master", "master" is never - merged into it again (either directly or indirectly). - - * Once a topic branch is fully cooked and merged into "master", - it is deleted. If you need to build on top of it to correct - earlier mistakes, a new topic branch is created by forking at - the tip of the "master". This is not strictly necessary, but - it makes it easier to keep your history simple. - - * Whenever you need to test or publish your changes to topic - branches, merge them into "next" branch. - -The script, being an example, hardcodes the publish branch name -to be "next", but it is trivial to make it configurable via -$GIT_DIR/config mechanism. - -With this workflow, you would want to know: - -(1) ... if a topic branch has ever been merged to "next". Young - topic branches can have stupid mistakes you would rather - clean up before publishing, and things that have not been - merged into other branches can be easily rebased without - affecting other people. But once it is published, you would - not want to rewind it. - -(2) ... if a topic branch has been fully merged to "master". - Then you can delete it. More importantly, you should not - build on top of it -- other people may already want to - change things related to the topic as patches against your - "master", so if you need further changes, it is better to - fork the topic (perhaps with the same name) afresh from the - tip of "master". - -Let's look at this example: - - o---o---o---o---o---o---o---o---o---o "next" - / / / / - / a---a---b A / / - / / / / - / / c---c---c---c B / - / / / \ / - / / / b---b C \ / - / / / / \ / - ---o---o---o---o---o---o---o---o---o---o---o "master" - - -A, B and C are topic branches. - - * A has one fix since it was merged up to "next". - - * B has finished. It has been fully merged up to "master" and "next", - and is ready to be deleted. - - * C has not merged to "next" at all. - -We would want to allow C to be rebased, refuse A, and encourage -B to be deleted. - -To compute (1): - - git rev-list ^master ^topic next - git rev-list ^master next - - if these match, topic has not merged in next at all. - -To compute (2): - - git rev-list master..topic - - if this is empty, it is fully merged to "master". - -DOC_END diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/pre-receive.sample b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/pre-receive.sample deleted file mode 100755 index a1fd29ec14..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/pre-receive.sample +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -# -# An example hook script to make use of push options. -# The example simply echoes all push options that start with 'echoback=' -# and rejects all pushes when the "reject" push option is used. -# -# To enable this hook, rename this file to "pre-receive". - -if test -n "$GIT_PUSH_OPTION_COUNT" -then - i=0 - while test "$i" -lt "$GIT_PUSH_OPTION_COUNT" - do - eval "value=\$GIT_PUSH_OPTION_$i" - case "$value" in - echoback=*) - echo "echo from the pre-receive-hook: ${value#*=}" >&2 - ;; - reject) - exit 1 - esac - i=$((i + 1)) - done -fi diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/prepare-commit-msg.sample b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/prepare-commit-msg.sample deleted file mode 100755 index f093a02ec4..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/prepare-commit-msg.sample +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh -# -# An example hook script to prepare the commit log message. -# Called by "git commit" with the name of the file that has the -# commit message, followed by the description of the commit -# message's source. The hook's purpose is to edit the commit -# message file. If the hook fails with a non-zero status, -# the commit is aborted. -# -# To enable this hook, rename this file to "prepare-commit-msg". - -# This hook includes three examples. The first comments out the -# "Conflicts:" part of a merge commit. -# -# The second includes the output of "git diff --name-status -r" -# into the message, just before the "git status" output. It is -# commented because it doesn't cope with --amend or with squashed -# commits. -# -# The third example adds a Signed-off-by line to the message, that can -# still be edited. This is rarely a good idea. - -case "$2,$3" in - merge,) - /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; - -# ,|template,) -# /usr/bin/perl -i.bak -pe ' -# print "\n" . `git diff --cached --name-status -r` -# if /^#/ && $first++ == 0' "$1" ;; - - *) ;; -esac - -# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') -# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/update.sample b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/update.sample deleted file mode 100755 index 80ba94135c..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/hooks/update.sample +++ /dev/null @@ -1,128 +0,0 @@ -#!/bin/sh -# -# An example hook script to block unannotated tags from entering. -# Called by "git receive-pack" with arguments: refname sha1-old sha1-new -# -# To enable this hook, rename this file to "update". -# -# Config -# ------ -# hooks.allowunannotated -# This boolean sets whether unannotated tags will be allowed into the -# repository. By default they won't be. -# hooks.allowdeletetag -# This boolean sets whether deleting tags will be allowed in the -# repository. By default they won't be. -# hooks.allowmodifytag -# This boolean sets whether a tag may be modified after creation. By default -# it won't be. -# hooks.allowdeletebranch -# This boolean sets whether deleting branches will be allowed in the -# repository. By default they won't be. -# hooks.denycreatebranch -# This boolean sets whether remotely creating branches will be denied -# in the repository. By default this is allowed. -# - -# --- Command line -refname="$1" -oldrev="$2" -newrev="$3" - -# --- Safety check -if [ -z "$GIT_DIR" ]; then - echo "Don't run this script from the command line." >&2 - echo " (if you want, you could supply GIT_DIR then run" >&2 - echo " $0 )" >&2 - exit 1 -fi - -if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then - echo "usage: $0 " >&2 - exit 1 -fi - -# --- Config -allowunannotated=$(git config --bool hooks.allowunannotated) -allowdeletebranch=$(git config --bool hooks.allowdeletebranch) -denycreatebranch=$(git config --bool hooks.denycreatebranch) -allowdeletetag=$(git config --bool hooks.allowdeletetag) -allowmodifytag=$(git config --bool hooks.allowmodifytag) - -# check for no description -projectdesc=$(sed -e '1q' "$GIT_DIR/description") -case "$projectdesc" in -"Unnamed repository"* | "") - echo "*** Project description file hasn't been set" >&2 - exit 1 - ;; -esac - -# --- Check types -# if $newrev is 0000...0000, it's a commit to delete a ref. -zero="0000000000000000000000000000000000000000" -if [ "$newrev" = "$zero" ]; then - newrev_type=delete -else - newrev_type=$(git cat-file -t $newrev) -fi - -case "$refname","$newrev_type" in - refs/tags/*,commit) - # un-annotated tag - short_refname=${refname##refs/tags/} - if [ "$allowunannotated" != "true" ]; then - echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 - echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 - exit 1 - fi - ;; - refs/tags/*,delete) - # delete tag - if [ "$allowdeletetag" != "true" ]; then - echo "*** Deleting a tag is not allowed in this repository" >&2 - exit 1 - fi - ;; - refs/tags/*,tag) - # annotated tag - if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 - then - echo "*** Tag '$refname' already exists." >&2 - echo "*** Modifying a tag is not allowed in this repository." >&2 - exit 1 - fi - ;; - refs/heads/*,commit) - # branch - if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then - echo "*** Creating a branch is not allowed in this repository" >&2 - exit 1 - fi - ;; - refs/heads/*,delete) - # delete branch - if [ "$allowdeletebranch" != "true" ]; then - echo "*** Deleting a branch is not allowed in this repository" >&2 - exit 1 - fi - ;; - refs/remotes/*,commit) - # tracking branch - ;; - refs/remotes/*,delete) - # delete tracking branch - if [ "$allowdeletebranch" != "true" ]; then - echo "*** Deleting a tracking branch is not allowed in this repository" >&2 - exit 1 - fi - ;; - *) - # Anything else (is there anything else?) - echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 - exit 1 - ;; -esac - -# --- Finished -exit 0 diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/index b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/index deleted file mode 100644 index 1e5889eed8e31dee1093773a46c4f836b37a94a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11127 zcmeI2c~BEq9LKk6tHx3lL@Fx9608U0peV&E$`K^tQUWN5I7_m`Xp+TEkfT`6R;vg& zR?&L2w$i~7ty)J#Y}K|SRH0hs&{3 z`|Qix_2GwjBM35xe6yn5=H)Y+#iOF8&wuRnrd1C4nLjdb+9m`^--{rF>)YQ>(bYU@ zxYBjE`~3Pl2ff~PX8brdpavNc!1v|_33)74qKZ6F{nDJz)34F+d}D?ho^Q}yW=hP- zhQq?*Fw-w{UFph3zD3Qj_}Zoj zf5{}X`w78TV4`06SpfKvd8|6~Mpd?4_PO8N7Z`I&#@s)-Jr~I^VSNZpsnV8aK7lG! zo?c|x`LV$=F;9WVOO|)9E-L^Z$q%#k73A!xtF|Qy9t5wI3kpY08)hya?d8xK3B~aU zJYFGz`4}?yPffpsO^7Dv9oc_Yselh=P)x$dtmf(u z;>eDGwM&=fSfRufx_&p-Uk&J=vYDB12@5>>H1fCPhE3t`jh>q0Fu_dv;brKk|HFkZ z4S8i-1?Y$KDzB&cb4gxtSYBcL03Q=kOT%AdKQ(|KIIsR6Kb=yG#?Ljt51d!)OkSTZ z+eCLYq49AY@B!zQS$)9U1?q$1mCZ%K2b@A&(+9j9 zT6$@H==e*m-$s+`xQ^>Ln)Oyz@9GiA?f;dQraz2*lmI^9+%lh!PFba1Gt&5I0erxD zm12^5bemE1`Yi(i{cuj1TtB=SbZpY;cPO1%XSkjknF#2I^C_v<`S+Pg2J?pE(P#mn z8_pwB>xRd!VUU4tia(YI0NwEQQ!hCh;@$rMqVZ7&_<-}rj6S*o5Zs5A8{h-ZpEbRk z|6SFiCjg?+?+fUM^T+i1;hoR{KnD7$KDJB;^uzg+-243d3?MZ;$rp|Ot$=cFZ1UG@H~aQeq9u4>R{|6AE*PIM`rfX8Ix#yYzKV6d6aIt zdUTgbH2OaS^uu{%9{up9&@#zDKgA;(a{t%h_W_(oANDQ({$LV~{w;uhIFHPtA0EGs zNe23<^^wg9KtG&EJ>GAXp(^z@s@e9zZHfUOa2}b`)$|9$|GK_BaN9|v^9Ib>Sh z@YuBg(&*Ohb5Zl%ZXuu>&Y#Sl=1pKS3{_$#01%Cj5WokVKW6jMHGpV*2mv2({(NAH zdh`rHH2OmU{c!%6T0guK3;<-HpXy_~AV5EyKZ(7~zwZE|(GA|Wh4aV6y5X_614ymg zct7rS;Ql#M9J#&bQSHX?LHvfT3#>2hNg8J{p%sau@{YxERt!q8W6)$FMy!^Kuuks% zqsiXdyZ&5uhuJMell(B53^%v~3)jb3V>lm>)||6vtdJJpqKv3W!L^;!IPWJdwMQa) zpie&qx{{{}4z6n`u#YfIx-D-*Dchg8y=Q;%`8KQj@zT6WkB|`|JWroM9t#!YBJH{% zG=#@Pkl_-twx4f1O)jFRM%o4L{Q>xuteG@;gUmLnw8v?(R_v9 z@=oRv>6Qzr!L^5lX_r+alU#aMq9gyXBiDyEx8we5o=XbR@_^hSL_ zxnFdA>`QmTlBr1Xs>;>)b0IU#boBSZ^B0|r6lSIWTpxz*w`Qd3Gjt^fIu`ABX7Qq1 z7GJ(Ny{vM2Vr9DBjXdLl)RXH`9DnWeshn3miZf3gR8FZczw9KS2AY-Ix~i}s#O+o^ z#pH$d78M&rh0~~qcSxNa1~X%6>T7?otY_EFaJ;?z#PCgbfBIIt@)(FjA4&Ve27%mx zOu$UY4eNnWj6!MO#T*Dm9}IA{8o(`uTiAn412acIbI$tKIf)-Pov1vQ 1522062299 +0200 clone: from git@github.com:marcingrzejszczak/contract-git.git -0b36113e5fa9713025d50f046e8fd209fc8d9597 3bd42890d5105a30abd82d0205b63cbf20a59e83 Marcin Grzejszczak 1547107982 +0100 commit: Added more versions -3bd42890d5105a30abd82d0205b63cbf20a59e83 51326f92638a0342965bc511cbcc2eab61b41050 Marcin Grzejszczak 1547124882 +0100 commit: New names diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/logs/refs/heads/master b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/logs/refs/heads/master deleted file mode 100644 index d9a1c39de9..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/logs/refs/heads/master +++ /dev/null @@ -1,3 +0,0 @@ -0000000000000000000000000000000000000000 0b36113e5fa9713025d50f046e8fd209fc8d9597 Marcin Grzejszczak 1522062299 +0200 clone: from git@github.com:marcingrzejszczak/contract-git.git -0b36113e5fa9713025d50f046e8fd209fc8d9597 3bd42890d5105a30abd82d0205b63cbf20a59e83 Marcin Grzejszczak 1547107982 +0100 commit: Added more versions -3bd42890d5105a30abd82d0205b63cbf20a59e83 51326f92638a0342965bc511cbcc2eab61b41050 Marcin Grzejszczak 1547124882 +0100 commit: New names diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/logs/refs/remotes/origin/HEAD b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/logs/refs/remotes/origin/HEAD deleted file mode 100644 index 91006b3a8e..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/logs/refs/remotes/origin/HEAD +++ /dev/null @@ -1 +0,0 @@ -0000000000000000000000000000000000000000 0b36113e5fa9713025d50f046e8fd209fc8d9597 Marcin Grzejszczak 1522062299 +0200 clone: from git@github.com:marcingrzejszczak/contract-git.git diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/1e/c084220c52398ce8cd2f8235018019504030f2 b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/1e/c084220c52398ce8cd2f8235018019504030f2 deleted file mode 100644 index 117868894b378b6e21a5ac640a9c9f6280059d95..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 67 zcmV-J0KETr0V^p=O;s>8W-u`T0)?d1)FR!)f=u0lqWqN7WFRNCq9nB_FENLqS*osB ZEnszt#y8%;UA6NT+XS9h0|08q77VU!9IF5T diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/2b/42d52aec21936e5578be5ea0e2fdb9c539ce88 b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/2b/42d52aec21936e5578be5ea0e2fdb9c539ce88 deleted file mode 100644 index 91e89ac31180fd797d0d6093769f9dd318a26c5c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 84 zcmV-a0IUCa0V^p=O;s>AVlXiP0)^!KT)ota#N2|MR0g>NElNB=mOU@d>NlA(Hb@3I q7<_`LO3TmJOG+$aD6qMvn!G~$>XZE{@iXkwgdX!tJ_G<3WgG&k@FS@J diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/3b/d42890d5105a30abd82d0205b63cbf20a59e83 b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/3b/d42890d5105a30abd82d0205b63cbf20a59e83 deleted file mode 100644 index 891584b4b4..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/3b/d42890d5105a30abd82d0205b63cbf20a59e83 +++ /dev/null @@ -1 +0,0 @@ -x¥Î=N1@ajŸbúHhÆÿ–"D**1±Ç`’]G^“bO”& |ͧ—û²´ Úù—9Dàlk6‘tNNLu"Es¦ä-“!ë­N&DϬn8W-u`T0)?d1)FR!)f=u0lqWqN7WFRNCq9nB_FENMV>*q~( Ze_Dyplj53uW`BgPTtiCFGXRd47!A&)9u@!q diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/51/326f92638a0342965bc511cbcc2eab61b41050 b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/51/326f92638a0342965bc511cbcc2eab61b41050 deleted file mode 100644 index ef3caae7d1d111191803c8a2d9213cd9dbbb4133..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 166 zcmV;X09pTd0j1763IZ_@fMM&LVtPR)?*v5btn?0(WYksnK{hJv=>;1PVEH#6e;)h3 zYoLr)kys-Qxf zoX+X2kZk0j1wGq!tZ<~7y8#Y$;oH3Ah3>HJFTdJP-D_<0*mUC#q%~eD6M}*@N<@*r Uw~haG#EIW9P|vgY05Z)_hs2Ch!2kdN diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/83/1a7e732650ab7428f60d51ba7d9ea33c51cf26 b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/83/1a7e732650ab7428f60d51ba7d9ea33c51cf26 deleted file mode 100644 index bb8bb0630cea408888a7e55a019fdc6fb722258f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 88 zcmV-e0H^ElAYa$iG&CI&eZp~lt6)iKx=t62ai|3cQ1ha>9% diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/8d/d4290a6ccef367cde77cf95ec7449dca23d6bb b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/8d/d4290a6ccef367cde77cf95ec7449dca23d6bb deleted file mode 100644 index e1810f0850cee278ddd6ca496e538b672cf31e41..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 84 zcmV-a0IUCa0V^p=O;s>AVlXiP0)^!KT)ota#N2|MR0dnG*_Mrp$ApDLyKi`zCl{p$ q&sK$~O3TmJOG+$aD6qMvn!G~$>XZE{@iXkwgdX!tJ_G;|r5oi-7$^Av diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/b4/fc3812c95e3f5eed2ac1964a131464293786aa b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/b4/fc3812c95e3f5eed2ac1964a131464293786aa deleted file mode 100644 index e74d64efc7ddda955c3c63774f6973e02ac09267..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 127 zcmV-_0D%8^0V^p=O;s>7G-fa~FfcPQQSk9}cJ&K()hnqeVYud+8CGmE&(i(H({)b9 zx?G3Fe6E`q0D*$9Ylx$+r=J^xw$oLuH;R+7G-fa~FfcPQQSk9}cJ&K()hnqeVYud+8CGmE&(i(H({)b9 zx?G3Fe6E`q0D*$9Ylx$+r=J@`?-fn1oO7Sk&pxmD8F$=e?kVMKyP+lpxjMS|y6PpS h%Cn9zM(-@E9+!qq!Z{S$swnmIx70{|Z!FLTsgJ^%m! diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/f5/f3b2ddf93a179e1a0a93ccbf582d1e80648ce6 b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/f5/f3b2ddf93a179e1a0a93ccbf582d1e80648ce6 deleted file mode 100644 index 3f92ba9ec01dda769fb4b14712a1cbd798b4d600..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 106 zcmV-w0G0oE0V^p=O;s>5Gh;9@00IRAJp(;M-C#e*fM5^*5C;DUpHIg{lU)}y7)I52 z`Q6bE%R3HHXb4njpyw3o>ElAYa$iG&CI&eZp~lt6)iKx=k6Ag1C8@hK)yJQu_VxZ zY*-2?j*g{)V${YmKr^vnS)e$ru^iA2c`~sAP@e*~nV?<#%0dIxtNbi^{g*iZ^iG}5 z-J@1{;#dQV;aTsZ&jJE}{`?J65dZSiKZ`x*M7e1~M)C_@_SJjS?yJ-!?RvS<|A**% zmFrW2O`7uT^B1Z##n!XE)f2UOVygNeV+ZHNXGb<0UoBmmypKVN{Km-yQw1yyJoXDjv-p$FskB@?PgCefT}nJ6$pOP*Kdfo3e{? z-#hJz*s=QcKhdd|qGn$I@US~r~+;$~HEm;CAB zyP|?y8c)6mO3>MQC>IaXc<^n#wtu!DZh~FyX8yNy{eZJ!z=_f z`;=v-^ULLo{mu8XH*^?G#)t|e;zeE1l#W?m$meHZ+Gj?XqeC1WVEzaXWMEHH)MSu3kU(v3( z(kORl!tScwcl+aVZ&!TV%dGm+E64fc^dA?js=hbty1bIlAZ zHkoJX{^IF6Cu3c%!(u+y-?yw>+PCn@HL0Sdul?I|y;ksRaeOH7Z2zrkz-qU%dC$6H zjTdJw>3IFi?l$Q!|Nk}S%+;xunaZMmQ2FP9olwS$Nfk1uTKpI#NN>wv3Faqlw zkpn<6AeOjj_S!GoW%1-aON2b;T+upyCS2R;^65?dGdvD|-*2|yg`}8jlam>TsyYC1 Crno`? diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/pack/pack-36eb4e6b44a393bca412489cd42ac7cc572b42d3.pack b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/objects/pack/pack-36eb4e6b44a393bca412489cd42ac7cc572b42d3.pack deleted file mode 100644 index fb8e35c7d121e3cef73384dfff5428d05b9ecf9d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8048 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 OpvAW%lX`5D3;zQ)q;;zR diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/packed-refs b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/packed-refs deleted file mode 100644 index 5a69e4592d..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/packed-refs +++ /dev/null @@ -1,2 +0,0 @@ -# pack-refs with: peeled fully-peeled -0b36113e5fa9713025d50f046e8fd209fc8d9597 refs/remotes/origin/master diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/refs/heads/master b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/refs/heads/master deleted file mode 100644 index 84ea19cf42..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/refs/heads/master +++ /dev/null @@ -1 +0,0 @@ -51326f92638a0342965bc511cbcc2eab61b41050 diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/refs/remotes/origin/HEAD b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/refs/remotes/origin/HEAD deleted file mode 100644 index 6efe28fff8..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/contract-predefined-names-git/git/refs/remotes/origin/HEAD +++ /dev/null @@ -1 +0,0 @@ -ref: refs/remotes/origin/master diff --git a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/sample_stubs/META-INF/com.example/hello-world/0.0.2/mappings/someMapping.json b/spring-cloud-contract-stub-runner/src/test/resources/git_samples/sample_stubs/META-INF/com.example/hello-world/0.0.2/mappings/someMapping.json deleted file mode 100644 index 126b353289..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/git_samples/sample_stubs/META-INF/com.example/hello-world/0.0.2/mappings/someMapping.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "id": "b54426bb-b2ef-4b12-adc9-a05fcf6a4e08", - "request": { - "url": "/hello", - "method": "GET" - }, - "response": { - "status": 200, - "body": "world", - "transformers": [ - "response-template" - ] - }, - "uuid": "b54426bb-b2ef-4b12-adc9-a05fcf6a4e08" -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/logback.xml b/spring-cloud-contract-stub-runner/src/test/resources/logback.xml deleted file mode 100644 index 347f98926e..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/logback.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - diff --git a/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/0.0.1-SNAPSHOT/bootService-0.0.1-SNAPSHOT-stubs.jar b/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/0.0.1-SNAPSHOT/bootService-0.0.1-SNAPSHOT-stubs.jar deleted file mode 100644 index 7916329c40a4bdf72ab7b04c163a9c5fcc023c1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1583 zcmWIWW@h1HVBp|j&|{wF!2kqIAOZ+Df!NnI#8KDN&rP41Apk|;rh2A#(m(~0KrDi+ z(AUw=)6F$FM9W7$;qWfsl_EwJs?>Q2Aj^i9!u4p-QN!6{Rd(V1{th+lJfJj zgHlUMi}F%a4E55B^7G3oLqj+jm=8ZG4&MvJr4`%^j4a<785meVCY$yh@>9NA|eAD=Q{xc6`6Mc4J@eSr2QMl>d3wcMbPUpDr-_4)2|a&k0u_ckej+y3cLy z^%UFHx7d41>tdG0ZPl>vd=b(*m&MI~ldkrnZFiiMq^x`FiXQGXWRv{*aIWK%?UAmv z@ebRXLY0=eTzGLftnr+t@$pvY*YBqs?04}ES>nv`K>2dS?w0)Eos(ZSYfKGh2&`Ik z=|o=MpLQO;>#r+|Z;Go&cys*9@%#Ac3o9ZLwa{W4EiiKv3kovx(u+|7^U%z<9(Mcs zujK0qHO1!%+$OR$6~jl#L^VxV7*h;77oH_!CE^p(EpHu zNbCHY>ocS#^R^lWgj6U?%;!AR-PV39cKgPQ=eEtBl=}bfw%abATljt7?LE8mdCgf) zUr&~fqGc=#y{!1eC+ZhZ-0;G80&`8l#9tv1z5C*}8TZ7Q=RCT_6?+?(-F-5(-F>}wRj&*GWgW(4VG4?ei)#X>s%Rg` z-Zig*!_M}*s>Hdns}?Kn*3~ztbO^OP?^C~Se);z9-;oP$o62ozl2p$re83u9VQ0L2 zTXSCF{dYm57 zzU2IF&u4Q^_RR`$5f$=ndT`|6i&vW4qP&}5p4@k+xPh=e1p4whx#M8JR?wac6&ELI(l?hPRF&8eSNnYeO##K#DRf8ju}_!AOSW2n7$br z8n5Co0ee}&3Mnhl5;U@Vv1K{1b-)n*>-Y|6DUy5P84%gMm>Ce+y-L6kL^1*HV?x;x Z=yEJsF~FOZ4dgm@Ad~@`{FfQT0|2R$^o;-j diff --git a/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/0.0.1-SNAPSHOT/bootService-0.0.1-SNAPSHOT.pom b/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/0.0.1-SNAPSHOT/bootService-0.0.1-SNAPSHOT.pom deleted file mode 100644 index dd16575a19..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/0.0.1-SNAPSHOT/bootService-0.0.1-SNAPSHOT.pom +++ /dev/null @@ -1,27 +0,0 @@ - - - - - 4.0.0 - org.springframework.cloud.contract.verifier.stubs - bootService - 0.0.1-SNAPSHOT - pom - diff --git a/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/maven-metadata.xml b/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/maven-metadata.xml deleted file mode 100644 index 8461d4b2a6..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/maven-metadata.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - org.springframework.cloud.contract.verifier.stubs - bootService - 0.0.1-SNAPSHOT - - - 0.0.1-SNAPSHOT - - 20160409062112 - - diff --git a/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/0.0.1-SNAPSHOT/fraudDetectionServer-0.0.1-SNAPSHOT-stubs.jar b/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/0.0.1-SNAPSHOT/fraudDetectionServer-0.0.1-SNAPSHOT-stubs.jar deleted file mode 100644 index fdb70e383f00ec1a31fd06d81aa618347b8aa5b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1897 zcmWIWW@h1HVBp|jSmxB}!2kqIAOZ+Df!NnI#8KDN&rP41Apk|;rh2A#(m(~0KrDi+ z(AUw=)6F$FM9Q}aq3i`_uh=w%h>=Y@uFGBCR?

Ai(h6<{MwahD zlUYEPO`YKDf7pPh?fqZTiLE9AOJ5&*uI6jNTlgTP_uZB^0#VLZo0gcoT$1^!Uj3xi zi^3-YC+prG|F)Z-qmgTW_7%1hGv4Ip7?-NXu>9@sx>|Y6@ORS(h1?4TQ>#rQmmGhy z`&2onF`M?vx!ZC)*ELFVUsxaI8GW$!`OQxs|7Z$zoqXwb_0oisEj@R3M>M|AJ`~I_ zQzKv&iz%1;3*NTt=G)7^^Do}5`^e1o3HeZ_Sr<~2P( zH|KW#zDb8>96DXIt74fzkatY-vuQJwH#hIS^(%df(w-krM5KNk-@82KnLgJnc~DA1 zM2gvpoP`p=ppybdiXAzT;+J1SY`mQHJ8U4(^1hZUyEQ~W(f4%yQm%mf0)?i6tSW<( ziv-!GI;H&mEnmgsMH^J#SL~lVH|>DLl^@B0(h0%WF3i^2CiaeX@%mY}ZL|%3 zweJikKn{gkJOx;e1dsn^|PRW04*WXbl^_R{e!^wjnA)jN6SJhz{&mbWg`>|>$aKwmL3i7?|X+JN2z0s)4% zjvyLd(4lKXFX%vuL10OvCXj?{Ln`*rO#rDzE>l5#h{a_<8eW9q(*`Q*AOPgv`9LOI z8}^b9WSAT?B2rOHJ_)c{z&yv$(0GrqVff2IR!BLBRtBOw05z8*JD?aCHUxZw=>W7m lPn;W2Q#P_2m|2K)16n%AWiKlmD1_O8unOqAn?TbU7yzYKYMcN7 diff --git a/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/0.0.1-SNAPSHOT/fraudDetectionServer-0.0.1-SNAPSHOT.pom b/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/0.0.1-SNAPSHOT/fraudDetectionServer-0.0.1-SNAPSHOT.pom deleted file mode 100644 index 33e8194127..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/0.0.1-SNAPSHOT/fraudDetectionServer-0.0.1-SNAPSHOT.pom +++ /dev/null @@ -1,27 +0,0 @@ - - - - - 4.0.0 - org.springframework.cloud.contract.verifier.stubs - fraudDetectionServer - 0.0.1-SNAPSHOT - pom - diff --git a/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/maven-metadata.xml b/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/maven-metadata.xml deleted file mode 100644 index 75dc4041ba..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/maven-metadata.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - org.springframework.cloud.contract.verifier.stubs - fraudDetectionServer - 0.0.1-SNAPSHOT - - - 0.0.1-SNAPSHOT - - 20160409062112 - - diff --git a/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/loanIssuance/0.0.1-SNAPSHOT/loanIssuance-0.0.1-SNAPSHOT-stubs.jar b/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/loanIssuance/0.0.1-SNAPSHOT/loanIssuance-0.0.1-SNAPSHOT-stubs.jar deleted file mode 100644 index e322590636a2642f1814bfec0720ea78f93fc4ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 639 zcmWIWW@h1HVBp|jSnAa2!2kqIAOZ+Df!NnI#8KDN&rP41Apk|;rh2A#(m(~0KrDi+ z(AUw=)6F$FM9tz+^=Y@uFGB8Ii z

Ai(h6<{Mwai43=AwF(^fwV3JB2h($(?R)e8*T5VV5rQ=`&SS4)L?lj`D<@>Wga zb1^XAs-kSqs`Kuh)FKv;A - - - - 4.0.0 - org.springframework.cloud.contract.verifier.stubs - loanIssuance - 0.0.1-SNAPSHOT - pom - diff --git a/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/loanIssuance/maven-metadata.xml b/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/loanIssuance/maven-metadata.xml deleted file mode 100644 index 4533bc03e8..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/loanIssuance/maven-metadata.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - org.springframework.cloud.contract.verifier.stubs - loanIssuance - 0.0.1-SNAPSHOT - - - 0.0.1-SNAPSHOT - - 20160409062111 - - diff --git a/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/producerWithMultipleConsumers/0.0.1-SNAPSHOT/producerWithMultipleConsumers-0.0.1-SNAPSHOT-stubs.jar b/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/producerWithMultipleConsumers/0.0.1-SNAPSHOT/producerWithMultipleConsumers-0.0.1-SNAPSHOT-stubs.jar deleted file mode 100644 index b5a09c6c90c0f4b3a7d5777a9ece1091501589e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3681 zcmWIWW@h1HVBp|j&|{wF!2kqIAOZ+Df!NnI#8KDN&rP41Apk|;rh2A#(m(~0KrDi+ z(AUw=)6F$FM9TRCpkZ_q$n}Dq*y;R zgp+~U+le_6gi9;985mh!Ff%ZK38>eBhM*g#gv+?J{Cr)Y;l-u7sYL|M26=>o;nze@ zZyu4V;L|{!4kH7DHBn|K<>zMyrIwTy<)x;$!}Gf<3f-!R^RRKn(HF zcc7^(Aj?Ag53V|7AmDoaWq8SSkuCBc%KQr#uaGWRnzSsLXYEV_&xxO2?4SKn^F>lZ zTlKShk}A>19nRh6ekpxt;;vg?EVgWQobNGvN~*!vPqueU*q_ELR^4@o_i8ekU~k@W z_h-`-?o`D&{LV>UDn-|r9Cu4hJ+o+4N@&MQ0gEMPaunTi=eH>}`Ll<7icj=0xzYD( zhIHP>+fTXcy|(>4A*8OhenIqtA0}12UV7htpRM`6JND$w?_pm(KQ5NBWjis4Z(+Hc zdV8Jh#noLmJN@U$f#L=dexSIKw`Z=c1$uA}5StMde#II2r8z0ii8(oFL5CwPnD#jG z9WvlyIe$`n(Yyx^D}FFJ)im%&tdtIzWp$&^V!^+;EGxI)oqJbTK**(}F)Wos>za_e zertU897&_Pj>-JoS5LlQ+GhCU^*bY#lK55GDY zPnb24J$swo#7j;8?{qYU6;3aFle5{LjD(n!SVU?<1O?>USKVI;1|*8vh=6oTEJ99$ zBn70zb(Sg1IJYVDt*BRbe3e_CUe2A+;=uQL5zmUG+-DD#e#qwJZ*!S{=HlZyub*rW zI^6Pa&rX(!cdkn}0I|_PhITp4u$kSN^~m7?2(8+1C&Oxf~dfTfqSd zNj0B=x$bj=&+fB?avh3i(Q+M{k5>V6ToKk>mj}#sF6YmMKS^`f`q^-g>(x?@9RHQ56l^tg@?wxxlG~23T+qo}1;(LVnx5{O{%JS7SdNCvE%GYNv z^$ZezhIa@?$#|cXP%rcKHZid+yv%gkDdPF^8JdDOrJ8&0R)rb0u9_68IL+yTi16ma z0tfDJyE=&XFL_cw$?#&3`RZVy$V(gi#p|YRQm?wHdT!<)*B28G?|qRtB}Sg__SJvc z-*xTpEngL`Wj`zYyqqxmz5X!gEl=v0EJIVvPO9shBa)(SHEI#7h??)<#WH4*cnnz7 zf-uhFR-Z_tQQ`(%@SOx23&L28hQzxe(CDx4qUu6{@m>VP#yDJ!Vl-+R&nnK(16y_$ zXb}jbS+@FFP(Xl|m#&Vlu3li!hM*N}pBj~xx>_pCn^YH+G%>HJF0L>$FKgl?J{KeN ztt!g)tUB-CNiAX#S#z~fA~=R2WL8&-U!iA`XQrXYffEN9mP}YJ2Cg|FJ}?IQ;FZ&A zF+x5-33r4KK*b&02bX}Z2VoL?5LLI2Tputpi7?}Ca{wa)2m~13I)Z3;3naiBRU3K> z1f&=QmNaStNw_wo_6WKOAl0zO4yf4y0Rjwv9m{}Bq?QG;Mr@4`gvN!a8sTXlWP%*X z&p?3Qh7e_t0E>hCe8BN4kd0(Das!1G(m+9rBYZ|Hp%|?Ktp2eYjgmq_L-5%HNqU$~ z6^Ivr7BDn4HV|bGS`i9Ljq^^~er50E|__9!1RxNOogw z0pgB7)IeSfY&2rE8>Jv2CXg|!VPrpYvJhhr!jH&R6yXTQtQC>%{zjDDXc3I&08kx? zHG(0T1hZ0sH~^AKEZ9&y56@wz1scr(;sF5i CaYm2; diff --git a/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/producerWithMultipleConsumers/0.0.1-SNAPSHOT/producerWithMultipleConsumers-0.0.1-SNAPSHOT.pom b/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/producerWithMultipleConsumers/0.0.1-SNAPSHOT/producerWithMultipleConsumers-0.0.1-SNAPSHOT.pom deleted file mode 100644 index 7b63f844ba..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/producerWithMultipleConsumers/0.0.1-SNAPSHOT/producerWithMultipleConsumers-0.0.1-SNAPSHOT.pom +++ /dev/null @@ -1,27 +0,0 @@ - - - - - 4.0.0 - org.springframework.cloud.contract.verifier.stubs - producerWithMultipleConsumers - 0.0.1-SNAPSHOT - pom - diff --git a/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/producerWithMultipleConsumers/maven-metadata.xml b/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/producerWithMultipleConsumers/maven-metadata.xml deleted file mode 100644 index 1f6934542c..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/producerWithMultipleConsumers/maven-metadata.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - org.springframework.cloud.contract.verifier.stubs - producerWithMultipleConsumers - 0.0.1-SNAPSHOT - - - 0.0.1-SNAPSHOT - - 20160409062112 - - diff --git a/spring-cloud-contract-stub-runner/src/test/resources/messages/message.groovy b/spring-cloud-contract-stub-runner/src/test/resources/messages/message.groovy deleted file mode 100644 index f42ec96f2c..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/messages/message.groovy +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -org.springframework.cloud.contract.spec.Contract.make { - description 'issue #650' - label 'trigger' - input { - triggeredBy('createNewPerson()') - } - outputMessage { - sentTo 'personEventsTopic' - headers { - [ - header('contentType': 'application/json'), - header('type': 'person'), - header('eventType': 'PersonChangedEvent'), - header('customerId': $(producer(regex(uuid())))) - ] - } - body([ - "type" : 'CREATED', - "personId" : $(producer(regex(uuid())), - consumer('0fd552ba-8043-42da-ab97-4fc77e1057c9')), - "userId" : $(producer(optional(regex(uuid()))), - consumer('f043ccf1-0b72-423b-ad32-4ef123718897')), - "firstName" : $(regex(nonEmpty())), - "middleName": $(optional(regex(nonEmpty()))), - "lastName" : $(regex(nonEmpty())), - "version" : $(producer(regex(number())), consumer(0l)), - "uid" : $(producer(regex(uuid()))) - ]) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/contracts/contract1.groovy b/spring-cloud-contract-stub-runner/src/test/resources/repository/contracts/contract1.groovy deleted file mode 100644 index 09aec59dde..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/repository/contracts/contract1.groovy +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -org.springframework.cloud.contract.spec.Contract.make { - request { - method """PUT""" - url """/fraudcheck""" - body(""" - { - "clientPesel":"${ - value(consumer(regex('[0-9]{10}')), producer('1234567890')) - }", - "loanAmount":99999} - """ - ) - headers { - contentType("application/vnd.fraud.v1+json") - } - - } - response { - status OK() - body("""{ - "fraudCheckStatus": "${value(c('FRAUD'), p(regex('[A-Z]{5}')))}", - "rejectionReason": "Amount too high" -}""") - headers { - contentType("application/vnd.fraud.v1+json") - } - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/contracts/contract2.groovy b/spring-cloud-contract-stub-runner/src/test/resources/repository/contracts/contract2.groovy deleted file mode 100644 index 437eba8000..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/repository/contracts/contract2.groovy +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -org.springframework.cloud.contract.spec.Contract.make { - // Human readable description - description 'Sends an order message' - // Label by means of which the output message can be triggered - label 'send_order' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('orderTrigger()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo('orders') - // any headers for the output message - headers { - header('contentType': 'application/json') - } - // the body of the output message - body( - orderId: value( - consumer('40058c70-891c-4176-a033-f70bad0c5f77'), - producer(regex('([0-9|a-f]*-*)*'))), - description: "This is the order description" - ) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/httpcontract/contract1.groovy b/spring-cloud-contract-stub-runner/src/test/resources/repository/httpcontract/contract1.groovy deleted file mode 100644 index 09aec59dde..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/repository/httpcontract/contract1.groovy +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -org.springframework.cloud.contract.spec.Contract.make { - request { - method """PUT""" - url """/fraudcheck""" - body(""" - { - "clientPesel":"${ - value(consumer(regex('[0-9]{10}')), producer('1234567890')) - }", - "loanAmount":99999} - """ - ) - headers { - contentType("application/vnd.fraud.v1+json") - } - - } - response { - status OK() - body("""{ - "fraudCheckStatus": "${value(c('FRAUD'), p(regex('[A-Z]{5}')))}", - "rejectionReason": "Amount too high" -}""") - headers { - contentType("application/vnd.fraud.v1+json") - } - } - -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/lv/spring/cloud/bye/lv_bye.json b/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/lv/spring/cloud/bye/lv_bye.json deleted file mode 100644 index d93ef4731a..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/lv/spring/cloud/bye/lv_bye.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "request": { - "method": "GET", - "url": "/lv/bye" - }, - "response": { - "status": 200, - "body": "Another goodbye world!", - "headers": { - "Content-Type": "text/plain" - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/pl/spring/cloud/bye/pl_bye.json b/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/pl/spring/cloud/bye/pl_bye.json deleted file mode 100644 index fada15f45a..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/pl/spring/cloud/bye/pl_bye.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "request": { - "method": "GET", - "url": "/pl/bye" - }, - "response": { - "status": 200, - "body": "pl-bye", - "headers": { - "Content-Type": "text/plain" - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/pl/spring/cloud/bye/pl_overridden_bye.json b/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/pl/spring/cloud/bye/pl_overridden_bye.json deleted file mode 100644 index d08c92f1e5..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/pl/spring/cloud/bye/pl_overridden_bye.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "request": { - "method": "GET", - "url": "/bye" - }, - "response": { - "status": 200, - "body": "overridden-bye", - "headers": { - "Content-Type": "text/plain" - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/spring/cloud/bye/admin/admin.json b/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/spring/cloud/bye/admin/admin.json deleted file mode 100644 index a3ac323a5c..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/spring/cloud/bye/admin/admin.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "request": { - "method": "GET", - "url": "/admin" - }, - "response": { - "status": 401 - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/spring/cloud/bye/bye.json b/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/spring/cloud/bye/bye.json deleted file mode 100644 index da1f754a1c..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/spring/cloud/bye/bye.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "request": { - "method": "GET", - "url": "/bye" - }, - "response": { - "status": 200, - "body": "Goodbye world!", - "headers": { - "Content-Type": "text/plain" - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/spring/cloud/hello/README.md b/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/spring/cloud/hello/README.md deleted file mode 100644 index 13f6cf17e3..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/spring/cloud/hello/README.md +++ /dev/null @@ -1 +0,0 @@ -### Hello service stub diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/spring/cloud/hello/admin/admin.json b/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/spring/cloud/hello/admin/admin.json deleted file mode 100644 index a3ac323a5c..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/spring/cloud/hello/admin/admin.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "request": { - "method": "GET", - "url": "/admin" - }, - "response": { - "status": 401 - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/spring/cloud/hello/hello.json b/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/spring/cloud/hello/hello.json deleted file mode 100644 index 13d165d71d..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/spring/cloud/hello/hello.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "request": { - "method": "GET", - "url": "/hello" - }, - "response": { - "status": 200, - "body": "Hello world!", - "headers": { - "Content-Type": "text/plain" - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/spring/cloud/ping/ping.json b/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/spring/cloud/ping/ping.json deleted file mode 100644 index 864f856445..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/repository/mappings/spring/cloud/ping/ping.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "request": { - "method": "GET", - "url": "/ping" - }, - "response": { - "status": 200, - "body": "pong", - "headers": { - "Content-Type": "text/plain" - } - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract1.groovy b/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract1.groovy deleted file mode 100644 index ab8578e008..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract1.groovy +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2013-2023 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -org.springframework.cloud.contract.spec.Contract.make { - description 'issue #1864' - label 'send_order_bin' - input { - triggeredBy('sendOrder()') - } - outputMessage { - sentTo 'orderEventsTopic' - headers { - [ - header('contentType': 'application/vnd.orderplaced.v1+avro') - ] - } - body(fileAsBytes("orderplaced-event.bin")) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract2.groovy b/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract2.groovy deleted file mode 100644 index 13cd178572..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract2.groovy +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2013-2023 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -org.springframework.cloud.contract.spec.Contract.make { - description 'issue #1864' - label 'send_order_json' - input { - triggeredBy('sendOrderJson()') - } - outputMessage { - sentTo 'orderEventsTopic' - headers { - [ - header('contentType': 'application/json') - ] - } - body(file("orderplaced-event.json")) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract3.groovy b/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract3.groovy deleted file mode 100644 index 4aefcf7b6d..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract3.groovy +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2013-2023 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -org.springframework.cloud.contract.spec.Contract.make { - description 'issue #1864' - label 'send_order_xml' - input { - triggeredBy('sendOrderXml()') - } - outputMessage { - sentTo 'orderEventsTopic' - headers { - [ - header('contentType': 'application/xml') - ] - } - body(file("orderplaced-event.xml")) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract4.groovy b/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract4.groovy deleted file mode 100644 index d31b91d419..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract4.groovy +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2013-2023 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -org.springframework.cloud.contract.spec.Contract.make { - description 'issue #1864' - label 'send_order_csv' - input { - triggeredBy('sendOrderCsv()') - } - outputMessage { - sentTo 'orderEventsTopic' - headers { - [ - header('contentType': 'text/plain') - ] - } - body(file("orderplaced-event.csv")) - } -} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.bin b/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.bin deleted file mode 100644 index 3522c31111..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.bin +++ /dev/null @@ -1 +0,0 @@ -H505c50a7-0c26-4582-b9ae-bc1c0f65fec10fakeCustomer@example.com��ٳ�a \ No newline at end of file diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.csv b/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.csv deleted file mode 100644 index 8ca6f9ca0b..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.csv +++ /dev/null @@ -1,2 +0,0 @@ -orderId,customerId,orderCreated -505c50a7-0c26-4582-b9ae-bc1c0f65fec1,fakeUser@example.com,orderCreated": "2023-01-30T15:11:00Z \ No newline at end of file diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.json b/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.json deleted file mode 100644 index c258dcc8c4..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "orderId": "505c50a7-0c26-4582-b9ae-bc1c0f65fec1", - "customerId": "fakeUser@example.com", - "orderCreated": "2023-01-30T15:11:00Z" -} \ No newline at end of file diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.xml b/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.xml deleted file mode 100644 index 2c168cc670..0000000000 --- a/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - 505c50a7-0c26-4582-b9ae-bc1c0f65fec1 - fakeCustomer@example.com - 2023-01-30T15:11:00Z - \ No newline at end of file diff --git a/spring-cloud-contract-stub-runner/src/test/resources/request.pdf b/spring-cloud-contract-stub-runner/src/test/resources/request.pdf deleted file mode 100644 index 69503635d87cbdfa660d5cd8be66d3e74b3b20e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14631 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 diff --git a/spring-cloud-contract-stub-runner/src/test/resources/response.pdf b/spring-cloud-contract-stub-runner/src/test/resources/response.pdf deleted file mode 100644 index c3b233056b758d1cc9bf3176e99a95add89ba607..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15767 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 diff --git a/spring-cloud-contract-tools/pom.xml b/spring-cloud-contract-tools/pom.xml deleted file mode 100644 index 479f880812..0000000000 --- a/spring-cloud-contract-tools/pom.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - 4.0.0 - - - org.springframework.cloud - spring-cloud-contract-parent - 4.1.0-SNAPSHOT - .. - - - spring-cloud-contract-tools - pom - - Spring Cloud Contract Tools - Spring Cloud Contract Tools - - - spring-cloud-contract-converters - spring-cloud-contract-maven-plugin - spring-cloud-contract-gradle-plugin - spring-cloud-contract-gradle-portal-plugin - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-converters/pom.xml deleted file mode 100644 index 429dae41e1..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/pom.xml +++ /dev/null @@ -1,102 +0,0 @@ - - - 4.0.0 - - org.springframework.cloud - spring-cloud-contract-tools - 4.1.0-SNAPSHOT - .. - - spring-cloud-contract-converters - jar - Spring Cloud Contract Converters - Spring Cloud Contract Converters - - - org.springframework - spring-context - - - org.springframework.cloud - spring-cloud-contract-spec - - - org.springframework.cloud - spring-cloud-contract-shade - - - org.springframework.cloud - spring-cloud-contract-verifier - - - org.springframework.boot - spring-boot-starter-logging - - - org.apache.groovy - groovy - - - org.apache.groovy - groovy-nio - - - com.github.tomakehurst - wiremock-jre8-standalone - - - org.springframework.boot - spring-boot-autoconfigure-processor - true - - - org.spockframework - spock-core - test - - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.cloud - spring-cloud-contract-wiremock - test - - - org.springframework.cloud - spring-cloud-test-support - test - - - org.springframework.boot - spring-boot-starter-web - test - - - io.rest-assured - rest-assured - test - - - org.spockframework - spock-junit4 - test - - - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/converter/ConversionContractVerifierException.java b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/converter/ConversionContractVerifierException.java deleted file mode 100644 index dee298408a..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/converter/ConversionContractVerifierException.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.converter; - -import org.springframework.cloud.contract.spec.ContractVerifierException; - -/** - * Thrown when a a DSL can't be properly converted. - * - * @since 1.0.0 - */ -public class ConversionContractVerifierException extends ContractVerifierException { - - public ConversionContractVerifierException(String message, Throwable cause) { - super(message, cause); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/converter/RecursiveFilesConverter.java b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/converter/RecursiveFilesConverter.java deleted file mode 100644 index ec7ca2bac4..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/converter/RecursiveFilesConverter.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.converter; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Set; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.verifier.file.ContractFileScanner; -import org.springframework.cloud.contract.verifier.file.ContractMetadata; -import org.springframework.cloud.contract.verifier.util.NamesUtil; -import org.springframework.cloud.contract.verifier.wiremock.DslToWireMockClientConverter; -import org.springframework.util.MultiValueMap; -import org.springframework.util.StringUtils; - -/** - * Recursively converts contracts into their stub representations. - * - * @since 1.1.0 - */ -public class RecursiveFilesConverter { - - private static final Log log = LogFactory.getLog(RecursiveFilesConverter.class); - - private final StubGeneratorProvider holder; - - private final File outMappingsDir; - - private final File contractsDslDir; - - private final List excludedFiles; - - private final String includedContracts; - - private final boolean excludeBuildFolders; - - public RecursiveFilesConverter(File stubsOutputDir, File contractsDslDir, List excludedFiles, - String includedContracts, boolean excludeBuildFolders, StubGeneratorProvider holder) { - this.outMappingsDir = stubsOutputDir; - this.contractsDslDir = contractsDslDir; - this.excludedFiles = excludedFiles; - this.includedContracts = includedContracts; - this.excludeBuildFolders = excludeBuildFolders; - this.holder = holder == null ? new StubGeneratorProvider() : holder; - } - - public RecursiveFilesConverter(File stubsOutputDir, File contractsDslDir, List excludedFiles, - String includedContracts, boolean excludeBuildFolders) { - this(stubsOutputDir, contractsDslDir, excludedFiles, includedContracts, excludeBuildFolders, null); - } - - public void processFiles() { - ContractFileScanner scanner = ContractFileScanner.builder().baseDir(contractsDslDir) - .excluded(new HashSet<>(excludedFiles)).ignored(new HashSet<>()).included(new HashSet<>()) - .includeMatcher(includedContracts).build(); - MultiValueMap contracts = scanner.findContractsRecursively(); - if (log.isDebugEnabled()) { - log.debug("Found the following contracts " + contracts); - } - for (Map.Entry> entry : contracts.entrySet()) { - for (ContractMetadata contract : entry.getValue()) { - if (log.isDebugEnabled()) { - log.debug("Will create a stub for contract [" + contract + "]"); - } - File sourceFile = contract.getPath().toFile(); - Collection stubGenerators = holder.allOrDefault(new DslToWireMockClientConverter()); - try { - String path = sourceFile.getPath(); - if (excludeBuildFolders && (matchesPath(path, "target") || matchesPath(path, "build"))) { - if (log.isDebugEnabled()) { - log.debug("Exclude build folder is set. Path [" + path - + "] contains [target] or [build] in its path"); - } - - continue; - } - if (nullOrEmpty(contract) && nullOrEmpty(stubGenerators)) { - continue; - } - int contractsSize = contract.getConvertedContract().size(); - Path entryKey = entry.getKey(); - if (log.isDebugEnabled()) { - log.debug( - "Stub Generators [" + stubGenerators + "] will convert contents of [" + entryKey + "]"); - } - - for (StubGenerator stubGenerator : stubGenerators) { - Map convertedContent = stubGenerator - .convertContents(last(entryKey).toString(), contract); - if (convertedContent == null || convertedContent.isEmpty()) { - continue; - } - Set> entrySet = convertedContent.entrySet(); - Iterator> iterator = entrySet.iterator(); - int index = 0; - while (iterator.hasNext()) { - Map.Entry content = iterator.next(); - Contract dsl = content.getKey(); - String converted = content.getValue(); - if (StringUtils.hasText(converted)) { - Path absoluteTargetPath = createAndReturnTargetDirectory(sourceFile); - File newJsonFile = createTargetFileWithProperName(stubGenerator, absoluteTargetPath, - sourceFile, contractsSize, index, dsl); - Files.write(newJsonFile.toPath(), Collections.singletonList(converted), - StandardCharsets.UTF_8); - } - index = index + 1; - } - - } - - } - catch (Exception e) { - throw new ConversionContractVerifierException( - "Unable to make conversion of " + sourceFile.getName(), e); - } - - } - - } - - } - - private static T last(Iterable self) { - Iterator iterator = self.iterator(); - if (!iterator.hasNext()) { - throw new NoSuchElementException("Cannot access last() element from an empty Iterable"); - } - T result = null; - while (iterator.hasNext()) { - result = iterator.next(); - } - return result; - } - - private boolean nullOrEmpty(ContractMetadata contract) { - return contract.getConvertedContract() == null || nullOrEmpty(contract.getConvertedContract()); - } - - private boolean nullOrEmpty(Collection collection) { - return collection == null || collection.isEmpty(); - } - - private boolean matchesPath(String path, String folder) { - return path.matches("^.*" + File.separator + folder + File.separator + ".*$"); - } - - private Path createAndReturnTargetDirectory(File sourceFile) { - Path relativePath = Paths.get(contractsDslDir.toURI()).relativize(sourceFile.getParentFile().toPath()); - Path absoluteTargetPath = outMappingsDir.toPath().resolve(relativePath); - try { - Files.createDirectories(absoluteTargetPath); - } - catch (IOException ex) { - throw new IllegalStateException(ex); - } - return absoluteTargetPath; - } - - private File createTargetFileWithProperName(StubGenerator stubGenerator, Path absoluteTargetPath, File sourceFile, - int contractsSize, int index, Contract dsl) { - String name = generateName(dsl, contractsSize, stubGenerator, sourceFile, index); - File newJsonFile = new File(absoluteTargetPath.toFile(), name); - log.info("Creating new stub [" + newJsonFile.getPath() + "]"); - return newJsonFile; - } - - private String generateName(Contract dsl, int contractsSize, StubGenerator converter, File sourceFile, int index) { - String generatedName = converter.generateOutputFileNameForInput(sourceFile.getName()); - boolean hasDot = NamesUtil.hasDot(generatedName); - String extension = hasDot ? NamesUtil.afterLastDot(generatedName) : ""; - if (StringUtils.hasText(dsl.getName()) && StringUtils.hasText(extension)) { - return dsl.getName() + "." + extension; - } - else if (contractsSize == 1) { - return generatedName; - } - return index + "_" + generatedName; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/converter/RecursiveFilesConverterApplication.java b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/converter/RecursiveFilesConverterApplication.java deleted file mode 100644 index 25683424f7..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/converter/RecursiveFilesConverterApplication.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.converter; - -import java.io.File; -import java.util.Arrays; -import java.util.List; - -import org.springframework.util.StringUtils; - -public final class RecursiveFilesConverterApplication { - - private RecursiveFilesConverterApplication() { - } - - public static void main(String[] args) { - if (args.length != 5) { - throw new RuntimeException("Invalid number of arguments"); - } - - File stubsOutputDir = new File(args[0]); - File contractsDslDir = new File(args[1]); - List excludedFiles = Arrays.asList(StringUtils.commaDelimitedListToStringArray(args[2])); - String includedContracts = args[3]; - boolean excludeBuildFolders = Boolean.parseBoolean(args[4]); - - RecursiveFilesConverter converter = new RecursiveFilesConverter(stubsOutputDir, contractsDslDir, excludedFiles, - includedContracts, excludeBuildFolders); - converter.processFiles(); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/converter/StubGenerator.java b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/converter/StubGenerator.java deleted file mode 100644 index 7ab7e37c72..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/converter/StubGenerator.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.converter; - -import java.io.File; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.verifier.file.ContractMetadata; - -/** - * Converts contracts into their stub representation. - * - * @param - type of stub mapping - * @since 1.1.0 - */ -public interface StubGenerator { - - /** - * @param mapping - potential stub mapping mapping - * @return {@code true} if this converter could have generated this mapping stub. - */ - default boolean canReadStubMapping(File mapping) { - return mapping.getName().endsWith(fileExtension()); - } - - /** - * @param rootName - root name of the contract - * @param content - metadata of the contract - * @return the collection of converted contracts into stubs. One contract can result - * in multiple stubs. - */ - Map convertContents(String rootName, ContractMetadata content); - - /** - * Post process a generated stub mapping. - * @param stubMapping - mapping of a stub - * @param contract - contract for which stub was generated - * @return the converted stub mapping - */ - default T postProcessStubMapping(T stubMapping, Contract contract) { - List processors = StubPostProcessor.PROCESSORS.stream().filter(p -> p.isApplicable(contract)) - .collect(Collectors.toList()); - if (processors.isEmpty()) { - return defaultStubMappingPostProcessing(stubMapping, contract); - } - T stub = stubMapping; - for (StubPostProcessor processor : processors) { - stub = (T) processor.postProcess(stub, contract); - } - return stub; - } - - /** - * Stub mapping to chose when no post processors where found on the classpath. - * @param stubMapping - mapping of a stub - * @param contract - contract for which stub was generated - * @return the converted stub mapping - */ - default T defaultStubMappingPostProcessing(T stubMapping, Contract contract) { - return stubMapping; - } - - /** - * @param inputFileName - name of the input file - * @return the name of the converted stub file. If you have multiple contracts in a - * single file then a prefix will be added to the generated file. If you provide the - * {@link Contract#getName} field then that field will override the generated file - * name. - * - * Example: name of file with 2 contracts is {@code foo.groovy}, it will be converted - * by the implementation to {@code foo.json}. The recursive file converter will create - * two files {@code 0_foo.json} and {@code 1_foo.json} - */ - String generateOutputFileNameForInput(String inputFileName); - - /** - * Describes the file extension of the generated mapping that this stub generator can - * handle. - * @return string describing the file extension - */ - default String fileExtension() { - return ".json"; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/converter/StubGeneratorProvider.java b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/converter/StubGeneratorProvider.java deleted file mode 100644 index 2c9f6c6ece..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/converter/StubGeneratorProvider.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.converter; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import org.springframework.core.io.support.SpringFactoriesLoader; - -/** - * Retrieves file converters from the class path and operates on them. - * - * @author Marcin Grzejszczak - * @since 1.1.0 - */ -public class StubGeneratorProvider { - - private final List converters = new ArrayList<>(); - - public StubGeneratorProvider() { - this.converters.addAll(SpringFactoriesLoader.loadFactories(StubGenerator.class, null)); - } - - public StubGeneratorProvider(List converters) { - this.converters.addAll(converters); - } - - public Collection allOrDefault(StubGenerator defaultStubGenerator) { - return this.converters.isEmpty() ? Collections.singletonList(defaultStubGenerator) : this.converters; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/converter/StubPostProcessor.java b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/converter/StubPostProcessor.java deleted file mode 100644 index 7e23f8250e..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/converter/StubPostProcessor.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.converter; - -import java.util.List; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.core.io.support.SpringFactoriesLoader; - -/** - * Post processor of stub mappings. - * - * @param type of stub mapping - * @author Marcin Grzejszczak - * @since 3.0.0 - */ -public interface StubPostProcessor { - - /** - * List of registered stub post processors. - */ - List PROCESSORS = SpringFactoriesLoader.loadFactories(StubPostProcessor.class, null); - - /** - * @param stubMapping - generated stub mapping - * @param contract - contract for which the mapping was generated - * @return modified stub mapping - */ - default T postProcess(T stubMapping, Contract contract) { - return stubMapping; - } - - /** - * @param contract - contract for which the mapping was generated - * @return {@code true} if this post process should be applied - */ - boolean isApplicable(Contract contract); - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/wiremock/DefaultWireMockStubPostProcessor.java b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/wiremock/DefaultWireMockStubPostProcessor.java deleted file mode 100644 index c7a646d4c9..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/wiremock/DefaultWireMockStubPostProcessor.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.wiremock; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.tomakehurst.wiremock.common.Metadata; -import com.github.tomakehurst.wiremock.extension.Parameters; -import com.github.tomakehurst.wiremock.extension.PostServeActionDefinition; -import com.github.tomakehurst.wiremock.http.ChunkedDribbleDelay; -import com.github.tomakehurst.wiremock.http.DelayDistribution; -import com.github.tomakehurst.wiremock.http.Fault; -import com.github.tomakehurst.wiremock.http.ResponseDefinition; -import com.github.tomakehurst.wiremock.stubbing.StubMapping; - -import org.springframework.cloud.contract.spec.Contract; - -class DefaultWireMockStubPostProcessor implements WireMockStubPostProcessor { - - private final ObjectMapper objectMapper = new ObjectMapper(); - - @Override - public StubMapping postProcess(StubMapping stubMapping, Contract contract) { - WireMockMetaData wireMockMetaData = WireMockMetaData.fromMetadata(contract.getMetadata()); - StubMapping stubMappingFromMetadata = stubMappingFromMetadata(wireMockMetaData.getStubMapping()); - stubMapping.setResponse(mergedResponse(stubMapping, stubMappingFromMetadata)); - if (stubMappingFromMetadata.getPostServeActions() != null) { - setPostServeActions(stubMapping, stubMappingFromMetadata); - } - if (stubMappingFromMetadata.getMetadata() != null) { - setMetadata(stubMapping, stubMappingFromMetadata); - } - return stubMapping; - } - - public void setPostServeActions(StubMapping stubMapping, StubMapping stubMappingFromMetadata) { - List postServeActions = stubMapping.getPostServeActions(); - postServeActions = postServeActions != null ? postServeActions : new ArrayList<>(); - postServeActions.addAll(stubMappingFromMetadata.getPostServeActions()); - stubMapping.setPostServeActions(postServeActions); - } - - public void setMetadata(StubMapping stubMapping, StubMapping stubMappingFromMetadata) { - Metadata metadata = stubMapping.getMetadata(); - metadata = metadata != null ? metadata : new Metadata(); - metadata.putAll(stubMappingFromMetadata.getMetadata()); - stubMapping.setMetadata(metadata); - } - - public ResponseDefinition mergedResponse(StubMapping stubMapping, StubMapping stubMappingFromMetadata) { - return new ResponseDefinition(stubMapping.getResponse().getStatus(), - stubMapping.getResponse().getStatusMessage(), stubMapping.getResponse().getBody(), - stubMapping.getResponse().getJsonBody(), stubMapping.getResponse().getBase64Body(), - stubMapping.getResponse().getBodyFileName(), stubMapping.getResponse().getHeaders(), - stubMapping.getResponse().getAdditionalProxyRequestHeaders(), - fixedDelayMilliseconds(stubMapping, stubMappingFromMetadata), - delayDistribution(stubMapping, stubMappingFromMetadata), - chunkedDribbleDelay(stubMapping, stubMappingFromMetadata), - proxyBaseUrl(stubMapping, stubMappingFromMetadata), - proxyUrlPrefixToRemove(stubMapping, stubMappingFromMetadata), - fault(stubMapping, stubMappingFromMetadata), transformers(stubMapping, stubMappingFromMetadata), - transformerParameters(stubMapping, stubMappingFromMetadata), - wasConfigured(stubMapping, stubMappingFromMetadata)); - } - - public Boolean wasConfigured(StubMapping stubMapping, StubMapping stubMappingFromMetadata) { - return stubMappingFromMetadata.getResponse().isFromConfiguredStub() != null - ? stubMappingFromMetadata.getResponse().isFromConfiguredStub() - : stubMapping.getResponse().isFromConfiguredStub(); - } - - public Parameters transformerParameters(StubMapping stubMapping, StubMapping stubMappingFromMetadata) { - return stubMappingFromMetadata.getResponse().getTransformerParameters() != null - ? stubMappingFromMetadata.getResponse().getTransformerParameters() - : stubMapping.getResponse().getTransformerParameters(); - } - - public List transformers(StubMapping stubMapping, StubMapping stubMappingFromMetadata) { - return stubMappingFromMetadata.getResponse().getTransformers() != null - ? stubMappingFromMetadata.getResponse().getTransformers() : stubMapping.getResponse().getTransformers(); - } - - public Fault fault(StubMapping stubMapping, StubMapping stubMappingFromMetadata) { - return stubMappingFromMetadata.getResponse().getFault() != null - ? stubMappingFromMetadata.getResponse().getFault() : stubMapping.getResponse().getFault(); - } - - public String proxyBaseUrl(StubMapping stubMapping, StubMapping stubMappingFromMetadata) { - return stubMappingFromMetadata.getResponse().getProxyBaseUrl() != null - ? stubMappingFromMetadata.getResponse().getProxyBaseUrl() : stubMapping.getResponse().getProxyBaseUrl(); - } - - public String proxyUrlPrefixToRemove(StubMapping stubMapping, StubMapping stubMappingFromMetadata) { - return stubMappingFromMetadata.getResponse().getProxyUrlPrefixToRemove() != null - ? stubMappingFromMetadata.getResponse().getProxyUrlPrefixToRemove() - : stubMapping.getResponse().getProxyUrlPrefixToRemove(); - } - - public ChunkedDribbleDelay chunkedDribbleDelay(StubMapping stubMapping, StubMapping stubMappingFromMetadata) { - return stubMappingFromMetadata.getResponse().getChunkedDribbleDelay() != null - ? stubMappingFromMetadata.getResponse().getChunkedDribbleDelay() - : stubMapping.getResponse().getChunkedDribbleDelay(); - } - - public DelayDistribution delayDistribution(StubMapping stubMapping, StubMapping stubMappingFromMetadata) { - return stubMappingFromMetadata.getResponse().getDelayDistribution() != null - ? stubMappingFromMetadata.getResponse().getDelayDistribution() - : stubMapping.getResponse().getDelayDistribution(); - } - - public Integer fixedDelayMilliseconds(StubMapping stubMapping, StubMapping stubMappingFromMetadata) { - return stubMappingFromMetadata.getResponse().getFixedDelayMilliseconds() != null - ? stubMappingFromMetadata.getResponse().getFixedDelayMilliseconds() - : stubMapping.getResponse().getFixedDelayMilliseconds(); - } - - private StubMapping stubMappingFromMetadata(Object wiremock) { - if (wiremock instanceof String) { - return StubMapping.buildFrom((String) wiremock); - } - else if (wiremock instanceof StubMapping) { - return (StubMapping) wiremock; - } - else if (wiremock instanceof Map) { - try { - return StubMapping.buildFrom(this.objectMapper.writeValueAsString(wiremock)); - } - catch (JsonProcessingException e) { - throw new IllegalStateException("Failed to build StubMapping for map [" + wiremock + "]", e); - } - } - throw new UnsupportedOperationException("Unsupported type for wiremock metadata extension"); - } - - @Override - public boolean isApplicable(Contract contract) { - boolean contains = contract.getMetadata().containsKey(WireMockMetaData.METADATA_KEY); - if (!contains) { - return false; - } - Object stubMapping = WireMockMetaData.fromMetadata(contract.getMetadata()).getStubMapping(); - return WireMockMetaData.APPLICABLE_CLASSES.stream() - .anyMatch(aClass -> aClass.isAssignableFrom(stubMapping.getClass())); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverter.java b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverter.java deleted file mode 100644 index 32ec854aed..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverter.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.wiremock; - -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.stream.Collectors; - -import com.github.tomakehurst.wiremock.stubbing.StubMapping; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockStubStrategy; -import org.springframework.cloud.contract.verifier.file.ContractMetadata; -import org.springframework.cloud.contract.verifier.util.NamesUtil; -import org.springframework.util.StringUtils; - -/** - * Converts DSLs to WireMock stubs. - * - * @since 1.0.0 - */ -public class DslToWireMockClientConverter extends DslToWireMockConverter { - - private String convertASingleContract(String rootName, ContractMetadata contract, Contract dsl) { - StubMapping stubMapping = new WireMockStubStrategy(rootName, contract, dsl).toWireMockClientStub(); - StubMapping mapping = postProcessStubMapping(stubMapping, dsl); - if (mapping == null) { - return ""; - } - return mapping.toString(); - } - - @Override - public StubMapping postProcessStubMapping(StubMapping stubMapping, Contract contract) { - // apply the default WireMock processor as the last one - return super.postProcessStubMapping(stubMapping, contract); - } - - @Override - public StubMapping defaultStubMappingPostProcessing(StubMapping stubMapping, Contract contract) { - DefaultWireMockStubPostProcessor processor = new DefaultWireMockStubPostProcessor(); - if (processor.isApplicable(contract)) { - return processor.postProcess(stubMapping, contract); - } - return stubMapping; - } - - @Override - public Map convertContents(String rootName, ContractMetadata contract) { - List httpContracts = httpContracts(contract); - if (httpContracts.isEmpty()) { - return new HashMap<>(); - } - if (contract.getConvertedContract().size() == 1) { - return Collections.singletonMap(first((List) contract.getConvertedContract()), - convertASingleContract(rootName, contract, - first((List) contract.getConvertedContract()))); - } - return convertContracts(rootName, contract, httpContracts); - } - - private List httpContracts(ContractMetadata contract) { - return contract.getConvertedContract().stream().filter(c -> c.getRequest() != null) - .collect(Collectors.toList()); - } - - private Map convertContracts(String rootName, ContractMetadata contract, - List contractsWithRequest) { - Map convertedContracts = new LinkedHashMap<>(); - for (int i = 0; i < contractsWithRequest.size(); i++) { - Contract dsl = contractsWithRequest.get(i); - String name = StringUtils.hasText(dsl.getName()) ? NamesUtil.convertIllegalPackageChars(dsl.getName()) - : rootName + "_" + i; - convertedContracts.put(dsl, convertASingleContract(name, contract, dsl)); - } - return convertedContracts; - } - - private static T first(List self) { - if (self.isEmpty()) { - throw new NoSuchElementException("Cannot access first() element from an empty List"); - } - return self.get(0); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockConverter.java b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockConverter.java deleted file mode 100644 index ed106685c9..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockConverter.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.wiremock; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.Charset; -import java.nio.file.Files; - -import com.github.tomakehurst.wiremock.common.JsonException; -import com.github.tomakehurst.wiremock.stubbing.StubMapping; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.verifier.converter.StubGenerator; -import org.springframework.util.StreamUtils; - -/** - * WireMock implementation of the {@link StubGenerator}. - * - * @since 1.0.0 - */ -public abstract class DslToWireMockConverter implements StubGenerator { - - private static final Log log = LogFactory.getLog(DslToWireMockConverter.class); - - @Override - public String generateOutputFileNameForInput(String inputFileName) { - return inputFileName.replaceAll(extension(inputFileName), "json"); - } - - private String extension(String inputFileName) { - int i = inputFileName.lastIndexOf("."); - if (i > 0) { - return inputFileName.substring(i + 1); - } - return ""; - } - - @Override - public boolean canReadStubMapping(File mapping) { - if (!mapping.getName().endsWith(".json")) { - return false; - } - try (InputStream stream = Files.newInputStream(mapping.toPath())) { - StubMapping.buildFrom(StreamUtils.copyToString(stream, Charset.forName("UTF-8"))); - return true; - } - catch (IOException | JsonException e) { - if (log.isDebugEnabled()) { - log.debug("Cannot read file", e); - } - return false; - } - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/wiremock/WireMockMetaData.java b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/wiremock/WireMockMetaData.java deleted file mode 100644 index c21c1012d0..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/wiremock/WireMockMetaData.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.wiremock; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import com.github.tomakehurst.wiremock.stubbing.StubMapping; - -import org.springframework.cloud.contract.verifier.util.MetadataUtil; -import org.springframework.cloud.contract.verifier.util.SpringCloudContractMetadata; - -public class WireMockMetaData implements SpringCloudContractMetadata { - - /** - * Key under which this metadata entry can be found in contract's metadata. - */ - public static final String METADATA_KEY = "wiremock"; - - /** - * Applicable classes for Stub Mapping. - */ - static final List APPLICABLE_CLASSES = Arrays.asList(String.class, StubMapping.class, Map.class); - - /** - * {@link StubMapping} represented by one of the classes in - * {@link #APPLICABLE_CLASSES}. - */ - private Object stubMapping; - - public Object getStubMapping() { - return stubMapping; - } - - public void setStubMapping(Object stubMapping) { - this.stubMapping = stubMapping; - } - - public static WireMockMetaData fromMetadata(Map metadata) { - return MetadataUtil.fromMetadata(metadata, WireMockMetaData.METADATA_KEY, new WireMockMetaData()); - } - - @Override - public String key() { - return METADATA_KEY; - } - - @Override - public String description() { - return "Metadata for extending WireMock stubs.\n\nStubMapping can be " + "one of the following classes " - + APPLICABLE_CLASSES.stream().map(aClass -> "`" + aClass.getSimpleName() + "`") - .collect(Collectors.toList()) - + ". Please check " - + "the http://wiremock.org/docs/stubbing/ for more information about the StubMapping class properties."; - } - - @Override - public List additionalClassesToLookAt() { - return Collections.singletonList(StubMapping.class); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/wiremock/WireMockStubPostProcessor.java b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/wiremock/WireMockStubPostProcessor.java deleted file mode 100644 index 0bd63abf26..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/wiremock/WireMockStubPostProcessor.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.wiremock; - -import com.github.tomakehurst.wiremock.stubbing.StubMapping; - -import org.springframework.cloud.contract.verifier.converter.StubPostProcessor; - -/** - * Post processor of WireMock stub mappings. - * - * @author Marcin Grzejszczak - * @since 3.0.0 - */ -public interface WireMockStubPostProcessor extends StubPostProcessor { - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/wiremock/WireMockToDslConverter.java b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/wiremock/WireMockToDslConverter.java deleted file mode 100644 index 8aeb142ec9..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/java/org/springframework/cloud/contract/verifier/wiremock/WireMockToDslConverter.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.wiremock; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.stream.StreamSupport; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonPointer; -import com.fasterxml.jackson.core.util.DefaultIndenter; -import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; -import com.fasterxml.jackson.core.util.Separators; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.IntNode; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.fasterxml.jackson.databind.node.TextNode; -import repackaged.nl.flotsam.xeger.Xeger; - -import static org.apache.commons.text.StringEscapeUtils.escapeJava; - -/** - * Converts WireMock stubs into the DSL format. - * - * @author Marcin Grzejszczak - * @author Konstantin Shevchuk - * @since 1.0.0 - */ -public class WireMockToDslConverter { - - private static final JsonPointer PRIORITY_POINTER = JsonPointer.compile("/priority"); - - private static final JsonPointer REQUEST_METHOD_POINTER = JsonPointer.compile("/request/method"); - - private static final JsonPointer REQUEST_URL_POINTER = JsonPointer.compile("/request/url"); - - private static final JsonPointer REQUEST_URL_PATH_POINTER = JsonPointer.compile("/request/urlPath"); - - private static final JsonPointer REQUEST_URL_PATTERN_POINTER = JsonPointer.compile("/request/urlPattern"); - - private static final JsonPointer REQUEST_URL_PATH_PATTERN_POINTER = JsonPointer.compile("/request/urlPathPattern"); - - private static final JsonPointer REQUEST_HEADERS_POINTER = JsonPointer.compile("/request/headers"); - - private static final JsonPointer REQUEST_BODY_POINTER = JsonPointer.compile("/request/bodyPatterns"); - - private static final JsonPointer RESPONSE_STATUS_POINTER = JsonPointer.compile("/response/status"); - - private static final JsonPointer RESPONSE_BODY_POINTER = JsonPointer.compile("/response/body"); - - private static final JsonPointer RESPONSE_HEADERS_POINTER = JsonPointer.compile("/response/headers"); - - private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - - static { - OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_COMMENTS, true); - OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_YAML_COMMENTS, true); - OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); - OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); - } - - /** - * Returns the string content of the contract. - * @param wireMockStringStub - string content of the WireMock JSON stub - */ - public static String fromWireMockStub(String wireMockStringStub) { - return new WireMockToDslConverter().convertFromWireMockStub(wireMockStringStub); - } - - private String convertFromWireMockStub(String wireMockStringStub) { - JsonNode wireMockStub = parseStubDefinition(wireMockStringStub); - return buildPriority(wireMockStub) + "request {\n" + buildRequestMethod(wireMockStub) - + buildRequestUrl(wireMockStub) + buildRequestUrlPattern(wireMockStub) - + buildRequestUrlPathPattern(wireMockStub) + buildRequestUrlPath(wireMockStub) - + buildRequestHeaders(wireMockStub) + buildRequestBody(wireMockStub) + "}\n" + "response {\n" - + buildResponseStatus(wireMockStub) + buildResponseBody(wireMockStub) - + buildResponseHeaders(wireMockStub) + "}" + "\n"; - } - - private JsonNode parseStubDefinition(String wireMockStringStub) { - try { - return OBJECT_MAPPER.reader().readTree(wireMockStringStub); - } - catch (IOException e) { - throw new RuntimeException("WireMock string stub could not be read", e); - } - } - - private String buildPriority(JsonNode wireMockStub) { - String priority = ""; - JsonNode priorityNode = wireMockStub.at(PRIORITY_POINTER); - if (priorityNode != null && priorityNode.asInt() > 0) { - priority = "priority " + priorityNode.asInt() + "\n"; - } - return priority; - } - - private String buildRequestMethod(JsonNode wireMockStub) { - String requestMethod = ""; - JsonNode requestMethodNode = wireMockStub.at(REQUEST_METHOD_POINTER); - if (requestMethodNode != null) { - requestMethod = "method '" + requestMethodNode.asText() + "'\n"; - } - return requestMethod; - } - - private String buildRequestUrl(JsonNode wireMockStub) { - String requestUrl = ""; - JsonNode requestUrlNode = wireMockStub.at(REQUEST_URL_POINTER); - if (!requestUrlNode.isMissingNode()) { - requestUrl = "url '" + requestUrlNode.asText() + "'\n"; - } - return requestUrl; - } - - private String buildRequestUrlPath(JsonNode wireMockStub) { - String requestUrlPath = ""; - JsonNode requestUrlPathNode = wireMockStub.at(REQUEST_URL_PATH_POINTER); - if (!requestUrlPathNode.isMissingNode()) { - requestUrlPath = "url '" + requestUrlPathNode.asText() + "'\n"; - } - return requestUrlPath; - } - - private String buildRequestUrlPattern(JsonNode wireMockStub) { - String requestUrlPattern = ""; - JsonNode requestUrlPatternNode = wireMockStub.at(REQUEST_URL_PATTERN_POINTER); - if (!requestUrlPatternNode.isMissingNode()) { - String escapedRequestUrlPatternValue = escapeJava(requestUrlPatternNode.asText()); - requestUrlPattern = "url $(consumer(regex('" + escapedRequestUrlPatternValue + "')), producer('" - + new Xeger(escapedRequestUrlPatternValue).generate() + "'))\n"; - } - return requestUrlPattern; - } - - private String buildRequestUrlPathPattern(JsonNode wireMockStub) { - String requestUrlPathPattern = ""; - JsonNode requestUrlPathPatternNode = wireMockStub.at(REQUEST_URL_PATH_PATTERN_POINTER); - if (!requestUrlPathPatternNode.isMissingNode()) { - String escapedRequestUrlPathPatternValue = escapeJava(requestUrlPathPatternNode.asText()); - requestUrlPathPattern = "urlPath $(consumer(regex('" + escapedRequestUrlPathPatternValue + "')), producer('" - + new Xeger(escapedRequestUrlPathPatternValue).generate() + "'))'\n"; - } - return requestUrlPathPattern; - } - - private String buildRequestHeaders(JsonNode wireMockStub) { - final StringBuilder requestHeadersBuilder = new StringBuilder(); - JsonNode requestHeadersNode = wireMockStub.at(REQUEST_HEADERS_POINTER); - - if (requestHeadersNode.isObject()) { - requestHeadersBuilder.append("headers {\n"); - ObjectNode requestHeadersObjectNode = requestHeadersNode.deepCopy(); - Iterator> fields = requestHeadersObjectNode.fields(); - fields.forEachRemaining(c -> { - requestHeadersBuilder.append("header('").append(c.getKey()).append("',"); - Map.Entry headerValue = c.getValue().deepCopy().fields().next(); - String header = buildHeader(headerValue.getKey(), headerValue.getValue().asText()); - requestHeadersBuilder.append(header).append(")").append("\n"); - }); - requestHeadersBuilder.append("}"); - } - return requestHeadersBuilder.toString(); - } - - private String buildHeader(String method, String value) { - switch (method) { - case "equalTo": - return "'" + value + "'"; - case "contains": - String regex = "^.*" + value + ".*$"; - return "c(regex('" + escapeJava(regex) + "'))"; - default: - return "c(regex('" + escapeJava(value) + "'))"; - } - } - - private String buildRequestBody(JsonNode wireMockStub) { - final StringBuilder requestBody = new StringBuilder(); - JsonNode requestBodyNode = wireMockStub.at(REQUEST_BODY_POINTER); - if (requestBodyNode.isArray()) { - ArrayNode requestBodyArrayNode = requestBodyNode.deepCopy(); - Iterator elements = requestBodyArrayNode.elements(); - Iterable iterableFields = () -> elements; - List> requestBodyObjectNodes = new ArrayList<>(); - StreamSupport.stream(iterableFields.spliterator(), false).filter(f -> f instanceof ObjectNode) - .map(f -> (ObjectNode) f).map(ObjectNode::fields) - .forEachOrdered(i -> i.forEachRemaining(requestBodyObjectNodes::add)); - requestBodyObjectNodes.stream().filter(b -> b.getKey().equals("equalTo")).findFirst() - .ifPresent(b -> requestBody.append("body ('").append(b.getValue().asText()).append("')")); - requestBodyObjectNodes.stream().filter(b -> b.getKey().equals("equalToJson")).findFirst() - .ifPresent(b -> requestBody.append("body ('").append(b.getValue().asText()).append("')")); - requestBodyObjectNodes.stream().filter(b -> b.getKey().equals("matches")).findFirst() - .ifPresent(b -> requestBody.append("body $(consumer(regex('") - .append(escapeJava(b.getValue().asText())).append("')), producer('") - .append(new Xeger(escapeJava(b.getValue().asText())).generate()).append("'))")); - } - return requestBody.toString(); - } - - private String buildResponseStatus(JsonNode wireMockStub) { - String responseStatus = ""; - JsonNode responseStatusNode = wireMockStub.at(RESPONSE_STATUS_POINTER); - if (!responseStatusNode.isMissingNode()) { - int responseStatusValue = responseStatusNode.asInt(); - responseStatus += "status " + responseStatusValue + "\n"; - } - return responseStatus; - } - - private String buildResponseBody(JsonNode wireMockStub) { - String responseBody = ""; - JsonNode responseBodyNode = wireMockStub.at(RESPONSE_BODY_POINTER); - if (responseBodyNode.isInt()) { - responseBody += "body( " + escapeJava(buildPrettyPrintResponseBody((IntNode) responseBodyNode)) + ")\n"; - } - if (responseBodyNode.isTextual()) { - responseBody += "body( \"" + escapeJava(buildPrettyPrintResponseBody((TextNode) responseBodyNode)) - + "\")\n"; - } - return responseBody; - } - - private String buildPrettyPrintResponseBody(IntNode node) { - return node.asText(); - } - - private String buildPrettyPrintResponseBody(TextNode node) { - try { - String textNode = node.asText(); - Object intermediateObjectForPrettyPrinting = OBJECT_MAPPER.reader().readValue(textNode, Object.class); - DefaultIndenter customIndenter = new DefaultIndenter(" ", "\n"); - return OBJECT_MAPPER - .writer(new PrivatePrettyPrinter().withArrayIndenter(customIndenter) - .withObjectIndenter(customIndenter)) - .writeValueAsString(intermediateObjectForPrettyPrinting); - } - catch (IOException e) { - throw new RuntimeException("WireMock response body could not be pretty printed"); - } - } - - private String buildResponseHeaders(JsonNode wireMockStub) { - final StringBuilder responseHeadersBuilder = new StringBuilder(); - JsonNode requestHeadersNode = wireMockStub.at(RESPONSE_HEADERS_POINTER); - - if (requestHeadersNode.isObject()) { - responseHeadersBuilder.append("headers {\n"); - ObjectNode responseHeadersObjectNode = requestHeadersNode.deepCopy(); - Iterator> fields = responseHeadersObjectNode.fields(); - fields.forEachRemaining(c -> responseHeadersBuilder.append("header('").append(c.getKey()).append("',") - .append("'").append(c.getValue().asText()).append("')\n")); - responseHeadersBuilder.append("}"); - } - return responseHeadersBuilder.toString(); - } - - private static class PrivatePrettyPrinter extends DefaultPrettyPrinter { - - @Override - public DefaultPrettyPrinter createInstance() { - return new PrivatePrettyPrinter(); - } - - @Override - public DefaultPrettyPrinter withSeparators(Separators separators) { - _separators = separators; - _objectFieldValueSeparatorWithSpaces = separators.getObjectFieldValueSeparator() + " "; - return this; - } - - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/resources/META-INF/spring.factories b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 9c00e75f2b..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,3 +0,0 @@ -# Stub converters -org.springframework.cloud.contract.verifier.converter.StubGenerator=\ -org.springframework.cloud.contract.verifier.wiremock.DslToWireMockClientConverter diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/converter/RecursiveFilesConverterSpec.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/converter/RecursiveFilesConverterSpec.groovy deleted file mode 100755 index 8e5036c215..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/converter/RecursiveFilesConverterSpec.groovy +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.converter - -import java.nio.file.Path -import java.nio.file.Paths - -import groovy.io.FileType -import org.junit.Rule -import org.junit.rules.TemporaryFolder -import spock.lang.Specification - -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.file.ContractMetadata -import org.springframework.util.FileSystemUtils - -class RecursiveFilesConverterSpec extends Specification { - - private static - final Set EXPECTED_TARGET_FILES = [Paths.get("dslRoot.json"), - Paths.get("dir1/1_scenario.json"), - Paths.get("dir1/2_scenario.json"), - Paths.get("dir1/1_scenario_multiple.json"), - Paths.get("dir1/2_scenario_multiple.json"), - Paths.get("dir1/dsl1.json"), - Paths.get("dir1/dsl1b.json"), - Paths.get("dir2/dsl2.json"), - Paths.get("dir1/dsl1_list_0.json"), - Paths.get("dir1/dsl1_list_1.json"), - Paths.get("dir1/shouldHaveIndex1.json"), - Paths.get("dir1/shouldHaveIndex2.json")] - - @Rule - public TemporaryFolder tmpFolder = new TemporaryFolder() - - def "should recursively convert all matching files with stubs"() { - given: - File originalSourceRootDirectory = new File(this.getClass() - .getResource("/converter/dir3").toURI()) - File contractsDslDir = tmpFolder.newFolder("source") - File stubsOutputDir = tmpFolder.newFolder("target") - FileSystemUtils - .copyRecursively(originalSourceRootDirectory, contractsDslDir) - and: - RecursiveFilesConverter recursiveFilesConverter = new RecursiveFilesConverter(stubsOutputDir, contractsDslDir, new ArrayList<>(), ".*", false) - when: - recursiveFilesConverter.processFiles() - then: - Collection createdFiles = [] as List - stubsOutputDir. - eachFileRecurse(FileType.FILES) { createdFiles << it } - Set relativizedCreatedFiles = - getRelativePathsForFilesInDirectory(createdFiles, stubsOutputDir) - relativizedCreatedFiles == [Paths.get("Account creating.json"), - Paths.get("Test route.json")] as Set - } - - def "should recursively convert all matching files"() { - given: - File originalSourceRootDirectory = new File(this.getClass() - .getResource("/converter/source").toURI()) - File contractsDslDir = tmpFolder.newFolder("source") - File stubsOutputDir = tmpFolder.newFolder("target") - FileSystemUtils - .copyRecursively(originalSourceRootDirectory, contractsDslDir) - and: - RecursiveFilesConverter recursiveFilesConverter = new RecursiveFilesConverter(stubsOutputDir, contractsDslDir, new ArrayList<>(), ".*", false) - when: - recursiveFilesConverter.processFiles() - then: - Collection createdFiles = [] as List - stubsOutputDir. - eachFileRecurse(FileType.FILES) { createdFiles << it } - Set relativizedCreatedFiles = - getRelativePathsForFilesInDirectory(createdFiles, stubsOutputDir) - relativizedCreatedFiles == EXPECTED_TARGET_FILES - and: - createdFiles.each { assert it.text.contains("uuid") } - } - - def "should recursively convert matching files with exlusions"() { - given: - File originalSourceRootDirectory = new File(this.getClass() - .getResource("/converter/source").toURI()) - File contractsDslDir = tmpFolder.newFolder("source") - File stubsOutputDir = tmpFolder.newFolder("target") - List excludedFiles = ["dir1/**"] - FileSystemUtils - .copyRecursively(originalSourceRootDirectory, contractsDslDir) - and: - RecursiveFilesConverter recursiveFilesConverter = new RecursiveFilesConverter(stubsOutputDir, contractsDslDir, excludedFiles, ".*", false) - when: - recursiveFilesConverter.processFiles() - then: - Collection createdFiles = [] as List - stubsOutputDir. - eachFileRecurse(FileType.FILES) { createdFiles << it } - Set relativizedCreatedFiles = - getRelativePathsForFilesInDirectory(createdFiles, stubsOutputDir) - [Paths.get("dslRoot.json"), Paths. - get("dir2/dsl2.json")] as Set == relativizedCreatedFiles as Set - and: - createdFiles.each { assert it.text.contains("uuid") } - } - - def "on failure should break processing and throw meaningful exception"() { - given: - File sourceFile = tmpFolder.newFile("test.groovy") - sourceFile.text = """\ -org.springframework.cloud.contract.spec.Contract.make { - request { - method GET() - url '/foo' - } - response { - status OK() - } - }""" - and: - StubGenerator stubGenerator = Stub(StubGenerator) - stubGenerator.canReadStubMapping(_) >> { true } - stubGenerator.convertContents(_, _) >> { - throw new NullPointerException("Test conversion error") - } - stubGenerator - .generateOutputFileNameForInput(_) >> { String inputFileName -> "${inputFileName}2" } - File contractsDslDir = tmpFolder.root - File stubsOutputDir = tmpFolder.root - RecursiveFilesConverter recursiveFilesConverter = new RecursiveFilesConverter(stubsOutputDir, contractsDslDir, new ArrayList<>(), ".*", false, new StubGeneratorProvider([stubGenerator])) - when: - recursiveFilesConverter.processFiles() - then: - ConversionContractVerifierException e = thrown(ConversionContractVerifierException) - e.message?.contains(sourceFile.name) - e.cause?.message == "Test conversion error" - } - - def "should convert contract into stub using all possible converters"() { - given: - File sourceFile = tmpFolder.newFile("test.groovy") - sourceFile.text = """ - org.springframework.cloud.contract.spec.Contract.make { - request { - url "/baz" - method "GET" - } - response { - status OK() - } - } - """ - and: - StubGenerator stubGenerator1 = stubGenerator("foo") - and: - StubGenerator stubGenerator2 = stubGenerator("bar") - and: - File contractsDslDir = tmpFolder.root - File stubsOutputDir = tmpFolder.root - and: - RecursiveFilesConverter recursiveFilesConverter = new RecursiveFilesConverter(stubsOutputDir, contractsDslDir, new ArrayList<>(), ".*", false, new StubGeneratorProvider([stubGenerator1, stubGenerator2])) - when: - recursiveFilesConverter.processFiles() - then: - tmpFolder.root.list().toList().containsAll("foo", "bar") - } - - def "should not create stub file when generated stub is empty"() { - given: - File sourceFile = tmpFolder.newFile("test.groovy") - sourceFile.text = """ - org.springframework.cloud.contract.spec.Contract.make { - request { - url "/baz" - method "GET" - } - response { - status OK() - } - } - """ - and: - StubGenerator stubGenerator = stubGenerator("") - and: - File contractsDslDir = tmpFolder.root - File stubsOutputDir = tmpFolder.newFolder("target") - and: - RecursiveFilesConverter recursiveFilesConverter = new RecursiveFilesConverter(stubsOutputDir, contractsDslDir, new ArrayList<>(), ".*", false, new StubGeneratorProvider([stubGenerator])) - when: - recursiveFilesConverter.processFiles() - then: - stubsOutputDir.list().toList().isEmpty() - } - - private static Set getRelativePathsForFilesInDirectory(Collection createdFiles, File targetRootDirectory) { - Path rootSourcePath = Paths.get(targetRootDirectory.toURI()) - Set relativizedCreatedFiles = createdFiles.collect { File file -> - rootSourcePath.relativize(Paths.get(file.toURI())) - } - return relativizedCreatedFiles - } - - private StubGenerator stubGenerator(String stub) { - return new StubGenerator() { - - @Override - boolean canReadStubMapping(File mapping) { - return true - } - - @Override - Map convertContents(String rootName, ContractMetadata content) { - return [ - (content.convertedContract.first()): stub - ] - } - - @Override - String generateOutputFileNameForInput(String inputFileName) { - return stub - } - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverterSpec.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverterSpec.groovy deleted file mode 100755 index 932d951541..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverterSpec.groovy +++ /dev/null @@ -1,1197 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.wiremock - -import java.util.regex.Pattern - -import com.github.tomakehurst.wiremock.junit.WireMockRule -import com.github.tomakehurst.wiremock.matching.RegexPattern -import com.github.tomakehurst.wiremock.stubbing.StubMapping -import groovy.json.JsonOutput -import org.junit.Rule -import org.junit.rules.TemporaryFolder -import org.skyscreamer.jsonassert.JSONAssert -import spock.lang.Issue -import spock.lang.Specification - -import org.springframework.boot.test.web.client.TestRestTemplate -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockStubMapping -import org.springframework.cloud.contract.verifier.file.ContractMetadata -import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter -import org.springframework.cloud.test.TestSocketUtils -import org.springframework.core.io.ByteArrayResource -import org.springframework.http.HttpEntity -import org.springframework.http.RequestEntity -import org.springframework.util.LinkedMultiValueMap -import org.springframework.util.MultiValueMap - -class DslToWireMockClientConverterSpec extends Specification { - - int port = TestSocketUtils.findAvailableTcpPort() - @Rule - public WireMockRule wireMockRule = new WireMockRule(port) - @Rule - public TemporaryFolder tmpFolder = new TemporaryFolder() - TestRestTemplate restTemplate = new TestRestTemplate() - String url - - def setup() { - url = "http://localhost:${port}" - } - - def "should convert DSL file to WireMock JSON"() { - given: - def converter = new DslToWireMockClientConverter() - and: - File file = tmpFolder.newFile("dsl1.groovy") - file.write(""" - org.springframework.cloud.contract.spec.Contract.make { - request { - method('PUT') - url \$(consumer(~/\\/[0-9]{2}/), producer('/12')) - } - response { - status OK() - } - } -""") - when: - String json = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null, - ContractVerifierDslConverter.convertAsCollection(new File("/"), file))).values().first() - then: - JSONAssert.assertEquals(''' -{"request":{"method":"PUT","urlPattern":"/[0-9]{2}"},"response":{"status":200}} -''', json, false) - and: - StubMapping mapping = stubMappingIsValidWireMockStub(json) - and: - wireMockRule.addStubMapping(mapping) - and: - restTemplate.exchange(RequestEntity.put("${url}/12".toURI()).body(""), String) - } - - @Issue("#546") - def "should convert DSL file to WireMock JSON with byte arrays"() { - given: - def converter = new DslToWireMockClientConverter() - and: - File file = tmpFolder.newFile("dsl1.groovy") - file.write(""" - [ - org.springframework.cloud.contract.spec.Contract.make { - request { - method "POST" - url "/multipart" - headers { - contentType('multipart/form-data') - } - multipart( - file: named( - name: value(stub(regex('.+')), test('file')), - content: value(stub(regex('.+')), test([100, 117, 100, 97] as byte[])) - ) - ) - } - response { - status 200 - body "hello" - } - } - ] -""") - when: - String json = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null, - ContractVerifierDslConverter.convertAsCollection(new File("/"), file))).values().first() - then: - JSONAssert.assertEquals(''' -{"request":{"url":"/multipart","method":"POST","headers":{"Content-Type":{"matches":"multipart/form-data.*"}},"bodyPatterns":[{"matches" : ".*--(.*)\\r?\\nContent-Disposition: form-data; name=\\"file\\"; filename=\\".+\\"\\r?\\n(Content-Type: .*\\r?\\n)?(Content-Transfer-Encoding: .*\\r?\\n)?(Content-Length: \\\\d+\\r?\\n)?\\r?\\n.+\\r?\\n--.*"}]},"response":{"status":200,"body":"hello","transformers":["response-template", "spring-cloud-contract" ]}} -''', json, false) - and: - StubMapping mapping = stubMappingIsValidWireMockStub(json) - and: - wireMockRule.addStubMapping(mapping) - and: - MultiValueMap parameters = new LinkedMultiValueMap() - parameters.add("file", new ByteArrayResource([100, 117, 100, 97] as byte[]) { - @Override - String getFilename() { - return "file" - } - }) - org.springframework.http.HttpHeaders headers = new org.springframework.http.HttpHeaders() - headers.set("Content-Type", "multipart/form-data;boundary=AaB03xssssss") - headers.set("Accept", "text/plain") - String result = restTemplate.postForObject( - "${url}/multipart", - new HttpEntity>(parameters, headers), - String.class) - result == "hello" - } - - def "should convert DSL file with list of contracts to WireMock JSONs"() { - given: - def converter = new DslToWireMockClientConverter() - and: - File file = tmpFolder.newFile("dsl1_list.groovy") - file.write(''' -(1..2).collect { int index -> - org.springframework.cloud.contract.spec.Contract.make { - request { - method(PUT()) - headers { - contentType(applicationJson()) - } - url "/${index}" - } - response { - status OK() - } - } -} -''') - when: - Map convertedContents = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null, - ContractVerifierDslConverter.convertAsCollection(new File("/"), file))) - then: - convertedContents.size() == 2 - JSONAssert.assertEquals(jsonResponse(1), convertedContents.values().first(), false) - JSONAssert.assertEquals(jsonResponse(2), convertedContents.values().last(), false) - and: - StubMapping mapping = stubMappingIsValidWireMockStub(convertedContents.values().first()) - StubMapping mapping2 = stubMappingIsValidWireMockStub(convertedContents.values().last()) - and: - wireMockRule.addStubMapping(mapping) - wireMockRule.addStubMapping(mapping2) - and: - restTemplate.exchange(RequestEntity.put("${url}/1".toURI()) - .header('Content-Type', 'application/json') - .body(""), String) - restTemplate.exchange(RequestEntity.put("${url}/2".toURI()) - .header('Content-Type', 'application/json') - .body(""), String) - } - - private String jsonResponse(int index) { - return """{"request":{"method":"PUT","url":"/${index}"},"response":{"status":200}}""" - } - - def "should not convert if contract is messaging related"() { - given: - def converter = new DslToWireMockClientConverter() - and: - File file = tmpFolder.newFile("dsl1_list.groovy") - file.write(''' - (1..2).collect { int index -> - org.springframework.cloud.contract.spec.Contract.make { - input { - triggeredBy("foo") - } - } - } - ''') - when: - Map convertedContents = converter.convertContents("Test", - new ContractMetadata(file.toPath(), false, 0, null, - ContractVerifierDslConverter.convertAsCollection(new File("/"), file))) - then: - convertedContents.isEmpty() - } - - @Issue("196") - def "should creation of delayed stub responses be possible"() { - given: - def converter = new DslToWireMockClientConverter() - and: - File file = tmpFolder.newFile("dsl-delay.groovy") - file.write(""" - org.springframework.cloud.contract.spec.Contract.make { - request { - method 'GET' - url '/foo' - } - response { - status OK() - fixedDelayMilliseconds 1000 - } - } -""") - when: - String json = converter.convertContents("test", new ContractMetadata(file.toPath(), false, 0, null, - ContractVerifierDslConverter.convertAsCollection(new File("/"), file))).values().first() - then: - JSONAssert.assertEquals(''' -{"request":{ - "url" : "/foo", - "method" : "GET"}, -"response":{ -"status":200,"fixedDelayMilliseconds":1000 -}} -''', json, false) - and: - StubMapping mapping = stubMappingIsValidWireMockStub(json) - and: - wireMockRule.addStubMapping(mapping) - and: - restTemplate.exchange(RequestEntity.get("${url}/foo".toURI()).build(), String) - } - - def "should convert DSL file with a nested list to WireMock JSON"() { - given: - def converter = new DslToWireMockClientConverter() - and: - File file = tmpFolder.newFile("dsl2.groovy") - file.write(""" - org.springframework.cloud.contract.spec.Contract.make { - request { - method 'PUT' - url '/api/12' - headers { - header 'Content-Type': 'application/vnd.org.springframework.cloud.contract.verifier.twitter-places-analyzer.v1+json' - } - body ''' - [{ - "created_at": "Sat Jul 26 09:38:57 +0000 2014", - "id": 492967299297845248, - "id_str": "492967299297845248", - "text": "Gonna see you at Warsaw", - "place": - { - "attributes":{}, - "bounding_box": - { - "coordinates": - [[ - [-77.119759,38.791645], - [-76.909393,38.791645], - [-76.909393,38.995548], - [-77.119759,38.995548] - ]], - "type":"Polygon" - }, - "country":"United States", - "country_code":"US", - "full_name":"Washington, DC", - "id":"01fbe706f872cb32", - "name":"Washington", - "place_type":"city", - "url": "https://api.twitter.com/1/geo/id/01fbe706f872cb32.json" - } - }] - ''' - } - response { - status OK() - } - } -""") - when: - String json = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null, - ContractVerifierDslConverter.convertAsCollection(new File("/"), file))).values().first() - then: - JSONAssert.assertEquals(''' -{ - "request" : { - "url" : "/api/12", - "method" : "PUT", - "bodyPatterns" : [ { - "matchesJsonPath" : "$[*].['place'].['bounding_box'].['coordinates'][*][*][?(@ == -77.119759)]" - }, { - "matchesJsonPath" : "$[*][?(@.['text'] == 'Gonna see you at Warsaw')]" - }, { - "matchesJsonPath" : "$[*].['place'][?(@.['place_type'] == 'city')]" - }, { - "matchesJsonPath" : "$[*][?(@.['id'] == 492967299297845248)]" - }, { - "matchesJsonPath" : "$[*].['place'].['bounding_box'].['coordinates'][*][*][?(@ == 38.791645)]" - }, { - "matchesJsonPath" : "$[*].['place'][?(@.['country'] == 'United States')]" - }, { - "matchesJsonPath" : "$[*][?(@.['id_str'] == '492967299297845248')]" - }, { - "matchesJsonPath" : "$[*].['place'].['bounding_box'].['coordinates'][*][*][?(@ == -76.909393)]" - }, { - "matchesJsonPath" : "$[*].['place'][?(@.['name'] == 'Washington')]" - }, { - "matchesJsonPath" : "$[*].['place'].['bounding_box'][?(@.['type'] == 'Polygon')]" - }, { - "matchesJsonPath" : "$[*].['place'][?(@.['url'] == 'https://api.twitter.com/1/geo/id/01fbe706f872cb32.json')]" - }, { - "matchesJsonPath" : "$[*].['place'].['bounding_box'].['coordinates'][*][*][?(@ == 38.995548)]" - }, { - "matchesJsonPath" : "$[*].['place'][?(@.['country_code'] == 'US')]" - }, { - "matchesJsonPath" : "$[*].['place'][?(@.['full_name'] == 'Washington, DC')]" - }, { - "matchesJsonPath" : "$[*][?(@.['created_at'] == 'Sat Jul 26 09:38:57 +0000 2014')]" - }, { - "matchesJsonPath" : "$[*].['place'][?(@.['id'] == '01fbe706f872cb32')]" - } ], - "headers" : { - "Content-Type" : { - "equalTo" : "application/vnd.org.springframework.cloud.contract.verifier.twitter-places-analyzer.v1+json" - } - } - }, - "response" : { - "status" : 200 - } -} -''', json, false) - and: - StubMapping mapping = stubMappingIsValidWireMockStub(json) - and: - wireMockRule.addStubMapping(mapping) - and: - restTemplate.exchange(RequestEntity.put("${url}/api/12".toURI()) - .header('Content-Type', 'application/vnd.org.springframework.cloud.contract.verifier.twitter-places-analyzer.v1+json') - .body(''' - [{ - "created_at": "Sat Jul 26 09:38:57 +0000 2014", - "id": 492967299297845248, - "id_str": "492967299297845248", - "text": "Gonna see you at Warsaw", - "place": - { - "attributes":{}, - "bounding_box": - { - "coordinates": - [[ - [-77.119759,38.791645], - [-76.909393,38.791645], - [-76.909393,38.995548], - [-77.119759,38.995548] - ]], - "type":"Polygon" - }, - "country":"United States", - "country_code":"US", - "full_name":"Washington, DC", - "id":"01fbe706f872cb32", - "name":"Washington", - "place_type":"city", - "url": "https://api.twitter.com/1/geo/id/01fbe706f872cb32.json" - } - }]'''), String) - } - - @Issue("262") - def "should create stub with map inside list"() { - given: - def converter = new DslToWireMockClientConverter() - and: - File file = tmpFolder.newFile("dsl-mapinlist.groovy") - file.write(""" - org.springframework.cloud.contract.spec.Contract.make { - request { - method 'GET' - urlPath '/foos' - } - response { - status OK() - body([[id: value( - consumer('123'), - producer(regex('[0-9]+')) - )], [id: value( - consumer('567'), - producer(regex('[0-9]+')) - )]]) - headers { - header 'Content-Type': 'application/json' - } - } - } -""") - when: - String json = converter.convertContents("test", new ContractMetadata(file.toPath(), false, 0, null, - ContractVerifierDslConverter.convertAsCollection(new File("/"), file))).values().first() - then: - JSONAssert.assertEquals(''' -{"request":{"urlPath":"/foos","method":"GET"},"response":{"body":"[{\\"id\\":\\"123\\"},{\\"id\\":\\"567\\"}]"}} -''', json, false) - and: - StubMapping mapping = stubMappingIsValidWireMockStub(json) - and: - wireMockRule.addStubMapping(mapping) - and: - def response = restTemplate.exchange(RequestEntity.get("${url}/foos".toURI()).build(), String) - response.headers.get('Content-Type') == ['application/json'] - JSONAssert.assertEquals('''[ { "id":"123" }, { "id": "567" } ]''', response.body, false) - } - - - @Issue("94") - def "should create stub when response has only one side of the dynamic value"() { - given: - def converter = new DslToWireMockClientConverter() - and: - File file = tmpFolder.newFile("dsl-dynamic.groovy") - file.write(""" - org.springframework.cloud.contract.spec.Contract.make { - request { - method 'GET' - urlPath '/foos' - } - response { - status OK() - body( - digit: \$(producer(regex('[0-9]{1}'))), - id: \$(producer(regex(number()))) - ) - } - } -""") - when: - String json = converter.convertContents("test", new ContractMetadata(file.toPath(), false, 0, null, - ContractVerifierDslConverter.convertAsCollection(new File("/"), file))).values().first() - then: - noExceptionThrown() - and: - !json.contains('cursor') - and: - StubMapping mapping = stubMappingIsValidWireMockStub(json) - and: - wireMockRule.addStubMapping(mapping) - and: - def response = restTemplate.exchange(RequestEntity.get("${url}/foos".toURI()).build(), String) - response.body - } - - def 'should convert dsl to wiremock to show it in the docs'() { - given: - def converter = new DslToWireMockClientConverter() - and: - File file = tmpFolder.newFile("dsl_from_docs.groovy") - file.write(''' - org.springframework.cloud.contract.spec.Contract.make { - priority 1 - request { - method 'POST' - url '/users/password' - headers { - header 'Content-Type': 'application/json' - } - body( - email: $(consumer(optional(regex(email()))), producer('abc@abc.com')), - callback_url: $(consumer(regex(hostname())), producer('https://partners.com')) - ) - } - response { - status 404 - headers { - header 'Content-Type': 'application/json' - } - body( - code: value(consumer("123123"), producer(optional("123123"))), - message: "User not found by email == [${value(producer(regex(email())), consumer('not.existing@user.com'))}]" - ) - } - } - ''') - when: - String json = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null, - ContractVerifierDslConverter.convertAsCollection(new File("/"), file))).values().first() - then: - JSONAssert.assertEquals( // tag::wiremock[] - ''' -{ - "request" : { - "url" : "/users/password", - "method" : "POST", - "bodyPatterns" : [ { - "matchesJsonPath" : "$[?(@.['email'] =~ /([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,6})?/)]" - }, { - "matchesJsonPath" : "$[?(@.['callback_url'] =~ /((http[s]?|ftp):\\\\/)\\\\/?([^:\\\\/\\\\s]+)(:[0-9]{1,5})?/)]" - } ], - "headers" : { - "Content-Type" : { - "equalTo" : "application/json" - } - } - }, - "response" : { - "status" : 404, - "body" : "{\\"code\\":\\"123123\\",\\"message\\":\\"User not found by email == [not.existing@user.com]\\"}", - "headers" : { - "Content-Type" : "application/json" - } - }, - "priority" : 1 -} -''' -// end::wiremock[] - , json, false) - and: - StubMapping mapping = stubMappingIsValidWireMockStub(json) - and: - wireMockRule.addStubMapping(mapping) - and: - def response = restTemplate.exchange(RequestEntity.post("${url}/users/password".toURI()) - .header("Content-Type", "application/json") - .body('''{"email":"abc@abc.com", "callback_url":"https://partners.com"}''') - , String) - response.headers.get('Content-Type') == ['application/json'] - response.statusCodeValue == 404 - JSONAssert.assertEquals('''{"code":"123123","message":"User not found by email == [not.existing@user.com]"}"''', response.body, false) - } - - def 'should convert dsl to wiremock with stub matchers'() { - given: - def converter = new DslToWireMockClientConverter() - and: - File file = tmpFolder.newFile("dsl_from_docs.groovy") - file.write(''' - org.springframework.cloud.contract.spec.Contract.make { - request { - method 'POST' - urlPath '/get' - body([ - duck: 123, - alpha: "abc", - number: 123, - aBoolean: true, - date: "2017-01-01", - dateTime: "2017-01-01T01:23:45", - time: "01:02:34", - valueWithoutAMatcher: "foo", - valueWithTypeMatch: "string", - list: [ - some: [ - nested: [ - json: "with value", - anothervalue: 4 - ] - ], - someother: [ - nested: [ - json: "with value", - anothervalue: 4 - ] - ] - ], - valueWithMin: [ - 1,2,3 - ], - valueWithMax: [ - 1,2,3 - ], - valueWithMinMax: [ - 1,2,3 - ] - ]) - bodyMatchers { - jsonPath('$.duck', byRegex("[0-9]{3}")) - jsonPath('$.duck', byEquality()) - jsonPath('$.alpha', byRegex(onlyAlphaUnicode())) - jsonPath('$.alpha', byEquality()) - jsonPath('$.number', byRegex(number())) - jsonPath('$.aBoolean', byRegex(anyBoolean())) - jsonPath('$.date', byDate()) - jsonPath('$.dateTime', byTimestamp()) - jsonPath('$.time', byTime()) - jsonPath('$.list.some.nested.json', byRegex(".*")) - jsonPath('$.valueWithMin', byType { - // results in verification of size of array (min 1) - minOccurrence(1) - }) - jsonPath('$.valueWithMax', byType { - // results in verification of size of array (max 3) - maxOccurrence(3) - }) - jsonPath('$.valueWithMinMax', byType { - // results in verification of size of array (min 1 & max 3) - minOccurrence(1) - maxOccurrence(3) - }) - jsonPath('$.valueWithOccurrence', byType { - // results in verification of size of array (min 4 & max 4) - occurrence(4) - }) - } - headers { - contentType(applicationJson()) - } - } - response { - status OK() - body([ - duck: 123, - alpha: "abc", - number: 123, - aBoolean: true, - date: "2017-01-01", - dateTime: "2017-01-01T01:23:45", - time: "01:02:34", - valueWithoutAMatcher: "foo", - valueWithTypeMatch: "string", - valueWithMin: [ - 1,2,3 - ], - valueWithMax: [ - 1,2,3 - ], - valueWithMinMax: [ - 1,2,3 - ], - valueWithOccurrence: [ - 1,2,3,4 - ], - ]) - bodyMatchers { - // asserts the jsonpath value against manual regex - jsonPath('$.duck', byRegex("[0-9]{3}")) - jsonPath('$.duck', byEquality()) - // asserts the jsonpath value against some default regex - jsonPath('$.alpha', byRegex(onlyAlphaUnicode())) - jsonPath('$.alpha', byEquality()) - jsonPath('$.number', byRegex(number())) - jsonPath('$.aBoolean', byRegex(anyBoolean())) - // asserts vs inbuilt time related regex - jsonPath('$.date', byDate()) - jsonPath('$.dateTime', byTimestamp()) - jsonPath('$.time', byTime()) - // asserts that the resulting type is the same as in response body - jsonPath('$.valueWithTypeMatch', byType()) - jsonPath('$.valueWithMin', byType { - // results in verification of size of array (min 1) - minOccurrence(1) - }) - jsonPath('$.valueWithMax', byType { - // results in verification of size of array (max 3) - maxOccurrence(3) - }) - jsonPath('$.valueWithMinMax', byType { - // results in verification of size of array (min 1 & max 3) - minOccurrence(1) - maxOccurrence(3) - }) - jsonPath('$.valueWithOccurrence', byType { - // results in verification of size of array (min 4 & max 4) - occurrence(4) - }) - } - headers { - contentType(applicationJson()) - } - } - } - ''') - when: - String json = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null, - ContractVerifierDslConverter.convertAsCollection(new File("/"), file))).values().first() - then: - JSONAssert.assertEquals(//tag::matchers[] - ''' -{ - "request" : { - "urlPath" : "/get", - "method" : "POST", - "headers" : { - "Content-Type" : { - "matches" : "application/json.*" - } - }, - "bodyPatterns" : [ { - "matchesJsonPath" : "$.['list'].['some'].['nested'][?(@.['anothervalue'] == 4)]" - }, { - "matchesJsonPath" : "$[?(@.['valueWithoutAMatcher'] == 'foo')]" - }, { - "matchesJsonPath" : "$[?(@.['valueWithTypeMatch'] == 'string')]" - }, { - "matchesJsonPath" : "$.['list'].['someother'].['nested'][?(@.['json'] == 'with value')]" - }, { - "matchesJsonPath" : "$.['list'].['someother'].['nested'][?(@.['anothervalue'] == 4)]" - }, { - "matchesJsonPath" : "$[?(@.duck =~ /([0-9]{3})/)]" - }, { - "matchesJsonPath" : "$[?(@.duck == 123)]" - }, { - "matchesJsonPath" : "$[?(@.alpha =~ /([\\\\p{L}]*)/)]" - }, { - "matchesJsonPath" : "$[?(@.alpha == 'abc')]" - }, { - "matchesJsonPath" : "$[?(@.number =~ /(-?(\\\\d*\\\\.\\\\d+|\\\\d+))/)]" - }, { - "matchesJsonPath" : "$[?(@.aBoolean =~ /((true|false))/)]" - }, { - "matchesJsonPath" : "$[?(@.date =~ /((\\\\d\\\\d\\\\d\\\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01]))/)]" - }, { - "matchesJsonPath" : "$[?(@.dateTime =~ /(([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9]))/)]" - }, { - "matchesJsonPath" : "$[?(@.time =~ /((2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9]))/)]" - }, { - "matchesJsonPath" : "$.list.some.nested[?(@.json =~ /(.*)/)]" - }, { - "matchesJsonPath" : "$[?(@.valueWithMin.size() >= 1)]" - }, { - "matchesJsonPath" : "$[?(@.valueWithMax.size() <= 3)]" - }, { - "matchesJsonPath" : "$[?(@.valueWithMinMax.size() >= 1 && @.valueWithMinMax.size() <= 3)]" - }, { - "matchesJsonPath" : "$[?(@.valueWithOccurrence.size() >= 4 && @.valueWithOccurrence.size() <= 4)]" - } ] - }, - "response" : { - "status" : 200, - "body" : "{\\"duck\\":123,\\"alpha\\":\\"abc\\",\\"number\\":123,\\"aBoolean\\":true,\\"date\\":\\"2017-01-01\\",\\"dateTime\\":\\"2017-01-01T01:23:45\\",\\"time\\":\\"01:02:34\\",\\"valueWithoutAMatcher\\":\\"foo\\",\\"valueWithTypeMatch\\":\\"string\\",\\"valueWithMin\\":[1,2,3],\\"valueWithMax\\":[1,2,3],\\"valueWithMinMax\\":[1,2,3],\\"valueWithOccurrence\\":[1,2,3,4]}", - "headers" : { - "Content-Type" : "application/json" - }, - "transformers" : [ "response-template", "spring-cloud-contract" ] - } -} -''' -//end::matchers[] - , json, false) - and: - StubMapping mapping = stubMappingIsValidWireMockStub(json) - and: - wireMockRule.addStubMapping(mapping) - and: - def response = restTemplate.exchange(RequestEntity.post("${url}/get".toURI()) - .header("Content-Type", "application/json") - .body(JsonOutput.toJson([ - duck : 123, - alpha : "abc", - number : 123, - aBoolean : true, - date : "2017-01-01", - dateTime : "2017-01-01T01:23:45", - time : "01:02:34", - valueWithoutAMatcher: "foo", - valueWithTypeMatch : "string", - list : [ - some : [ - nested: [ - json : "with value", - anothervalue: 4 - ] - ], - someother: [ - nested: [ - json : "with value", - anothervalue: 4 - ] - ] - ], - valueWithMin : [ - 1, 2, 3 - ], - valueWithMax : [ - 1, 2, 3 - ], - valueWithMinMax : [ - 1, 2, 3 - ], - valueWithOccurrence : [ - 1, 2, 3, 4 - ] - ])) - , String) - response.headers.get('Content-Type') == ['application/json'] - response.statusCodeValue == 200 - JSONAssert.assertEquals(JsonOutput.toJson([ - duck : 123, - alpha : "abc", - number : 123, - aBoolean : true, - date : "2017-01-01", - dateTime : "2017-01-01T01:23:45", - time : "01:02:34", - valueWithoutAMatcher: "foo", - valueWithTypeMatch : "string", - valueWithMin : [ - 1, 2, 3 - ], - valueWithMax : [ - 1, 2, 3 - ], - valueWithMinMax : [ - 1, 2, 3 - ], - valueWithOccurrence : [ - 1, 2, 3, 4 - ], - ]), response.body, false) - } - - def 'should convert dsl to wiremock with stub matchers with docs example'() { - given: - def converter = new DslToWireMockClientConverter() - and: - File file = tmpFolder.newFile("dsl_from_docs.groovy") - file.write(''' - org.springframework.cloud.contract.spec.Contract.make { - priority 1 - request { - method 'POST' - url '/users/password2' - headers { - header 'Content-Type': 'application/json' - } - body( - email: 'abc@abc.com', - callback_url: 'https://partners.com' - ) - bodyMatchers { - jsonPath('$.[\\'email\\']', byRegex(email())) - jsonPath('$.[\\'callback_url\\']', byRegex(hostname())) - } - } - response { - status 404 - headers { - header 'Content-Type': 'application/json' - } - body( - code: "123123", - message: "User not found by email == [not.existing@user.com]" - ) - bodyMatchers { - jsonPath('$.code', byRegex("123123")) - jsonPath('$.message', byRegex("User not found by email == ${email()}")) - } - } - } - ''') - when: - String json = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null, - ContractVerifierDslConverter.convertAsCollection(new File("/"), file))).values().first() - then: - JSONAssert.assertEquals( - ''' - { - "request" : { - "url" : "/users/password2", - "method" : "POST", - "bodyPatterns" : [ { - "matchesJsonPath" : "$[?(@.['email'] =~ /([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,6})/)]" - }, { - "matchesJsonPath" : "$[?(@.['callback_url'] =~ /(((http[s]?|ftp):\\\\/)\\\\/?([^:\\\\/\\\\s]+)(:[0-9]{1,5})?)/)]" - } ], - "headers" : { - "Content-Type" : { - "equalTo" : "application/json" - } - } - }, - "response" : { - "status" : 404, - "body" : "{\\"code\\":\\"123123\\",\\"message\\":\\"User not found by email == [not.existing@user.com]\\"}", - "headers" : { - "Content-Type" : "application/json" - } - }, - "priority" : 1 - } - ''' - , json, false) - and: - StubMapping mapping = stubMappingIsValidWireMockStub(json) - and: - wireMockRule.addStubMapping(mapping) - and: - def response = restTemplate.exchange(RequestEntity.post("${url}/users/password2".toURI()) - .header("Content-Type", "application/json") - .body('''{"email":"abc@abc.com", "callback_url":"https://partners.com"}''') - , String) - response.headers.get('Content-Type') == ['application/json'] - response.statusCodeValue == 404 - JSONAssert.assertEquals('''{"code":"123123","message":"User not found by email == [not.existing@user.com]"}"''', response.body, false) - } - - @Issue("#515") - def 'should not escape any java chars in the javascript WireMock stub'() { - given: - def converter = new DslToWireMockClientConverter() - and: - File file = tmpFolder.newFile("dsl_from_docs.groovy") - file.write(''' - org.springframework.cloud.contract.spec.Contract.make { - priority 1 - request { - method 'POST' - url '/users/password2' - headers { - header 'Content-Type': 'application/json' - } - body( - email: 'abc@abc.com', - callback_url: 'https://partners.com' - ) - bodyMatchers { - jsonPath('$.[\\'email\\']', byRegex(email())) - jsonPath('$.[\\'callback_url\\']', byRegex(hostname())) - } - } - response { - status 400 - headers { - header 'CorrelationID': '11111111-1111-1111-1111-111111111111\' - header 'Content-Type': value(test(regex('application/json(;.*)?')), stub('application/json;charset=UTF-8')) - } - body( - [ - subject: [ - '@type' :'ErrorSubject', - 'oid' :'8.2', - 'description':'Profile' - ], - reason : [ - '@type' :'ErrorReason', - 'oid' :'3.7', - 'description':'Bad Request', - 'httpCode':'400' - ], - message: '[8.2 Profile/3.7 Bad Request]\' - ] - ) - } - } - ''') - when: - String json = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null, - ContractVerifierDslConverter.convertAsCollection(new File("/"), file))).values().first() - then: - JSONAssert.assertEquals( - ''' - { - "request" : { - "url" : "/users/password2", - "method" : "POST", - "headers" : { - "Content-Type" : { - "equalTo" : "application/json" - } - }, - "bodyPatterns" : [ { - "matchesJsonPath" : "$[?(@.['email'] =~ /([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,6})/)]" - }, { - "matchesJsonPath" : "$[?(@.['callback_url'] =~ /(((http[s]?|ftp):\\\\/)\\\\/?([^:\\\\/\\\\s]+)(:[0-9]{1,5})?)/)]" - } ] - }, - "response" : { - "status" : 400, - "body" : "{\\"subject\\":{\\"@type\\":\\"ErrorSubject\\",\\"oid\\":\\"8.2\\",\\"description\\":\\"Profile\\"},\\"reason\\":{\\"@type\\":\\"ErrorReason\\",\\"oid\\":\\"3.7\\",\\"description\\":\\"Bad Request\\",\\"httpCode\\":\\"400\\"},\\"message\\":\\"[8.2 Profile/3.7 Bad Request]\\"}", - "headers" : { - "CorrelationID" : "11111111-1111-1111-1111-111111111111", - "Content-Type" : "application/json;charset=UTF-8" - }, - "transformers" : [ "response-template", "spring-cloud-contract" ] - }, - "priority" : 1 - } - } - ''' - , json, false) - and: - StubMapping mapping = stubMappingIsValidWireMockStub(json) - and: - wireMockRule.addStubMapping(mapping) - and: - def response = restTemplate.exchange(RequestEntity.post("${url}/users/password2".toURI()) - .header("Content-Type", "application/json") - .body('''{"email":"abc@abc.com", "callback_url":"https://partners.com"}''') - , String) - response.headers.get('Content-Type') == ['application/json;charset=UTF-8'] - response.statusCodeValue == 400 - JSONAssert.assertEquals('''{"message":"[8.2 Profile/3.7 Bad Request]"}"''', response.body, false) - } - - @Issue("#449") - def 'should properly convert regex for headers'() { - given: - def converter = new DslToWireMockClientConverter() - and: - File file = tmpFolder.newFile("dsl_from_docs.groovy") - file.write(''' - org.springframework.cloud.contract.spec.Contract.make { - request { - method 'GET' - urlPath($( - consumer(regex('/v1/communities/(.+)/channels/[0-9]+')), - producer('/v1/communities/contract/channels/1'))) - - headers { - header("X-Smartup-Test", - $( - consumer(regex(nonEmpty())), - producer(1))) - } - } - response { - status 204 - } - } - ''') - when: - String json = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null, - ContractVerifierDslConverter.convertAsCollection(new File("/"), file))).values().first() - then: - JSONAssert.assertEquals( - ''' - { - "request" : { - "urlPathPattern" : "/v1/communities/(.+)/channels/[0-9]+", - "method" : "GET", - "headers" : { - "X-Smartup-Test" : { - "matches" : "[\\\\S\\\\s]+" - } - } - }, - "response" : { - "status" : 204 - } - } - ''' - , json, false) - and: - StubMapping mapping = stubMappingIsValidWireMockStub(json) - and: - wireMockRule.addStubMapping(mapping) - and: - def response = restTemplate.exchange(RequestEntity - .get("${url}/v1/communities/abc/channels/123".toURI()) - .header("X-Smartup-Test", "asd123") - .build() - , String) - response.statusCodeValue == 204 - } - - - @Issue("1727") - def "should create WireMock JSON() with no duplicate metadata fields"() { - given: - def converter = new DslToWireMockClientConverter() - and: - File file = tmpFolder.newFile("stub_mapping_duplicate.groovy") - file.write(""" - org.springframework.cloud.contract.spec.Contract.make { - request { - method 'POST' - url ('/ping') - } - response { - status 200 - } - - metadata([wiremock: [ - stubMapping: ''' { - "postServeActions" :{ - "webhook" : { - "url" : "/pong", - "method" : "PATCH" - } - } - }''']]) - } -""") - when: - String json = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null, - ContractVerifierDslConverter.convertAsCollection(new File("/"), file))).values().first() - then: - JSONAssert.assertEquals(""" - { - "request" : { - "url" : "/ping", - "method" : "POST" - }, - "response" : { - "status" : 200 - }, - "postServeActions" : [ { - "name" : "webhook", - "parameters" : { - "url" : "/pong", - "method" : "PATCH" - } - } ] - }""", json, false) - } - - StubMapping stubMappingIsValidWireMockStub(String mappingDefinition) { - StubMapping stubMapping = WireMockStubMapping.buildFrom(mappingDefinition) - stubMapping.request.bodyPatterns.findAll { it.isPresent() && it instanceof RegexPattern }.every { - Pattern.compile(it.getValue()) - } - assert !mappingDefinition.contains('org.springframework.cloud.contract.spec.internal') - return stubMapping - } - - @Issue("1656") - def "should convert DSL file to WireMock JSON with array"() { - given: - def converter = new DslToWireMockClientConverter() - and: - File file = tmpFolder.newFile("dsl1656.groovy") - file.write(''' - org.springframework.cloud.contract.spec.Contract.make { - request { - method "GET" - url "/api/foo/61923376" - headers { - accept 'application/json' - } - } - response { - status OK() - headers { - contentType(applicationJson()) - } - //language=JSON - body( - """ - [ - 813146, - 814952, - 813102, - 813282 - ] - """ - ) - } - } - ''') - when: - String json = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null, - ContractVerifierDslConverter.convertAsCollection(new File("/"), file))).values().first() - then: - JSONAssert.assertEquals(''' - { - "request" : { - "url" : "/api/foo/61923376", - "method" : "GET", - "headers" : { - "Accept" : { - "matches" : "application/json.*" - } - } - }, - "response" : { - "status" : 200, - "body" : "[813146,814952,813102,813282]", - "headers" : { - "Content-Type" : "application/json" - }, - "transformers" : [ "response-template", "spring-cloud-contract" ] - } - }''', json, false) - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/WireMockToDslConverterSpec.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/WireMockToDslConverterSpec.groovy deleted file mode 100755 index ef997ee7ad..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/WireMockToDslConverterSpec.groovy +++ /dev/null @@ -1,576 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.wiremock - -import java.util.regex.Pattern - -import spock.lang.Specification - -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.spec.internal.RegexProperty -import org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockStubMapping -import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter - -class WireMockToDslConverterSpec extends Specification { - - def 'should produce a Groovy DSL from WireMock stub'() { - given: - String wireMockStub = '''\ -{ - "request": { - "method": "GET", - "url": "/path", - "headers" : { - "X-Custom-Header": { - "contains": "2134" - }, - "Accept": { - "matches": "text/.*" - } - } - }, - "response": { - "status": 200, - "body": '{"id": { "value": "132" }, "surname": "Kowalsky", "name": "Jan", "created": "2014-02-02 12:23:43" }', - "headers": { - "Content-Type": "text/plain" - } - } -} -''' - and: - stubMappingIsValidWireMockStub(wireMockStub) - and: - Contract expectedGroovyDsl = Contract.make { - request { - method 'GET' - url '/path' - headers { - header('X-Custom-Header': $( - consumer(regex('^.*2134.*$')), - producer('121345') - )) - header('Accept': $( - consumer(regex('text/.*')), - producer('text/plain') - )) - } - } - response { - status OK() - body("""{ - "id": { - "value": "132" - }, - "surname": "Kowalsky", - "name": "Jan", - "created": "2014-02-02 12:23:43" -}""") - headers { - header 'Content-Type': 'text/plain' - } - } - } - when: - String groovyDsl = WireMockToDslConverter.fromWireMockStub(wireMockStub) - then: - def contracts = ContractVerifierDslConverter.convertAsCollection(new File("/"), - """org.springframework.cloud.contract.spec.Contract.make { - $groovyDsl - }""") - def b = expectedGroovyDsl - def a = contracts.first() - a.request.method == b.request.method - a.request.url == b.request.url - a.request.headers.entries.find { it.name == 'X-Custom-Header'}.clientValue.pattern() == - b.request.headers.entries.find { it.name == 'X-Custom-Header'}.clientValue.pattern() - a.request.headers.entries.find { it.name == 'Accept'}.clientValue.pattern() == - b.request.headers.entries.find { it.name == 'Accept'}.clientValue.pattern() - a.response == b.response - } - - - def 'should convert WireMock stub with response body containing JSON with escaped double quotes'() { - given: - String wireMockStub = '''\ -{ - "request": { - "method": "DELETE", - "urlPattern": "1", - "headers": { - "Content-Type": { - "equalTo": "application/vnd.mymoid-adapter.v2+json; charset=UTF-8" - } - } - }, - "response": { - "status": 200, - "body": "{\\"status\\": \\"OK\\"}", - "headers": { - "Content-Type": "application/json" - } - } -} -''' - and: - stubMappingIsValidWireMockStub(wireMockStub) - and: - Contract expectedGroovyDsl = Contract.make { - request { - method 'DELETE' - url $(consumer(~/1/), producer('1')) - headers { - header('Content-Type': 'application/vnd.mymoid-adapter.v2+json; charset=UTF-8') - } - } - response { - status OK() - body("""{ - "status": "OK" -}""") - headers { - header 'Content-Type': 'application/json' - } - } - } - when: - String groovyDsl = WireMockToDslConverter.fromWireMockStub(wireMockStub) - then: - def a = ContractVerifierDslConverter.convertAsCollection(new File("/"), - """org.springframework.cloud.contract.spec.Contract.make { - $groovyDsl - }""") - def b = expectedGroovyDsl - (a.first().request.url.clientValue as RegexProperty).pattern() == (b.request.url.clientValue as Pattern).pattern() - } - - def 'should convert WireMock stub with response body containing integer'() { - given: - String wireMockStub = '''\ -{ - "request": { - "method": "POST", - "url": "/charge/count", - "headers": { - "Content-Type": { - "equalTo": "application/vnd.creditcard-reporter.v1+json" - } - } - }, - "response": { - "status": 200, - "body": 200, - "headers": { - "Content-Type": "application/json" - } - } -} -''' - and: - stubMappingIsValidWireMockStub(wireMockStub) - and: - Contract expectedGroovyDsl = Contract.make { - request { - method 'POST' - url '/charge/count' - headers { - header('Content-Type': 'application/vnd.creditcard-reporter.v1+json') - } - } - response { - status OK() - body(200) - headers { - header 'Content-Type': 'application/json' - - } - } - } - when: - String groovyDsl = WireMockToDslConverter.fromWireMockStub(wireMockStub) - then: - ContractVerifierDslConverter.convertAsCollection(new File("/"), - """org.springframework.cloud.contract.spec.Contract.make { - $groovyDsl - }""").first() == expectedGroovyDsl - } - - def 'should convert WireMock stub with response body as a list'() { - given: - String wireMockStub = '''\ -{ - "request": { - "method": "POST", - "url": "/charge/count", - "headers": { - "Content-Type": { - "equalTo": "application/vnd.creditcard-reporter.v1+json" - } - } - }, - "response": { - "status": 200, - "body": '[ {"a":1, "c":"3"}, "b", "a" ]', - "headers": { - "Content-Type": "application/json" - } - } -} -''' - and: - stubMappingIsValidWireMockStub(wireMockStub) - and: - Contract expectedGroovyDsl = Contract.make { - request { - method 'POST' - url '/charge/count' - headers { - header('Content-Type': 'application/vnd.creditcard-reporter.v1+json') - } - } - response { - status OK() - body("""[ - { - "a": 1, - "c": "3" - }, - "b", - "a" -]""") - headers { - header 'Content-Type': 'application/json' - } - } - } - when: - String groovyDsl = WireMockToDslConverter.fromWireMockStub(wireMockStub) - then: - ContractVerifierDslConverter.convertAsCollection(new File("/"), - """org.springframework.cloud.contract.spec.Contract.make { - $groovyDsl - }""").first() == expectedGroovyDsl - } - - def 'should convert WireMock stub with response body containing a nested list'() { - given: - String wireMockStub = '''\ -{ - "request": { - "method": "POST", - "url": "/charge/search?pageNumber=0&size=2147483647", - "headers": { - "Content-Type": { - "equalTo": "application/vnd.creditcard-reporter.v1+json" - } - } - }, - "response": { - "status": 200, - "body": '[{"amount":1.01, "name":"Name", "info":{"title":"title1", "payload":null}, "booleanvalue":true, "user":null}, {"amount":2.01, "name":"Name2", "info":{"title":"title2", "payload":null}, "booleanvalue":true, "user":null}]' - } -} -''' - and: - stubMappingIsValidWireMockStub(wireMockStub) - and: - Contract expectedGroovyDsl = Contract.make { - request { - method 'POST' - url '/charge/search?pageNumber=0&size=2147483647' - headers { - header('Content-Type': 'application/vnd.creditcard-reporter.v1+json') - } - } - response { - status OK() - body("""[ - { - "amount": 1.01, - "name": "Name", - "info": { - "title": "title1", - "payload": null - }, - "booleanvalue": true, - "user": null - }, - { - "amount": 2.01, - "name": "Name2", - "info": { - "title": "title2", - "payload": null - }, - "booleanvalue": true, - "user": null - } -]""") - } - } - when: - String groovyDsl = WireMockToDslConverter.fromWireMockStub(wireMockStub) - then: - ContractVerifierDslConverter.convertAsCollection(new File("/"), - """org.springframework.cloud.contract.spec.Contract.make { - $groovyDsl - }""").first() == expectedGroovyDsl - } - - def 'should convert WireMock stub with request body checking equality to Json'() { - given: - String wireMockStub = '''\ -{ - "request": { - "method": "POST", - "url": "/test", - "bodyPatterns": [{ - "equalTo": '{"property1":"abc", "property2":"2017-01", "property3":"666", "property4":1428566412}' - }] - }, - "response": { - "status": 200 - } -} -''' - and: - stubMappingIsValidWireMockStub(wireMockStub) - and: - Contract expectedGroovyDsl = Contract.make { - request { - method 'POST' - url '/test' - body('''{"property1":"abc", "property2":"2017-01", "property3":"666", "property4":1428566412}''') - } - response { - status OK() - } - } - when: - String groovyDsl = WireMockToDslConverter.fromWireMockStub(wireMockStub) - then: - Contract evaluatedGroovyDsl = ContractVerifierDslConverter.convertAsCollection(new File("/"), - """org.springframework.cloud.contract.spec.Contract.make { - $groovyDsl - }""").first() - and: - evaluatedGroovyDsl == expectedGroovyDsl - } - - def 'should convert WireMock stub with request body checking matching to Json'() { - given: - String wireMockStub = '''\ -{ - "request": { - "method": "POST", - "url": "/test", - "bodyPatterns": [{ - "matches": "1" - }] - }, - "response": { - "status": 200 - } -} -''' - and: - stubMappingIsValidWireMockStub(wireMockStub) - and: - Contract expectedGroovyDsl = Contract.make { - request { - method 'POST' - url '/test' - body $(consumer(~/1/), producer('1')) - } - response { - status OK() - } - } - when: - String groovyDsl = WireMockToDslConverter.fromWireMockStub(wireMockStub) - then: - Contract evaluatedGroovyDsl = ContractVerifierDslConverter.convertAsCollection(new File("/"), - """org.springframework.cloud.contract.spec.Contract.make { - $groovyDsl - }""").first() - and: - (evaluatedGroovyDsl.request.body.clientValue as RegexProperty).pattern() == (expectedGroovyDsl.request.body.clientValue as Pattern).pattern() - } - - def 'should convert WireMock stub with request body with equalToJson'() { - given: - String wireMockStub = '''\ -{ - "request" : { - "url" : "/test", - "method" : "POST", - "bodyPatterns" : [ { - "equalToJson" : '{"pan":"4855141150107894", "expirationDate":"2017-01", "dcvx":"178"}', - "jsonCompareMode" : "LENIENT" - } ] - }, - "response" : { - "status" : 200 - } -} -''' - and: - stubMappingIsValidWireMockStub(wireMockStub) - and: - Contract expectedGroovyDsl = Contract.make { - request { - method 'POST' - url '/test' - body '''{"pan":"4855141150107894", "expirationDate":"2017-01", "dcvx":"178"}''' - } - response { - status OK() - } - } - when: - String groovyDsl = WireMockToDslConverter.fromWireMockStub(wireMockStub) - then: - Contract evaluatedGroovyDsl = ContractVerifierDslConverter.convertAsCollection(new File("/"), - """org.springframework.cloud.contract.spec.Contract.make { - $groovyDsl - }""").first() - and: - evaluatedGroovyDsl == expectedGroovyDsl - } - - def 'should convert WireMock stub with request body with equalTo'() { - given: - String wireMockStub = '''\ - { - "request" : { - "url" : "/test", - "method" : "POST", - "bodyPatterns" : [ { - "equalTo" : '{"pan":"4855141150107894", "expirationDate":"2017-01", "dcvx":"178"}' - } ] - }, - "response" : { - "status" : 200 - } - } - ''' - and: - stubMappingIsValidWireMockStub(wireMockStub) - and: - Contract expectedGroovyDsl = Contract.make { - request { - method 'POST' - url '/test' - body '''{"pan":"4855141150107894", "expirationDate":"2017-01", "dcvx":"178"}''' - } - response { - status OK() - } - } - when: - String groovyDsl = WireMockToDslConverter.fromWireMockStub(wireMockStub) - then: - Contract evaluatedGroovyDsl = ContractVerifierDslConverter.convertAsCollection(new File("/"), - """org.springframework.cloud.contract.spec.Contract.make { - $groovyDsl - }""").first() - and: - evaluatedGroovyDsl == expectedGroovyDsl - } - - def 'should convert WireMock stub with request body with matches'() { - given: - String wireMockStub = '''\ - { - "request" : { - "url" : "/test", - "method" : "POST", - "bodyPatterns" : [ { - "matches" : "1" - } ] - }, - "response" : { - "status" : 200 - } - } - ''' - and: - stubMappingIsValidWireMockStub(wireMockStub) - and: - Contract expectedGroovyDsl = Contract.make { - request { - method 'POST' - url '/test' - body $(consumer(~/1/), producer('1')) - } - response { - status OK() - } - } - when: - String groovyDsl = WireMockToDslConverter.fromWireMockStub(wireMockStub) - then: - Contract evaluatedGroovyDsl = ContractVerifierDslConverter.convertAsCollection(new File("/"), - """org.springframework.cloud.contract.spec.Contract.make { - $groovyDsl - }""").first() - and: - (evaluatedGroovyDsl.request.body.clientValue as RegexProperty).pattern() == (expectedGroovyDsl.request.body.clientValue as Pattern).pattern() - } - - def 'should convert WireMock stub with priorities'() { - given: - String wireMockStub = '''\ - { - "priority" : 2, - "request" : { - "url" : "/test", - "method" : "POST" - }, - "response" : { - "status" : 200 - } - } - ''' - and: - stubMappingIsValidWireMockStub(wireMockStub) - and: - Contract expectedGroovyDsl = Contract.make { - priority 2 - request { - method 'POST' - url '/test' - } - response { - status OK() - } - } - when: - String groovyDsl = WireMockToDslConverter.fromWireMockStub(wireMockStub) - then: - Contract evaluatedGroovyDsl = ContractVerifierDslConverter.convertAsCollection(new File("/"), - """org.springframework.cloud.contract.spec.Contract.make { - $groovyDsl - }""").first() - and: - evaluatedGroovyDsl == expectedGroovyDsl - } - - void stubMappingIsValidWireMockStub(String mappingDefinition) { - WireMockStubMapping.buildFrom(mappingDefinition) - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/WiremockScenarioConverterSpec.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/WiremockScenarioConverterSpec.groovy deleted file mode 100755 index a1fc774c54..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/WiremockScenarioConverterSpec.groovy +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.wiremock - -import java.nio.file.Path -import java.nio.file.Paths - -import spock.lang.Specification - -import org.springframework.cloud.contract.verifier.file.ContractMetadata -import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter - -class WiremockScenarioConverterSpec extends Specification { - - def "should generate first scenario step"() { - given: - DslToWireMockClientConverter converter = new DslToWireMockClientConverter() - Path dsl = Paths.get(this.getClass().getResource("/converter/scenario/main_scenario/01_login.groovy").toURI()) - when: - String content = converter.convertContents("Test", new ContractMetadata(dsl, false, 3, 0, - ContractVerifierDslConverter.convertAsCollection(new File("/"), dsl.toFile()))).values().first() - then: - content.contains('"requiredScenarioState" : "Started"') - content.contains('"newScenarioState" : "Step1"') - content.contains('"scenarioName" : "Scenario_Test"') - } - - def "should generate mid scenario step"() { - given: - DslToWireMockClientConverter converter = new DslToWireMockClientConverter() - Path dsl = Paths.get(this.getClass().getResource("/converter/scenario/main_scenario/02_showCart.groovy").toURI()) - when: - String content = converter.convertContents("Test", new ContractMetadata(dsl, false, 3, 1, - ContractVerifierDslConverter.convertAsCollection(new File("/"), dsl.toFile()))).values().first() - then: - content.contains('"requiredScenarioState" : "Step1"') - content.contains('"newScenarioState" : "Step2"') - content.contains('"scenarioName" : "Scenario_Test"') - } - - def "should generate last scenario step"() { - given: - DslToWireMockClientConverter converter = new DslToWireMockClientConverter() - Path dsl = Paths.get(this.getClass().getResource("/converter/scenario/main_scenario/03_logout.groovy").toURI()) - when: - String content = converter.convertContents("Test", new ContractMetadata(dsl, false, 3, 2, - ContractVerifierDslConverter.convertAsCollection(new File("/"), dsl.toFile()))).values().first() - then: - content.contains('"requiredScenarioState" : "Step2"') - !content.contains('"newScenarioState"') - content.contains('"scenarioName" : "Scenario_Test"') - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/java/org/springframework/cloud/contract/verifier/wiremock/DefaultWireMockStubPostProcessorTests.java b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/java/org/springframework/cloud/contract/verifier/wiremock/DefaultWireMockStubPostProcessorTests.java deleted file mode 100644 index cbf006e6e2..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/java/org/springframework/cloud/contract/verifier/wiremock/DefaultWireMockStubPostProcessorTests.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.wiremock; - -import java.util.HashMap; -import java.util.Map; -import java.util.stream.Collectors; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.tomakehurst.wiremock.extension.PostServeActionDefinition; -import com.github.tomakehurst.wiremock.stubbing.StubMapping; -import org.junit.jupiter.api.Test; - -import org.springframework.cloud.contract.spec.Contract; - -import static org.assertj.core.api.BDDAssertions.then; - -class DefaultWireMockStubPostProcessorTests { - - // @formatter:off - private static final String STUB_MAPPING = "{\n" + " \"request\": {\n" - + " \"method\": \"GET\",\n" + " \"url\": \"/ping\"\n" - + " },\n" + " \"response\": {\n" + " \"status\": 200,\n" - + " \"body\": \"pong\",\n" + " \"headers\": {\n" - + " \"Content-Type\": \"text/plain\"\n" + " }\n" + " }\n" - + "}"; - - private static final String POST_SERVE_ACTION = "{ \"postServeActions\": {\n" - + " \"webhook\": {\n" + " \"headers\": {\n" - + " \"Content-Type\": \"application/json\"\n" + " },\n" - + " \"method\": \"POST\",\n" - + " \"body\": \"{ \\\"result\\\": \\\"SUCCESS\\\" }\",\n" - + " \"url\": \"http://localhost:56299/callback\"\n" + " }\n" - + " } }"; - - private static final String RESPONSE_DELAY = "{\n" - + " \"response\": {\n" - + " \"delayDistribution\": {\n" - + " \"type\": \"lognormal\",\n" - + " \"median\": 80,\n" - + " \"sigma\": 0.4\n" - + " }\n" - + " }\n" - + "}\n"; - // @formatter:on - - @Test - void should_not_be_applicable_for_missing_metadata_entry() { - then(new DefaultWireMockStubPostProcessor().isApplicable(new Contract())).isFalse(); - } - - @Test - void should_not_be_applicable_for_invalid_metadata_entry() { - Contract contract = new Contract(); - Map map = new HashMap<>(); - map.put("stubMapping", 5); - contract.getMetadata().put("wiremock", map); - - then(new DefaultWireMockStubPostProcessor().isApplicable(contract)).isFalse(); - } - - @Test - void should_be_applicable_for_valid_metadata_entry() { - Contract contract = new Contract(); - Map map = new HashMap<>(); - map.put("stubMapping", "foo"); - contract.getMetadata().put("wiremock", map); - - then(new DefaultWireMockStubPostProcessor().isApplicable(contract)).isTrue(); - - map.put("stubMapping", new StubMapping()); - - then(new DefaultWireMockStubPostProcessor().isApplicable(contract)).isTrue(); - - map.put("stubMapping", new HashMap<>()); - - then(new DefaultWireMockStubPostProcessor().isApplicable(contract)).isTrue(); - } - - @Test - void should_merge_stub_mappings_when_stub_mapping_is_string() { - Contract contract = new Contract(); - Map map = new HashMap<>(); - map.put("stubMapping", POST_SERVE_ACTION); - contract.getMetadata().put("wiremock", map); - StubMapping stubMapping = StubMapping.buildFrom(STUB_MAPPING); - - StubMapping result = new DefaultWireMockStubPostProcessor().postProcess(stubMapping, contract); - - thenPostServerActionWasSet(result); - } - - @Test - void should_merge_stub_mappings_when_stub_mapping_is_stub_mapping() { - Contract contract = new Contract(); - Map map = new HashMap<>(); - map.put("stubMapping", StubMapping.buildFrom(POST_SERVE_ACTION)); - contract.getMetadata().put("wiremock", map); - StubMapping stubMapping = StubMapping.buildFrom(STUB_MAPPING); - - StubMapping result = new DefaultWireMockStubPostProcessor().postProcess(stubMapping, contract); - - thenPostServerActionWasSet(result); - } - - @Test - void should_merge_stub_mappings_when_stub_mapping_is_map() throws JsonProcessingException { - Contract contract = new Contract(); - Map map = new HashMap<>(); - map.put("stubMapping", new ObjectMapper().readValue(POST_SERVE_ACTION, HashMap.class)); - contract.getMetadata().put("wiremock", map); - StubMapping stubMapping = StubMapping.buildFrom(STUB_MAPPING); - - StubMapping result = new DefaultWireMockStubPostProcessor().postProcess(stubMapping, contract); - - thenPostServerActionWasSet(result); - } - - @Test - void should_merge_stub_mappings_when_stub_mapping_is_string_and_contains_response() { - Contract contract = new Contract(); - Map map = new HashMap<>(); - map.put("stubMapping", RESPONSE_DELAY); - contract.getMetadata().put("wiremock", map); - StubMapping stubMapping = StubMapping.buildFrom(STUB_MAPPING); - - StubMapping result = new DefaultWireMockStubPostProcessor().postProcess(stubMapping, contract); - - then(result.getRequest().getMethod().getName()).isEqualTo("GET"); - then(result.getResponse().getStatus()).isEqualTo(200); - then(result.getResponse().getBody()).isEqualTo("pong"); - then(result.getResponse().getHeaders().size()).isEqualTo(1); - then(result.getResponse().getDelayDistribution()).isNotNull(); - } - - private void thenPostServerActionWasSet(StubMapping result) { - then(result.getRequest().getMethod().getName()).isEqualTo("GET"); - then(result.getResponse().getStatus()).isEqualTo(200); - then(result.getResponse().getBody()).isEqualTo("pong"); - then(result.getPostServeActions().stream().map(a -> a.getName()).collect(Collectors.toList())) - .contains("webhook"); - PostServeActionDefinition definition = result.getPostServeActions().stream() - .filter(a -> a.getName().equals("webhook")).findFirst() - .orElseThrow(() -> new AssertionError("No webhook action found")); - then(definition.getParameters().getString("method")).isEqualTo("POST"); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/dir3/Account creating.yml b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/dir3/Account creating.yml deleted file mode 100644 index bb3454fe4e..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/dir3/Account creating.yml +++ /dev/null @@ -1,51 +0,0 @@ ---- -request: - method: "POST" - url: null - urlPath: "/post-route" - queryParameters: {} - headers: - Content-Type: "application/json" - cookies: null - body: - age: 35 - name: "Jonh" - bodyFromFile: null - bodyFromFileAsBytes: null - matchers: - url: null - body: [] - headers: - - key: "Content-Type" - regex: "application/json.*" - predefined: null - command: null - regexType: "as_string" - queryParameters: [] - cookies: [] - multipart: null - multipart: null -response: - status: 200 - headers: null - cookies: null - body: - age: 35 - name: "Jonh" - bodyFromFile: null - bodyFromFileAsBytes: null - matchers: - body: [] - headers: [] - cookies: [] - async: false - fixedDelayMilliseconds: null -input: null -outputMessage: null -description: null -label: null -name: "Account creating" -priority: 1 -ignored: false -inProgress: false -metadata: {} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/dir3/Test route.yml b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/dir3/Test route.yml deleted file mode 100644 index 57309d7600..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/dir3/Test route.yml +++ /dev/null @@ -1,55 +0,0 @@ ---- -request: - method: "GET" - url: null - urlPath: "/my-first-route" - queryParameters: {} - headers: - Content-Type: "application/json" - cookies: null - body: null - bodyFromFile: null - bodyFromFileAsBytes: null - matchers: - url: null - body: [] - headers: - - key: "Content-Type" - regex: "application/json.*" - predefined: null - command: null - regexType: "as_string" - queryParameters: [] - cookies: [] - multipart: null - multipart: null -response: - status: 200 - headers: null - cookies: null - body: - test: "MVZWIKTLUUXDCDGKXMDC" - bodyFromFile: null - bodyFromFileAsBytes: null - matchers: - body: - - path: "$.['test']" - type: "by_regex" - value: "^\\s*\\S[\\S\\s]*" - minOccurrence: null - maxOccurrence: null - predefined: null - regexType: "as_string" - headers: [] - cookies: [] - async: false - fixedDelayMilliseconds: null -input: null -outputMessage: null -description: null -label: null -name: "Test route" -priority: 1 -ignored: false -inProgress: false -metadata: {} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/scenario/main_scenario/01_login.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/scenario/main_scenario/01_login.groovy deleted file mode 100644 index 6f036a279d..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/scenario/main_scenario/01_login.groovy +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - request { - method('POST') - url '/login' - } - response { - status OK() - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/scenario/main_scenario/02_showCart.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/scenario/main_scenario/02_showCart.groovy deleted file mode 100644 index 75fd2b3e3d..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/scenario/main_scenario/02_showCart.groovy +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - request { - method('GET') - url '/cart' - } - response { - status OK() - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/scenario/main_scenario/03_logout.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/scenario/main_scenario/03_logout.groovy deleted file mode 100644 index e710ebc6b3..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/scenario/main_scenario/03_logout.groovy +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - request { - method('POST') - url '/logout' - } - response { - status OK() - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/1_scenario.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/1_scenario.groovy deleted file mode 100644 index c052870cb0..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/1_scenario.groovy +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - request { - method('PUT') - headers { - header 'Content-Type': 'application/json' - } - url $(consumer('/[0-9]{2}'), producer('/12')) - } - response { - status OK() - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/2_scenario.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/2_scenario.groovy deleted file mode 100644 index c052870cb0..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/2_scenario.groovy +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - request { - method('PUT') - headers { - header 'Content-Type': 'application/json' - } - url $(consumer('/[0-9]{2}'), producer('/12')) - } - response { - status OK() - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/dsl1.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/dsl1.groovy deleted file mode 100644 index c052870cb0..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/dsl1.groovy +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - request { - method('PUT') - headers { - header 'Content-Type': 'application/json' - } - url $(consumer('/[0-9]{2}'), producer('/12')) - } - response { - status OK() - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/dsl1_list.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/dsl1_list.groovy deleted file mode 100644 index 04870ee861..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/dsl1_list.groovy +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.springframework.cloud.contract.spec.Contract - -(1..2).collect { int index -> - Contract.make { - request { - method(PUT()) - headers { - contentType(applicationJson()) - } - url "/${index}" - } - response { - status OK() - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/dsl1_list2.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/dsl1_list2.groovy deleted file mode 100644 index ecffc2828f..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/dsl1_list2.groovy +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.springframework.cloud.contract.spec.Contract - -(1..2).collect { int index -> - Contract.make { - name("shouldHaveIndex${index}") - request { - method(PUT()) - headers { - contentType(applicationJson()) - } - url "/${index}" - } - response { - status OK() - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/dsl1b.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/dsl1b.groovy deleted file mode 100644 index c052870cb0..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/dsl1b.groovy +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - request { - method('PUT') - headers { - header 'Content-Type': 'application/json' - } - url $(consumer('/[0-9]{2}'), producer('/12')) - } - response { - status OK() - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/scenario.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/scenario.groovy deleted file mode 100644 index f0a3653373..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/scenario.groovy +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.springframework.cloud.contract.spec.Contract - -[ - Contract.make { - name("1_scenario_multiple") - request { - method('PUT') - headers { - header 'Content-Type': 'application/json' - } - url $(consumer('/[0-9]{2}'), producer('/12')) - } - response { - status OK() - } - }, - Contract.make { - name("2_scenario_multiple") - request { - method('PUT') - headers { - header 'Content-Type': 'application/json' - } - url $(consumer('/[0-9]{2}'), producer('/12')) - } - response { - status OK() - } - } - -] diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir2/dsl2.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir2/dsl2.groovy deleted file mode 100644 index c052870cb0..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir2/dsl2.groovy +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - request { - method('PUT') - headers { - header 'Content-Type': 'application/json' - } - url $(consumer('/[0-9]{2}'), producer('/12')) - } - response { - status OK() - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dslRoot.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dslRoot.groovy deleted file mode 100644 index c052870cb0..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dslRoot.groovy +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - request { - method('PUT') - headers { - header 'Content-Type': 'application/json' - } - url $(consumer('/[0-9]{2}'), producer('/12')) - } - response { - status OK() - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gitignore b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gitignore deleted file mode 100644 index 466e24805a..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gitignore +++ /dev/null @@ -1 +0,0 @@ -out/ \ No newline at end of file diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.3/checksums/checksums.lock b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.3/checksums/checksums.lock new file mode 100644 index 0000000000000000000000000000000000000000..a098e20282c888e67ac2016d13efc131bab36fbe GIT binary patch literal 17 VcmZQJ@%cZ0lA|{-0~j#r0st#C1AG7g literal 0 HcmV?d00001 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.3/checksums/md5-checksums.bin b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.3/checksums/md5-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..1aeb2067843ce93c230668536e9ce3bc2ba1370b GIT binary patch literal 26447 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 literal 0 HcmV?d00001 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.3/checksums/sha1-checksums.bin b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.3/checksums/sha1-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..6307f49066dc5c8b399957a3063b3adf2d60314b GIT binary patch literal 28595 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 literal 0 HcmV?d00001 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.3/fileHashes/fileHashes.lock b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.3/fileHashes/fileHashes.lock new file mode 100644 index 0000000000000000000000000000000000000000..553944495ede3a2ebdba43aa836c809a57216b9f GIT binary patch literal 17 VcmZRMHvE`;Fn-P}1~A}!3jjBI1%Lnm literal 0 HcmV?d00001 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.3/fileHashes/resourceHashesCache.bin b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.3/fileHashes/resourceHashesCache.bin new file mode 100644 index 0000000000000000000000000000000000000000..40402010185faaae3219cec0b0260d646e1d6773 GIT binary patch literal 24379 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¬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 literal 0 HcmV?d00001 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.6.1/dependencies-accessors/dependencies-accessors.lock b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.6.1/dependencies-accessors/dependencies-accessors.lock new file mode 100644 index 0000000000000000000000000000000000000000..b0c82fd4723ecdb6318295a453d6d481d0ce3eef GIT binary patch literal 17 TcmZQxY}~eL1#eI$0~7!NEV~1G literal 0 HcmV?d00001 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.6.1/dependencies-accessors/gc.properties b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.6.1/dependencies-accessors/gc.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.6.1/executionHistory/executionHistory.bin b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/7.6.1/executionHistory/executionHistory.bin new file mode 100644 index 0000000000000000000000000000000000000000..cfaa27dad2846557ce5c78699d761f26ac68b8f3 GIT binary patch literal 730587 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 C0x9{@eo1;_vZ literal 0 HcmV?d00001 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/checksums/md5-checksums.bin b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/checksums/md5-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..273c92430db601fd5dd4b49a0507806bd1677f21 GIT binary patch literal 27897 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 VZ*+XKz^s6|nvkFfB>pI9{2$@5NDu%3 literal 0 HcmV?d00001 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/checksums/sha1-checksums.bin b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/checksums/sha1-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..de5ef5f87761cf56c6335360930c372a4318c72c GIT binary patch literal 29243 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 literal 0 HcmV?d00001 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/checksums/sha512-checksums.bin b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/checksums/sha512-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..ed8d53f717cbf8c68a509350696038be39128848 GIT binary patch literal 18595 zcmeI(zbnLH7y$4u!xgDhQa6~?k?XFMWThm!iF3(fm0!ic)fr?H3o^)Zb$y99Abp;C-skCkm-qRsZ|`IjrMka=BWgu&tJM)8K!5-N0t5&UAV7cs z0RjXF5FkK+009F3MW7f4>5PX-W!oD~vJ^$bU7=~KUp(xcKAmmF$I}zd_k(5)`$O@W zl>h+(1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U z_zMCf;S!4>XB#=bQ<%RyKhAFt^dI#l%QNMA?&fN0Y`yySoGIR(eC0oPYjf31E|={X neM#4PHue)A%d793uLqTMY2k9P5Iz?it~{qr>LtXj-R5U`s literal 0 HcmV?d00001 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/dependencies-accessors/dependencies-accessors.lock b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/dependencies-accessors/dependencies-accessors.lock new file mode 100644 index 0000000000000000000000000000000000000000..a3c40ed64367635371661845b1b7d295ad40f5dc GIT binary patch literal 17 ScmZQ}N}hPl-lJN80SW*pX9FSt literal 0 HcmV?d00001 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/dependencies-accessors/gc.properties b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/dependencies-accessors/gc.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/executionHistory/executionHistory.bin b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/executionHistory/executionHistory.bin new file mode 100644 index 0000000000000000000000000000000000000000..988d0f7ae811d7c516bc07875abce7ee08a3d537 GIT binary patch literal 348390 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 literal 0 HcmV?d00001 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/fileChanges/last-build.bin b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/fileChanges/last-build.bin new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/fileHashes/fileHashes.bin b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/8.3/fileHashes/fileHashes.bin new file mode 100644 index 0000000000000000000000000000000000000000..1a788d7b8bd4f66b7ab72f819e0b0eb7a05abbb6 GIT binary patch literal 34447 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 literal 0 HcmV?d00001 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/checksums/checksums.lock b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/checksums/checksums.lock new file mode 100644 index 0000000000000000000000000000000000000000..19997062f2811e20df8e51b72e2ceafaab373965 GIT binary patch literal 17 UcmZS1*sd0IwfD?&1_;;&05($vCIA2c literal 0 HcmV?d00001 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/checksums/md5-checksums.bin b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/checksums/md5-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..f2c8b6914b1f352cb6e9dc8f7cb0a052913eadf5 GIT binary patch literal 22797 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 QiEOY&Q#Gu?!Gjt90Unze5C8xG literal 0 HcmV?d00001 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/checksums/sha1-checksums.bin b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/checksums/sha1-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..7b22d5d76c21dc8f65bd9421d8bb10fc163d756b GIT binary patch literal 23141 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

%6hIrl~W8vgQsjug{d{TInPpm1Fqc=YGXqDFt zG_a}FT=&9Xs+S?c7Pr2}cCv(H+>Ew9*+xART$kD-pt!sL?LUM^S4(T4^A?nbq~~#9 zaeYEtj!MM(O}d8SvuS*z$@}|Wcm@3Mg)JHWBXPjur9)e0t7Y-k=Ec<~->CD3(I=@f zzL|%ThWcV2tppY!7HwsFTl)rBN@+PJ^4_d+wxTXhzf?A#EqKt^I(VH?W!Rmuue(ig@o7PIAXm#^dj_9!fj_XiDOW@c l3ux=bjFR8`fT=LWm{SFn-ub7>dZY=!YJUj&Vqt@={{RfrzD585 literal 0 HcmV?d00001 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/file-system.probe b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/file-system.probe new file mode 100644 index 0000000000000000000000000000000000000000..57a8a42408238a1476d8c60581fdd3592bc7d635 GIT binary patch literal 8 PcmZQzVC-s1ddvU-2fPAR literal 0 HcmV?d00001 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/vcs-1/gc.properties b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.gradle/vcs-1/gc.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/.gitignore b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/.gitignore new file mode 100644 index 0000000000..13566b81b0 --- /dev/null +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/codeStyles/Project.xml b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/codeStyles/Project.xml new file mode 100644 index 0000000000..45b42daae1 --- /dev/null +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/codeStyles/Project.xml @@ -0,0 +1,524 @@ + + + + +

+ + + + true + true + true + true + + + +
+
+ + + + true + true + true + true + + + +
+
+ + + + true + true + true + true + + + +
+
+ + + + true + true + true + true + + + +
+
+ + + + true + true + true + + + +
+
+ + + + true + true + true + + + +
+
+ + + + true + true + true + + + +
+
+ + + + true + true + true + + + +
+
+ + + + true + true + + + +
+
+ + + + true + true + true + + + +
+
+ + + + true + true + true + + + +
+
+ + + + true + true + true + + + +
+
+ + + + true + true + true + + + +
+
+ + + + true + true + true + + + +
+
+ + + + true + true + + + +
+
+ + + + true + true + + + +
+
+ + + + true + true + + + +
+
+ + + + true + true + + + +
+
+ + + true + + +
+
+ + + true + + +
+
+ + + true + + +
+
+ + + + true + true + + + +
+
+ + + true + + +
+
+ + + true + + +
+
+ + + true + + +
+
+ + + + true + true + + + +
+
+ + + true + + +
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/codeStyles/codeStyleConfig.xml b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000000..f243e6123e --- /dev/null +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/compiler.xml b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/compiler.xml new file mode 100644 index 0000000000..61a9130cd9 --- /dev/null +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/gradle.xml b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/gradle.xml new file mode 100644 index 0000000000..699474d945 --- /dev/null +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/gradle.xml @@ -0,0 +1,18 @@ + + + + + + + \ No newline at end of file diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/jarRepositories.xml b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/jarRepositories.xml new file mode 100644 index 0000000000..b78b0dc44a --- /dev/null +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/jarRepositories.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/misc.xml b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/misc.xml new file mode 100644 index 0000000000..92a3772fb3 --- /dev/null +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/misc.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/sonarlint/issuestore/index.pb b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/sonarlint/issuestore/index.pb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/sonarlint/securityhotspotstore/index.pb b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/sonarlint/securityhotspotstore/index.pb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/uiDesigner.xml b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/uiDesigner.xml new file mode 100644 index 0000000000..e96534fb27 --- /dev/null +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/vcs.xml b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/vcs.xml new file mode 100644 index 0000000000..b2bdec2d71 --- /dev/null +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/build.gradle b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/build.gradle deleted file mode 100644 index f8118e351d..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/build.gradle +++ /dev/null @@ -1,139 +0,0 @@ -buildscript { - repositories { - mavenCentral() - mavenLocal() - //For plugin-publish-plugin. Could be limited only to that dependency with Gradle 5.1+ - https://docs.gradle.org/5.1.1/release-notes.html#repository-to-dependency-matching - gradlePluginPortal() - } - dependencies { - classpath 'com.gradle.publish:plugin-publish-plugin:0.14.0' - } -} - -// TODO: Remove me for Gradle 8.4 - https://github.com/gradle/gradle/issues/25434 -configurations { - all { - resolutionStrategy { - eachDependency { dependency -> - // Downgrade Spring Framework as Gradle cannot cope with 6.1.0-M1's - // multi-version jar files with bytecode in META-INF/versions/21 - if (dependency.requested.group.equals("org.springframework")) { - dependency.useVersion("6.0.10") - } - } - } - } -} - - -ext { - repoUser = System.getenv('REPO_USERNAME') ?: project.findProperty('REPO_USERNAME') ?: '' - repoPass = System.getenv('REPO_PASSWORD') ?: project.findProperty('REPO_PASSWORD') ?: '' - - testSystemProperties = [ - "WORK_OFFLINE" : gradle.startParameter.isOffline() ? 'TRUE' : 'FALSE' - ] - JavaVersion javaVer = JavaVersion.current() - println "Current Java version equal to [${javaVer}]" - javaVersionNumber = javaVer.toString() -} - -project.version = findProperty('verifierVersion') -apply plugin: 'groovy' -apply plugin: "java-gradle-plugin" -apply from: "$rootDir/gradle/release.gradle" -//apply plugin: "jacoco" - -group = 'org.springframework.cloud' - -sourceCompatibility = 17 -targetCompatibility = 17 - -repositories { - mavenLocal() - mavenCentral() - maven { url "https://repo.spring.io/snapshot" } - maven { url "https://repo.spring.io/milestone" } - maven { url "https://repo.spring.io/release" } -} - -//Dependencies in all subprojects - https://solidsoft.wordpress.com/2014/11/13/gradle-tricks-display-dependencies-for-all-subprojects-in-multi-project-build/ -task allDeps(type: DependencyReportTask) {} -task allInsight(type: DependencyInsightReportTask) {} - -configurations { - // fixing the groovydoc issue https://stackoverflow.com/questions/20618857/gradle-task-groovydoc-failing-with-noclassdeffounderror - jansi.extendsFrom(runtime) -} - -dependencies { - compileOnly gradleApi() - - // provide version alignment with project - implementation(platform("org.springframework.cloud:spring-cloud-contract-tools:${project.version}")) - - // Need to set the versions manually cause otherwise Gradle will not publish a proper pom - implementation "org.apache.maven.resolver:maven-resolver-api:${mavenResolverVersion}" - implementation "org.eclipse.jgit:org.eclipse.jgit:${jgitVersion}" - implementation "org.eclipse.jgit:org.eclipse.jgit.ssh.jsch:${jgitVersion}" - implementation "com.jcraft:jsch.agentproxy.jsch:${jschVersion}" - implementation "com.jcraft:jsch.agentproxy.sshagent:${jschVersion}" - implementation "com.jcraft:jsch.agentproxy.usocket-jna:${jschVersion}" - implementation "com.fasterxml.jackson.core:jackson-databind:${jacksonDatabindVersion}" - - implementation "org.springframework:spring-core:${springVersion}" - implementation("org.springframework.cloud:spring-cloud-contract-shade:${project.version}") - api("org.springframework.cloud:spring-cloud-contract-stub-runner:${project.version}") { - exclude(group: '*') - } - api("org.springframework.cloud:spring-cloud-contract-verifier:${project.version}") { - exclude(group: '*') - } - - testImplementation "org.springframework.boot:spring-boot-starter-test" - testImplementation localGroovy() - testImplementation gradleTestKit() -} - -task libtest() { - doLast { - configurations.testCompile.files.each { println it } - } -} - -test { - useJUnitPlatform() - testLogging { - exceptionFormat = 'full' - } - systemProperties = testSystemProperties - enabled = !project.hasProperty('fast') -} - -groovydoc { - def title = "IPDS ${version}" - groovyClasspath = project.configurations.jansi -} - -dependencies { - jansi 'org.fusesource.jansi:jansi:1.11' -} - -jar { - manifest { - attributes 'Implementation-Version': project.version - } -} - -task resolveDependencies { - doLast { - project.rootProject.allprojects.each { subProject -> - subProject.buildscript.configurations.each { configuration -> - configuration.resolve() - } - subProject.configurations.each { configuration -> - configuration.resolve() - } - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/gradle.properties b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/gradle.properties deleted file mode 100644 index 50d5f3ee5b..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/gradle.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright 2013-2020 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -nexusUsername= -nexusPassword= -verifierVersion=4.1.0-SNAPSHOT -org.gradle.daemon=false -aetherVersion=1.1.0 -springCloudBuildVersion=4.1.0-SNAPSHOT -springVersion=6.0.10 -jacksonDatabindVersion=2.13.2.1 -mavenResolverVersion=1.4.1 -jgitVersion=5.12.0.202106070339-r -jschVersion=0.0.9 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/gradle/release.gradle b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/gradle/release.gradle deleted file mode 100644 index d29b64f85a..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/gradle/release.gradle +++ /dev/null @@ -1,86 +0,0 @@ -// This setup seems to work. Let's not touch it. - -apply plugin: 'maven-publish' -//apply plugin: 'signing' - -task sourcesJar(type: Jar) { - archiveClassifier = 'sources' - from sourceSets.main.allSource -} - -task groovydocJar(type: Jar, dependsOn: groovydoc) { - archiveClassifier = 'groovydoc' - from groovydoc.destinationDir -} - -task javadocJar(type: Jar, dependsOn: javadoc) { - archiveClassifier = 'javadoc' - from javadoc.destinationDir -} - -artifacts { - archives sourcesJar - archives groovydocJar - archives javadocJar -} - -ext { - resolveRepoName = { Project project -> - resolvedRepoName = "libs-${resolveVersion(project.version)}-local" - logger.lifecycle("For project [$project.name] with " + - "version [$project.version] the resolved Artifactory repo is [$resolvedRepoName]") - return resolvedRepoName - } - - isReleaseVersion = version.endsWith("RELEASE") - isMilestoneVersion = version.matches('[0-9].[0-9].[0-9].M[0-9]+') || version.matches('[0-9].[0-9].[0-9].RC[0-9]+') - isSnapshotVersion = !(isReleaseVersion || isMilestoneVersion) - isReleaseToCentral = project.hasProperty('central') - - resolveVersion = { String version -> - if (isMilestoneVersion) { - return 'milestone' - } - if (isReleaseVersion) { - return 'release' - } - return 'snapshot' - } - - repoUrl = isReleaseToCentral ? - "https://oss.sonatype.org/service/local/staging/deploy/maven2/" : - "https://repo.spring.io/${resolveRepoName(project)}" -} - -if (isReleaseToCentral) { - /*signing { - sign configurations.archives - }*/ - - apply plugin: 'com.gradle.plugin-publish' - - pluginBundle { - website = 'https://github.com/spring-cloud/spring-cloud-contract' - vcsUrl = 'https://github.com/spring-cloud/spring-cloud-contract' - - plugins { - plugin { - id = 'org.springframework.cloud.contract' - displayName = 'spring-cloud-contract' - description = 'Spring Cloud Contract Gradle Plugin' - tags = ['spring', 'spring-framework', 'spring-cloud', 'spring-cloud-contract'] - } - } - - mavenCoordinates { - groupId = project.group - artifactId = project.name - } - } -} - -String getProp(String propName) { - return hasProperty(propName) ? - (getProperty(propName) ?: System.properties[propName]) : System.properties[propName] ?: - System.getenv(propName) -} \ No newline at end of file diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/gradle/wrapper/gradle-wrapper.jar b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 943f0cbfa754578e88a3dae77fce6e3dea56edbf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61574 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 ScNgau(U?ep-K_E5zy1%ZQTdPn diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/gradle/wrapper/gradle-wrapper.properties b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index c30b486a89..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip -networkTimeout=10000 -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/gradlew b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/gradlew deleted file mode 100755 index 65dcd68d65..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/gradlew +++ /dev/null @@ -1,244 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/gradlew.bat b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/gradlew.bat deleted file mode 100644 index 6689b85bee..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/pom.xml deleted file mode 100644 index 0ba5086a4e..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/pom.xml +++ /dev/null @@ -1,399 +0,0 @@ - - - 4.0.0 - - - org.springframework.cloud - spring-cloud-contract-tools - 4.1.0-SNAPSHOT - .. - - - spring-cloud-contract-gradle-plugin - pom - - Spring Cloud Contract Gradle Plugin - Spring Cloud Contract Gradle Plugin - - - UTF-8 - UTF-8 - build - package - publishPlugins - - - - - org.springframework.cloud - spring-cloud-contract-verifier - - - * - * - - - - - org.springframework.cloud - spring-cloud-contract-converters - - - * - * - - - - - org.springframework.cloud - spring-cloud-contract-stub-runner - - - * - * - - - - - org.springframework.cloud - spring-cloud-contract-shade - - - org.apache.maven.resolver - maven-resolver-api - - - org.eclipse.jgit - org.eclipse.jgit - - - org.eclipse.jgit - org.eclipse.jgit.ssh.jsch - - - com.jcraft - jsch.agentproxy.jsch - - - com.fasterxml.jackson.core - jackson-databind - - - org.springframework - spring-core - - - - - - src/main/fake - - - org.apache.maven.plugins - maven-surefire-plugin - - false - - - - org.apache.maven.plugins - maven-clean-plugin - 3.1.0 - - - - build - - - target - - - - - - org.codehaus.mojo - build-helper-maven-plugin - ${build-helper-maven-plugin.version} - - - attach-zip - none - - - attach-artifacts - ${build-helper-maven-plugin.phase} - - attach-artifact - - - - - build/libs/${project.artifactId}-${project.version}.jar - jar - - - build/libs/${project.artifactId}-${project.version}-groovydoc.jar - jar - groovydoc - - - build/libs/${project.artifactId}-${project.version}-javadoc.jar - jar - javadoc - - - build/libs/${project.artifactId}-${project.version}-sources.jar - jar - sources - - - - - - - - - - - - default - - true - - - - - org.codehaus.mojo - exec-maven-plugin - - ${exec-maven-plugin.version} - - - gradle - package - - ./gradlew - - ${gradle.task} - - -PverifierVersion=${project.version} - - - - exec - - - - - - - - - milestone - - true - - - - - org.codehaus.mojo - exec-maven-plugin - - ${exec-maven-plugin.version} - - - gradle - package - - ./gradlew - - ${gradle.task} - - -PverifierVersion=${project.version} - - - - exec - - - - - - - - - windows - - - windows - - - - - - org.codehaus.mojo - exec-maven-plugin - - ${exec-maven-plugin.version} - - - gradle - package - - gradlew.bat - - ${gradle.task} - - -PverifierVersion=${project.version} - - - - exec - - - - - - - - - fast - - false - - - - - org.codehaus.mojo - exec-maven-plugin - - ${exec-maven-plugin.version} - - - gradle - package - - ./gradlew - - ${gradle.task} - - -Pfast - -PverifierVersion=${project.version} - - - - exec - - - - - - - - - dry-run - - true - - env.DRY_RUN - true - - - - -Pexample=value - - - - central - - false - - - - - org.codehaus.mojo - exec-maven-plugin - - ${exec-maven-plugin.version} - - - gradle - package - - ./gradlew - - clean - ${gradle.task} - -PverifierVersion=${project.version} - -Pcentral - -PsonatypeUsername=${env.SONATYPE_USER} - -PsonatypePassword=${env.SONATYPE_PASSWORD} - -Pgradle.publish.key=${env.GRADLE_PUBLISH_KEY} - -Pgradle.publish.secret=${env.GRADLE_PUBLISH_SECRET} - ${gradle.publish-plugins.task} - - - - exec - - - - - - - - - java13 - - 13 - - - none - - - - - org.codehaus.mojo - exec-maven-plugin - - ${exec-maven-plugin.version} - - - gradle-update-to-6 - package - - ./gradlew - - wrapper - --gradle-version - 6.0 - - - - exec - - - - gradle - package - - ./gradlew - - ${gradle.task} - - -PverifierVersion=${project.version} - - - - exec - - - - - - - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/ContractVerifierExtension.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/ContractVerifierExtension.java deleted file mode 100644 index c6aa5a8bfd..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/ContractVerifierExtension.java +++ /dev/null @@ -1,740 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.plugin; - -import java.io.File; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.inject.Inject; - -import org.gradle.api.Action; -import org.gradle.api.file.DirectoryProperty; -import org.gradle.api.file.ProjectLayout; -import org.gradle.api.model.ObjectFactory; -import org.gradle.api.provider.ListProperty; -import org.gradle.api.provider.MapProperty; -import org.gradle.api.provider.Property; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.config.TestMode; -import org.springframework.util.Assert; - -/** - * @author Marcin Grzejszczak - * @author Anatoliy Balakirev - * @author Shannon Pamperl - */ -public class ContractVerifierExtension implements Serializable { - - /** - * For which unit test library tests should be generated - */ - private final Property testFramework; - - /** - * Which mechanism should be used to invoke REST calls during tests - */ - private final Property testMode; - - /** - * Base package for generated tests - */ - private final Property basePackageForTests; - - /** - * Class which all generated tests should extend - */ - private final Property baseClassForTests; - - /** - * Suffix for generated test classes, like Spec or Test - */ - private final Property nameSuffixForTests; - - /** - * Patterns that should not be taken into account for processing - */ - private final ListProperty excludedFiles; - - /** - * Patterns that should be taken into account for processing - */ - private final ListProperty includedFiles; - - /** - * Patterns for which generated tests should be @Ignored - */ - private final ListProperty ignoredFiles; - - /** - * Imports that should be added to generated tests - */ - private final ListProperty imports; - - /** - * Static imports that should be added to generated tests - */ - private final ListProperty staticImports; - - /** - * Directory containing contracts written using the GroovyDSL - */ - private final DirectoryProperty contractsDslDir; - - /** - * Java test source directory where tests generated from Contract DSL should be placed - */ - private final DirectoryProperty generatedTestJavaSourcesDir; - - /** - * Groovy test source directory where tests generated from Contract DSL should be - * placed - */ - private final DirectoryProperty generatedTestGroovySourcesDir; - - /** - * Test resource directory where tests generated from Groovy DSL should be referenced - */ - private final DirectoryProperty generatedTestResourcesDir; - - /** - * Dir where the generated stubs from Groovy DSL should be placed. You can then - * mention them in your packaging task to create jar with stubs - */ - private final DirectoryProperty stubsOutputDir; - - /** - * Suffix for the generated Stubs Jar task - */ - private final Property stubsSuffix; - - /** - * Incubating feature. You can check the size of JSON arrays. If not turned on - * explicitly will be disabled. - */ - private final Property assertJsonSize; - - /** - * When enabled, this flag will tell stub runner to throw an exception when no stubs / - * contracts were found. - */ - private final Property failOnNoContracts; - - /** - * If set to true then if any contracts that are in progress are found, will break the - * build. On the producer side you need to be explicit about the fact that you have - * contracts in progress and take into consideration that you might be causing false - * positive test execution results on the consumer side. - */ - private final Property failOnInProgress; - - private final ContractRepository contractRepository; - - private final PublishStubsToScm publishStubsToScm; - - /** - * Dependency that contains packaged contracts - */ - private final Dependency contractDependency; - - /** - * The path in the JAR with all the contracts where contracts for this particular - * service lay. If not provided will be resolved to {@code groupid/artifactid}. - * Example: If {@code groupid} is {@code com.example} and {@code artifactid} is - * {@code service} then the resolved path will be {@code /com/example/artifactid} - */ - private final Property contractsPath; - - /** - * Picks the mode in which stubs will be found and registered - */ - private final Property contractsMode; - - /** - * A package that contains all the base clases for generated tests. If your contract - * resides in a location {@code src/contractTest/resources/contracts/com/example/v1/} and you - * provide the {@code packageWithBaseClasses} value to - * {@code com.example.contracts.base} then we will search for a test source file that - * will have the package {@code com.example.contracts.base} and name - * {@code ExampleV1Base}. As you can see it will take the two last folders to and - * attach {@code Base} to its name. - */ - private final Property packageWithBaseClasses; - - /** - * A way to override any base class mappings. The keys are regular expressions on the - * package name and the values FQN to a base class for that given expression. Example - * of a mapping [.*.com.example.v1..*] to [com.example.SomeBaseClass] When a - * contract's package matches the provided regular expression then extending class - * will be the one provided in the map - in this case - * {@code com.example.SomeBaseClass} - */ - private final BaseClassMapping baseClassMappings; - - /** - * If set to true then the {@code target} or {@code build} folders are getting - * excluded from any operations. This is used out of the box when working with common - * repo with contracts. - */ - private final Property excludeBuildFolders; - - /** - * If set to {@code false} will NOT delete stubs from a temporary folder after running - * tests - */ - private final Property deleteStubsAfterTest; - - /** - * If {@code true} then will convert contracts to a YAML representation - */ - private final Property convertToYaml; - - /** - * Map of properties that can be passed to custom - * {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder} - */ - private final MapProperty contractsProperties; - - /** - * Source set where the contracts are stored. If not provided will assume - * {@code test}. - */ - private final Property sourceSet; - - @Inject - public ContractVerifierExtension(ProjectLayout layout, ObjectFactory objects) { - this.testFramework = objects.property(TestFramework.class).convention(TestFramework.JUNIT5); - this.testMode = objects.property(TestMode.class).convention(TestMode.MOCKMVC); - this.basePackageForTests = objects.property(String.class); - this.baseClassForTests = objects.property(String.class); - this.nameSuffixForTests = objects.property(String.class); - this.excludedFiles = objects.listProperty(String.class).convention(new ArrayList<>()); - this.includedFiles = objects.listProperty(String.class).convention(new ArrayList<>()); - this.ignoredFiles = objects.listProperty(String.class).convention(new ArrayList<>()); - this.imports = objects.listProperty(String.class).convention(new ArrayList<>()); - this.staticImports = objects.listProperty(String.class).convention(new ArrayList<>()); - this.contractsDslDir = objects.directoryProperty() - .convention(layout.getProjectDirectory().dir("src/contractTest/resources/contracts")); - this.generatedTestJavaSourcesDir = objects.directoryProperty() - .convention(layout.getBuildDirectory().dir("generated-test-sources/contractTest/java")); - this.generatedTestGroovySourcesDir = objects.directoryProperty() - .convention(layout.getBuildDirectory().dir("generated-test-sources/contractTest/groovy")); - this.generatedTestResourcesDir = objects.directoryProperty() - .convention(layout.getBuildDirectory().dir("generated-test-resources/contractTest")); - this.stubsOutputDir = objects.directoryProperty().convention(layout.getBuildDirectory().dir("stubs")); - this.stubsSuffix = objects.property(String.class).convention("stubs"); - this.assertJsonSize = objects.property(Boolean.class).convention(false); - this.failOnNoContracts = objects.property(Boolean.class).convention(true); - this.failOnInProgress = objects.property(Boolean.class).convention(true); - this.contractRepository = objects.newInstance(ContractRepository.class); - this.publishStubsToScm = objects.newInstance(PublishStubsToScm.class); - this.contractDependency = objects.newInstance(Dependency.class); - this.contractsPath = objects.property(String.class); - this.contractsMode = objects.property(StubRunnerProperties.StubsMode.class) - .convention(StubRunnerProperties.StubsMode.CLASSPATH); - this.packageWithBaseClasses = objects.property(String.class); - this.baseClassMappings = objects.newInstance(BaseClassMapping.class); - this.excludeBuildFolders = objects.property(Boolean.class).convention(false); - this.deleteStubsAfterTest = objects.property(Boolean.class).convention(true); - this.convertToYaml = objects.property(Boolean.class).convention(false); - this.contractsProperties = objects.mapProperty(String.class, String.class).convention(new HashMap<>()); - this.sourceSet = objects.property(String.class); - } - - public Property getTestFramework() { - return testFramework; - } - - public void setTestFramework(TestFramework testFramework) { - this.testFramework.set(testFramework); - } - - public void setTestFramework(String testFramework) { - this.testFramework.set(TestFramework.valueOf(testFramework.toUpperCase())); - } - - public Property getTestMode() { - return testMode; - } - - public void setTestMode(TestMode testMode) { - this.testMode.set(testMode); - } - - public void setTestMode(String testMode) { - this.testMode.set(TestMode.valueOf(testMode.toUpperCase())); - } - - public Property getBasePackageForTests() { - return basePackageForTests; - } - - public void setBasePackageForTests(String basePackageForTests) { - this.basePackageForTests.set(basePackageForTests); - } - - public Property getBaseClassForTests() { - return baseClassForTests; - } - - public void setBaseClassForTests(String baseClassForTests) { - this.baseClassForTests.set(baseClassForTests); - } - - public Property getNameSuffixForTests() { - return nameSuffixForTests; - } - - public void setNameSuffixForTests(String nameSuffixForTests) { - this.nameSuffixForTests.set(nameSuffixForTests); - } - - public ListProperty getExcludedFiles() { - return excludedFiles; - } - - public void setExcludedFiles(List excludedFiles) { - this.excludedFiles.set(excludedFiles); - } - - public ListProperty getIncludedFiles() { - return includedFiles; - } - - public void setIncludedFiles(List includedFiles) { - this.includedFiles.set(includedFiles); - } - - public ListProperty getIgnoredFiles() { - return ignoredFiles; - } - - public void setIgnoredFiles(List ignoredFiles) { - this.ignoredFiles.set(ignoredFiles); - } - - public ListProperty getImports() { - return imports; - } - - public void setImports(String[] imports) { - this.imports.set(new ArrayList<>(Arrays.asList(imports))); - } - - public void setInputs(List imports) { - this.imports.set(imports); - } - - public ListProperty getStaticImports() { - return staticImports; - } - - public void setStaticImports(String[] staticImports) { - this.staticImports.set(new ArrayList<>(Arrays.asList(staticImports))); - } - - public void setStaticImports(List staticImports) { - this.staticImports.set(staticImports); - } - - public DirectoryProperty getContractsDslDir() { - return contractsDslDir; - } - - public void setContractsDslDir(File contractsDslDir) { - this.contractsDslDir.set(contractsDslDir); - } - - public DirectoryProperty getGeneratedTestJavaSourcesDir() { - return generatedTestJavaSourcesDir; - } - - public void setGeneratedTestJavaSourcesDir(File generatedTestJavaSourcesDir) { - this.generatedTestJavaSourcesDir.set(generatedTestJavaSourcesDir); - } - - public DirectoryProperty getGeneratedTestGroovySourcesDir() { - return generatedTestGroovySourcesDir; - } - - public void setGeneratedTestGroovySourcesDir(File generatedTestGroovySourcesDir) { - this.generatedTestGroovySourcesDir.set(generatedTestGroovySourcesDir); - } - - public DirectoryProperty getGeneratedTestResourcesDir() { - return generatedTestResourcesDir; - } - - public void setGeneratedTestResourcesDir(File generatedTestResourcesDir) { - this.generatedTestResourcesDir.set(generatedTestResourcesDir); - } - - public DirectoryProperty getStubsOutputDir() { - return stubsOutputDir; - } - - public void setStubsOutputDir(File stubsOutputDir) { - this.stubsOutputDir.set(stubsOutputDir); - } - - public Property getStubsSuffix() { - return stubsSuffix; - } - - public void setStubsSuffix(String stubsSuffix) { - this.stubsSuffix.set(stubsSuffix); - } - - public Property getAssertJsonSize() { - return assertJsonSize; - } - - public void setAssertJsonSize(boolean assertJsonSize) { - this.assertJsonSize.set(assertJsonSize); - } - - public Property getFailOnNoContracts() { - return failOnNoContracts; - } - - public void setFailOnNoContracts(boolean failOnNoContracts) { - this.failOnNoContracts.set(failOnNoContracts); - } - - public Property getFailOnInProgress() { - return failOnInProgress; - } - - public void setFailOnInProgress(boolean failOnInProgress) { - this.failOnInProgress.set(failOnInProgress); - } - - public ContractRepository getContractRepository() { - return contractRepository; - } - - public void contractRepository(Action action) { - action.execute(contractRepository); - } - - public PublishStubsToScm getPublishStubsToScm() { - return publishStubsToScm; - } - - public void publishStubsToScm(Action action) { - action.execute(publishStubsToScm); - } - - public Dependency getContractDependency() { - return contractDependency; - } - - public void contractDependency(Action action) { - action.execute(contractDependency); - } - - public Property getContractsPath() { - return contractsPath; - } - - public void setContractsPath(String contractsPath) { - this.contractsPath.set(contractsPath); - } - - public Property getContractsMode() { - return contractsMode; - } - - public void setContractsMode(StubRunnerProperties.StubsMode contractsMode) { - this.contractsMode.set(contractsMode); - } - - public void setContractsMode(String contractsMode) { - this.contractsMode.set(StubRunnerProperties.StubsMode.valueOf(contractsMode.toUpperCase())); - } - - public Property getPackageWithBaseClasses() { - return packageWithBaseClasses; - } - - public void setPackageWithBaseClasses(String packageWithBaseClasses) { - this.packageWithBaseClasses.set(packageWithBaseClasses); - } - - public BaseClassMapping getBaseClassMappings() { - return baseClassMappings; - } - - public void setBaseClassMappings(Map baseClassMappings) { - this.baseClassMappings.getBaseClassMappings().set(baseClassMappings); - } - - public void baseClassMappings(Action action) { - action.execute(baseClassMappings); - } - - public Property getExcludeBuildFolders() { - return excludeBuildFolders; - } - - public void setExcludeBuildFolders(boolean excludeBuildFolders) { - this.excludeBuildFolders.set(excludeBuildFolders); - } - - public Property getDeleteStubsAfterTest() { - return deleteStubsAfterTest; - } - - public void setDeleteStubsAfterTest(boolean deleteStubsAfterTest) { - this.deleteStubsAfterTest.set(deleteStubsAfterTest); - } - - public Property getConvertToYaml() { - return convertToYaml; - } - - public void setConvertToYaml(boolean convertToYaml) { - this.convertToYaml.set(convertToYaml); - } - - public MapProperty getContractsProperties() { - return contractsProperties; - } - - public void setContractsProperties(Map contractsProperties) { - this.contractsProperties.set(contractsProperties); - } - - public Property getSourceSet() { - return sourceSet; - } - - public void setSourceSet(String sourceSet) { - this.sourceSet.set(sourceSet); - } - - public static class Dependency implements Serializable { - - private final Property groupId; - - private final Property artifactId; - - private final Property version; - - private final Property classifier; - - private final Property stringNotation; - - @Inject - public Dependency(ObjectFactory objects) { - groupId = objects.property(String.class); - artifactId = objects.property(String.class); - version = objects.property(String.class); - classifier = objects.property(String.class); - stringNotation = objects.property(String.class); - } - - public Property getGroupId() { - return groupId; - } - - public void setGroupId(String groupId) { - this.groupId.set(groupId); - } - - public Property getArtifactId() { - return artifactId; - } - - public void setArtifactId(String artifactId) { - this.artifactId.set(artifactId); - } - - public Property getVersion() { - return version; - } - - public void setVersion(String version) { - this.version.set(version); - } - - public Property getClassifier() { - return classifier; - } - - public void setClassifier(String classifier) { - this.classifier.set(classifier); - } - - public Property getStringNotation() { - return stringNotation; - } - - public void setStringNotation(String stringNotation) { - this.stringNotation.set(stringNotation); - } - - @Override - public String toString() { - return "Dependency{" + "groupId=" + groupId.getOrNull() + ", artifactId=" + artifactId.getOrNull() - + ", classifier=" + classifier.getOrNull() + ", version=" + version.getOrNull() - + ", stringNotation=" + stringNotation.getOrNull() + '}'; - } - - } - - public static class BaseClassMapping implements Serializable { - - private final MapProperty baseClassMappings; - - @Inject - public BaseClassMapping(ObjectFactory objects) { - this.baseClassMappings = objects.mapProperty(String.class, String.class).convention(new HashMap<>()); - } - - public MapProperty getBaseClassMappings() { - return baseClassMappings; - } - - public void baseClassMapping(String packageRegex, String fqnBaseClass) { - baseClassMappings.put(packageRegex, fqnBaseClass); - } - - public void baseClassMapping(Map mapping) { - baseClassMappings.putAll(mapping); - } - - } - - // This class is used as an input to the tasks, so all fields are marked as `@Input` - // to allow incremental build - public static class ContractRepository implements Serializable { - - private final Property repositoryUrl; - - private final Property username; - - private final Property password; - - private final Property proxyPort; - - private final Property proxyHost; - - @Inject - public ContractRepository(ObjectFactory objects) { - this.repositoryUrl = objects.property(String.class); - this.username = objects.property(String.class); - this.password = objects.property(String.class); - this.proxyHost = objects.property(String.class); - this.proxyPort = objects.property(Integer.class); - } - - public Property getRepositoryUrl() { - return repositoryUrl; - } - - public void setRepositoryUrl(String repositoryUrl) { - this.repositoryUrl.set(repositoryUrl); - } - - public Property getUsername() { - return username; - } - - public void setUsername(String username) { - this.username.set(username); - } - - public Property getPassword() { - return password; - } - - public void setPassword(String password) { - this.password.set(password); - } - - public Property getProxyHost() { - return proxyHost; - } - - public void setProxyHost(String proxyHost) { - this.proxyHost.set(proxyHost); - } - - public Property getProxyPort() { - return proxyPort; - } - - public void setProxyPort(int proxyPort) { - Assert.state(0 < proxyPort && proxyPort <= 65536, "Proxy port should be between 1 and 65536"); - this.proxyPort.set(proxyPort); - } - - @Override - public String toString() { - return "ContractRepository{" + "repositoryUrl=" + repositoryUrl.getOrNull() + ", username=" - + username.getOrNull() + ", password=" + password.getOrNull() + ", proxyPort=" - + proxyPort.getOrNull() + ", proxyHost=" + proxyHost.getOrNull() + '}'; - } - - } - - public static class PublishStubsToScm implements Serializable { - - /** - * Dependency that contains packaged contracts - */ - private final Dependency contractDependency; - - private final ContractRepository contractRepository; - - @Inject - public PublishStubsToScm(ObjectFactory objects) { - contractDependency = objects.newInstance(Dependency.class); - contractRepository = objects.newInstance(ContractRepository.class); - } - - public Dependency getContractDependency() { - return contractDependency; - } - - public void contractDependency(Action action) { - action.execute(contractDependency); - } - - public ContractRepository getContractRepository() { - return contractRepository; - } - - public void contractRepository(Action action) { - action.execute(contractRepository); - } - - @Override - public String toString() { - return "PublishStubsToScm{" + "contractDependency=" + contractDependency + ", contractRepository=" - + contractRepository + '}'; - } - - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/ContractsCopyTask.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/ContractsCopyTask.java deleted file mode 100644 index f67c709e42..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/ContractsCopyTask.java +++ /dev/null @@ -1,569 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.plugin; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.OutputStream; -import java.net.URI; -import java.util.Collection; -import java.util.Map; - -import javax.inject.Inject; - -import org.eclipse.jgit.api.Git; -import org.eclipse.jgit.api.errors.GitAPIException; -import org.eclipse.jgit.lib.Ref; -import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; -import org.eclipse.jgit.util.io.NullOutputStream; -import org.gradle.api.DefaultTask; -import org.gradle.api.GradleException; -import org.gradle.api.file.ConfigurableFileCollection; -import org.gradle.api.file.DirectoryProperty; -import org.gradle.api.file.FileSystemOperations; -import org.gradle.api.model.ObjectFactory; -import org.gradle.api.provider.MapProperty; -import org.gradle.api.provider.Property; -import org.gradle.api.provider.Provider; -import org.gradle.api.provider.ProviderFactory; -import org.gradle.api.tasks.CacheableTask; -import org.gradle.api.tasks.Classpath; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.InputDirectory; -import org.gradle.api.tasks.Internal; -import org.gradle.api.tasks.Nested; -import org.gradle.api.tasks.Optional; -import org.gradle.api.tasks.OutputDirectory; -import org.gradle.api.tasks.PathSensitive; -import org.gradle.api.tasks.PathSensitivity; -import org.gradle.api.tasks.TaskAction; -import org.gradle.process.ExecOperations; -import org.springframework.cloud.contract.stubrunner.ContractDownloader; -import org.springframework.cloud.contract.stubrunner.ScmStubDownloaderBuilder; -import org.springframework.cloud.contract.stubrunner.StubConfiguration; -import org.springframework.cloud.contract.stubrunner.StubDownloader; -import org.springframework.cloud.contract.stubrunner.StubDownloaderBuilderProvider; -import org.springframework.cloud.contract.stubrunner.StubRunnerOptions; -import org.springframework.cloud.contract.stubrunner.StubRunnerOptionsBuilder; -import org.springframework.cloud.contract.stubrunner.StubRunnerPropertyUtils; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.lang.Nullable; -import org.springframework.util.StringUtils; - -// TODO: Convert to incremental task: https://docs.gradle.org/current/userguide/custom_tasks.html#incremental_tasks -/** - * Task that copies the contracts in order for the jar task to generate the jar. It takes - * into consideration the inclusion patterns when working with repo with shared contracts. - * - * @author Marcin Grzejszczak - * @author Anatoliy Balakirev - * @author Shannon Pamperl - * @since 1.0.2 - */ -@CacheableTask -class ContractsCopyTask extends DefaultTask { - - static final String TASK_NAME = "copyContracts"; - static final String CONTRACTS = "contracts"; - static final String BACKUP = "original"; - - // inputs - private final Property convertToYaml; - - private final Property failOnNoContracts; - - private final DirectoryProperty contractsDirectory; - - private final Dependency contractDependency; - - private final Repository contractRepository; - - private final Property contractsMode; - - private final MapProperty contractsProperties; - - private final Provider> allContractsProperties; - - private final Property contractsPath; - - private final Property excludeBuildFolders; - - /** - * @see ContractVerifierExtension#getDeleteStubsAfterTest() - * - * This property will delete the temporary dependency or Git repository from which - * stubs were copied to this task's output directory. - */ - private final Property deleteStubsAfterTest; - - private final ConfigurableFileCollection classpath; - - // outputs - private final DirectoryProperty copiedContractsFolder; - - private final DirectoryProperty backupContractsFolder; - - private final Property projectGroup; - private final Property projectName; - private final Property projectVersion; - - private final ExecOperations executors; - private final FileSystemOperations files; - - @Inject - public ContractsCopyTask( - final ObjectFactory objects, - final ProviderFactory providers, - final ExecOperations executors, - final FileSystemOperations files - ) { - this.executors = executors; - this.files = files; - - convertToYaml = objects.property(Boolean.class); - failOnNoContracts = objects.property(Boolean.class); - contractsDirectory = objects.directoryProperty(); - contractDependency = objects.newInstance(Dependency.class); - contractRepository = objects.newInstance(Repository.class); - contractsMode = objects.property(StubRunnerProperties.StubsMode.class); - contractsProperties = objects.mapProperty(String.class, String.class); - allContractsProperties = contractsProperties.flatMap(contractsProps -> { - MapProperty allProps = objects.mapProperty(String.class, String.class); - allProps.putAll(contractsProps); - String gitCommitId = this.discoverGitCommitId(contractsProps); - if (StringUtils.hasText(gitCommitId)) { - allProps.put("git.commit", gitCommitId); - } - return allProps; - }); - contractsPath = objects.property(String.class); - excludeBuildFolders = objects.property(Boolean.class); - deleteStubsAfterTest = objects.property(Boolean.class); - classpath = objects.fileCollection(); - - copiedContractsFolder = objects.directoryProperty(); - backupContractsFolder = objects.directoryProperty(); - - projectGroup = objects.property(String.class).convention(providers.provider(() -> getProject().getGroup().toString())); - projectName = objects.property(String.class).convention(providers.provider(() -> getProject().getName())); - projectVersion = objects.property(String.class).convention(providers.provider(() -> getProject().getVersion().toString())); - - this.getOutputs().upToDateWhen(task -> !(this.shouldDownloadContracts() - && this.getContractDependency().toStubConfiguration().isVersionChanging())); - } - - @TaskAction - void sync() { - final File contractsDirectory; - final String antPattern; - if (shouldDownloadContracts()) { - DownloadedData downloadedData = downloadContracts(); - contractsDirectory = downloadedData.downloadedContracts; - antPattern = downloadedData.inclusionProperties.getIncludedRootFolderAntPattern() + "*.*"; - getLogger().info("Contracts got downloaded to [{}]", contractsDirectory); - } - else { - contractsDirectory = this.contractsDirectory.getAsFile().getOrNull(); - antPattern = "**/"; - } - getLogger().info("For project [{}] will use contracts provided in the folder [{}]", projectName.get(), - contractsDirectory); - final String contractsRepository = this.contractRepository.getRepositoryUrl().getOrElse(""); - throwExceptionWhenFailOnNoContracts(contractsDirectory, contractsRepository); - - final String slashSeparatedGroupId = projectGroup.get().replace(".", File.separator); - final String dotSeparatedAntPattern = antPattern.replace(slashSeparatedGroupId, projectGroup.get()); - File output = copiedContractsFolder.get().getAsFile(); - getLogger().info( - "Downloading and unpacking files from [{}] to [{}]. The inclusion ant patterns are [{}] and [{}]", - contractsDirectory, output, antPattern, dotSeparatedAntPattern); - sync(contractsDirectory, antPattern, dotSeparatedAntPattern, excludeBuildFolders.get(), output); - if (convertToYaml.get()) { - convertContractsToYaml(contractsDirectory, antPattern, dotSeparatedAntPattern, output, - excludeBuildFolders.get()); - } - } - - private void convertContractsToYaml(File file, String antPattern, String slashSeparatedAntPattern, - File outputContractsFolder, boolean excludeBuildFolders) { - sync(file, antPattern, slashSeparatedAntPattern, excludeBuildFolders, backupContractsFolder.get().getAsFile()); - OutputStream os; - if (getLogger().isDebugEnabled()) { - os = new ByteArrayOutputStream(); - } else { - os = NullOutputStream.INSTANCE; - } - try { - executors.javaexec(exec -> { - exec.getMainClass().set("org.springframework.cloud.contract.verifier.converter.ToYamlConverterApplication"); - exec.classpath(classpath); - exec.args(quoteAndEscape(outputContractsFolder.getAbsolutePath())); - exec.setStandardOutput(os); - exec.setErrorOutput(os); - }); - } catch (Exception e) { - throw new GradleException("Spring Cloud Contract Verifier Plugin exception: " + e.getMessage(), e); - } finally { - if (getLogger().isDebugEnabled()) { - getLogger().debug(os.toString()); - } - } - getLogger().info("Replaced DSL files with their YAML representation at [{}]", outputContractsFolder); - } - - private void sync(File file, String antPattern, String dotSeparatedAntPattern, boolean excludeBuildFolders, - File outputContractsFolder) { - files.sync(spec -> { - spec.from(file); - // by default group id is slash separated... - spec.include(antPattern); - // ...we also want to allow dot separation - spec.include(dotSeparatedAntPattern); - if (excludeBuildFolders) { - spec.exclude("**/target/**", "**/build/**", "**/.mvn/**", "**/.gradle/**"); - } - spec.into(outputContractsFolder); - }); - } - - private DownloadedData downloadContracts() { - String groupId = projectGroup.get(); - String artifactId = projectName.get(); - getLogger().info("Project has group id [{}], artifact id [{}]", groupId, artifactId); - getLogger().info("For project [{}] Download dependency is provided - will download contract jars", artifactId); - getLogger().info("Contract dependency [{}]", contractDependency); - StubConfiguration configuration = contractDependency.toStubConfiguration(); - getLogger().info("Got the following contract dependency to download [{}]", configuration); - getLogger().info("The contract dependency is a changing one [{}]", configuration.isVersionChanging()); - - final StubDownloader downloader = new StubDownloaderBuilderProvider().get(createStubRunnerOptions()); - final ContractDownloader contractDownloader = new ContractDownloader(downloader, configuration, - contractsPath.getOrNull(), groupId, artifactId, projectVersion.get()); - final File downloadedContracts = contractDownloader.unpackAndDownloadContracts(); - final ContractDownloader.InclusionProperties inclusionProperties = contractDownloader - .createNewInclusionProperties(downloadedContracts); - - // TODO: inclusionProperties.includedContracts is never used eventually. Review - // this: - return new DownloadedData(contractsSubDirIfPresent(downloadedContracts), inclusionProperties); - } - - private void throwExceptionWhenFailOnNoContracts(@Nullable File file, String contractsRepository) { - if (StringUtils.hasText(contractsRepository)) { - if (getLogger().isDebugEnabled()) { - getLogger().debug( - "Contracts repository is set, will not throw an exception that the contracts are not found"); - } - return; - } - if (failOnNoContracts.get() && (file == null || !file.exists() || file.listFiles().length == 0)) { - String path = file != null ? file.getAbsolutePath() : ""; - throw new GradleException("Contracts could not be found: [" + path - + "]\nPlease make sure that the contracts were defined, or set the [failOnNoContracts] flag to [false]"); - } - } - - private File contractsSubDirIfPresent(File contractsDirectory) { - File contracts = new File(contractsDirectory, "contracts"); - if (contracts.exists()) { - if (getLogger().isDebugEnabled()) { - getLogger().debug("Contracts folder found [{}]", contracts); - } - contractsDirectory = contracts; - } - return contractsDirectory; - } - - private class DownloadedData { - - final File downloadedContracts; - - final ContractDownloader.InclusionProperties inclusionProperties; - - private DownloadedData(File downloadedContracts, ContractDownloader.InclusionProperties inclusionProperties) { - this.downloadedContracts = downloadedContracts; - this.inclusionProperties = inclusionProperties; - } - - } - - @Input protected Property getProjectGroup() { return projectGroup; } - @Input protected Property getProjectName() { return projectName; } - @Input protected Property getProjectVersion() { return projectVersion; } - - @Input - Property getConvertToYaml() { - return convertToYaml; - } - - @Input - Property getFailOnNoContracts() { - return failOnNoContracts; - } - - @InputDirectory - @Optional - @PathSensitive(PathSensitivity.RELATIVE) - DirectoryProperty getContractsDirectory() { - return contractsDirectory; - } - - @Nested - Dependency getContractDependency() { - return contractDependency; - } - - static class Dependency { - - private static final String LATEST_VERSION = "+"; - - private final Property groupId; - - private final Property artifactId; - - private final Property version; - - private final Property classifier; - - private final Property stringNotation; - - @Inject - public Dependency(ObjectFactory objects) { - groupId = objects.property(String.class); - artifactId = objects.property(String.class); - version = objects.property(String.class); - classifier = objects.property(String.class); - stringNotation = objects.property(String.class); - } - - @Input - @Optional - Property getGroupId() { - return groupId; - } - - @Input - @Optional - Property getArtifactId() { - return artifactId; - } - - @Input - @Optional - Property getVersion() { - return version; - } - - @Input - @Optional - Property getClassifier() { - return classifier; - } - - @Input - @Optional - Property getStringNotation() { - return stringNotation; - } - - StubConfiguration toStubConfiguration() { - String stringNotation = this.stringNotation.getOrNull(); - if (StringUtils.hasText(stringNotation)) { - return new StubConfiguration(stringNotation); - } - - String groupId = this.groupId.getOrNull(); - String artifactId = this.artifactId.getOrNull(); - String version = StringUtils.hasText(this.version.getOrNull()) ? this.version.getOrNull() : LATEST_VERSION; - String classifier = this.classifier.getOrNull(); - return new StubConfiguration(groupId, artifactId, version, classifier); - } - - } - - @Nested - Repository getContractRepository() { - return contractRepository; - } - - static class Repository { - - private final Property repositoryUrl; - - private final Property username; - - private final Property password; - - private final Property proxyHost; - - private final Property proxyPort; - - @Inject - public Repository(ObjectFactory objects) { - repositoryUrl = objects.property(String.class); - username = objects.property(String.class); - password = objects.property(String.class); - proxyHost = objects.property(String.class); - proxyPort = objects.property(Integer.class); - } - - @Input - @Optional - Property getRepositoryUrl() { - return repositoryUrl; - } - - @Input - @Optional - Property getUsername() { - return username; - } - - @Input - @Optional - Property getPassword() { - return password; - } - - @Input - @Optional - Property getProxyHost() { - return proxyHost; - } - - @Input - @Optional - Property getProxyPort() { - return proxyPort; - } - - } - - @Input - @Optional - Property getContractsMode() { - return contractsMode; - } - - @Internal - MapProperty getContractsProperties() { - return contractsProperties; - } - - @Input - Provider> getAllContractsProperties() { - return allContractsProperties; - } - - @Input - @Optional - Property getContractsPath() { - return contractsPath; - } - - @Input - Property getExcludeBuildFolders() { - return excludeBuildFolders; - } - - @Input - Property getDeleteStubsAfterTest() { - return deleteStubsAfterTest; - } - - @Classpath - ConfigurableFileCollection getClasspath() { - return classpath; - } - - @OutputDirectory - DirectoryProperty getCopiedContractsFolder() { - return copiedContractsFolder; - } - - @Optional - @OutputDirectory - DirectoryProperty getBackupContractsFolder() { - return backupContractsFolder; - } - - private boolean shouldDownloadContracts() { - return StringUtils.hasText(contractDependency.getArtifactId().getOrNull()) - || StringUtils.hasText(contractDependency.getStringNotation().getOrNull()) - || StringUtils.hasText(contractRepository.getRepositoryUrl().getOrNull()); - } - - private StubRunnerOptions createStubRunnerOptions() { - StubRunnerOptionsBuilder options = new StubRunnerOptionsBuilder() - .withOptions(StubRunnerOptions.fromSystemProps()) - .withStubRepositoryRoot(contractRepository.repositoryUrl.getOrNull()).withStubsMode(contractsMode.get()) - .withUsername(contractRepository.username.getOrNull()) - .withPassword(contractRepository.password.getOrNull()) - .withDeleteStubsAfterTest(deleteStubsAfterTest.get()).withProperties(allContractsProperties.getOrNull()) - .withFailOnNoStubs(failOnNoContracts.get()); - if (contractRepository.proxyPort.isPresent()) { - options = options.withProxy(contractRepository.proxyHost.getOrNull(), contractRepository.proxyPort.get()); - } - return options.build(); - } - - @Nullable - private String discoverGitCommitId(Map props) { - String repositoryUrl = contractRepository.getRepositoryUrl().getOrNull(); - if (repositoryUrl != null && ScmStubDownloaderBuilder.isProtocolAccepted(repositoryUrl)) { - String branch = StubRunnerPropertyUtils.getProperty(props, "git.branch"); - branch = StringUtils.hasText(branch) ? branch : "master"; - UsernamePasswordCredentialsProvider provider = null; - if (StringUtils.hasText(contractRepository.getUsername().getOrNull())) { - provider = new UsernamePasswordCredentialsProvider(contractRepository.getUsername().get(), - contractRepository.getPassword().get()); - } - try { - String repoUrl; - URI repoUri = URI.create(repositoryUrl); - String part = repoUri.getSchemeSpecificPart(); - if (!StringUtils.hasLength(part)) { - repoUrl = part; - } - else { - repoUrl = part.startsWith("//") ? part.substring(2) : part; - } - Collection refs = Git.lsRemoteRepository().setRemote(repoUrl).setCredentialsProvider(provider) - .call(); - for (Ref ref : refs) { - if (ref.getName().equals(branch) || ref.getName().equals("refs/heads/" + branch) - || ref.getName().equals("refs/tags/" + branch)) { - return ref.getObjectId().name(); - } - } - } - catch (GitAPIException e) { - ContractsCopyTask.this.getLogger().warn("Unable to determine git repository commit id", e); - } - } - return null; - } - - // See: https://github.com/gradle/gradle/issues/6072 - private String quoteAndEscape(String str) { - if (System.getProperty("os.name").contains("Windows")) { - return "\"" + str.replace("\"", "\\\"") + "\""; - } - return str; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/GenerateClientStubsFromDslTask.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/GenerateClientStubsFromDslTask.java deleted file mode 100644 index b20c60b78d..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/GenerateClientStubsFromDslTask.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.plugin; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.OutputStream; - -import javax.inject.Inject; - -import org.eclipse.jgit.util.io.NullOutputStream; -import org.gradle.api.DefaultTask; -import org.gradle.api.GradleException; -import org.gradle.api.file.ConfigurableFileCollection; -import org.gradle.api.file.Directory; -import org.gradle.api.file.DirectoryProperty; -import org.gradle.api.model.ObjectFactory; -import org.gradle.api.provider.ListProperty; -import org.gradle.api.provider.Property; -import org.gradle.api.tasks.CacheableTask; -import org.gradle.api.tasks.Classpath; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.InputDirectory; -import org.gradle.api.tasks.OutputDirectory; -import org.gradle.api.tasks.PathSensitive; -import org.gradle.api.tasks.PathSensitivity; -import org.gradle.api.tasks.SkipWhenEmpty; -import org.gradle.api.tasks.TaskAction; -import org.gradle.process.ExecOperations; -import org.springframework.util.StringUtils; - -//TODO: Implement as an incremental task: https://gradle.org/docs/current/userguide/custom_tasks.html#incremental_tasks ? -/** - * Generates stubs from the contracts. - * - * @author Marcin Grzejszczak - * @author Anatoliy Balakirev - * @author Shannon Pamperl - * @since 2.0.0 - */ -@CacheableTask -class GenerateClientStubsFromDslTask extends DefaultTask { - - static final String TASK_NAME = "generateClientStubs"; - static final String DEFAULT_MAPPINGS_FOLDER = "mappings"; - - private final Property contractsDslDir; - - private final ListProperty excludedFiles; - - private final Property excludeBuildFolders; - - private final ConfigurableFileCollection classpath; - - private final DirectoryProperty stubsOutputDir; - - final ExecOperations executors; - - @Inject - public GenerateClientStubsFromDslTask( - final ObjectFactory objects, - final ExecOperations executors - ) { - this.executors = executors; - - contractsDslDir = objects.directoryProperty(); - excludedFiles = objects.listProperty(String.class); - excludeBuildFolders = objects.property(Boolean.class); - classpath = objects.fileCollection(); - - stubsOutputDir = objects.directoryProperty(); - } - - @TaskAction - void generate() { - File output = stubsOutputDir.get().getAsFile(); - getLogger().info("Stubs output dir [{}]", output); - getLogger().info("Spring Cloud Contract Verifier Plugin: Invoking DSL to client stubs conversion"); - getLogger().info("Contracts dir is [{}] output stubs dir is [{}]", contractsDslDir.get().getAsFile(), output); - OutputStream os; - if (getLogger().isDebugEnabled()) { - os = new ByteArrayOutputStream(); - } else { - os = NullOutputStream.INSTANCE; - } - try { - executors.javaexec(exec -> { - exec.getMainClass().set("org.springframework.cloud.contract.verifier.converter.RecursiveFilesConverterApplication"); - exec.classpath(classpath); - exec.args(quoteAndEscape(output.getAbsolutePath()), quoteAndEscape(contractsDslDir.get().getAsFile().getAbsolutePath()), - quoteAndEscape(StringUtils.collectionToCommaDelimitedString(excludedFiles.get())), quoteAndEscape(".*"), excludeBuildFolders.get()); - exec.setStandardOutput(os); - exec.setErrorOutput(os); - }); - } catch (Exception e) { - throw new GradleException("Spring Cloud Contract Verifier Plugin exception: " + e.getMessage(), e); - } finally { - if (getLogger().isDebugEnabled()) { - getLogger().debug(os.toString()); - } - } - } - - @InputDirectory - @SkipWhenEmpty - @PathSensitive(PathSensitivity.RELATIVE) - public Property getContractsDslDir() { - return contractsDslDir; - } - - @Input - public ListProperty getExcludedFiles() { - return excludedFiles; - } - - @Input - public Property getExcludeBuildFolders() { - return excludeBuildFolders; - } - - @Classpath - public ConfigurableFileCollection getClasspath() { - return classpath; - } - - @OutputDirectory - public Property getStubsOutputDir() { - return stubsOutputDir; - } - - // See: https://github.com/gradle/gradle/issues/6072 - private String quoteAndEscape(String str) { - if (System.getProperty("os.name").contains("Windows")) { - return "\"" + str.replace("\"", "\\\"") + "\""; - } - return str; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/GenerateServerTestsTask.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/GenerateServerTestsTask.java deleted file mode 100644 index eee13489a2..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/GenerateServerTestsTask.java +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.plugin; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.OutputStream; -import java.util.List; - -import javax.inject.Inject; - -import org.eclipse.jgit.util.io.NullOutputStream; -import org.gradle.api.DefaultTask; -import org.gradle.api.GradleException; -import org.gradle.api.file.ConfigurableFileCollection; -import org.gradle.api.file.DirectoryProperty; -import org.gradle.api.model.ObjectFactory; -import org.gradle.api.provider.ListProperty; -import org.gradle.api.provider.MapProperty; -import org.gradle.api.provider.Property; -import org.gradle.api.tasks.CacheableTask; -import org.gradle.api.tasks.Classpath; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.InputDirectory; -import org.gradle.api.tasks.Optional; -import org.gradle.api.tasks.OutputDirectory; -import org.gradle.api.tasks.PathSensitive; -import org.gradle.api.tasks.PathSensitivity; -import org.gradle.api.tasks.SkipWhenEmpty; -import org.gradle.api.tasks.TaskAction; -import org.gradle.process.ExecOperations; -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties; -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.config.TestMode; - -import com.fasterxml.jackson.databind.ObjectMapper; - -/** - * Task used to generate server side tests - * - * @author Marcin Grzejszczak - * @author Anatoliy Balakirev - * @author Shannon Pamperl - * @since 1.0.0 - */ -@CacheableTask -class GenerateServerTestsTask extends DefaultTask { - - static final String TASK_NAME = "generateContractTests"; - - private final DirectoryProperty contractsDslDir; - - private final Property nameSuffixForTests; - - private final Property basePackageForTests; - - private final Property baseClassForTests; - - private final Property packageWithBaseClasses; - - private final ListProperty excludedFiles; - - private final ListProperty ignoredFiles; - - private final ListProperty includedFiles; - - private final ListProperty imports; - - private final ListProperty staticImports; - - private final Property testMode; - - private final Property testFramework; - - private final MapProperty baseClassMappings; - - private final Property assertJsonSize; - - private final Property failOnInProgress; - - private final ConfigurableFileCollection classpath; - - private final DirectoryProperty generatedTestSourcesDir; - - private final DirectoryProperty generatedTestResourcesDir; - - final ExecOperations executors; - - @Inject - public GenerateServerTestsTask( - final ObjectFactory objects, - final ExecOperations executors - ) { - this.executors = executors; - - this.contractsDslDir = objects.directoryProperty(); - this.nameSuffixForTests = objects.property(String.class); - this.basePackageForTests = objects.property(String.class); - this.baseClassForTests = objects.property(String.class); - this.packageWithBaseClasses = objects.property(String.class); - this.excludedFiles = objects.listProperty(String.class); - this.ignoredFiles = objects.listProperty(String.class); - this.includedFiles = objects.listProperty(String.class); - this.imports = objects.listProperty(String.class); - this.staticImports = objects.listProperty(String.class); - this.testMode = objects.property(TestMode.class); - this.testFramework = objects.property(TestFramework.class); - this.baseClassMappings = objects.mapProperty(String.class, String.class); - this.assertJsonSize = objects.property(Boolean.class); - this.failOnInProgress = objects.property(Boolean.class); - this.classpath = objects.fileCollection(); - this.generatedTestSourcesDir = objects.directoryProperty(); - this.generatedTestResourcesDir = objects.directoryProperty(); - } - - @TaskAction - void generate() { - File generatedTestSources = this.generatedTestSourcesDir.get().getAsFile(); - File generatedTestResources = this.generatedTestResourcesDir.get().getAsFile(); - getLogger().info("Generated test sources dir [{}]", generatedTestSources); - getLogger().info("Generated test resources dir [{}]", generatedTestResources); - File contractsDslDir = this.contractsDslDir.get().getAsFile(); - String includedContracts = ".*"; - getLogger().info("Spring Cloud Contract Verifier Plugin: Invoking test sources generation"); - getLogger().info("Contracts are unpacked to [{}]", contractsDslDir); - getLogger().info("Included contracts are [{}]", includedContracts); - ContractVerifierConfigProperties properties = toConfigProperties(contractsDslDir, includedContracts, generatedTestSources, generatedTestResources); - OutputStream os; - if (getLogger().isDebugEnabled()) { - os = new ByteArrayOutputStream(); - } else { - os = NullOutputStream.INSTANCE; - } - try { - String propertiesJson = new ObjectMapper().writeValueAsString(properties); - executors.javaexec(exec -> { - exec.getMainClass().set("org.springframework.cloud.contract.verifier.TestGeneratorApplication"); - exec.classpath(classpath); - exec.args(quoteAndEscape(propertiesJson)); - exec.setStandardOutput(os); - exec.setErrorOutput(os); - }); - } - catch (Exception e) { - throw new GradleException("Spring Cloud Contract Verifier Plugin exception: " + e.getMessage(), e); - } finally { - if (getLogger().isDebugEnabled()) { - getLogger().debug(os.toString()); - } - } - } - - @InputDirectory - @SkipWhenEmpty - @PathSensitive(PathSensitivity.RELATIVE) - DirectoryProperty getContractsDslDir() { - return contractsDslDir; - } - - @Input - @Optional - Property getNameSuffixForTests() { - return nameSuffixForTests; - } - - @Input - @Optional - Property getBasePackageForTests() { - return basePackageForTests; - } - - @Input - @Optional - Property getBaseClassForTests() { - return baseClassForTests; - } - - @Input - @Optional - Property getPackageWithBaseClasses() { - return packageWithBaseClasses; - } - - @Input - ListProperty getExcludedFiles() { - return excludedFiles; - } - - @Input - ListProperty getIgnoredFiles() { - return ignoredFiles; - } - - @Input - ListProperty getIncludedFiles() { - return includedFiles; - } - - @Input - ListProperty getImports() { - return imports; - } - - @Input - ListProperty getStaticImports() { - return staticImports; - } - - @Input - Property getTestMode() { - return testMode; - } - - @Input - Property getTestFramework() { - return testFramework; - } - - @Input - MapProperty getBaseClassMappings() { - return baseClassMappings; - } - - @Input - Property getAssertJsonSize() { - return assertJsonSize; - } - - @Input - Property getFailOnInProgress() { - return failOnInProgress; - } - - @Classpath - ConfigurableFileCollection getClasspath() { - return classpath; - } - - @OutputDirectory - DirectoryProperty getGeneratedTestSourcesDir() { - return generatedTestSourcesDir; - } - - @OutputDirectory - DirectoryProperty getGeneratedTestResourcesDir() { - return generatedTestResourcesDir; - } - - private ContractVerifierConfigProperties toConfigProperties(File contractsDslDir, String includedContracts, - File generatedTestSources, File generatedTestResources) { - List excludedFiles = this.excludedFiles.get(); - List ignoredFiles = this.ignoredFiles.get(); - List includedFiles = this.includedFiles.get(); - String[] imports = this.imports.get().toArray(new String[0]); - String[] staticImports = this.staticImports.get().toArray(new String[0]); - - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties(); - properties.setIncludedContracts(includedContracts); - properties.setContractsDslDir(contractsDslDir); - properties.setNameSuffixForTests(nameSuffixForTests.getOrNull()); - properties.setGeneratedTestSourcesDir(generatedTestSources); - properties.setGeneratedTestResourcesDir(generatedTestResources); - properties.setBasePackageForTests(basePackageForTests.getOrNull()); - properties.setBaseClassForTests(baseClassForTests.getOrNull()); - properties.setPackageWithBaseClasses(packageWithBaseClasses.getOrNull()); - properties.setExcludedFiles(excludedFiles); - properties.setIgnoredFiles(ignoredFiles); - properties.setIncludedFiles(includedFiles); - properties.setImports(imports); - properties.setStaticImports(staticImports); - properties.setTestMode(testMode.get()); - properties.setTestFramework(testFramework.get()); - properties.setBaseClassMappings(baseClassMappings.get()); - properties.setAssertJsonSize(assertJsonSize.get()); - properties.setFailOnInProgress(failOnInProgress.get()); - return properties; - } - - // See: https://github.com/gradle/gradle/issues/6072 - private String quoteAndEscape(String str) { - if (System.getProperty("os.name").contains("Windows")) { - return "\"" + str.replace("\"", "\\\"") + "\""; - } - return str; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/PublishStubsToScmTask.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/PublishStubsToScmTask.java deleted file mode 100644 index d27e081375..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/PublishStubsToScmTask.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.plugin; - -import javax.inject.Inject; - -import org.gradle.api.DefaultTask; -import org.gradle.api.file.DirectoryProperty; -import org.gradle.api.model.ObjectFactory; -import org.gradle.api.provider.MapProperty; -import org.gradle.api.provider.Property; -import org.gradle.api.provider.ProviderFactory; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.InputDirectory; -import org.gradle.api.tasks.Nested; -import org.gradle.api.tasks.Optional; -import org.gradle.api.tasks.PathSensitive; -import org.gradle.api.tasks.PathSensitivity; -import org.gradle.api.tasks.TaskAction; -import org.springframework.cloud.contract.stubrunner.ContractProjectUpdater; -import org.springframework.cloud.contract.stubrunner.ScmStubDownloaderBuilder; -import org.springframework.cloud.contract.stubrunner.StubRunnerOptions; -import org.springframework.cloud.contract.stubrunner.StubRunnerOptionsBuilder; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.util.StringUtils; - -/** - * For SCM based repositories will copy the generated stubs to the cloned repo with - * contracts and stubs. Will also commit the changes and push them to origin. - *

- * NOTE: starting with 2.3.0.RELEASE the customize{} closure previously used - * for {@link PublishStubsToScmTask} customisation is no longer available. The settings - * should be applied directly within the publishStubsToScm closure as in the - * example above. - * - * @author Marcin Grzejszczak - * @author Anatoliy Balakirev - * @author Shannon Pamperl - * @since 2.0.0 - */ -class PublishStubsToScmTask extends DefaultTask { - - static final String TASK_NAME = "publishStubsToScm"; - - private final Repository contractRepository; - - private final Property contractsMode; - - /** - * @see ContractVerifierExtension#getDeleteStubsAfterTest() - * - * This property will delete the Git repository where the input stubs to this task - * have been committed. - */ - private final Property deleteStubsAfterTest; - - private final Property failOnNoContracts; - - private final MapProperty contractsProperties; - - private final DirectoryProperty stubsDir; - - private final Property projectGroup; - private final Property projectName; - private final Property projectVersion; - - @Inject - public PublishStubsToScmTask( - final ObjectFactory objects, - final ProviderFactory providers - ) { - this.contractRepository = objects.newInstance(Repository.class); - this.contractsMode = objects.property(StubRunnerProperties.StubsMode.class); - this.deleteStubsAfterTest = objects.property(Boolean.class); - this.failOnNoContracts = objects.property(Boolean.class); - this.contractsProperties = objects.mapProperty(String.class, String.class); - this.stubsDir = objects.directoryProperty(); - - projectGroup = objects.property(String.class).convention(providers.provider(() -> getProject().getGroup().toString())); - projectName = objects.property(String.class).convention(providers.provider(() -> getProject().getName())); - projectVersion = objects.property(String.class).convention(providers.provider(() -> getProject().getVersion().toString())); - - this.onlyIf(task -> { - String contractRepoUrl = contractRepository.repositoryUrl.getOrElse(""); - if (!StringUtils.hasText(contractRepoUrl) || !ScmStubDownloaderBuilder.isProtocolAccepted(contractRepoUrl)) { - getLogger().warn( - "Skipping pushing stubs to scm since your contracts repository URL [{}] doesn't match any of the accepted protocols for SCM stub downloader", - contractRepoUrl); - return false; - } - return true; - }); - } - - @TaskAction - void publishStubsToScm() { - String projectGroupNameVersion = projectGroup.get() + ":" + projectName.get() + ":" + projectVersion.get(); - getLogger().info("Pushing Stubs to SCM for project [{}]", projectGroupNameVersion); - StubRunnerOptions stubRunnerOptions = createStubRunnerOptions(); - new ContractProjectUpdater(stubRunnerOptions).updateContractProject(projectGroupNameVersion, - stubsDir.get().getAsFile().toPath()); - } - - @Nested - Repository getContractRepository() { - return contractRepository; - } - - static class Repository { - - private final Property repositoryUrl; - - private final Property username; - - private final Property password; - - private final Property proxyPort; - - private final Property proxyHost; - - @Inject - public Repository(ObjectFactory objects) { - this.repositoryUrl = objects.property(String.class); - this.username = objects.property(String.class); - this.password = objects.property(String.class); - this.proxyHost = objects.property(String.class); - this.proxyPort = objects.property(Integer.class); - } - - @Input - @Optional - Property getRepositoryUrl() { - return repositoryUrl; - } - - @Input - @Optional - Property getUsername() { - return username; - } - - @Input - @Optional - Property getPassword() { - return password; - } - - @Input - @Optional - Property getProxyPort() { - return proxyPort; - } - - @Input - @Optional - Property getProxyHost() { - return proxyHost; - } - - } - - @Input - Property getContractsMode() { - return contractsMode; - } - - @Input - Property getDeleteStubsAfterTest() { - return deleteStubsAfterTest; - } - - @Input - Property getFailOnNoContracts() { - return failOnNoContracts; - } - - @Input - MapProperty getContractsProperties() { - return contractsProperties; - } - - @InputDirectory - @PathSensitive(PathSensitivity.RELATIVE) - DirectoryProperty getStubsDir() { - return stubsDir; - } - - private StubRunnerOptions createStubRunnerOptions() { - StubRunnerOptionsBuilder options = new StubRunnerOptionsBuilder() - .withOptions(StubRunnerOptions.fromSystemProps()) - .withStubRepositoryRoot(contractRepository.repositoryUrl.getOrNull()).withStubsMode(contractsMode.get()) - .withUsername(contractRepository.username.getOrNull()) - .withPassword(contractRepository.password.getOrNull()) - .withDeleteStubsAfterTest(deleteStubsAfterTest.get()).withProperties(contractsProperties.getOrNull()) - .withFailOnNoStubs(failOnNoContracts.get()); - if (contractRepository.proxyPort.isPresent()) { - options = options.withProxy(contractRepository.proxyHost.getOrNull(), contractRepository.proxyPort.get()); - } - return options.build(); - } - - @Input protected Property getProjectGroup() { return projectGroup; } - @Input protected Property getProjectName() { return projectName; } - @Input protected Property getProjectVersion() { return projectVersion; } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/SpringCloudContractVerifierGradlePlugin.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/SpringCloudContractVerifierGradlePlugin.java deleted file mode 100644 index 332f41d92a..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/SpringCloudContractVerifierGradlePlugin.java +++ /dev/null @@ -1,439 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.plugin; - -import java.io.File; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -import javax.inject.Inject; - -import org.gradle.api.Plugin; -import org.gradle.api.Project; -import org.gradle.api.artifacts.Configuration; -import org.gradle.api.artifacts.ConfigurationContainer; -import org.gradle.api.attributes.Bundling; -import org.gradle.api.attributes.Category; -import org.gradle.api.attributes.LibraryElements; -import org.gradle.api.attributes.Usage; -import org.gradle.api.file.Directory; -import org.gradle.api.file.FileCollection; -import org.gradle.api.file.ProjectLayout; -import org.gradle.api.internal.HasConvention; -import org.gradle.api.logging.Logger; -import org.gradle.api.logging.Logging; -import org.gradle.api.model.ObjectFactory; -import org.gradle.api.plugins.GroovyPlugin; -import org.gradle.api.plugins.JavaBasePlugin; -import org.gradle.api.plugins.JavaPlugin; -import org.gradle.api.plugins.JavaPluginConvention; -import org.gradle.api.plugins.JvmTestSuitePlugin; -import org.gradle.api.plugins.jvm.JvmTestSuite; -import org.gradle.api.provider.Property; -import org.gradle.api.provider.Provider; -import org.gradle.api.provider.ProviderFactory; -import org.gradle.api.tasks.GroovySourceSet; -import org.gradle.api.tasks.SourceSet; -import org.gradle.api.tasks.SourceSetContainer; -import org.gradle.api.tasks.SourceSetOutput; -import org.gradle.api.tasks.TaskProvider; -import org.gradle.api.tasks.bundling.Jar; -import org.gradle.api.tasks.testing.Test; -import org.gradle.testing.base.TestingExtension; -import org.gradle.util.GradleVersion; -import org.springframework.cloud.contract.verifier.config.TestFramework; - -/** - * Gradle plugin for Spring Cloud Contract Verifier that from the DSL contract can - *

    - *
  • generate tests
  • - *
  • generate stubs
  • - *
- * - * @author Jakub Kubrynski, codearte.io - * @author Marcin Grzejszczak - * @author Anatoliy Balakirev - * @author Shannon Pamperl - * @since 1.0.0 - */ -public class SpringCloudContractVerifierGradlePlugin implements Plugin { - - private static final Logger logger = Logging.getLogger(SpringCloudContractVerifierGradlePlugin.class); - - private static final String SPRING_CLOUD_VERSION = VersionExtractor.forClass(SpringCloudContractVerifierGradlePlugin.class); - - private static final String GROUP_NAME = "Verification"; - - private static final String EXTENSION_NAME = "contracts"; - - private static final String CONTRACT_TEST_SOURCE_SET_NAME = "contractTest"; - - private static final String CONTRACT_TEST_COMPILE_ONLY_CONFIGURATION_NAME = "contractTestCompileOnly"; - - private static final String CONTRACT_TEST_IMPLEMENTATION_CONFIGURATION_NAME = "contractTestImplementation"; - - private static final String CONTRACT_TEST_RUNTIME_ONLY_CONFIGURATION_NAME = "contractTestRuntimeOnly"; - - private static final String CONTRACT_TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME = "contractTestRuntimeClasspath"; - - private static final String CONTRACT_TEST_GENERATOR_RUNTIME_CLASSPATH_CONFIGURATION_NAME = "contractTestGeneratorRuntimeClasspath"; - - private static final String VERIFIER_STUBS_JAR_TASK_NAME = "verifierStubsJar"; - - private static final String CONTRACT_TEST_TASK_NAME = "contractTest"; - - private Project project; - - private final ProjectLayout layout; - private final ProviderFactory providers; - private final ObjectFactory objects; - - @Inject - public SpringCloudContractVerifierGradlePlugin( - final ProjectLayout layout, - final ProviderFactory providers, - final ObjectFactory objects - ) { - this.layout = layout; - this.providers = providers; - this.objects = objects; - } - - @Override - public void apply(Project project) { - this.project = project; - project.getPlugins().apply(JavaPlugin.class); - project.getPlugins().apply(JvmTestSuitePlugin.class); - ContractVerifierExtension extension = project.getExtensions().create(EXTENSION_NAME, - ContractVerifierExtension.class); - - TaskProvider copyContracts = registerCopyContractsTask(extension); - TaskProvider generateClientStubs = registerGenerateClientStubsTask( - extension, copyContracts); - - registerStubsJarTask(extension, copyContracts, generateClientStubs); - TaskProvider generateServerTestsTaskProvider = - registerGenerateServerTestsTask(extension, copyContracts); - registerPublishStubsToScmTask(extension, generateClientStubs); - - - JavaPluginConvention javaConvention = project.getConvention().getPlugin(JavaPluginConvention.class); - TestingExtension testing = project.getExtensions().getByType(TestingExtension.class); - testing.getSuites().register("contractTest", JvmTestSuite.class, contractTestSuite -> { - contractTestSuite.useJUnitJupiter(); - - contractTestSuite.dependencies(dependencies -> { - if (GradleVersion.current().compareTo(GradleVersion.version("7.6")) < 0) { - try { - Method implementation = dependencies.getClass().getMethod("implementation", Object.class); - implementation.invoke(dependencies, project); - } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { - throw new RuntimeException("Unable to add project dependencies", e); - } - } else { - dependencies.getImplementation().add(dependencies.project()); - } - }); - - contractTestSuite.sources(sourceSet -> { - configureSourceSets(extension, javaConvention, sourceSet); - - project.getTasks().named(sourceSet.getProcessResourcesTaskName(), processContractTestResourcesTask -> { - processContractTestResourcesTask.dependsOn(generateServerTestsTaskProvider); - }); - project.getTasks().named(sourceSet.getCompileJavaTaskName(), compileContractTestJava -> compileContractTestJava.dependsOn(generateServerTestsTaskProvider)); - project.getPlugins().withType(GroovyPlugin.class, groovyPlugin -> { - project.getTasks().named(sourceSet.getCompileTaskName("groovy"), compileContractTestGroovy -> { - compileContractTestGroovy.dependsOn(generateServerTestsTaskProvider); - }); - }); - project.getPlugins().withId("kotlin", kotlinPlugin -> { - project.getTasks().named(sourceSet.getCompileTaskName("kotlin"), compileContractTestKotlin -> { - compileContractTestKotlin.dependsOn(generateServerTestsTaskProvider); - }); - }); - project.getPlugins().withId("org.jetbrains.kotlin.jvm", kotlinJvmPlugin -> { - project.getTasks().named(sourceSet.getCompileTaskName("kotlin"), compileContractTestKotlin -> { - compileContractTestKotlin.dependsOn(generateServerTestsTaskProvider); - }); - }); - }); - - contractTestSuite.getTargets().all(testSuiteTarget -> configureTestTask(testSuiteTarget.getTestTask())); - }); - - configureConfigurations(); - - project.getDependencies().add(CONTRACT_TEST_GENERATOR_RUNTIME_CLASSPATH_CONFIGURATION_NAME, "org.springframework.cloud:spring-cloud-contract-converters:" + SPRING_CLOUD_VERSION); - } - - private SourceSet configureSourceSets(ContractVerifierExtension extension, JavaPluginConvention javaConvention, SourceSet contractTest) { - SourceSetContainer sourceSets = javaConvention.getSourceSets(); - contractTest.getJava().srcDirs(extension.getGeneratedTestJavaSourcesDir()); - project.getPlugins().withType(GroovyPlugin.class, groovyPlugin -> { - GroovySourceSet groovy = ((HasConvention) contractTest).getConvention().getPlugin(GroovySourceSet.class); - groovy.getGroovy().srcDirs(extension.getGeneratedTestGroovySourcesDir()); - }); - contractTest.getResources().srcDirs(extension.getGeneratedTestResourcesDir()); - - SourceSetOutput mainOutput = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME).getOutput(); - SourceSetOutput testOutput = sourceSets.getByName(SourceSet.TEST_SOURCE_SET_NAME).getOutput(); - - FileCollection compileClasspath = contractTest.getCompileClasspath(); - contractTest.setCompileClasspath(compileClasspath.plus(mainOutput).plus(testOutput)); - - FileCollection runtimeClasspath = contractTest.getRuntimeClasspath(); - contractTest.setRuntimeClasspath(runtimeClasspath.plus(mainOutput).plus(testOutput)); - return contractTest; - } - - private void configureConfigurations() { - ConfigurationContainer configurations = project.getConfigurations(); - - Configuration testCompileOnly = configurations.getByName(JavaPlugin.TEST_COMPILE_ONLY_CONFIGURATION_NAME); - Configuration testImplementation = configurations.getByName(JavaPlugin.TEST_IMPLEMENTATION_CONFIGURATION_NAME); - Configuration testRuntimeOnly = configurations.getByName(JavaPlugin.TEST_RUNTIME_ONLY_CONFIGURATION_NAME); - Configuration contractTestCompileOnly = configurations.getByName(CONTRACT_TEST_COMPILE_ONLY_CONFIGURATION_NAME); - Configuration contractTestImplementation = configurations - .getByName(CONTRACT_TEST_IMPLEMENTATION_CONFIGURATION_NAME); - Configuration contractTestRuntimeOnly = configurations.getByName(CONTRACT_TEST_RUNTIME_ONLY_CONFIGURATION_NAME); - - contractTestCompileOnly.extendsFrom(testCompileOnly); - contractTestImplementation.extendsFrom(testImplementation); - contractTestRuntimeOnly.extendsFrom(testRuntimeOnly); - - configurations.create(CONTRACT_TEST_GENERATOR_RUNTIME_CLASSPATH_CONFIGURATION_NAME, conf -> { - conf.setVisible(false); - conf.setCanBeResolved(true); - conf.setCanBeConsumed(false); - conf.attributes(attributes -> { - attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.class, Usage.JAVA_RUNTIME)); - attributes.attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.class, Category.LIBRARY)); - attributes.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.class, LibraryElements.JAR)); - attributes.attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.class, Bundling.EXTERNAL)); - }); - conf.extendsFrom(configurations.getByName(CONTRACT_TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME)); - }); - } - - private void configureTestTask(TaskProvider contractTestTaskProvider) { - contractTestTaskProvider.configure(contractTest -> { - contractTest.setDescription("Runs the contract tests"); - contractTest.setGroup(GROUP_NAME); - - contractTest.shouldRunAfter(project.getTasks().named(JavaPlugin.TEST_TASK_NAME)); - }); - - project.getTasks().named(JavaBasePlugin.CHECK_TASK_NAME, check -> check.dependsOn(contractTestTaskProvider)); - } - - private TaskProvider registerGenerateServerTestsTask(ContractVerifierExtension extension, - TaskProvider copyContracts) { - TaskProvider task = project.getTasks().register(GenerateServerTestsTask.TASK_NAME, - GenerateServerTestsTask.class); - task.configure(generateServerTestsTask -> { - generateServerTestsTask.setDescription("Generate server tests from the contracts"); - generateServerTestsTask.setGroup(GROUP_NAME); - - generateServerTestsTask.getContractsDslDir() - .convention(copyContracts.flatMap(ContractsCopyTask::getCopiedContractsFolder)); - generateServerTestsTask.getNameSuffixForTests().convention(extension.getNameSuffixForTests()); - generateServerTestsTask.getBasePackageForTests().convention(extension.getBasePackageForTests()); - generateServerTestsTask.getBaseClassForTests().convention(extension.getBaseClassForTests()); - generateServerTestsTask.getPackageWithBaseClasses().convention(extension.getPackageWithBaseClasses()); - generateServerTestsTask.getExcludedFiles().convention(extension.getExcludedFiles()); - generateServerTestsTask.getIgnoredFiles().convention(extension.getIgnoredFiles()); - generateServerTestsTask.getIncludedFiles().convention(extension.getIncludedFiles()); - generateServerTestsTask.getImports().convention(extension.getImports()); - generateServerTestsTask.getStaticImports().convention(extension.getStaticImports()); - generateServerTestsTask.getTestMode().convention(extension.getTestMode()); - generateServerTestsTask.getTestFramework().convention(extension.getTestFramework()); - generateServerTestsTask.getBaseClassMappings() - .convention(extension.getBaseClassMappings().getBaseClassMappings()); - generateServerTestsTask.getAssertJsonSize().convention(extension.getAssertJsonSize()); - generateServerTestsTask.getFailOnInProgress().convention(extension.getFailOnInProgress()); - generateServerTestsTask.getClasspath() - .from(project.getConfigurations().getByName(CONTRACT_TEST_GENERATOR_RUNTIME_CLASSPATH_CONFIGURATION_NAME)); - generateServerTestsTask.getGeneratedTestSourcesDir() - .convention(extension.getTestFramework().flatMap(testFramework -> { - Property correctSourceSetDir; - if (testFramework == TestFramework.SPOCK) { - correctSourceSetDir = extension.getGeneratedTestGroovySourcesDir(); - return extension.getGeneratedTestGroovySourcesDir().orElse(correctSourceSetDir); - } - else { - correctSourceSetDir = extension.getGeneratedTestJavaSourcesDir(); - return extension.getGeneratedTestJavaSourcesDir().orElse(correctSourceSetDir); - } - })); - generateServerTestsTask.getGeneratedTestResourcesDir().convention(extension.getGeneratedTestResourcesDir()); - - generateServerTestsTask.dependsOn(copyContracts); - }); - return task; - } - - private void registerPublishStubsToScmTask(ContractVerifierExtension extension, - TaskProvider generateClientStubs) { - TaskProvider task = project.getTasks().register(PublishStubsToScmTask.TASK_NAME, - PublishStubsToScmTask.class); - task.configure(publishStubsToScmTask -> { - publishStubsToScmTask - .setDescription("The generated stubs get committed to the SCM repo and pushed to origin"); - publishStubsToScmTask.setGroup(GROUP_NAME); - - ContractVerifierExtension.ContractRepository stubs = extension.getPublishStubsToScm() - .getContractRepository(); - ContractVerifierExtension.ContractRepository original = extension.getContractRepository(); - - publishStubsToScmTask.getContractRepository().getRepositoryUrl() - .convention(stubs.getRepositoryUrl().orElse(original.getRepositoryUrl())); - publishStubsToScmTask.getContractRepository().getUsername() - .convention(stubs.getUsername().orElse(original.getUsername())); - publishStubsToScmTask.getContractRepository().getPassword() - .convention(stubs.getPassword().orElse(original.getPassword())); - publishStubsToScmTask.getContractRepository().getProxyHost() - .convention(stubs.getProxyHost().orElse(original.getProxyHost())); - publishStubsToScmTask.getContractRepository().getProxyPort() - .convention(stubs.getProxyPort().orElse(original.getProxyPort())); - publishStubsToScmTask.getContractsMode().convention(extension.getContractsMode()); - publishStubsToScmTask.getDeleteStubsAfterTest().convention(extension.getDeleteStubsAfterTest()); - publishStubsToScmTask.getFailOnNoContracts().convention(extension.getFailOnNoContracts()); - publishStubsToScmTask.getContractsProperties().convention(extension.getContractsProperties()); - publishStubsToScmTask.getStubsDir().convention(extension.getStubsOutputDir()); - publishStubsToScmTask.dependsOn(generateClientStubs); - }); - } - - private TaskProvider registerGenerateClientStubsTask( - ContractVerifierExtension extension, TaskProvider copyContracts) { - TaskProvider task = project.getTasks().register( - GenerateClientStubsFromDslTask.TASK_NAME, GenerateClientStubsFromDslTask.class, generateClientStubs -> { - generateClientStubs.setGroup(GROUP_NAME); - generateClientStubs.setDescription("Generate client stubs from the contracts"); - - generateClientStubs.getContractsDslDir() - .convention(copyContracts.flatMap(ContractsCopyTask::getCopiedContractsFolder)); - generateClientStubs.getExcludedFiles().convention(extension.getExcludedFiles()); - generateClientStubs.getExcludeBuildFolders().convention(extension.getExcludeBuildFolders()); - generateClientStubs.getClasspath() - .from(project.getConfigurations().getByName(CONTRACT_TEST_GENERATOR_RUNTIME_CLASSPATH_CONFIGURATION_NAME)); - - generateClientStubs.getStubsOutputDir().convention(extension.getStubsOutputDir() - .dir(buildRootPath(GenerateClientStubsFromDslTask.DEFAULT_MAPPINGS_FOLDER))); - - generateClientStubs.dependsOn(copyContracts); - }); - return task; - } - - private void registerStubsJarTask(ContractVerifierExtension extension, - TaskProvider copyContracts, - TaskProvider generateClientStubs) { - TaskProvider verifierStubsJar = project.getTasks().register(VERIFIER_STUBS_JAR_TASK_NAME, Jar.class); - verifierStubsJar.configure(stubsJar -> { - stubsJar.setDescription("Creates the stubs JAR task"); - stubsJar.setGroup(GROUP_NAME); - stubsJar.getArchiveBaseName().convention(providers.provider(project::getName)); - stubsJar.getArchiveClassifier().convention(extension.getStubsSuffix()); - stubsJar.from(extension.getStubsOutputDir()); - - stubsJar.dependsOn(copyContracts); - stubsJar.dependsOn(generateClientStubs); - }); - project.artifacts(artifactHandler -> artifactHandler.add("archives", verifierStubsJar)); - } - - private TaskProvider registerCopyContractsTask(ContractVerifierExtension extension) { - TaskProvider task = project.getTasks().register(ContractsCopyTask.TASK_NAME, - ContractsCopyTask.class, contractsCopyTask -> { - contractsCopyTask.setGroup(GROUP_NAME); - contractsCopyTask.setDescription("Copies contracts to the output folder"); - - contractsCopyTask.getConvertToYaml().convention(extension.getConvertToYaml()); - contractsCopyTask.getFailOnNoContracts().convention(extension.getFailOnNoContracts()); - contractsCopyTask.getContractsDirectory() - .convention(extension.getContractsDslDir().flatMap(contractsDslDir -> { - return providers.provider(() -> { - if (contractsDslDir.getAsFile().exists()) { - return contractsDslDir; - } - else { - Directory legacyContractsDslDir = layout.getProjectDirectory() - .dir("src/test/resources/contracts"); - if (legacyContractsDslDir.getAsFile().exists()) { - logger.warn( - "Spring Cloud Contract Verifier Plugin: Locating contracts in has been removed. Please move them to . This warning message will be removed in a future release."); - return contractsDslDir; - } - else { - return null; - } - } - }); - })); - contractsCopyTask.getContractDependency().getGroupId() - .convention(extension.getContractDependency().getGroupId()); - contractsCopyTask.getContractDependency().getArtifactId() - .convention(extension.getContractDependency().getArtifactId()); - contractsCopyTask.getContractDependency().getVersion() - .convention(extension.getContractDependency().getVersion()); - contractsCopyTask.getContractDependency().getClassifier() - .convention(extension.getContractDependency().getClassifier()); - contractsCopyTask.getContractDependency().getStringNotation() - .convention(extension.getContractDependency().getStringNotation()); - contractsCopyTask.getContractRepository().getRepositoryUrl() - .convention(extension.getContractRepository().getRepositoryUrl()); - contractsCopyTask.getContractRepository().getUsername() - .convention(extension.getContractRepository().getUsername()); - contractsCopyTask.getContractRepository().getPassword() - .convention(extension.getContractRepository().getPassword()); - contractsCopyTask.getContractRepository().getProxyHost() - .convention(extension.getContractRepository().getProxyHost()); - contractsCopyTask.getContractRepository().getProxyPort() - .convention(extension.getContractRepository().getProxyPort()); - contractsCopyTask.getContractsMode().convention(extension.getContractsMode()); - contractsCopyTask.getContractsProperties().convention(extension.getContractsProperties()); - contractsCopyTask.getContractsPath().convention(extension.getContractsPath()); - contractsCopyTask.getExcludeBuildFolders().convention(extension.getExcludeBuildFolders()); - contractsCopyTask.getDeleteStubsAfterTest().convention(extension.getDeleteStubsAfterTest()); - contractsCopyTask.getClasspath() - .from(project.getConfigurations().getByName(CONTRACT_TEST_GENERATOR_RUNTIME_CLASSPATH_CONFIGURATION_NAME)); - - contractsCopyTask.getCopiedContractsFolder() - .convention(extension.getStubsOutputDir().dir(buildRootPath(ContractsCopyTask.CONTRACTS))); - contractsCopyTask.getBackupContractsFolder() - .convention(extension.getStubsOutputDir().dir(buildRootPath(ContractsCopyTask.BACKUP))); - }); - return task; - } - - private Provider buildRootPath(String path) { - return providers.provider(() -> - "META-INF" - + File.separator - + project.getGroup() - + File.separator - + project.getName() - + File.separator - + project.getVersion() - + File.separator - + path - ); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/VersionExtractor.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/VersionExtractor.java deleted file mode 100644 index 296c7c08ec..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/VersionExtractor.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.plugin; - -import java.io.File; -import java.io.IOException; -import java.net.JarURLConnection; -import java.net.URL; -import java.net.URLConnection; -import java.util.jar.Attributes; -import java.util.jar.JarFile; - -final class VersionExtractor { - private VersionExtractor() { - } - - static String forClass(Class cls) { - String implementationVersion = cls.getPackage().getImplementationVersion(); - if (implementationVersion != null) { - return implementationVersion; - } - URL codeSourceLocation = cls.getProtectionDomain().getCodeSource().getLocation(); - try { - URLConnection connection = codeSourceLocation.openConnection(); - if (connection instanceof JarURLConnection) { - return getImplementationVersion(((JarURLConnection) connection).getJarFile()); - } - try (JarFile jarFile = new JarFile(new File(codeSourceLocation.toURI()))) { - return getImplementationVersion(jarFile); - } - } - catch (Exception e) { - return null; - } - } - - private static String getImplementationVersion(JarFile jarFile) throws IOException { - return jarFile.getManifest().getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_VERSION); - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/resources/META-INF/gradle-plugins/org.springframework.cloud.contract.properties b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/resources/META-INF/gradle-plugins/org.springframework.cloud.contract.properties deleted file mode 100644 index 1d4121eb86..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/resources/META-INF/gradle-plugins/org.springframework.cloud.contract.properties +++ /dev/null @@ -1,16 +0,0 @@ -# -# Copyright 2013-2020 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -implementation-class=org.springframework.cloud.contract.verifier.plugin.SpringCloudContractVerifierGradlePlugin diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/resources/META-INF/gradle-plugins/spring-cloud-contract.properties b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/resources/META-INF/gradle-plugins/spring-cloud-contract.properties deleted file mode 100644 index 1d4121eb86..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/resources/META-INF/gradle-plugins/spring-cloud-contract.properties +++ /dev/null @@ -1,16 +0,0 @@ -# -# Copyright 2013-2020 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -implementation-class=org.springframework.cloud.contract.verifier.plugin.SpringCloudContractVerifierGradlePlugin diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/groovy/org/springframework/cloud/contract/verifier/plugin/ContractVerifierIntegrationTest.groovy b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/groovy/org/springframework/cloud/contract/verifier/plugin/ContractVerifierIntegrationTest.groovy deleted file mode 100644 index 51ec3c6c35..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/groovy/org/springframework/cloud/contract/verifier/plugin/ContractVerifierIntegrationTest.groovy +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.plugin - -import java.nio.file.FileVisitResult -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.SimpleFileVisitor -import java.nio.file.attribute.BasicFileAttributes -import java.util.zip.ZipException -import java.util.zip.ZipFile - -import org.gradle.testkit.runner.BuildResult -import org.gradle.testkit.runner.BuildTask -import org.gradle.testkit.runner.GradleRunner -import org.gradle.testkit.runner.TaskOutcome -import org.junit.jupiter.api.BeforeEach - -import static java.nio.charset.StandardCharsets.UTF_8 - -abstract class ContractVerifierIntegrationTest { - - public static final String SPOCK = "testFramework = 'Spock'" - public static final String JUNIT = "testFramework = 'JUnit'" - public static final String MVC_SPEC = "'org.springframework.cloud.MvcSpec'" - public static final String MVC_TEST = "'org.springframework.cloud.MvcTest'" - protected static final boolean WORK_OFFLINE = Boolean.parseBoolean(System.getProperty('WORK_OFFLINE', 'false')) - - File testProjectDir - - @BeforeEach - void setup() { - def dateString = new Date().format("yyyy-MM-dd_HH-mm-ss") - def testFolder = new File("build/generated-tests/${getClass().simpleName}/${dateString}") - testFolder.mkdirs() - testProjectDir = testFolder - } - - protected void setupForProject(String projectRoot) { - copyResourcesToRoot(projectRoot) - } - - protected void switchToJunitTestFramework() { - switchToJunitTestFramework(MVC_SPEC, MVC_TEST) - } - - protected void switchToJunitTestFramework(String from, String to) { - Path path = buildFile.toPath() - String content = new StringBuilder(new String(Files.readAllBytes(path), UTF_8)).replaceAll(SPOCK, JUNIT).replaceAll(from, to) - Files.write(path, content.getBytes(UTF_8)) - } - - protected void emptySourceSet() { - Path path = buildFile.toPath() - String content = new StringBuilder(new String(Files.readAllBytes(path), UTF_8)).replaceAll("sourceSet = \"java\"", "") - Files.write(path, content.getBytes(UTF_8)) - } - - protected BuildResult runTasksSuccessfully(String... tasks) { - BuildResult result = run(tasks) - result.tasks.each { - assert it.outcome == TaskOutcome.SUCCESS || it.outcome == TaskOutcome.UP_TO_DATE || it.outcome == TaskOutcome.NO_SOURCE - } - return result - } - - protected BuildResult validateTasksOutcome(BuildResult result, TaskOutcome expectedOutcome, String... tasks) { - tasks.each { - BuildTask task = result.task(":" + it) - assert task - assert task.outcome == expectedOutcome - } - return result - } - - protected String[] checkAndPublishToMavenLocal() { - String[] args = ["check", "publishToMavenLocal", "--info", "--stacktrace"] as String[] - if (WORK_OFFLINE) { - args << "--offline" - } - return args - } - - protected BuildResult run(String... tasks) { - return GradleRunner.create() - .withProjectDir(testProjectDir) - .withArguments(tasks) - .withPluginClasspath() -// .withDebug(true) - .forwardOutput() - .build() - } - - protected void copyResourcesToRoot(String srcDir) { - copyResources(srcDir, testProjectDir) - } - - protected void copyResources(String srcDir, File destinationFile) { - ClassLoader classLoader = getClass().getClassLoader() - URL resource = classLoader.getResource(srcDir) - if (resource == null) { - throw new RuntimeException("Could not find classpath resource: $srcDir") - } - File resourceFile = new File(resource.toURI()) - if (resourceFile.file) { - Files.copy(resourceFile.toPath(), destinationFile.toPath()) - } - else { - Files.walkFileTree(resourceFile.toPath(), - new CopyFileVisitor(destinationFile.toPath())) - } - } - - protected File file(String path) { - File file = new File(testProjectDir, path) - println "Resolved path is [$file]" - return file - } - - protected boolean fileExists(String path) { - return file(path).exists() - } - - protected File getBuildFile() { - return new File(testProjectDir, 'build.gradle') - } - - protected boolean jarContainsContractVerifierContracts(String path) { - assert fileExists(path) - File rootFile = file(path) - boolean containsGroovyFiles = false - rootFile.eachFileRecurse { File file -> - try { - if (file.isFile() && file.name.endsWith('jar')) { - ZipFile zipFile; - try { - zipFile = new ZipFile(file) - zipFile.entries().each { - if (it.name.endsWith('.groovy')) { - containsGroovyFiles = true - } - } - } finally { - zipFile?.close() - } - } - } - catch (ZipException zipEx) { - println "Unable to open file ${file.name}" - } - } - return containsGroovyFiles - } - - private static class CopyFileVisitor extends SimpleFileVisitor { - private final Path targetPath - private Path sourcePath = null - - CopyFileVisitor(Path targetPath) { - this.targetPath = targetPath - } - - @Override - FileVisitResult preVisitDirectory(final Path dir, - final BasicFileAttributes attrs) throws IOException { - if (sourcePath == null) { - sourcePath = dir - } - else { - Files.createDirectories(targetPath.resolve(sourcePath - .relativize(dir))) - } - return FileVisitResult.CONTINUE - } - - @Override - FileVisitResult visitFile(final Path file, - final BasicFileAttributes attrs) throws IOException { - Path target = targetPath.resolve(sourcePath.relativize(file)) - if (!target.toFile().exists()) { - Files.copy(file, target) - } - return FileVisitResult.CONTINUE - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/groovy/org/springframework/cloud/contract/verifier/plugin/ContractVerifierKotlinIntegrationTest.groovy b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/groovy/org/springframework/cloud/contract/verifier/plugin/ContractVerifierKotlinIntegrationTest.groovy deleted file mode 100644 index e23cb69926..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/groovy/org/springframework/cloud/contract/verifier/plugin/ContractVerifierKotlinIntegrationTest.groovy +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.plugin - -import java.nio.file.Files -import java.nio.file.Path - -import static java.nio.charset.StandardCharsets.UTF_8 - -abstract class ContractVerifierKotlinIntegrationTest extends ContractVerifierIntegrationTest { - public static final String SPOCK = "testFramework.set(TestFramework.SPOCK)" - public static final String JUNIT = "testFramework.set(TestFramework.JUNIT)" - - @Override - protected File getBuildFile() { - return new File(testProjectDir, 'build.gradle.kts') - } - - @Override - protected void switchToJunitTestFramework(String from, String to) { - Path path = buildFile.toPath() - String content = new StringBuilder(new String(Files.readAllBytes(path), UTF_8)).replaceAll(SPOCK, JUNIT) - .replaceAll(from, to) - Files.write(path, content.getBytes(UTF_8)) - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/groovy/org/springframework/cloud/contract/verifier/plugin/ContractVerifierTest.groovy b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/groovy/org/springframework/cloud/contract/verifier/plugin/ContractVerifierTest.groovy deleted file mode 100644 index c004a5a09d..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/groovy/org/springframework/cloud/contract/verifier/plugin/ContractVerifierTest.groovy +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.plugin - -import org.gradle.api.artifacts.Configuration -import org.gradle.api.file.Directory -import org.gradle.api.internal.project.DefaultProject -import org.gradle.api.plugins.GroovyPlugin -import org.gradle.api.plugins.JavaPlugin -import org.gradle.api.plugins.JavaPluginConvention -import org.gradle.api.publish.PublicationContainer -import org.gradle.api.publish.PublishingExtension -import org.gradle.api.publish.maven.plugins.MavenPublishPlugin -import org.gradle.api.tasks.SourceSet -import org.gradle.testfixtures.ProjectBuilder -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test - -import org.springframework.cloud.contract.verifier.config.TestFramework - -class ContractVerifierTest { - DefaultProject project - - @BeforeEach - void setup() { - String dateString = new Date().format("yyyy-MM-dd_HH-mm-ss") - File testFolder = new File("build/generated-tests/${getClass().simpleName}/${dateString}") - testFolder.mkdirs() - project = (DefaultProject) ProjectBuilder.builder().withProjectDir(testFolder).build() - project.plugins.apply(SpringCloudContractVerifierGradlePlugin) - } - - @Test - void "should apply java plugin"() { - expect: - project.plugins.hasPlugin(JavaPlugin) - } - - @Test - void "should create contracts extension"() { - expect: - assert project.extensions.findByType(ContractVerifierExtension) != null - } - - @Test - void "should create a test sourceset with java sources"() { - given: - ContractVerifierExtension extension = project.extensions.getByType(ContractVerifierExtension) - Directory projectDir = project.layout.projectDirectory - SourceSet contractTest = project.convention.getPlugin(JavaPluginConvention).getSourceSets().getByName("contractTest") - - expect: - assert contractTest != null - assert contractTest.java.srcDirs.contains(projectDir.dir("src/contractTest/java").asFile) - assert contractTest.java.srcDirs.contains(extension.generatedTestJavaSourcesDir.get().asFile) - assert contractTest.resources.srcDirs.contains(projectDir.dir("src/contractTest/resources").asFile) - assert contractTest.resources.srcDirs.contains(extension.generatedTestResourcesDir.get().asFile) - } - - @Test - void "should create a test sourceset with groovy sources, if the groovy plugin is present"() { - given: - project.plugins.apply(GroovyPlugin) - ContractVerifierExtension extension = project.extensions.getByType(ContractVerifierExtension) - Directory projectDir = project.layout.projectDirectory - SourceSet contractTest = project.convention.getPlugin(JavaPluginConvention).getSourceSets().getByName("contractTest") - - expect: - assert contractTest != null - assert contractTest.java.srcDirs.contains(projectDir.dir("src/contractTest/java").asFile) - assert contractTest.java.srcDirs.contains(extension.generatedTestJavaSourcesDir.get().asFile) - assert contractTest.groovy.srcDirs.contains(projectDir.dir('src/contractTest/groovy').asFile) - assert contractTest.groovy.srcDirs.contains(extension.generatedTestGroovySourcesDir.get().asFile) - assert contractTest.resources.srcDirs.contains(projectDir.dir("src/contractTest/resources").asFile) - assert contractTest.resources.srcDirs.contains(extension.generatedTestResourcesDir.get().asFile) - } - - @Test - void "should setup dependency configurations"() { - given: - Configuration contractTestCompileOnly = project.configurations.contractTestCompileOnly - Configuration contractTestImplementation = project.configurations.contractTestImplementation - Configuration contractTestRuntimeOnly = project.configurations.contractTestRuntimeOnly - - expect: - assert contractTestCompileOnly != null - assert contractTestCompileOnly.extendsFrom.contains(project.configurations.testCompileOnly) - assert contractTestImplementation != null - assert contractTestImplementation.extendsFrom.contains(project.configurations.testImplementation) - assert contractTestRuntimeOnly != null - assert contractTestRuntimeOnly.extendsFrom.contains(project.configurations.testRuntimeOnly) - } - - @Test - void "should create contract test task"() { - expect: - assert project.tasks.named("contractTest").get() != null - } - - @Test - void "should create generateContractTests task"() { - expect: - assert project.tasks.named("generateContractTests").get() != null - } - - @Test - void "should configure generateContractTests task as a dependency of the compileContractTestJava task"() { - expect: - assert project.tasks.compileContractTestJava.getDependsOn().contains(project.tasks.named("generateContractTests")) - assert project.tasks.findByName("compileContractTestGroovy") == null - } - - @Test - void "should configure generateContractTests task as a dependency of the compileContractTestGroovy task"() { - given: - project.plugins.apply(GroovyPlugin) - - expect: - assert project.tasks.compileContractTestJava.getDependsOn().contains(project.tasks.named("generateContractTests")) - assert project.tasks.compileContractTestGroovy.getDependsOn().contains(project.tasks.named("generateContractTests")) - } - - @Test - void "should create generateClientStubs task"() { - expect: - assert project.tasks.named("generateClientStubs").get() != null - } - - @Test - void "should create verifierStubsJar task"() { - expect: - assert project.tasks.named("verifierStubsJar").get() != null - } - - @Test - void "should configure generateClientStubs task as a dependency of the verifierStubsJar task"() { - expect: - project.tasks.verifierStubsJar.getDependsOn().contains(project.tasks.named("generateClientStubs")) - } - - @Test - void "should configure generateClientStubs task as a dependency of the publishStubsToScm task"() { - expect: - assert project.tasks.publishStubsToScm.getDependsOn().contains(project.tasks.named("generateClientStubs")) - } - - @Test - void "should create copyContracts task"() { - expect: - assert project.tasks.named("copyContracts").get() != null - } - - @Test - void "should configure copyContracts task as a dependency of the verifierStubsJar task"() { - expect: - assert project.tasks.verifierStubsJar.getDependsOn().contains(project.tasks.named("generateClientStubs")) - } - - @Test - void "should compile"() { - given: - project.plugins.apply(SpringCloudContractVerifierGradlePlugin) - ContractVerifierExtension extension = project.getExtensions().findByType(ContractVerifierExtension) - extension.with { - - // tag::package_with_base_classes[] - packageWithBaseClasses = 'com.example.base' - // end::package_with_base_classes[] - - // tag::base_class_mappings[] - baseClassForTests = "com.example.FooBase" - baseClassMappings { - baseClassMapping('.*/com/.*', 'com.example.ComBase') - baseClassMapping('.*/bar/.*': 'com.example.BarBase') - } - // end::base_class_mappings[] - } - expect: - assert extension - } - - @Test - void "should property merge scm repository settings for publishing stubs to scm"() { - given: - project.plugins.apply(SpringCloudContractVerifierGradlePlugin) - ContractVerifierExtension extension = project.extensions.findByType(ContractVerifierExtension) - PublishStubsToScmTask task = project.tasks.findByName(PublishStubsToScmTask.TASK_NAME) - - when: - extension.contractRepository.with { - repositoryUrl = "https://git.example.com" - username = "username" - password = "password" - proxyHost = "host" - proxyPort = 8080 - } - - then: - assert task.contractRepository.repositoryUrl.get() == "https://git.example.com" - assert task.contractRepository.username.get() == "username" - assert task.contractRepository.password.get() == "password" - assert task.contractRepository.proxyHost.get() == "host" - assert task.contractRepository.proxyPort.get() == 8080 - - and: - extension.publishStubsToScm.contractRepository.with { - repositoryUrl = "https://git2.example.com" - username = "username2" - password = "password2" - proxyHost = "host2" - proxyPort = 8081 - } - - then: - assert task.contractRepository.repositoryUrl.get() == "https://git2.example.com" - assert task.contractRepository.username.get() == "username2" - assert task.contractRepository.password.get() == "password2" - assert task.contractRepository.proxyHost.get() == "host2" - assert task.contractRepository.proxyPort.get() == 8081 - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/build.gradle b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/build.gradle deleted file mode 100644 index d27deebff9..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/build.gradle +++ /dev/null @@ -1,66 +0,0 @@ -buildscript { - repositories { - mavenCentral() - maven { url "https://repo.spring.io/snapshot" } - maven { url "https://repo.spring.io/milestone" } - maven { url "https://repo.spring.io/release" } - } -} - -apply plugin: 'groovy' -apply plugin: 'spring-cloud-contract' -apply plugin: 'maven-publish' - -group = 'org.springframework.cloud.testprojects' -sourceCompatibility = 17 -targetCompatibility = 17 - -ext { - restAssuredVersion = '3.0.7' - - contractsDir = file("repository/mappings") - stubsOutputDirRoot = file("${project.buildDir}/production/${project.name}-stubs/repository/") -} - -repositories { - mavenCentral() - mavenLocal() - maven { url "https://repo.spring.io/snapshot" } - maven { url "https://repo.spring.io/milestone" } - maven { url "https://repo.spring.io/release" } -} - -dependencies { - implementation "org.springframework:spring-web" - implementation "org.springframework:spring-context-support" - implementation "org.apache.groovy:groovy-all:${groovyVersion}" - implementation 'com.jayway.jsonpath:json-path-assert:2.2.0' - - testImplementation "com.github.tomakehurst:wiremock:${wiremockVersion}" - testImplementation "com.toomuchcoding.jsonassert:jsonassert:${jsonAssertVersion}" - testImplementation("org.spockframework:spock-spring:1.0-groovy-2.4") { - exclude(group: 'org.apache.groovy') - } - testImplementation "io.restassured:rest-assured:$restAssuredVersion" - testImplementation "io.restassured:spring-mock-mvc:$restAssuredVersion" - testImplementation "ch.qos.logback:logback-classic:1.1.2" - testImplementation "org.springframework.cloud:spring-cloud-contract-verifier:${verifierVersion}" -} - -contracts { - contractsMode = "REMOTE" - baseClassForTests = 'org.springframework.cloud.contract.verifier.twitter.places.BaseMockMvcSpec' - basePackageForTests = 'contracts' - contractsDslDir = contractsDir -// generatedTestSourcesDir = file("${project.rootDir}/src/test/groovy/") - stubsOutputDir = stubsOutputDirRoot - testFramework = 'Spock' -} - -project.tasks.named("generateContractTests").get().dependsOn project.tasks.named("generateClientStubs") - -test { - testLogging { - exceptionFormat = 'full' - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/gradle.properties b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/gradle.properties deleted file mode 100644 index 188bad3767..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/gradle.properties +++ /dev/null @@ -1,19 +0,0 @@ -# -# Copyright 2013-2020 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -wiremockVersion=2.35.0 -jsonAssertVersion=0.6.2 -verifierVersion=4.1.0-SNAPSHOT -groovyVersion=2.4.17 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/gradle/wrapper/gradle-wrapper.jar b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 490fda8577df6c95960ba7077c43220e5bb2c0d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58694 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 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/gradle/wrapper/gradle-wrapper.properties b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 4c5803d13c..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.4-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/gradlew b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/gradlew deleted file mode 100755 index 2fe81a7d95..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/gradlew +++ /dev/null @@ -1,183 +0,0 @@ -#!/usr/bin/env sh - -# -# Copyright 2015 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=`expr $i + 1` - done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -exec "$JAVACMD" "$@" diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/gradlew.bat b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/gradlew.bat deleted file mode 100644 index 9109989e3c..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/gradlew.bat +++ /dev/null @@ -1,103 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/repository/mappings/spring/cloud/twitter-places-analyzer/pairId/collerate_PlacesFrom_Tweet.groovy b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/repository/mappings/spring/cloud/twitter-places-analyzer/pairId/collerate_PlacesFrom_Tweet.groovy deleted file mode 100644 index ebe36065a3..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/repository/mappings/spring/cloud/twitter-places-analyzer/pairId/collerate_PlacesFrom_Tweet.groovy +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - priority 2 - request { - method 'PUT' - url '/api/12' - headers { - header 'Content-Type': 'application/json' - } - body '''\ - [{ - "text": "Gonna see you at Warsaw" - }] -''' - } - response { - status OK() - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/repository/mappings/spring/cloud/twitter-places-analyzer/pairId/moreComplexVersion.groovy b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/repository/mappings/spring/cloud/twitter-places-analyzer/pairId/moreComplexVersion.groovy deleted file mode 100644 index 55a66274b4..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/repository/mappings/spring/cloud/twitter-places-analyzer/pairId/moreComplexVersion.groovy +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - request { - method 'PUT' - url $(consumer(regex('^/api/[0-9]{2}$')), producer('/api/12')) - headers { - header 'Content-Type': 'application/json' - } - body '''\ - [{ - "text": "Gonna see you at Warsaw" - }] -''' - } - response { - headers { - header 'Content-Type': $(consumer('application/json'), producer(regex('application/json.*'))) - header 'Location': $(consumer('https://localhost:8080'), producer(execute('isEmpty($it)'))) - } - body( - path: $(consumer('/api/12'), producer(regex('^/api/[0-9]{2}$'))), - correlationId: $(consumer('1223456'), producer(execute('isProperCorrelationId($it)'))) - ) - status OK() - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/settings.gradle b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/settings.gradle deleted file mode 100644 index 34e881c102..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/settings.gradle +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -rootProject.name = 'bootSimple' diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/src/main/groovy/org/springframework/cloud/twitter/place/PairIdController.groovy b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/src/main/groovy/org/springframework/cloud/twitter/place/PairIdController.groovy deleted file mode 100644 index 92bb679a36..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/src/main/groovy/org/springframework/cloud/twitter/place/PairIdController.groovy +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.twitter.place - -import groovy.transform.TypeChecked -import groovy.util.logging.Slf4j - -import org.springframework.http.MediaType -import org.springframework.web.bind.annotation.PathVariable -import org.springframework.web.bind.annotation.RequestBody -import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RestController - -import static org.springframework.web.bind.annotation.RequestMethod.PUT - -@Slf4j -@RestController -@RequestMapping('/api') -@TypeChecked -class PairIdController { - - @RequestMapping( - value = '{pairId}', - method = PUT, - consumes = MediaType.APPLICATION_JSON_VALUE, - produces = MediaType.APPLICATION_JSON_VALUE) - String getPlacesFromTweets(@PathVariable long pairId, @RequestBody List tweets) { - log.info("Inside PairIdController, doing very important logic") - if (tweets?.text != ["Gonna see you at Warsaw"]) { - throw new IllegalArgumentException("Wrong text in tweet: ${tweets?.text}") - } - return """ - { - "path" : "/api/$pairId", - "correlationId" : 123456 - } - """ - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/src/main/groovy/org/springframework/cloud/twitter/place/Tweet.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/src/main/groovy/org/springframework/cloud/twitter/place/Tweet.java deleted file mode 100644 index 749ed93d49..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/src/main/groovy/org/springframework/cloud/twitter/place/Tweet.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.twitter.place; - -public class Tweet { - - private String text; - - public String getText() { - return this.text; - } - - public void setText(String text) { - this.text = text; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/src/test/groovy/org/springframework/cloud/contract/verifier/twitter/places/AcceptanceSpec.groovy b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/src/test/groovy/org/springframework/cloud/contract/verifier/twitter/places/AcceptanceSpec.groovy deleted file mode 100644 index bd7c621f15..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/src/test/groovy/org/springframework/cloud/contract/verifier/twitter/places/AcceptanceSpec.groovy +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.twitter.places - -import spock.lang.Specification - -import org.springframework.cloud.contract.verifier.twitter.place.PairIdController -import org.springframework.http.MediaType -import org.springframework.test.web.servlet.MockMvc -import org.springframework.test.web.servlet.setup.MockMvcBuilders - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status - -class AcceptanceSpec extends Specification { - - def "should have controller up and running"() { - given: - MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new PairIdController()).build() - expect: - mockMvc.perform(put("/api/${1}"). - contentType(MediaType.APPLICATION_JSON). - content("""[{"text":"Gonna see you at Warsaw"}]""")). - andExpect(status().isOk()) - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/src/test/groovy/org/springframework/cloud/contract/verifier/twitter/places/BaseMockMvcSpec.groovy b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/src/test/groovy/org/springframework/cloud/contract/verifier/twitter/places/BaseMockMvcSpec.groovy deleted file mode 100644 index ff8689e0ca..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/src/test/groovy/org/springframework/cloud/contract/verifier/twitter/places/BaseMockMvcSpec.groovy +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.twitter.places - -import io.restassured.module.mockmvc.RestAssuredMockMvc -import spock.lang.Specification - -import org.springframework.cloud.contract.verifier.twitter.place.PairIdController - -// tag::base_class[] -abstract class BaseMockMvcSpec extends Specification { - - def setup() { - RestAssuredMockMvc.standaloneSetup(new PairIdController()) - } - - void isProperCorrelationId(Integer correlationId) { - assert correlationId == 123456 - } - - void isEmpty(String value) { - assert value == null - } - -} -// end::base_class[] diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/src/test/resources/logback-test.groovy b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/src/test/resources/logback-test.groovy deleted file mode 100644 index 80026aa077..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/src/test/resources/logback-test.groovy +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -import ch.qos.logback.classic.encoder.PatternLayoutEncoder -import ch.qos.logback.core.ConsoleAppender - -String console = "CONSOLE" -String logPattern = "%d{yyyy-MM-dd HH:mm:ss.SSSZ, Europe/Warsaw} | %-5level | %X{correlationId} | %thread | %logger{1} | %m%n" - -appender(console, ConsoleAppender) { - encoder(PatternLayoutEncoder) { - pattern = logPattern - } -} - -root(INFO, [console]) -logger("org.springframework.cloud", DEBUG) diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/build.gradle b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/build.gradle deleted file mode 100644 index 2dd0fd6870..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/build.gradle +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -plugins { - id("org.springframework.boot") apply false - id("org.springframework.cloud.contract") apply false -} - -ext { - restAssuredVersion = '3.0.7' - spockVersion = '1.0-groovy-2.4' - - contractVerifierStubsBaseDirectory = 'src/test/resources/stubs' -} - -group = 'org.springframework.cloud.testprojects' - -subprojects { - apply plugin: 'groovy' - - sourceCompatibility = 17 - targetCompatibility = 17 - version = "1.0.0" - - repositories { - mavenCentral() - mavenLocal() - maven { url "https://repo.spring.io/snapshot" } - maven { url "https://repo.spring.io/milestone" } - maven { url "https://repo.spring.io/release" } - } - - dependencies { - testImplementation "org.apache.groovy:groovy" - testImplementation("org.spockframework:spock-core:$spockVersion") { - exclude(group: 'org.apache.groovy') - } - testImplementation "junit:junit:4.12" - testImplementation "com.github.tomakehurst:wiremock:${wiremockVersion}" - testImplementation "com.toomuchcoding.jsonassert:jsonassert:${jsonAssertVersion}" - testImplementation "org.assertj:assertj-core:2.4.1" - testImplementation "org.springframework.cloud:spring-cloud-contract-verifier:${verifierVersion}" - } -} - -configure([project(':fraudDetectionService'), project(':loanApplicationService')]) { - apply plugin: 'org.springframework.boot' - apply plugin: 'io.spring.dependency-management' - apply plugin: 'org.springframework.cloud.contract' - apply plugin: 'maven-publish' - - // tag::jar_setup[] - ext { - contractsDir = file("mappings") - stubsOutputDirRoot = file("${project.buildDir}/production/${project.name}-stubs/") - } - - // Automatically added by plugin: - // copyContracts - copies contracts to the output folder from which JAR will be created - // verifierStubsJar - JAR with a provided stub suffix - - publishing { - publications { - stubs(MavenPublication) { - artifactId "${project.name}-stubs" - artifact verifierStubsJar - } - } - } - // end::jar_setup[] - - contracts { - contractsMode = "REMOTE" - // tag::target_framework[] - testFramework = 'Spock' - // end::target_framework[] - testMode = 'MockMvc' - //baseClassForTests = 'org.springframework.cloud.MvcSpec' - // tag::base_class_mapping[] - baseClassMappings { - baseClassMapping('.*', 'org.springframework.cloud.MvcSpec') - } - // end::base_class_mapping[] - contractsDslDir = file("${project.projectDir.absolutePath}/mappings/") - generatedTestSourcesDir = file("${project.buildDir}/generated-test-sources/") - stubsOutputDir = stubsOutputDirRoot - sourceSet = "contractTest" - } - - jar { - version = '0.0.1' - } - - dependencies { - implementation("org.springframework.boot:spring-boot-starter-web") { - exclude module: "spring-boot-starter-tomcat" - } - implementation("org.springframework.boot:spring-boot-starter-jetty") - implementation("org.springframework.boot:spring-boot-starter-actuator") - - testRuntime("org.spockframework:spock-spring:$spockVersion") { - exclude(group: 'org.apache.groovy') - } - testImplementation "org.mockito:mockito-core" - testImplementation "org.springframework:spring-test" - testImplementation "org.springframework.boot:spring-boot-test" - testImplementation "org.springframework.cloud:spring-cloud-test-support" - testImplementation "io.rest-assured:rest-assured:$restAssuredVersion" - testImplementation "io.rest-assured:spring-mock-mvc:$restAssuredVersion" - } - - task cleanup(type: Delete) { - delete 'src/test/resources/mappings', 'src/test/resources/stubs' - } - - clean.dependsOn('cleanup') - - test { - testLogging { - exceptionFormat = 'full' - } - } -} - -configure(project(':fraudDetectionService')) { - test.dependsOn('generateClientStubs') -} - -configure(project(':loanApplicationService')) { - - task copyCollaboratorStubs(type: Copy) { - File fraudBuildDir = project(':fraudDetectionService').buildDir - from(new File(fraudBuildDir, "/production/${project(':fraudDetectionService').name}-stubs/")) - into "src/test/resources/mappings" - } - - project.tasks.named("test").get().dependsOn('copyCollaboratorStubs') -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/mappings/fraudDetectionService/1_shouldMarkClientAsNotFraud.groovy b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/mappings/fraudDetectionService/1_shouldMarkClientAsNotFraud.groovy deleted file mode 100644 index 9f55b24eb4..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/mappings/fraudDetectionService/1_shouldMarkClientAsNotFraud.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - request { - method 'PUT' - url '/fraudcheck' - body(""" - { - "clientPesel":"${value(consumer(regex('[0-9]{10}')), producer('1234567890'))}", - "loanAmount":123.123 - } - """ - ) - headers { - header('Content-Type', 'application/vnd.fraud.v1+json') - } - - } - response { - status OK() - body( - fraudCheckStatus: "OK", - rejectionReason: $(consumer(null), producer(execute('assertThatRejectionReasonIsNull($it)'))) - ) - headers { - header('Content-Type': value( - producer(regex('application/vnd.fraud.v1.json.*')), - consumer('application/vnd.fraud.v1+json')) - ) - } - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/mappings/fraudDetectionService/2_shouldMarkClientAsFraud.groovy b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/mappings/fraudDetectionService/2_shouldMarkClientAsFraud.groovy deleted file mode 100644 index d5eaf57206..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/mappings/fraudDetectionService/2_shouldMarkClientAsFraud.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - request { - method """PUT""" - url """/fraudcheck""" - body(""" - { - "clientPesel":"${value(consumer(regex('[0-9]{10}')), producer('1234567890'))}", - "loanAmount":99999} - """ - ) - headers { - header("""Content-Type""", """application/vnd.fraud.v1+json""") - } - - } - response { - status OK() - body("""{ - "fraudCheckStatus": "${value(consumer('FRAUD'), producer(regex('[A-Z]{5}')))}", - "rejectionReason": "Amount too high" -}""") - headers { - header('Content-Type': value( - producer(regex('application/vnd.fraud.v1.json.*')), - consumer('application/vnd.fraud.v1+json')) - ) - } - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/Application.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/Application.java deleted file mode 100644 index 0dfa308777..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/Application.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; - -@Configuration -@EnableAutoConfiguration -@ComponentScan -public class Application { - - public static void main(String[] args) { - SpringApplication.run(org.springframework.cloud.frauddetection.Application.class, - args); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/FraudDetectionController.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/FraudDetectionController.java deleted file mode 100644 index 72d7b0d09f..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/FraudDetectionController.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection; - -import java.math.BigDecimal; - -import org.springframework.cloud.frauddetection.model.FraudCheck; -import org.springframework.cloud.frauddetection.model.FraudCheckResult; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import static org.springframework.cloud.frauddetection.model.FraudCheckStatus.FRAUD; -import static org.springframework.cloud.frauddetection.model.FraudCheckStatus.OK; -import static org.springframework.web.bind.annotation.RequestMethod.PUT; - -@RestController -public class FraudDetectionController { - - private static final String FRAUD_SERVICE_JSON_VERSION_1 = "application/vnd.fraud.v1+json"; - - private static final String NO_REASON = null; - - private static final String AMOUNT_TOO_HIGH = "Amount too high"; - - private static final BigDecimal MAX_AMOUNT = new BigDecimal("5000"); - - @RequestMapping(value = "/fraudcheck", method = PUT, consumes = FRAUD_SERVICE_JSON_VERSION_1, produces = FRAUD_SERVICE_JSON_VERSION_1) - public FraudCheckResult fraudCheck(@RequestBody FraudCheck fraudCheck) { - if (amountGreaterThanThreshold(fraudCheck)) { - return new FraudCheckResult(FRAUD, AMOUNT_TOO_HIGH); - } - return new FraudCheckResult(OK, NO_REASON); - } - - private boolean amountGreaterThanThreshold(FraudCheck fraudCheck) { - return MAX_AMOUNT.compareTo(fraudCheck.getLoanAmount()) < 0; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheck.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheck.java deleted file mode 100644 index 2dbed39e4e..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheck.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection.model; - -import java.math.BigDecimal; - -public class FraudCheck { - - private String clientPesel; - - private BigDecimal loanAmount; - - public FraudCheck() { - } - - public String getClientPesel() { - return this.clientPesel; - } - - public void setClientPesel(String clientPesel) { - this.clientPesel = clientPesel; - } - - public BigDecimal getLoanAmount() { - return this.loanAmount; - } - - public void setLoanAmount(BigDecimal loanAmount) { - this.loanAmount = loanAmount; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheckResult.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheckResult.java deleted file mode 100644 index ca5eed7947..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheckResult.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection.model; - -public class FraudCheckResult { - - private FraudCheckStatus fraudCheckStatus; - - private String rejectionReason; - - public FraudCheckResult() { - } - - public FraudCheckResult(FraudCheckStatus fraudCheckStatus, String rejectionReason) { - this.fraudCheckStatus = fraudCheckStatus; - this.rejectionReason = rejectionReason; - } - - public FraudCheckStatus getFraudCheckStatus() { - return this.fraudCheckStatus; - } - - public void setFraudCheckStatus(FraudCheckStatus fraudCheckStatus) { - this.fraudCheckStatus = fraudCheckStatus; - } - - public String getRejectionReason() { - return this.rejectionReason; - } - - public void setRejectionReason(String rejectionReason) { - this.rejectionReason = rejectionReason; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheckStatus.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheckStatus.java deleted file mode 100644 index e0c2f2cb9d..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheckStatus.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection.model; - -public enum FraudCheckStatus { - - OK, FRAUD - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/main/resources/application.yml b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/main/resources/application.yml deleted file mode 100644 index cbe617ef03..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/main/resources/application.yml +++ /dev/null @@ -1 +0,0 @@ -server.port=0 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/test/groovy/org/springframework/cloud/MvcSpec.groovy b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/test/groovy/org/springframework/cloud/MvcSpec.groovy deleted file mode 100644 index 6f76c4d5e5..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/test/groovy/org/springframework/cloud/MvcSpec.groovy +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud - -import io.restassured.module.mockmvc.RestAssuredMockMvc -import spock.lang.Specification - -import org.springframework.cloud.frauddetection.FraudDetectionController - -class MvcSpec extends Specification { - def setup() { - RestAssuredMockMvc.standaloneSetup(new FraudDetectionController()) - } - - void assertThatRejectionReasonIsNull(def rejectionReason) { - assert !rejectionReason - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/test/java/org/springframework/cloud/MvcTest.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/test/java/org/springframework/cloud/MvcTest.java deleted file mode 100644 index 8b238f28d3..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/fraudDetectionService/src/test/java/org/springframework/cloud/MvcTest.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud; - -import io.restassured.module.mockmvc.RestAssuredMockMvc; -import org.junit.Before; - -public class MvcTest { - - @Before - public void setup() { - RestAssuredMockMvc.standaloneSetup( - new org.springframework.cloud.frauddetection.FraudDetectionController()); - } - - public void assertThatRejectionReasonIsNull(Object rejectionReason) { - assert rejectionReason == null; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/gradle.properties b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/gradle.properties deleted file mode 100644 index 5f3dd769e3..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/gradle.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright 2013-2020 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -wiremockVersion=2.35.0 -jsonAssertVersion=0.6.2 -verifierVersion=4.1.0-SNAPSHOT -bootVersion=3.2.0-SNAPSHOT -groovyVersion=2.4.17 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/gradle/wrapper/gradle-wrapper.jar b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 490fda8577df6c95960ba7077c43220e5bb2c0d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58694 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 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/gradle/wrapper/gradle-wrapper.properties b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 4c5803d13c..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.4-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/gradlew b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/gradlew deleted file mode 100755 index 2fe81a7d95..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/gradlew +++ /dev/null @@ -1,183 +0,0 @@ -#!/usr/bin/env sh - -# -# Copyright 2015 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=`expr $i + 1` - done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -exec "$JAVACMD" "$@" diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/gradlew.bat b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/gradlew.bat deleted file mode 100644 index 9109989e3c..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/gradlew.bat +++ /dev/null @@ -1,103 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/Application.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/Application.java deleted file mode 100644 index 0dfa308777..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/Application.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; - -@Configuration -@EnableAutoConfiguration -@ComponentScan -public class Application { - - public static void main(String[] args) { - SpringApplication.run(org.springframework.cloud.frauddetection.Application.class, - args); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/LoanApplicationService.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/LoanApplicationService.java deleted file mode 100644 index 5cc56e38f9..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/LoanApplicationService.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection; - -import org.springframework.cloud.frauddetection.model.FraudCheckStatus; -import org.springframework.cloud.frauddetection.model.FraudServiceRequest; -import org.springframework.cloud.frauddetection.model.FraudServiceResponse; -import org.springframework.cloud.frauddetection.model.LoanApplication; -import org.springframework.cloud.frauddetection.model.LoanApplicationResult; -import org.springframework.cloud.frauddetection.model.LoanApplicationStatus; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Service; -import org.springframework.web.client.RestTemplate; - -@Service -public class LoanApplicationService { - - private static final String FRAUD_SERVICE_JSON_VERSION_1 = "application/vnd.fraud.v1+json"; - - private final RestTemplate restTemplate; - - private int port = 8080; - - public LoanApplicationService() { - this.restTemplate = new RestTemplate(); - } - - public LoanApplicationResult loanApplication(LoanApplication loanApplication) { - FraudServiceRequest request = new FraudServiceRequest(loanApplication); - - FraudServiceResponse response = sendRequestToFraudDetectionService(request); - - return buildResponseFromFraudResult(response); - } - - private FraudServiceResponse sendRequestToFraudDetectionService( - FraudServiceRequest request) { - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.add(HttpHeaders.CONTENT_TYPE, FRAUD_SERVICE_JSON_VERSION_1); - - ResponseEntity response = this.restTemplate.exchange( - "http://localhost:" + this.port + "/fraudcheck", HttpMethod.PUT, - new HttpEntity<>(request, httpHeaders), FraudServiceResponse.class); - - return response.getBody(); - } - - private LoanApplicationResult buildResponseFromFraudResult( - FraudServiceResponse response) { - LoanApplicationStatus applicationStatus = null; - if (FraudCheckStatus.OK == response.getFraudCheckStatus()) { - applicationStatus = LoanApplicationStatus.LOAN_APPLIED; - } - else if (FraudCheckStatus.FRAUD == response.getFraudCheckStatus()) { - applicationStatus = LoanApplicationStatus.LOAN_APPLICATION_REJECTED; - } - - return new LoanApplicationResult(applicationStatus, - response.getRejectionReason()); - } - - public void setPort(int port) { - this.port = port; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/Client.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/Client.java deleted file mode 100644 index b57fde319f..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/Client.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection.model; - -public class Client { - - private String pesel; - - public String getPesel() { - return this.pesel; - } - - public void setPesel(String pesel) { - this.pesel = pesel; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheckStatus.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheckStatus.java deleted file mode 100644 index e0c2f2cb9d..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheckStatus.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection.model; - -public enum FraudCheckStatus { - - OK, FRAUD - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/FraudServiceRequest.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/FraudServiceRequest.java deleted file mode 100644 index 7365314bdb..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/FraudServiceRequest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection.model; - -import java.math.BigDecimal; - -public class FraudServiceRequest { - - private String clientPesel; - - private BigDecimal loanAmount; - - public FraudServiceRequest() { - } - - public FraudServiceRequest(LoanApplication loanApplication) { - this.clientPesel = loanApplication.getClient().getPesel(); - this.loanAmount = loanApplication.getAmount(); - } - - public String getClientPesel() { - return this.clientPesel; - } - - public void setClientPesel(String clientPesel) { - this.clientPesel = clientPesel; - } - - public BigDecimal getLoanAmount() { - return this.loanAmount; - } - - public void setLoanAmount(BigDecimal loanAmount) { - this.loanAmount = loanAmount; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/FraudServiceResponse.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/FraudServiceResponse.java deleted file mode 100644 index 9698951ffc..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/FraudServiceResponse.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection.model; - -public class FraudServiceResponse { - - private FraudCheckStatus fraudCheckStatus; - - private String rejectionReason; - - public FraudServiceResponse() { - } - - public FraudCheckStatus getFraudCheckStatus() { - return this.fraudCheckStatus; - } - - public void setFraudCheckStatus(FraudCheckStatus fraudCheckStatus) { - this.fraudCheckStatus = fraudCheckStatus; - } - - public String getRejectionReason() { - return this.rejectionReason; - } - - public void setRejectionReason(String rejectionReason) { - this.rejectionReason = rejectionReason; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/LoanApplication.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/LoanApplication.java deleted file mode 100644 index 5a93cf631c..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/LoanApplication.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection.model; - -import java.math.BigDecimal; - -public class LoanApplication { - - private Client client; - - private BigDecimal amount; - - private String loanApplicationId; - - public Client getClient() { - return this.client; - } - - public void setClient(Client client) { - this.client = client; - } - - public BigDecimal getAmount() { - return this.amount; - } - - public void setAmount(BigDecimal amount) { - this.amount = amount; - } - - public String getLoanApplicationId() { - return this.loanApplicationId; - } - - public void setLoanApplicationId(String loanApplicationId) { - this.loanApplicationId = loanApplicationId; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/LoanApplicationResult.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/LoanApplicationResult.java deleted file mode 100644 index 701373b15c..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/LoanApplicationResult.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection.model; - -public class LoanApplicationResult { - - private LoanApplicationStatus loanApplicationStatus; - - private String rejectionReason; - - public LoanApplicationResult() { - } - - public LoanApplicationResult(LoanApplicationStatus loanApplicationStatus, - String rejectionReason) { - this.loanApplicationStatus = loanApplicationStatus; - this.rejectionReason = rejectionReason; - } - - public LoanApplicationStatus getLoanApplicationStatus() { - return this.loanApplicationStatus; - } - - public void setLoanApplicationStatus(LoanApplicationStatus loanApplicationStatus) { - this.loanApplicationStatus = loanApplicationStatus; - } - - public String getRejectionReason() { - return this.rejectionReason; - } - - public void setRejectionReason(String rejectionReason) { - this.rejectionReason = rejectionReason; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/LoanApplicationStatus.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/LoanApplicationStatus.java deleted file mode 100644 index eb8490c46f..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/LoanApplicationStatus.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection.model; - -public enum LoanApplicationStatus { - - LOAN_APPLIED, LOAN_APPLICATION_REJECTED - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/resources/application.yml b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/resources/application.yml deleted file mode 100644 index cbe617ef03..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/main/resources/application.yml +++ /dev/null @@ -1 +0,0 @@ -server.port=0 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/test/groovy/org/springframework/cloud/LoanApplicationServiceSpec.groovy b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/test/groovy/org/springframework/cloud/LoanApplicationServiceSpec.groovy deleted file mode 100644 index 3a63ee1dff..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/loanApplicationService/src/test/groovy/org/springframework/cloud/LoanApplicationServiceSpec.groovy +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud - -import com.github.tomakehurst.wiremock.junit.WireMockClassRule -import org.junit.ClassRule -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Stepwise - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootContextLoader -import org.springframework.cloud.frauddetection.Application -import org.springframework.cloud.frauddetection.LoanApplicationService -import org.springframework.cloud.frauddetection.model.Client -import org.springframework.cloud.frauddetection.model.LoanApplication -import org.springframework.cloud.frauddetection.model.LoanApplicationResult -import org.springframework.cloud.frauddetection.model.LoanApplicationStatus -import org.springframework.test.context.ContextConfiguration - -@ContextConfiguration(loader = SpringBootContextLoader, classes = Application) -@Stepwise -class LoanApplicationServiceSpec extends Specification { - - public static int port = org.springframework.cloud.test.TestSocketUtils.findAvailableTcpPort() - - @ClassRule - @Shared - WireMockClassRule wireMockRule = new WireMockClassRule(port) - - @Autowired - LoanApplicationService sut - - def setup() { - sut.port = port - } - - def 'should successfully apply for loan'() { - given: - LoanApplication application = - new LoanApplication(client: new Client(pesel: '1234567890'), amount: 123.123) - when: - LoanApplicationResult loanApplication = sut.loanApplication(application) - then: - loanApplication.loanApplicationStatus == LoanApplicationStatus.LOAN_APPLIED - loanApplication.rejectionReason == null - } - - def 'should be rejected due to abnormal loan amount'() { - given: - LoanApplication application = - new LoanApplication(client: new Client(pesel: '1234567890'), amount: 99_999) - when: - LoanApplicationResult loanApplication = sut.loanApplication(application) - then: - loanApplication.loanApplicationStatus == LoanApplicationStatus.LOAN_APPLICATION_REJECTED - loanApplication.rejectionReason == 'Amount too high' - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/settings.gradle b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/settings.gradle deleted file mode 100644 index 3b48f5ba2c..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/settings.gradle +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -pluginManagement { - repositories { - mavenCentral() - mavenLocal() - maven { url "https://repo.spring.io/snapshot" } - maven { url "https://repo.spring.io/milestone" } - maven { url "https://repo.spring.io/release" } - } - resolutionStrategy { - eachPlugin { - if (requested.id.id == "org.springframework.boot") { - useModule("org.springframework.boot:spring-boot-gradle-plugin:${bootVersion}") - } else if (requested.id.id == "org.springframework.cloud.contract") { - useModule("org.springframework.cloud:spring-cloud-contract-gradle-plugin:${verifierVersion}") - } - } - } -} - -include ':fraudDetectionService' -include ':loanApplicationService' diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/build.gradle.kts b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/build.gradle.kts deleted file mode 100644 index 16c6709a36..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/build.gradle.kts +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.gradle.api.publish.PublishingExtension -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties -import org.springframework.cloud.contract.verifier.config.TestFramework -import org.springframework.cloud.contract.verifier.config.TestMode -import org.springframework.cloud.contract.verifier.plugin.ContractVerifierExtension - -plugins { - groovy - id("org.springframework.boot") apply false - id("org.springframework.cloud.contract") apply false -} - -val restAssuredVersion by extra("3.0.7") -val spockVersion by extra("1.0-groovy-2.4") -val wiremockVersion: String by extra -val jsonAssertVersion: String by extra -val verifierVersion: String by extra - -val contractVerifierStubsBaseDirectory by extra("src/test/resources/stubs") - -group = "org.springframework.cloud.testprojects" - -subprojects { - apply(plugin = "groovy") - - java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 - } - - repositories { - mavenCentral() - mavenLocal() - maven(url = "https://repo.spring.io/snapshot") - maven(url = "https://repo.spring.io/milestone") - maven(url = "https://repo.spring.io/release") - } - - dependencies { - testCompile("org.apache.groovy:groovy") - testCompile("org.spockframework:spock-core:$spockVersion") - testCompile("junit:junit:4.12") - testCompile("com.github.tomakehurst:wiremock:$wiremockVersion") - testCompile("com.toomuchcoding.jsonassert:jsonassert:$jsonAssertVersion") - testCompile("org.springframework.cloud:spring-cloud-contract-verifier:$verifierVersion") - } -} - -configure(listOf(project(":fraudDetectionService"), project(":loanApplicationService"))) { - apply(plugin = "org.springframework.boot") - apply(plugin = "io.spring.dependency-management") - apply(plugin = "org.springframework.cloud.contract") - apply(plugin = "maven-publish") - - configure { - contractsMode.set(StubRunnerProperties.StubsMode.REMOTE) - testFramework.set(TestFramework.SPOCK) - testMode.set(TestMode.MOCKMVC) - baseClassForTests.set("org.springframework.cloud.MvcSpec") - contractsDslDir.set(file("${project.projectDir}/mappings/")) - generatedTestSourcesDir.set(file("${project.buildDir}/generated-test-sources/")) - stubsOutputDir.set(file("${project.buildDir}/production/${project.name}-stubs/")) - } - - configure { - publications { - create("stubs") { - artifactId = "${project.name}-stubs" - artifact(tasks.named("verifierStubsJar").get()) - } - } - } - - dependencies { - compile("org.springframework.boot:spring-boot-starter-web") { - exclude(module = "spring-boot-starter-tomcat") - } - compile("org.springframework.boot:spring-boot-starter-jetty") - compile("org.springframework.boot:spring-boot-starter-actuator") - - testRuntime("org.spockframework:spock-spring:$spockVersion") { - exclude(group = "org.apache.groovy") - } - testCompile("org.mockito:mockito-core") - testCompile("org.springframework:spring-test") - testCompile("org.springframework.boot:spring-boot-test") - testCompile("io.rest-assured:rest-assured:$restAssuredVersion") - testCompile("io.rest-assured:spring-mock-mvc:$restAssuredVersion") - } - - tasks { - jar { - version = "0.0.1" - } - - test { - testLogging.showExceptions = true - } - - val cleanup by registering(Delete::class) { - delete("src/test/resources/mappings", "src/test/resources/stubs") - } - - clean { - dependsOn(cleanup) - } - } -} - -configure(listOf(project(":fraudDetectionService"))) { - tasks { - test { - dependsOn("generateClientStubs") - } - } -} - -configure(listOf(project(":loanApplicationService"))) { - tasks { - val copyCollaboratorStubs by registering(Copy::class) { - val fraudDetectionService = project(":fraudDetectionService") - from(file("${fraudDetectionService.buildDir}/production/${fraudDetectionService.name}-stubs")) - into("src/test/resources/mappings") - } - - val test by existing - test { - dependsOn(copyCollaboratorStubs) - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/mappings/fraudDetectionService/1_shouldMarkClientAsNotFraud.groovy b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/mappings/fraudDetectionService/1_shouldMarkClientAsNotFraud.groovy deleted file mode 100644 index 9f55b24eb4..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/mappings/fraudDetectionService/1_shouldMarkClientAsNotFraud.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - request { - method 'PUT' - url '/fraudcheck' - body(""" - { - "clientPesel":"${value(consumer(regex('[0-9]{10}')), producer('1234567890'))}", - "loanAmount":123.123 - } - """ - ) - headers { - header('Content-Type', 'application/vnd.fraud.v1+json') - } - - } - response { - status OK() - body( - fraudCheckStatus: "OK", - rejectionReason: $(consumer(null), producer(execute('assertThatRejectionReasonIsNull($it)'))) - ) - headers { - header('Content-Type': value( - producer(regex('application/vnd.fraud.v1.json.*')), - consumer('application/vnd.fraud.v1+json')) - ) - } - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/mappings/fraudDetectionService/2_shouldMarkClientAsFraud.groovy b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/mappings/fraudDetectionService/2_shouldMarkClientAsFraud.groovy deleted file mode 100644 index d5eaf57206..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/mappings/fraudDetectionService/2_shouldMarkClientAsFraud.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - request { - method """PUT""" - url """/fraudcheck""" - body(""" - { - "clientPesel":"${value(consumer(regex('[0-9]{10}')), producer('1234567890'))}", - "loanAmount":99999} - """ - ) - headers { - header("""Content-Type""", """application/vnd.fraud.v1+json""") - } - - } - response { - status OK() - body("""{ - "fraudCheckStatus": "${value(consumer('FRAUD'), producer(regex('[A-Z]{5}')))}", - "rejectionReason": "Amount too high" -}""") - headers { - header('Content-Type': value( - producer(regex('application/vnd.fraud.v1.json.*')), - consumer('application/vnd.fraud.v1+json')) - ) - } - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/Application.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/Application.java deleted file mode 100644 index 0dfa308777..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/Application.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; - -@Configuration -@EnableAutoConfiguration -@ComponentScan -public class Application { - - public static void main(String[] args) { - SpringApplication.run(org.springframework.cloud.frauddetection.Application.class, - args); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/FraudDetectionController.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/FraudDetectionController.java deleted file mode 100644 index 72d7b0d09f..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/FraudDetectionController.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection; - -import java.math.BigDecimal; - -import org.springframework.cloud.frauddetection.model.FraudCheck; -import org.springframework.cloud.frauddetection.model.FraudCheckResult; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import static org.springframework.cloud.frauddetection.model.FraudCheckStatus.FRAUD; -import static org.springframework.cloud.frauddetection.model.FraudCheckStatus.OK; -import static org.springframework.web.bind.annotation.RequestMethod.PUT; - -@RestController -public class FraudDetectionController { - - private static final String FRAUD_SERVICE_JSON_VERSION_1 = "application/vnd.fraud.v1+json"; - - private static final String NO_REASON = null; - - private static final String AMOUNT_TOO_HIGH = "Amount too high"; - - private static final BigDecimal MAX_AMOUNT = new BigDecimal("5000"); - - @RequestMapping(value = "/fraudcheck", method = PUT, consumes = FRAUD_SERVICE_JSON_VERSION_1, produces = FRAUD_SERVICE_JSON_VERSION_1) - public FraudCheckResult fraudCheck(@RequestBody FraudCheck fraudCheck) { - if (amountGreaterThanThreshold(fraudCheck)) { - return new FraudCheckResult(FRAUD, AMOUNT_TOO_HIGH); - } - return new FraudCheckResult(OK, NO_REASON); - } - - private boolean amountGreaterThanThreshold(FraudCheck fraudCheck) { - return MAX_AMOUNT.compareTo(fraudCheck.getLoanAmount()) < 0; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheck.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheck.java deleted file mode 100644 index 2dbed39e4e..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheck.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection.model; - -import java.math.BigDecimal; - -public class FraudCheck { - - private String clientPesel; - - private BigDecimal loanAmount; - - public FraudCheck() { - } - - public String getClientPesel() { - return this.clientPesel; - } - - public void setClientPesel(String clientPesel) { - this.clientPesel = clientPesel; - } - - public BigDecimal getLoanAmount() { - return this.loanAmount; - } - - public void setLoanAmount(BigDecimal loanAmount) { - this.loanAmount = loanAmount; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheckResult.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheckResult.java deleted file mode 100644 index ca5eed7947..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheckResult.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection.model; - -public class FraudCheckResult { - - private FraudCheckStatus fraudCheckStatus; - - private String rejectionReason; - - public FraudCheckResult() { - } - - public FraudCheckResult(FraudCheckStatus fraudCheckStatus, String rejectionReason) { - this.fraudCheckStatus = fraudCheckStatus; - this.rejectionReason = rejectionReason; - } - - public FraudCheckStatus getFraudCheckStatus() { - return this.fraudCheckStatus; - } - - public void setFraudCheckStatus(FraudCheckStatus fraudCheckStatus) { - this.fraudCheckStatus = fraudCheckStatus; - } - - public String getRejectionReason() { - return this.rejectionReason; - } - - public void setRejectionReason(String rejectionReason) { - this.rejectionReason = rejectionReason; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheckStatus.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheckStatus.java deleted file mode 100644 index e0c2f2cb9d..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheckStatus.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection.model; - -public enum FraudCheckStatus { - - OK, FRAUD - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/main/resources/application.yml b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/main/resources/application.yml deleted file mode 100644 index cbe617ef03..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/main/resources/application.yml +++ /dev/null @@ -1 +0,0 @@ -server.port=0 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/test/groovy/org/springframework/cloud/MvcSpec.groovy b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/test/groovy/org/springframework/cloud/MvcSpec.groovy deleted file mode 100644 index 6f76c4d5e5..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/test/groovy/org/springframework/cloud/MvcSpec.groovy +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud - -import io.restassured.module.mockmvc.RestAssuredMockMvc -import spock.lang.Specification - -import org.springframework.cloud.frauddetection.FraudDetectionController - -class MvcSpec extends Specification { - def setup() { - RestAssuredMockMvc.standaloneSetup(new FraudDetectionController()) - } - - void assertThatRejectionReasonIsNull(def rejectionReason) { - assert !rejectionReason - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/test/java/org/springframework/cloud/MvcTest.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/test/java/org/springframework/cloud/MvcTest.java deleted file mode 100644 index 8b238f28d3..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/fraudDetectionService/src/test/java/org/springframework/cloud/MvcTest.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud; - -import io.restassured.module.mockmvc.RestAssuredMockMvc; -import org.junit.Before; - -public class MvcTest { - - @Before - public void setup() { - RestAssuredMockMvc.standaloneSetup( - new org.springframework.cloud.frauddetection.FraudDetectionController()); - } - - public void assertThatRejectionReasonIsNull(Object rejectionReason) { - assert rejectionReason == null; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/gradle.properties b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/gradle.properties deleted file mode 100644 index 5f3dd769e3..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/gradle.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright 2013-2020 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -wiremockVersion=2.35.0 -jsonAssertVersion=0.6.2 -verifierVersion=4.1.0-SNAPSHOT -bootVersion=3.2.0-SNAPSHOT -groovyVersion=2.4.17 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/gradle/wrapper/gradle-wrapper.jar b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 490fda8577df6c95960ba7077c43220e5bb2c0d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58694 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 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/gradle/wrapper/gradle-wrapper.properties b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 4c5803d13c..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.4-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/gradlew b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/gradlew deleted file mode 100755 index 2fe81a7d95..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/gradlew +++ /dev/null @@ -1,183 +0,0 @@ -#!/usr/bin/env sh - -# -# Copyright 2015 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=`expr $i + 1` - done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -exec "$JAVACMD" "$@" diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/gradlew.bat b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/gradlew.bat deleted file mode 100644 index 62bd9b9cce..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/gradlew.bat +++ /dev/null @@ -1,103 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/Application.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/Application.java deleted file mode 100644 index 0dfa308777..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/Application.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; - -@Configuration -@EnableAutoConfiguration -@ComponentScan -public class Application { - - public static void main(String[] args) { - SpringApplication.run(org.springframework.cloud.frauddetection.Application.class, - args); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/LoanApplicationService.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/LoanApplicationService.java deleted file mode 100644 index 5cc56e38f9..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/LoanApplicationService.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection; - -import org.springframework.cloud.frauddetection.model.FraudCheckStatus; -import org.springframework.cloud.frauddetection.model.FraudServiceRequest; -import org.springframework.cloud.frauddetection.model.FraudServiceResponse; -import org.springframework.cloud.frauddetection.model.LoanApplication; -import org.springframework.cloud.frauddetection.model.LoanApplicationResult; -import org.springframework.cloud.frauddetection.model.LoanApplicationStatus; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Service; -import org.springframework.web.client.RestTemplate; - -@Service -public class LoanApplicationService { - - private static final String FRAUD_SERVICE_JSON_VERSION_1 = "application/vnd.fraud.v1+json"; - - private final RestTemplate restTemplate; - - private int port = 8080; - - public LoanApplicationService() { - this.restTemplate = new RestTemplate(); - } - - public LoanApplicationResult loanApplication(LoanApplication loanApplication) { - FraudServiceRequest request = new FraudServiceRequest(loanApplication); - - FraudServiceResponse response = sendRequestToFraudDetectionService(request); - - return buildResponseFromFraudResult(response); - } - - private FraudServiceResponse sendRequestToFraudDetectionService( - FraudServiceRequest request) { - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.add(HttpHeaders.CONTENT_TYPE, FRAUD_SERVICE_JSON_VERSION_1); - - ResponseEntity response = this.restTemplate.exchange( - "http://localhost:" + this.port + "/fraudcheck", HttpMethod.PUT, - new HttpEntity<>(request, httpHeaders), FraudServiceResponse.class); - - return response.getBody(); - } - - private LoanApplicationResult buildResponseFromFraudResult( - FraudServiceResponse response) { - LoanApplicationStatus applicationStatus = null; - if (FraudCheckStatus.OK == response.getFraudCheckStatus()) { - applicationStatus = LoanApplicationStatus.LOAN_APPLIED; - } - else if (FraudCheckStatus.FRAUD == response.getFraudCheckStatus()) { - applicationStatus = LoanApplicationStatus.LOAN_APPLICATION_REJECTED; - } - - return new LoanApplicationResult(applicationStatus, - response.getRejectionReason()); - } - - public void setPort(int port) { - this.port = port; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/Client.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/Client.java deleted file mode 100644 index b57fde319f..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/Client.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection.model; - -public class Client { - - private String pesel; - - public String getPesel() { - return this.pesel; - } - - public void setPesel(String pesel) { - this.pesel = pesel; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheckStatus.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheckStatus.java deleted file mode 100644 index e0c2f2cb9d..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/FraudCheckStatus.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection.model; - -public enum FraudCheckStatus { - - OK, FRAUD - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/FraudServiceRequest.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/FraudServiceRequest.java deleted file mode 100644 index 7365314bdb..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/FraudServiceRequest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection.model; - -import java.math.BigDecimal; - -public class FraudServiceRequest { - - private String clientPesel; - - private BigDecimal loanAmount; - - public FraudServiceRequest() { - } - - public FraudServiceRequest(LoanApplication loanApplication) { - this.clientPesel = loanApplication.getClient().getPesel(); - this.loanAmount = loanApplication.getAmount(); - } - - public String getClientPesel() { - return this.clientPesel; - } - - public void setClientPesel(String clientPesel) { - this.clientPesel = clientPesel; - } - - public BigDecimal getLoanAmount() { - return this.loanAmount; - } - - public void setLoanAmount(BigDecimal loanAmount) { - this.loanAmount = loanAmount; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/FraudServiceResponse.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/FraudServiceResponse.java deleted file mode 100644 index 9698951ffc..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/FraudServiceResponse.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection.model; - -public class FraudServiceResponse { - - private FraudCheckStatus fraudCheckStatus; - - private String rejectionReason; - - public FraudServiceResponse() { - } - - public FraudCheckStatus getFraudCheckStatus() { - return this.fraudCheckStatus; - } - - public void setFraudCheckStatus(FraudCheckStatus fraudCheckStatus) { - this.fraudCheckStatus = fraudCheckStatus; - } - - public String getRejectionReason() { - return this.rejectionReason; - } - - public void setRejectionReason(String rejectionReason) { - this.rejectionReason = rejectionReason; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/LoanApplication.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/LoanApplication.java deleted file mode 100644 index 5a93cf631c..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/LoanApplication.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection.model; - -import java.math.BigDecimal; - -public class LoanApplication { - - private Client client; - - private BigDecimal amount; - - private String loanApplicationId; - - public Client getClient() { - return this.client; - } - - public void setClient(Client client) { - this.client = client; - } - - public BigDecimal getAmount() { - return this.amount; - } - - public void setAmount(BigDecimal amount) { - this.amount = amount; - } - - public String getLoanApplicationId() { - return this.loanApplicationId; - } - - public void setLoanApplicationId(String loanApplicationId) { - this.loanApplicationId = loanApplicationId; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/LoanApplicationResult.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/LoanApplicationResult.java deleted file mode 100644 index 701373b15c..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/LoanApplicationResult.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection.model; - -public class LoanApplicationResult { - - private LoanApplicationStatus loanApplicationStatus; - - private String rejectionReason; - - public LoanApplicationResult() { - } - - public LoanApplicationResult(LoanApplicationStatus loanApplicationStatus, - String rejectionReason) { - this.loanApplicationStatus = loanApplicationStatus; - this.rejectionReason = rejectionReason; - } - - public LoanApplicationStatus getLoanApplicationStatus() { - return this.loanApplicationStatus; - } - - public void setLoanApplicationStatus(LoanApplicationStatus loanApplicationStatus) { - this.loanApplicationStatus = loanApplicationStatus; - } - - public String getRejectionReason() { - return this.rejectionReason; - } - - public void setRejectionReason(String rejectionReason) { - this.rejectionReason = rejectionReason; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/LoanApplicationStatus.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/LoanApplicationStatus.java deleted file mode 100644 index eb8490c46f..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/java/org/springframework/cloud/frauddetection/model/LoanApplicationStatus.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.frauddetection.model; - -public enum LoanApplicationStatus { - - LOAN_APPLIED, LOAN_APPLICATION_REJECTED - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/resources/application.yml b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/resources/application.yml deleted file mode 100644 index cbe617ef03..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/main/resources/application.yml +++ /dev/null @@ -1 +0,0 @@ -server.port=0 diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/test/groovy/org/springframework/cloud/LoanApplicationServiceSpec.groovy b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/test/groovy/org/springframework/cloud/LoanApplicationServiceSpec.groovy deleted file mode 100644 index 3a63ee1dff..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/loanApplicationService/src/test/groovy/org/springframework/cloud/LoanApplicationServiceSpec.groovy +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud - -import com.github.tomakehurst.wiremock.junit.WireMockClassRule -import org.junit.ClassRule -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Stepwise - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootContextLoader -import org.springframework.cloud.frauddetection.Application -import org.springframework.cloud.frauddetection.LoanApplicationService -import org.springframework.cloud.frauddetection.model.Client -import org.springframework.cloud.frauddetection.model.LoanApplication -import org.springframework.cloud.frauddetection.model.LoanApplicationResult -import org.springframework.cloud.frauddetection.model.LoanApplicationStatus -import org.springframework.test.context.ContextConfiguration - -@ContextConfiguration(loader = SpringBootContextLoader, classes = Application) -@Stepwise -class LoanApplicationServiceSpec extends Specification { - - public static int port = org.springframework.cloud.test.TestSocketUtils.findAvailableTcpPort() - - @ClassRule - @Shared - WireMockClassRule wireMockRule = new WireMockClassRule(port) - - @Autowired - LoanApplicationService sut - - def setup() { - sut.port = port - } - - def 'should successfully apply for loan'() { - given: - LoanApplication application = - new LoanApplication(client: new Client(pesel: '1234567890'), amount: 123.123) - when: - LoanApplicationResult loanApplication = sut.loanApplication(application) - then: - loanApplication.loanApplicationStatus == LoanApplicationStatus.LOAN_APPLIED - loanApplication.rejectionReason == null - } - - def 'should be rejected due to abnormal loan amount'() { - given: - LoanApplication application = - new LoanApplication(client: new Client(pesel: '1234567890'), amount: 99_999) - when: - LoanApplicationResult loanApplication = sut.loanApplication(application) - then: - loanApplication.loanApplicationStatus == LoanApplicationStatus.LOAN_APPLICATION_REJECTED - loanApplication.rejectionReason == 'Amount too high' - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/settings.gradle.kts b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/settings.gradle.kts deleted file mode 100644 index 3d14f16553..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProjectKotlin/settings.gradle.kts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -pluginManagement { - repositories { - mavenCentral() - mavenLocal() - maven(url = "https://repo.spring.io/snapshot") - maven(url = "https://repo.spring.io/milestone") - maven(url = "https://repo.spring.io/release") - } - resolutionStrategy { - eachPlugin { - if (requested.id.id == "org.springframework.boot") { - val bootVersion: String by extra - useModule("org.springframework.boot:spring-boot-gradle-plugin:$bootVersion") - } else if (requested.id.id == "org.springframework.cloud.contract") { - val verifierVersion: String by extra - useModule("org.springframework.cloud:spring-cloud-contract-gradle-plugin:$verifierVersion") - } - } - } -} - -include(":fraudDetectionService") -include(":loanApplicationService") diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-portal-plugin/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-gradle-portal-plugin/pom.xml deleted file mode 100644 index aeb4cd7d79..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-portal-plugin/pom.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - 4.0.0 - - - org.springframework.cloud - spring-cloud-contract-tools - 4.1.0-SNAPSHOT - .. - - - org.springframework.cloud.contract - org.springframework.cloud.contract.gradle.plugin - jar - - Spring Cloud Contract Gradle Portal Plugin - Spring Cloud Contract Gradle Portal Plugin - - - - org.springframework.cloud - spring-cloud-contract-gradle-plugin - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/.gitignore b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/.gitignore deleted file mode 100644 index 2c95b068c5..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -.idea/ -*.iml -/target -pom.xml.tag -pom.xml.releaseBackup -pom.xml.versionsBackup -pom.xml.next -release.properties -dependency-reduced-pom.xml -buildNumber.properties -.mvn/timing.properties - -target \ No newline at end of file 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 deleted file mode 100644 index c98cd85bb5..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/pom.xml +++ /dev/null @@ -1,487 +0,0 @@ - - - 4.0.0 - - - org.springframework.cloud - spring-cloud-contract-tools - 4.1.0-SNAPSHOT - .. - - - - 3.6 - - - spring-cloud-contract-maven-plugin - maven-plugin - - Spring Cloud Contract Maven Plugin - Spring Cloud Contract Maven Plugin - https://github.com/spring-cloud/spring-cloud-contract - - - UTF-8 - UTF-8 - false - 3.6.1 - - 3.0.0-M3 - 1.6.0 - 3.1.1 - 3.0.0 - 3.1.1 - 3.6.1 - 3.5.1 - 4.2.5 - 4.3.0 - 3.9.1 - 3.3.0 - 1.1 - 2.0.7 - - - 2016 - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - **/PluginUnitTest.java - - - - - org.apache.maven.plugins - maven-failsafe-plugin - - - - org.junit.jupiter - junit-jupiter-engine - ${junit-jupiter.version} - - - org.junit.vintage - junit-vintage-engine - ${junit-vintage.version} - - - - plain - true - - org.junit.jupiter:junit-vintage-engine - - - **/PluginUnitTest.java - - - - - - integration-test - verify - - - - - - org.jacoco - jacoco-maven-plugin - ${jacoco-maven-plugin.version} - - - **/HelpMojo.class - - - - - prepare-agent - - prepare-agent - - - - - - org.eluder.coveralls - coveralls-maven-plugin - ${coveralls-maven-plugin.version} - - - org.apache.maven.plugins - maven-site-plugin - ${maven-site-plugin.version} - - true - - - true - true - false - en - UTF-8 - UTF-8 - - - - font - coderay - style - 2 - - - - - - org.asciidoctor - asciidoctor-maven-plugin - ${asciidoctor-maven-plugin.version} - - - - - org.apache.maven.plugins - maven-scm-publish-plugin - ${maven-scm-publish-plugin.version} - - ${project.reporting.outputDirectory} - - - - scm-publish - site-deploy - - publish-scm - - - - - - maven-plugin-plugin - ${maven.plugin.plugin.version} - - true - - - - generated-helpmojo - - helpmojo - - - - generate-descriptor - - descriptor - - - - - - org.apache.maven.plugins - maven-checkstyle-plugin - - - - - - - org.eclipse.m2e - lifecycle-mapping - 1.0.0 - - - - - - - org.apache.maven.plugins - - - maven-plugin-plugin - - - [3.5,) - - - descriptor - helpmojo - - - - - - - - - - - - - - - - - - maven-plugin-plugin - - - org.apache.maven.plugins - maven-project-info-reports-plugin - ${maven-project-info-reports-plugin.version} - - - - ci-management - help - index - issue-management - licenses - modules - plugin-management - plugins - team - scm - summary - - - - - - - - - - org.slf4j - slf4j-api - ${slf4j-api.version} - - - org.springframework.cloud - spring-cloud-contract-verifier - - - org.springframework.cloud - spring-cloud-contract-converters - - - org.apache.logging.log4j - log4j-to-slf4j - - - - - org.springframework.cloud - spring-cloud-contract-stub-runner - - - org.springframework.cloud - spring-cloud-contract-wiremock - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework - spring-jcl - - - - org.apache.maven.resolver - maven-resolver-api - provided - - - org.apache.maven.resolver - maven-resolver-impl - provided - - - org.apache.maven.resolver - maven-resolver-transport-file - provided - - - org.apache.maven.resolver - maven-resolver-transport-http - provided - - - org.apache.maven.resolver - maven-resolver-connector-basic - provided - - - org.apache.maven - maven-resolver-provider - provided - - - org.apache.maven - maven-settings-builder - provided - - - org.apache.maven.shared - maven-filtering - ${maven-filtering.version} - - - - ch.qos.logback - logback-core - - - org.slf4j - slf4j-simple - test - - - - javax.inject - javax.inject - provided - - - org.apache.maven - maven-core - ${maven.version} - provided - - - - org.apache.maven - maven-plugin-api - ${maven.version} - provided - - - org.apache.maven - maven-model - - - org.apache.maven - maven-artifact - - - org.eclipse.sisu - org.eclipse.sisu.plexus - - - - - org.apache.maven.plugin-tools - maven-plugin-annotations - ${maven-plugin-annotations.version} - provided - - - - org.apache.maven - maven-archiver - ${maven-archiver.version} - - - org.codehaus.plexus - plexus-archiver - ${plexus-archiver.version} - - - org.apache.maven.shared - maven-shared-incremental - ${maven-shared-incremental.version} - - - - org.apache.maven - maven-compat - ${maven.version} - test - - - junit - junit - test - - - org.assertj - assertj-core - test - - - org.apache.maven.plugin-testing - maven-plugin-testing-harness - ${maven-plugin-testing-harness.version} - test - - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - false - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - false - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/BaseClassMapping.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/BaseClassMapping.java deleted file mode 100644 index 4c1adbb5e3..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/BaseClassMapping.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.maven.verifier; - -/** - * Represents a single mapping of regex on package where contracts reside to the FQN of - * the base test class. - * - * @author Marcin Grzejszczak - * @since 1.0.0 - */ -public class BaseClassMapping { - - private String contractPackageRegex; - - private String baseClassFQN; - - public String getContractPackageRegex() { - return this.contractPackageRegex; - } - - public void setContractPackageRegex(String contractPackageRegex) { - this.contractPackageRegex = contractPackageRegex; - } - - public String getBaseClassFQN() { - return this.baseClassFQN; - } - - public void setBaseClassFQN(String baseClassFQN) { - this.baseClassFQN = baseClassFQN; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - BaseClassMapping that = (BaseClassMapping) o; - if (this.contractPackageRegex != null ? !this.contractPackageRegex.equals(that.contractPackageRegex) - : that.contractPackageRegex != null) { - return false; - } - return this.baseClassFQN != null ? this.baseClassFQN.equals(that.baseClassFQN) : that.baseClassFQN == null; - - } - - @Override - public int hashCode() { - int result = this.contractPackageRegex != null ? this.contractPackageRegex.hashCode() : 0; - result = 31 * result + (this.baseClassFQN != null ? this.baseClassFQN.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "BaseClassMapping{" + "contractPackageRegex='" + this.contractPackageRegex + '\'' + ", baseClassFQN='" - + this.baseClassFQN + '\'' + '}'; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/ChangeDetector.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/ChangeDetector.java deleted file mode 100644 index 801ff98e74..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/ChangeDetector.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.maven.verifier; - -import java.io.File; - -import org.apache.maven.execution.MavenSession; -import org.apache.maven.plugin.MojoExecution; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.shared.incremental.IncrementalBuildHelper; -import org.apache.maven.shared.utils.io.DirectoryScanner; - -final class ChangeDetector { - - private ChangeDetector() { - } - - static boolean inputFilesChangeDetected(File contractsDirectory, MojoExecution mojoExecution, MavenSession session) - throws MojoExecutionException { - if (session.getGoals().contains("clean")) { - return true; - } - IncrementalBuildHelper incrementalBuildHelper = new IncrementalBuildHelper(mojoExecution, session); - - DirectoryScanner scanner = incrementalBuildHelper.getDirectoryScanner(); - scanner.setBasedir(contractsDirectory); - scanner.scan(); - boolean changeDetected = incrementalBuildHelper.inputFileTreeChanged(scanner); - if (scanner.getIncludedFiles().length == 0) { - // at least one input file must exist to consider changed/unchanged - // return true to skip incremental build and make visible no input file at all - return true; - } - return changeDetected; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/ConvertMojo.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/ConvertMojo.java deleted file mode 100644 index 1c3615fd57..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/ConvertMojo.java +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.maven.verifier; - -import java.io.File; -import java.util.HashMap; -import java.util.Map; - -import org.apache.maven.execution.MavenSession; -import org.apache.maven.model.Dependency; -import org.apache.maven.plugin.AbstractMojo; -import org.apache.maven.plugin.MojoExecution; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugins.annotations.Component; -import org.apache.maven.plugins.annotations.LifecyclePhase; -import org.apache.maven.plugins.annotations.Mojo; -import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.project.MavenProject; -import org.apache.maven.shared.filtering.MavenResourcesFiltering; -import org.eclipse.aether.RepositorySystemSession; - -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties; -import org.springframework.cloud.contract.verifier.converter.RecursiveFilesConverter; -import org.springframework.cloud.contract.verifier.converter.ToYamlConverter; - -import static org.springframework.cloud.contract.maven.verifier.ChangeDetector.inputFilesChangeDetected; - -/** - * Convert Spring Cloud Contract Verifier contracts into stubs mappings. - *

- * This goal allows you to generate `stubs-jar` or execute `spring-cloud-contract:run` - * with generated mappings. - * - * @author Mariusz Smykula - */ -@Mojo(name = "convert", requiresProject = false, defaultPhase = LifecyclePhase.PROCESS_TEST_RESOURCES) -public class ConvertMojo extends AbstractMojo { - - static final String DEFAULT_STUBS_DIR = "${project.build.directory}/stubs/"; - static final String MAPPINGS_PATH = "/mappings"; - static final String CONTRACTS_PATH = "/contracts"; - static final String ORIGINAL_PATH = "/original"; - - @Parameter(defaultValue = "${repositorySystemSession}", readonly = true) - private RepositorySystemSession repoSession; - - /** - * Directory containing Spring Cloud Contract Verifier contracts written using the - * GroovyDSL. - */ - @Parameter(property = "spring.cloud.contract.verifier.contractsDirectory", - defaultValue = "${project.basedir}/src/test/resources/contracts") - private File contractsDirectory; - - /** - * Directory where the generated WireMock stubs from Groovy DSL should be placed. You - * can then mention them in your packaging task to create jar with stubs - */ - @Parameter(defaultValue = DEFAULT_STUBS_DIR) - private File stubsDirectory; - - /** - * Directory containing contracts written using the GroovyDSL - *

- * This parameter is only used when goal is executed outside of maven project. - */ - @Parameter(property = "contractsDirectory", defaultValue = "${basedir}") - private File source; - - @Parameter(property = "stubsDirectory", defaultValue = "${basedir}") - private File destination; - - @Parameter(property = "spring.cloud.contract.verifier.skip", defaultValue = "false") - private boolean skip; - - @Parameter(defaultValue = "${session}", readonly = true) - private MavenSession mavenSession; - - @Parameter(defaultValue = "${project}", readonly = true) - private MavenProject project; - - /** - * The URL from which a JAR containing the contracts should get downloaded. If not - * provided but artifactid / coordinates notation was provided then the current - * Maven's build repositories will be taken into consideration - */ - @Parameter(property = "contractsRepositoryUrl") - private String contractsRepositoryUrl; - - @Parameter(property = "contractDependency") - private Dependency contractDependency; - - /** - * The path in the JAR with all the contracts where contracts for this particular - * service lay. If not provided will be resolved to {@code groupid/artifactid}. - * Example: If {@code groupid} is {@code com.example} and {@code artifactid} is - * {@code service} then the resolved path will be {@code /com/example/artifactid} - */ - @Parameter(property = "contractsPath") - private String contractsPath; - - /** - * Picks the mode in which stubs will be found and registered. - */ - @Parameter(property = "contractsMode", defaultValue = "CLASSPATH") - private StubRunnerProperties.StubsMode contractsMode; - - /** - * If {@code true} then any file laying in a path that contains {@code build} or - * {@code target} will get excluded in further processing. - */ - @Parameter(property = "excludeBuildFolders", defaultValue = "false") - private boolean excludeBuildFolders; - - /** - * The user name to be used to connect to the repo with contracts. - */ - @Parameter(property = "contractsRepositoryUsername") - private String contractsRepositoryUsername; - - /** - * The password to be used to connect to the repo with contracts. - */ - @Parameter(property = "contractsRepositoryPassword") - private String contractsRepositoryPassword; - - /** - * The proxy host to be used to connect to the repo with contracts. - */ - @Parameter(property = "contractsRepositoryProxyHost") - private String contractsRepositoryProxyHost; - - /** - * The proxy port to be used to connect to the repo with contracts. - */ - @Parameter(property = "contractsRepositoryProxyPort") - private Integer contractsRepositoryProxyPort; - - /** - * If set to {@code false} will NOT delete stubs from a temporary folder after running - * tests. - */ - @Parameter(property = "deleteStubsAfterTest", defaultValue = "true") - private boolean deleteStubsAfterTest; - - /** - * Map of properties that can be passed to custom - * {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder}. - */ - @Parameter(property = "contractsProperties") - private Map contractsProperties = new HashMap<>(); - - /** - * If {@code true} then will convert contracts to a YAML representation. - */ - @Parameter(property = "convertToYaml", defaultValue = "false") - private boolean convertToYaml; - - @Component(role = MavenResourcesFiltering.class, hint = "default") - private MavenResourcesFiltering mavenResourcesFiltering; - - /** - * When enabled, this flag will tell stub runner to throw an exception when no stubs / - * contracts were found. - */ - @Parameter(property = "failOnNoContracts", defaultValue = "true") - private boolean failOnNoContracts; - - /** - * If set to true then stubs are created only when contracts have changed since last - * build. - */ - @Parameter(property = "incrementalContractStubs", defaultValue = "true") - private boolean incrementalContractStubs = true; - - @Parameter(defaultValue = "${mojoExecution}", readonly = true, required = true) - private MojoExecution mojoExecution; - - @Parameter(defaultValue = "${session}", readonly = true, required = true) - private MavenSession session; - - @Override - public void execute() throws MojoExecutionException { - if (this.skip) { - getLog().info(String.format( - "Skipping Spring Cloud Contract Verifier execution: spring.cloud.contract.verifier.skip=%s", - this.skip)); - return; - } - String groupId = this.project.getGroupId(); - String artifactId = this.project.getArtifactId(); - String version = this.project.getVersion(); - String rootPath = "META-INF/" + groupId + "/" + artifactId + "/" + version; - // download contracts, unzip them and pass as output directory - ContractVerifierConfigProperties config = new ContractVerifierConfigProperties(); - config.setExcludeBuildFolders(this.excludeBuildFolders); - File contractsDirectory = locationOfContracts(config); - contractsDirectory = contractSubfolderIfPresent(contractsDirectory); - - if (this.incrementalContractStubs && !inputFilesChangeDetected(contractsDirectory, mojoExecution, session)) { - getLog().info("Nothing to generate - all stubs are up to date"); - return; - } - - File contractsDslDir = contractsDslDir(contractsDirectory); - LeftOverPrevention leftOverPrevention = new LeftOverPrevention(this.stubsDirectory, mojoExecution, session); - - File copiedContracts = copyContracts(rootPath, config, contractsDirectory); - if (this.convertToYaml) { - contractsDslDir = copiedContracts; - convertBackedUpDslsToYaml(rootPath, config, contractsDirectory, contractsDslDir); - } - config.setContractsDslDir(contractsDslDir); - config.setStubsOutputDir(stubsOutputDir(rootPath)); - logSetup(config, contractsDslDir); - RecursiveFilesConverter converter = new RecursiveFilesConverter(config.getStubsOutputDir(), - config.getContractsDslDir(), config.getExcludedFiles(), config.getIncludedContracts(), - config.isExcludeBuildFolders()); - converter.processFiles(); - leftOverPrevention.deleteLeftOvers(); - } - - private void convertBackedUpDslsToYaml(String rootPath, ContractVerifierConfigProperties config, - File contractsDirectory, File contractsDslDir) throws MojoExecutionException { - copyOriginals(rootPath, config, contractsDirectory); - ToYamlConverter.replaceContractWithYaml(contractsDslDir); - getLog().info("Replaced DSL files with their YAML representation at [" + contractsDslDir + "]"); - } - - private File copyOriginals(String rootPath, ContractVerifierConfigProperties config, File contractsDirectory) - throws MojoExecutionException { - File outputFolderWithOriginals = new File(this.stubsDirectory, rootPath + ORIGINAL_PATH); - new CopyContracts(this.project, this.mavenSession, this.mavenResourcesFiltering, config) - .copy(contractsDirectory, outputFolderWithOriginals); - return outputFolderWithOriginals; - } - - private File copyContracts(String rootPath, ContractVerifierConfigProperties config, File contractsDirectory) - throws MojoExecutionException { - File outputFolderWithContracts = this.stubsDirectory.getPath().endsWith("contracts") ? this.stubsDirectory - : new File(this.stubsDirectory, rootPath + CONTRACTS_PATH); - new CopyContracts(this.project, this.mavenSession, this.mavenResourcesFiltering, config) - .copy(contractsDirectory, outputFolderWithContracts); - return outputFolderWithContracts; - } - - private void logSetup(ContractVerifierConfigProperties config, File contractsDslDir) { - if (getLog().isDebugEnabled()) { - getLog().debug("The contracts dir equals [" + contractsDslDir + "]"); - } - getLog().info("Converting from Spring Cloud Contract Verifier contracts to WireMock stubs mappings"); - getLog().info(String.format(" Spring Cloud Contract Verifier contracts directory: %s", - config.getContractsDslDir())); - getLog().info(String.format("Stub Server stubs mappings directory: %s", config.getStubsOutputDir())); - } - - private File contractSubfolderIfPresent(File contractsDirectory) { - File contractsSubFolder = new File(contractsDirectory, "contracts"); - if (contractsSubFolder.exists()) { - if (getLog().isDebugEnabled()) { - getLog().debug("The subfolder [contracts] exists, will pick it as a source of contracts"); - } - contractsDirectory = contractsSubFolder; - } - return contractsDirectory; - } - - private File locationOfContracts(ContractVerifierConfigProperties config) { - return new MavenContractsDownloader(this.project, this.contractDependency, this.contractsPath, - this.contractsRepositoryUrl, this.contractsMode, getLog(), this.contractsRepositoryUsername, - this.contractsRepositoryPassword, this.contractsRepositoryProxyHost, this.contractsRepositoryProxyPort, - this.deleteStubsAfterTest, this.contractsProperties, this.failOnNoContracts) - .downloadAndUnpackContractsIfRequired(config, this.contractsDirectory); - } - - private File stubsOutputDir(String rootPath) { - return isInsideProject() ? new File(this.stubsDirectory, rootPath + MAPPINGS_PATH) : this.destination; - } - - private File contractsDslDir(File contractsDirectory) { - return isInsideProject() ? contractsDirectory : this.source; - } - - private boolean isInsideProject() { - return this.mavenSession.getRequest().isProjectPresent(); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/CopyContracts.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/CopyContracts.java deleted file mode 100644 index 7468dd9d1a..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/CopyContracts.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.maven.verifier; - -import java.io.File; -import java.util.Collections; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.maven.execution.MavenSession; -import org.apache.maven.model.Resource; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.project.MavenProject; -import org.apache.maven.shared.filtering.MavenFilteringException; -import org.apache.maven.shared.filtering.MavenResourcesExecution; -import org.apache.maven.shared.filtering.MavenResourcesFiltering; - -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties; - -class CopyContracts { - - private static final Log log = LogFactory.getLog(CopyContracts.class); - - private final MavenProject project; - - private final MavenSession mavenSession; - - private final MavenResourcesFiltering mavenResourcesFiltering; - - private final ContractVerifierConfigProperties config; - - CopyContracts(MavenProject project, MavenSession mavenSession, MavenResourcesFiltering mavenResourcesFiltering, - ContractVerifierConfigProperties config) { - this.project = project; - this.mavenSession = mavenSession; - this.mavenResourcesFiltering = mavenResourcesFiltering; - this.config = config; - } - - public void copy(File contractsDirectory, File outputDirectory) throws MojoExecutionException { - log.info("Copying Spring Cloud Contract Verifier contracts to [" + outputDirectory + "]" - + ". Only files matching [" + this.config.getIncludedContracts() + "] pattern will end up in " - + "the final JAR with stubs."); - Resource resource = new Resource(); - String includedRootFolderAntPattern = this.config.getIncludedRootFolderAntPattern() + "*.*"; - String slashSeparatedGroupIdAntPattern = slashSeparatedGroupIdAntPattern(includedRootFolderAntPattern); - String dotSeparatedGroupIdAntPattern = dotSeparatedGroupIdAntPattern(includedRootFolderAntPattern); - // by default group id is slash separated... - resource.addInclude(slashSeparatedGroupIdAntPattern); - if (!slashSeparatedGroupIdAntPattern.equals(dotSeparatedGroupIdAntPattern)) { - // ...we also want to allow dot separation - resource.addInclude(dotSeparatedGroupIdAntPattern); - } - if (this.config.isExcludeBuildFolders()) { - resource.addExclude("**/target/**"); - resource.addExclude("**/.mvn/**"); - resource.addExclude("**/build/**"); - resource.addExclude("**/.gradle/**"); - } - resource.setDirectory(contractsDirectory.getAbsolutePath()); - MavenResourcesExecution execution = new MavenResourcesExecution(); - execution.setResources(Collections.singletonList(resource)); - execution.setOutputDirectory(outputDirectory); - execution.setMavenProject(this.project); - execution.setEncoding("UTF-8"); - execution.setMavenSession(this.mavenSession); - execution.setInjectProjectBuildFilters(false); - execution.setOverwrite(true); - execution.setIncludeEmptyDirs(false); - execution.setFilterFilenames(false); - execution.setFilters(Collections.emptyList()); - try { - this.mavenResourcesFiltering.filterResources(execution); - } - catch (MavenFilteringException e) { - throw new MojoExecutionException(e.getMessage(), e); - } - } - - private String slashSeparatedGroupIdAntPattern(String includedRootFolderAntPattern) { - if (includedRootFolderAntPattern.contains(slashSeparatedGroupId())) { - return includedRootFolderAntPattern; - } - else if (includedRootFolderAntPattern.contains(dotSeparatedGroupId())) { - return includedRootFolderAntPattern.replace(dotSeparatedGroupId(), slashSeparatedGroupId()); - } - return includedRootFolderAntPattern; - } - - private String dotSeparatedGroupIdAntPattern(String includedRootFolderAntPattern) { - if (includedRootFolderAntPattern.contains(dotSeparatedGroupId())) { - return includedRootFolderAntPattern; - } - else if (includedRootFolderAntPattern.contains(slashSeparatedGroupId())) { - return includedRootFolderAntPattern.replace(slashSeparatedGroupId(), dotSeparatedGroupId()); - } - return includedRootFolderAntPattern; - } - - private String slashSeparatedGroupId() { - return this.project.getGroupId().replace(".", File.separator); - } - - private String dotSeparatedGroupId() { - return this.project.getGroupId(); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/GenerateStubsMojo.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/GenerateStubsMojo.java deleted file mode 100644 index 1faf7a675f..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/GenerateStubsMojo.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.maven.verifier; - -import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.apache.maven.execution.MavenSession; -import org.apache.maven.plugin.AbstractMojo; -import org.apache.maven.plugin.MojoExecution; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.MojoFailureException; -import org.apache.maven.plugins.annotations.Component; -import org.apache.maven.plugins.annotations.LifecyclePhase; -import org.apache.maven.plugins.annotations.Mojo; -import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.project.MavenProject; -import org.apache.maven.project.MavenProjectHelper; -import org.codehaus.plexus.archiver.Archiver; -import org.codehaus.plexus.archiver.jar.JarArchiver; - -import static org.springframework.cloud.contract.maven.verifier.ChangeDetector.inputFilesChangeDetected; - -/** - * Picks the converted .json files and creates a jar. Requires convert to be executed - * first. - * - * @author Mariusz Smykula - */ -@Mojo(name = "generateStubs", defaultPhase = LifecyclePhase.PACKAGE, requiresProject = true) -public class GenerateStubsMojo extends AbstractMojo { - - @Parameter(defaultValue = "${project.build.directory}", readonly = true, required = true) - private File projectBuildDirectory; - - @Parameter(defaultValue = "${project.build.finalName}", readonly = true, required = true) - private String projectFinalName; - - @Parameter(property = "stubsDirectory", defaultValue = "${project.build.directory}/stubs") - private File stubsDirectory; - - /** - * Set this to "true" to bypass the whole Verifier execution. - */ - @Parameter(property = "spring.cloud.contract.verifier.skip", defaultValue = "false") - private boolean skip; - - /** - * Set this to "true" to bypass only JAR creation. - */ - @Parameter(property = "spring.cloud.contract.verifier.jar.skip", defaultValue = "false") - private boolean jarSkip; - - @Component - private MavenProjectHelper projectHelper; - - /** - * Patterns that should not be taken into account for processing. - */ - @Parameter - private String[] excludedFiles; - - @Parameter(defaultValue = "${project}", readonly = true) - private MavenProject project; - - @Component(role = Archiver.class, hint = "jar") - private JarArchiver archiver; - - @Parameter(defaultValue = "stubs") - private String classifier; - - /** - * If set to true then stubs jar is created only when stubs have changed since last - * build. - */ - @Parameter(property = "incrementalContractStubsJar", defaultValue = "true") - private boolean incrementalContractStubsJar = true; - - @Parameter(defaultValue = "${mojoExecution}", readonly = true, required = true) - private MojoExecution mojoExecution; - - @Parameter(defaultValue = "${session}", readonly = true, required = true) - private MavenSession session; - - /** - * When enabled, this flag will tell stub runner to throw an exception when no stubs / - * contracts were found. - */ - @Parameter(property = "failOnNoContracts", defaultValue = "true") - private boolean failOnNoContracts; - - public void execute() throws MojoExecutionException, MojoFailureException { - if (this.skip || this.jarSkip) { - getLog().info("Skipping Spring Cloud Contract Verifier execution: spring.cloud.contract.verifier.skip=" - + this.skip + ", spring.cloud.contract.verifier.jar.skip=" + this.jarSkip); - return; - } - else if (stubsOutputMissing(this.stubsDirectory) && !this.failOnNoContracts) { - getLog().warn( - "The stubs output directory is missing, the flag to fail on no stubs if off - will continue without throwing an exception"); - return; - } - else if (stubsOutputMissing(this.stubsDirectory) && this.failOnNoContracts) { - throw new MojoExecutionException("Stubs could not be found: [" + this.stubsDirectory.getAbsolutePath() - + "] .\nPlease make sure that spring-cloud-contract:convert was invoked"); - } - File stubsJarFile = getStubJarDestFile(); - if (this.incrementalContractStubsJar && !inputFilesChangeDetected(stubsDirectory, mojoExecution, session)) { - getLog().info("Nothing to generate - stubs jar is up to date"); - } - else { - fillStubJar(this.stubsDirectory, stubsJarFile); - } - this.projectHelper.attachArtifact(this.project, "jar", this.classifier, stubsJarFile); - } - - private File getStubJarDestFile() { - String stubArchiveName = this.projectFinalName + "-" + this.classifier + ".jar"; - return new File(this.projectBuildDirectory, stubArchiveName); - } - - private void fillStubJar(File stubsOutputDir, File stubsJarFile) throws MojoFailureException { - String[] excludes = excludes(); - getLog().info( - "Files matching this pattern will be excluded from " + "stubs generation " + Arrays.toString(excludes)); - try { - this.archiver.addDirectory(stubsOutputDir, new String[] { "**/*.*" }, - excludedFilesEmpty() ? new String[0] : this.excludedFiles); - this.archiver.setCompress(true); - this.archiver.setDestFile(stubsJarFile); - this.archiver.addConfiguredManifest(ManifestCreator.createManifest(this.project)); - this.archiver.createArchive(); - } - catch (Exception e) { - throw new MojoFailureException("Exception while packaging " + this.classifier + " jar.", e); - } - } - - private boolean stubsOutputMissing(File stubsOutputDir) { - return !stubsOutputDir.exists(); - } - - private String[] excludes() { - List excludes = new ArrayList<>(); - if (!excludedFilesEmpty()) { - excludes.addAll(Arrays.asList(this.excludedFiles)); - } - String[] array = new String[excludes.size()]; - array = excludes.toArray(array); - return array; - } - - private boolean excludedFilesEmpty() { - return this.excludedFiles == null || this.excludedFiles.length == 0; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/GenerateTestsMojo.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/GenerateTestsMojo.java deleted file mode 100644 index 868a952269..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/GenerateTestsMojo.java +++ /dev/null @@ -1,379 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.maven.verifier; - -import java.io.File; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.maven.execution.MavenSession; -import org.apache.maven.model.Dependency; -import org.apache.maven.model.Resource; -import org.apache.maven.plugin.AbstractMojo; -import org.apache.maven.plugin.MojoExecution; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.MojoFailureException; -import org.apache.maven.plugins.annotations.LifecyclePhase; -import org.apache.maven.plugins.annotations.Mojo; -import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.plugins.annotations.ResolutionScope; -import org.apache.maven.project.MavenProject; -import org.eclipse.aether.RepositorySystemSession; - -import org.springframework.cloud.contract.spec.ContractVerifierException; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.cloud.contract.verifier.TestGenerator; -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties; -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.config.TestMode; -import org.springframework.util.StringUtils; - -/** - * From the provided directory with contracts generates the acceptance tests on the - * producer side. - * - * @author Mariusz Smykula - */ -@Mojo(name = "generateTests", defaultPhase = LifecyclePhase.GENERATE_TEST_SOURCES, - requiresDependencyResolution = ResolutionScope.TEST) -public class GenerateTestsMojo extends AbstractMojo { - - @Parameter(defaultValue = "${repositorySystemSession}", readonly = true) - private RepositorySystemSession repoSession; - - @Parameter(property = "spring.cloud.contract.verifier.contractsDirectory", - defaultValue = "${project.basedir}/src/test/resources/contracts") - private File contractsDirectory; - - @Parameter(defaultValue = "${project.build.directory}/generated-test-sources/contracts") - private File generatedTestSourcesDir; - - @Parameter(defaultValue = "${project.build.directory}/generated-test-resources/contracts") - private File generatedTestResourcesDir; - - @Parameter - private String basePackageForTests; - - @Parameter - private String baseClassForTests; - - @Parameter(defaultValue = "MOCKMVC") - private TestMode testMode; - - @Parameter(defaultValue = "JUNIT5") - private TestFramework testFramework; - - @Parameter - private String ruleClassForTests; - - @Parameter - private String nameSuffixForTests; - - /** - * Imports that should be added to generated tests. - */ - @Parameter - private String[] imports; - - /** - * Static imports that should be added to generated tests. - */ - @Parameter - private String[] staticImports; - - /** - * Patterns that should not be taken into account for processing. - */ - @Parameter - private List excludedFiles; - - /** - * Patterns that should be taken into account for processing. - */ - @Parameter(property = "includedFiles") - private List includedFiles; - - /** - * Incubating feature. You can check the size of JSON arrays. If not turned on - * explicitly will be disabled. - */ - @Parameter(property = "spring.cloud.contract.verifier.assert.size", defaultValue = "false") - private boolean assertJsonSize; - - /** - * Patterns for which Spring Cloud Contract Verifier should generate @Ignored tests. - */ - @Parameter - private List ignoredFiles; - - @Parameter(defaultValue = "${project}", readonly = true) - private MavenProject project; - - @Parameter(property = "spring.cloud.contract.verifier.skip", defaultValue = "false") - private boolean skip; - - @Parameter(property = "maven.test.skip", defaultValue = "false") - private boolean mavenTestSkip; - - /** - * The URL from which a contracts should get downloaded. If not provided but - * artifactid / coordinates notation was provided then the current Maven's build - * repositories will be taken into consideration. - */ - @Parameter(property = "contractsRepositoryUrl") - private String contractsRepositoryUrl; - - @Parameter(property = "contractDependency") - private Dependency contractDependency; - - /** - * The path in the JAR with all the contracts where contracts for this particular - * service lay. If not provided will be resolved to {@code groupid/artifactid}. - * Example: If {@code groupid} is {@code com.example} and {@code artifactid} is - * {@code service} then the resolved path will be {@code /com/example/artifactid} - */ - @Parameter(property = "contractsPath") - private String contractsPath; - - /** - * Picks the mode in which stubs will be found and registered. - */ - @Parameter(property = "contractsMode", defaultValue = "CLASSPATH") - private StubRunnerProperties.StubsMode contractsMode; - - /** - * A package that contains all the base clases for generated tests. If your contract - * resides in a location {@code src/test/resources/contracts/com/example/v1/} and you - * provide the {@code packageWithBaseClasses} value to - * {@code com.example.contracts.base} then we will search for a test source file that - * will have the package {@code com.example.contracts.base} and name - * {@code ExampleV1Base}. As you can see it will take the two last folders to and - * attach {@code Base} to its name. - */ - @Parameter(property = "packageWithBaseClasses") - private String packageWithBaseClasses; - - /** - * A way to override any base class mappings. The keys are regular expressions on the - * package name of the contract and the values FQN to a base class for that given - * expression. Example of a mapping {@code .*.com.example.v1..*} -> - * {@code com.example.SomeBaseClass} When a contract's package matches the provided - * regular expression then extending class will be the one provided in the map - in - * this case {@code com.example.SomeBaseClass}. - */ - @Parameter(property = "baseClassMappings") - private List baseClassMappings; - - /** - * The user name to be used to connect to the repo with contracts. - */ - @Parameter(property = "contractsRepositoryUsername") - private String contractsRepositoryUsername; - - /** - * The password to be used to connect to the repo with contracts. - */ - @Parameter(property = "contractsRepositoryPassword") - private String contractsRepositoryPassword; - - /** - * The proxy host to be used to connect to the repo with contracts. - */ - @Parameter(property = "contractsRepositoryProxyHost") - private String contractsRepositoryProxyHost; - - /** - * The proxy port to be used to connect to the repo with contracts. - */ - @Parameter(property = "contractsRepositoryProxyPort") - private Integer contractsRepositoryProxyPort; - - /** - * If set to {@code false} will NOT delete stubs from a temporary folder after running - * tests. - */ - @Parameter(property = "deleteStubsAfterTest", defaultValue = "true") - private boolean deleteStubsAfterTest; - - /** - * Map of properties that can be passed to custom - * {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder}. - */ - @Parameter(property = "contractsProperties") - private Map contractsProperties = new HashMap<>(); - - /** - * When enabled, this flag will tell stub runner to throw an exception when no stubs / - * contracts were found. - */ - @Parameter(property = "failOnNoContracts", defaultValue = "true") - private boolean failOnNoContracts; - - /** - * If set to true then if any contracts that are in progress are found, will break the - * build. On the producer side you need to be explicit about the fact that you have - * contracts in progress and take into consideration that you might be causing false - * positive test execution results on the consumer side. - */ - @Parameter(property = "failOnInProgress", defaultValue = "true") - private boolean failOnInProgress = true; - - /** - * If set to true then tests are created only when contracts have changed since last - * build. - */ - @Parameter(property = "incrementalContractTests", defaultValue = "true") - private boolean incrementalContractTests = true; - - @Parameter(defaultValue = "${mojoExecution}", readonly = true, required = true) - private MojoExecution mojoExecution; - - @Parameter(defaultValue = "${session}", readonly = true, required = true) - private MavenSession session; - - @Override - public void execute() throws MojoExecutionException, MojoFailureException { - if (this.skip || this.mavenTestSkip) { - if (this.skip) { - getLog().info("Skipping Spring Cloud Contract Verifier execution: spring.cloud.contract.verifier.skip=" - + this.skip); - } - if (this.mavenTestSkip) { - getLog().info( - "Skipping Spring Cloud Contract Verifier execution: maven.test.skip=" + this.mavenTestSkip); - } - return; - } - getLog().info("Generating server tests source code for Spring Cloud Contract Verifier contract verification"); - final ContractVerifierConfigProperties config = new ContractVerifierConfigProperties(); - config.setFailOnInProgress(this.failOnInProgress); - // download contracts, unzip them and pass as output directory - File contractsDirectory = new MavenContractsDownloader(this.project, this.contractDependency, - this.contractsPath, this.contractsRepositoryUrl, this.contractsMode, getLog(), - this.contractsRepositoryUsername, this.contractsRepositoryPassword, this.contractsRepositoryProxyHost, - this.contractsRepositoryProxyPort, this.deleteStubsAfterTest, this.contractsProperties, - this.failOnNoContracts).downloadAndUnpackContractsIfRequired(config, this.contractsDirectory); - getLog().info("Directory with contract is present at [" + contractsDirectory + "]"); - throwExceptionWhenFailOnNoContracts(contractsDirectory, this.contractsRepositoryUrl); - - if (this.incrementalContractTests - && !ChangeDetector.inputFilesChangeDetected(contractsDirectory, mojoExecution, session)) { - getLog().info("Nothing to generate - all classes are up to date"); - return; - } - - setupConfig(config, contractsDirectory); - this.project.addTestCompileSourceRoot(this.generatedTestSourcesDir.getAbsolutePath()); - Resource resource = new Resource(); - resource.setDirectory(this.generatedTestResourcesDir.getAbsolutePath()); - this.project.addTestResource(resource); - if (getLog().isInfoEnabled()) { - getLog().info("Test Source directory: " + this.generatedTestSourcesDir.getAbsolutePath() + " added."); - getLog().info("Using [" + config.getBaseClassForTests() + "] as base class for test classes, [" - + config.getBasePackageForTests() + "] as base " + "package for tests, [" - + config.getPackageWithBaseClasses() + "] as package with " + "base classes, base class mappings " - + this.baseClassMappings); - } - try { - LeftOverPrevention leftOverPrevention = new LeftOverPrevention(this.generatedTestSourcesDir, mojoExecution, - session); - TestGenerator generator = new TestGenerator(config); - int generatedClasses = generator.generate(); - getLog().info("Generated " + generatedClasses + " test classes."); - leftOverPrevention.deleteLeftOvers(); - } - catch (ContractVerifierException e) { - throw new MojoExecutionException( - String.format("Spring Cloud Contract Verifier Plugin exception: %s", e.getMessage()), e); - } - } - - private void throwExceptionWhenFailOnNoContracts(File file, String contractsRepository) - throws MojoExecutionException { - if (StringUtils.hasText(contractsRepository)) { - if (getLog().isDebugEnabled()) { - getLog().debug( - "Contracts repository is set, will not throw an exception that the contracts are not found"); - } - return; - } - if (this.failOnNoContracts && (!file.exists() || file.listFiles().length == 0)) { - String path = file.getAbsolutePath(); - throw new MojoExecutionException("Contracts could not be found: [" + path - + "]\nPlease make sure that the contracts were defined, or set the [failOnNoContracts] property to [false]"); - } - } - - private void setupConfig(ContractVerifierConfigProperties config, File contractsDirectory) { - config.setContractsDslDir(contractsDirectory); - config.setGeneratedTestSourcesDir(this.generatedTestSourcesDir); - config.setGeneratedTestResourcesDir(this.generatedTestResourcesDir); - config.setTestFramework(this.testFramework); - config.setTestMode(this.testMode); - config.setBasePackageForTests(this.basePackageForTests); - config.setBaseClassForTests(this.baseClassForTests); - config.setRuleClassForTests(this.ruleClassForTests); - config.setNameSuffixForTests(this.nameSuffixForTests); - config.setImports(this.imports); - config.setStaticImports(this.staticImports); - config.setIgnoredFiles(this.ignoredFiles); - config.setExcludedFiles(this.excludedFiles); - config.setIncludedFiles(this.includedFiles); - config.setAssertJsonSize(this.assertJsonSize); - config.setPackageWithBaseClasses(this.packageWithBaseClasses); - if (this.baseClassMappings != null) { - config.setBaseClassMappings(mappingsToMap()); - } - } - - public Map mappingsToMap() { - Map map = new HashMap<>(); - if (this.baseClassMappings == null) { - return map; - } - for (BaseClassMapping mapping : this.baseClassMappings) { - map.put(mapping.getContractPackageRegex(), mapping.getBaseClassFQN()); - } - return map; - } - - public List getExcludedFiles() { - return this.excludedFiles; - } - - public void setExcludedFiles(List excludedFiles) { - this.excludedFiles = excludedFiles; - } - - public List getIgnoredFiles() { - return this.ignoredFiles; - } - - public void setIgnoredFiles(List ignoredFiles) { - this.ignoredFiles = ignoredFiles; - } - - public boolean isAssertJsonSize() { - return this.assertJsonSize; - } - - public void setAssertJsonSize(boolean assertJsonSize) { - this.assertJsonSize = assertJsonSize; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/LeftOverPrevention.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/LeftOverPrevention.java deleted file mode 100644 index 140183bc60..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/LeftOverPrevention.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.maven.verifier; - -import java.io.File; - -import org.apache.maven.execution.MavenSession; -import org.apache.maven.plugin.MojoExecution; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.shared.incremental.IncrementalBuildHelper; -import org.apache.maven.shared.incremental.IncrementalBuildHelperRequest; - -/** - * Prevents the following scenario: - * - * 1. Contract is added - * - * 2. Derived file is generated - * - * 3. Contract is deleted - * - * 4. Derived file still exists - */ -class LeftOverPrevention { - - private final IncrementalBuildHelper incrementalBuildHelper; - - private final File generatedDirectory; - - LeftOverPrevention(File generatedDirectory, MojoExecution mojoExecution, MavenSession session) - throws MojoExecutionException { - this.generatedDirectory = generatedDirectory; - this.incrementalBuildHelper = new IncrementalBuildHelper(mojoExecution, session); - this.incrementalBuildHelper - .beforeRebuildExecution(new IncrementalBuildHelperRequest().outputDirectory(generatedDirectory)); - } - - void deleteLeftOvers() throws MojoExecutionException { - if (generatedDirectory.exists()) { - incrementalBuildHelper - .afterRebuildExecution(new IncrementalBuildHelperRequest().outputDirectory(generatedDirectory)); - } - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/ManifestCreator.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/ManifestCreator.java deleted file mode 100644 index c70714e2d6..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/ManifestCreator.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.maven.verifier; - -import java.util.List; - -import org.apache.maven.model.Dependency; -import org.apache.maven.model.Plugin; -import org.apache.maven.project.MavenProject; -import org.codehaus.plexus.archiver.jar.Manifest; -import org.codehaus.plexus.archiver.jar.ManifestException; - -final class ManifestCreator { - - private ManifestCreator() { - throw new IllegalStateException("Can't instantiate a utility class"); - } - - public static Manifest createManifest(MavenProject project) throws ManifestException { - Manifest manifest = new Manifest(); - Plugin verifierMavenPlugin = findMavenPlugin(project.getBuildPlugins()); - if (verifierMavenPlugin != null) { - manifest.addConfiguredAttribute(new Manifest.Attribute("Spring-Cloud-Contract-Maven-Plugin-Version", - verifierMavenPlugin.getVersion())); - } - if (verifierMavenPlugin != null && !verifierMavenPlugin.getDependencies().isEmpty()) { - Dependency verifierDependency = findVerifierDependency(verifierMavenPlugin.getDependencies()); - if (verifierDependency != null) { - String verifierVersion = verifierDependency.getVersion(); - manifest.addConfiguredAttribute( - new Manifest.Attribute("Spring-Cloud-Contract-Verifier-Version", verifierVersion)); - } - } - return manifest; - } - - private static Plugin findMavenPlugin(List plugins) { - for (Plugin plugin : plugins) { - if ("spring-cloud-contract-maven-plugin".equals(plugin.getArtifactId())) { - return plugin; - } - } - return null; - } - - private static Dependency findVerifierDependency(List deps) { - for (Dependency dep : deps) { - if ("spring-cloud-contract-verifier".equals(dep.getArtifactId())) { - return dep; - } - } - return null; - } - -} 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 deleted file mode 100644 index e0eecb5626..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/MavenContractsDownloader.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.maven.verifier; - -import java.io.File; -import java.util.Map; - -import org.apache.maven.model.Dependency; -import org.apache.maven.plugin.logging.Log; -import org.apache.maven.project.MavenProject; - -import org.springframework.cloud.contract.stubrunner.ContractDownloader; -import org.springframework.cloud.contract.stubrunner.StubConfiguration; -import org.springframework.cloud.contract.stubrunner.StubDownloader; -import org.springframework.cloud.contract.stubrunner.StubDownloaderBuilderProvider; -import org.springframework.cloud.contract.stubrunner.StubRunnerOptions; -import org.springframework.cloud.contract.stubrunner.StubRunnerOptionsBuilder; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties; -import org.springframework.util.StringUtils; - -/** - * Downloads JAR with contracts. - * - * @author Marcin Grzejszczak - * @since 1.0.0 - */ -class MavenContractsDownloader { - - private static final String LATEST_VERSION = "+"; - - private static final String CONTRACTS_DIRECTORY_PROP = "CONTRACTS_DIRECTORY"; - - private final MavenProject project; - - private final Dependency contractDependency; - - private final String contractsPath; - - private final String contractsRepositoryUrl; - - private final StubRunnerProperties.StubsMode stubsMode; - - private final Log log; - - private final StubDownloaderBuilderProvider stubDownloaderBuilderProvider; - - private final String repositoryUsername; - - private final String repositoryPassword; - - private final String repositoryProxyHost; - - private final Integer repositoryProxyPort; - - private final boolean deleteStubsAfterTest; - - private final Map contractsProperties; - - private final boolean failOnNoStubs; - - MavenContractsDownloader(MavenProject project, Dependency contractDependency, String contractsPath, - String contractsRepositoryUrl, StubRunnerProperties.StubsMode stubsMode, Log log, String repositoryUsername, - String repositoryPassword, String repositoryProxyHost, Integer repositoryProxyPort, - boolean deleteStubsAfterTest, Map contractsProperties, boolean failOnNoContracts) { - this.project = project; - this.contractDependency = contractDependency; - this.contractsPath = contractsPath; - this.contractsRepositoryUrl = contractsRepositoryUrl; - this.stubsMode = stubsMode; - this.log = log; - this.repositoryUsername = repositoryUsername; - this.repositoryPassword = repositoryPassword; - this.repositoryProxyHost = repositoryProxyHost; - this.repositoryProxyPort = repositoryProxyPort; - this.stubDownloaderBuilderProvider = new StubDownloaderBuilderProvider(); - this.deleteStubsAfterTest = deleteStubsAfterTest; - this.contractsProperties = contractsProperties; - this.failOnNoStubs = failOnNoContracts; - } - - File downloadAndUnpackContractsIfRequired(ContractVerifierConfigProperties config, File defaultContractsDir) { - String contractsDirFromProp = this.project.getProperties().getProperty(directoryProperty()); - File downloadedContractsDir = StringUtils.hasText(contractsDirFromProp) ? new File(contractsDirFromProp) : null; - // reuse downloaded contracts from another mojo - if (downloadedContractsDir != null && downloadedContractsDir.exists()) { - this.log.info("Another mojo has downloaded the contracts - will reuse them from [" + downloadedContractsDir - + "]"); - final ContractDownloader.InclusionProperties inclusionProperties = contractDownloader() - .createNewInclusionProperties(downloadedContractsDir); - config.setIncludedContracts(inclusionProperties.getIncludedContracts()); - config.setIncludedRootFolderAntPattern(inclusionProperties.getIncludedRootFolderAntPattern()); - return downloadedContractsDir; - } - else if (shouldDownloadContracts()) { - this.log.info("Download dependency is provided - will retrieve contracts from a remote location"); - final ContractDownloader contractDownloader = contractDownloader(); - final File downloadedContracts = contractDownloader.unpackAndDownloadContracts(); - final ContractDownloader.InclusionProperties inclusionProperties = contractDownloader - .createNewInclusionProperties(downloadedContracts); - config.setIncludedContracts(inclusionProperties.getIncludedContracts()); - config.setIncludedRootFolderAntPattern(inclusionProperties.getIncludedRootFolderAntPattern()); - this.project.getProperties().setProperty(directoryProperty(), downloadedContracts.getAbsolutePath()); - return downloadedContracts; - } - this.log.info("Will use contracts provided in the folder [" + defaultContractsDir + "]"); - return defaultContractsDir; - } - - private String directoryProperty() { - if (this.contractDependency == null) { - return CONTRACTS_DIRECTORY_PROP; - } - return CONTRACTS_DIRECTORY_PROP + "_" + this.contractDependency.getGroupId() + ":" - + this.contractDependency.getArtifactId() + ":" + this.contractDependency.getVersion() + ":" - + this.contractDependency.getClassifier(); - } - - private boolean shouldDownloadContracts() { - return this.contractDependency != null && StringUtils.hasText(this.contractDependency.getArtifactId()) - || StringUtils.hasText(this.contractsRepositoryUrl); - } - - ContractDownloader contractDownloader() { - return new ContractDownloader(stubDownloader(), stubConfiguration(), this.contractsPath, - this.project.getGroupId(), this.project.getArtifactId(), this.project.getVersion()); - } - - private StubDownloader stubDownloader() { - StubRunnerOptions stubRunnerOptions = buildOptions(); - return this.stubDownloaderBuilderProvider.get(stubRunnerOptions); - } - - StubRunnerOptions buildOptions() { - StubRunnerOptionsBuilder builder = new StubRunnerOptionsBuilder() - .withOptions(StubRunnerOptions.fromSystemProps()).withStubsMode(this.stubsMode) - .withUsername(this.repositoryUsername).withPassword(this.repositoryPassword) - .withDeleteStubsAfterTest(this.deleteStubsAfterTest).withProperties(this.contractsProperties) - .withFailOnNoStubs(this.failOnNoStubs); - if (StringUtils.hasText(this.contractsRepositoryUrl)) { - builder.withStubRepositoryRoot(this.contractsRepositoryUrl); - } - if (this.repositoryProxyPort != null) { - builder.withProxy(this.repositoryProxyHost, this.repositoryProxyPort); - } - return builder.build(); - } - - private StubConfiguration stubConfiguration() { - String groupId = this.contractDependency.getGroupId(); - String artifactId = this.contractDependency.getArtifactId(); - String version = StringUtils.hasText(this.contractDependency.getVersion()) - ? this.contractDependency.getVersion() : LATEST_VERSION; - String classifier = this.contractDependency.getClassifier(); - return new StubConfiguration(groupId, artifactId, version, classifier); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/PushStubsToScmMojo.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/PushStubsToScmMojo.java deleted file mode 100644 index 95037a097b..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/PushStubsToScmMojo.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.maven.verifier; - -import java.io.File; -import java.util.HashMap; -import java.util.Map; - -import org.apache.maven.plugin.AbstractMojo; -import org.apache.maven.plugins.annotations.Mojo; -import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.project.MavenProject; - -import org.springframework.cloud.contract.stubrunner.ContractProjectUpdater; -import org.springframework.cloud.contract.stubrunner.ScmStubDownloaderBuilder; -import org.springframework.cloud.contract.stubrunner.StubRunnerOptions; -import org.springframework.cloud.contract.stubrunner.StubRunnerOptionsBuilder; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.util.StringUtils; - -/** - * The generated stubs get committed to the SCM repo and pushed to origin. - * - * @author Marcin Grzejszczak - */ -@Mojo(name = "pushStubsToScm") -public class PushStubsToScmMojo extends AbstractMojo { - - @Parameter(defaultValue = "${project.build.directory}", readonly = true, required = true) - private File projectBuildDirectory; - - @Parameter(property = "stubsDirectory", defaultValue = "${project.build.directory}/stubs") - private File outputDirectory; - - /** - * Set this to "true" to bypass the whole Verifier execution. - */ - @Parameter(property = "spring.cloud.contract.verifier.skip", defaultValue = "false") - private boolean skip; - - /** - * Set this to "true" to bypass only JAR creation. - */ - @Parameter(property = "spring.cloud.contract.verifier.publish-stubs-to-scm.skip", defaultValue = "false") - private boolean taskSkip; - - @Parameter(defaultValue = "${project}", readonly = true) - private MavenProject project; - - /** - * The user name to be used to connect to the repo with contracts. - */ - @Parameter(property = "contractsRepositoryUsername") - private String contractsRepositoryUsername; - - /** - * The password to be used to connect to the repo with contracts. - */ - @Parameter(property = "contractsRepositoryPassword") - private String contractsRepositoryPassword; - - /** - * The URL from which a contracts should get downloaded. If not provided but - * artifactid / coordinates notation was provided then the current Maven's build - * repositories will be taken into consideration. - */ - @Parameter(property = "contractsRepositoryUrl") - private String contractsRepositoryUrl; - - /** - * Picks the mode in which stubs will be found and registered. - */ - @Parameter(property = "contractsMode", defaultValue = "CLASSPATH") - private StubRunnerProperties.StubsMode contractsMode; - - /** - * If set to {@code false} will NOT delete stubs from a temporary folder after running - * tests. - */ - @Parameter(property = "deleteStubsAfterTest", defaultValue = "true") - private boolean deleteStubsAfterTest; - - /** - * Map of properties that can be passed to custom - * {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder}. - */ - @Parameter(property = "contractsProperties") - private Map contractsProperties = new HashMap<>(); - - @Override - public void execute() { - if (this.skip || this.taskSkip) { - getLog().info("Skipping Spring Cloud Contract Verifier execution: spring.cloud.contract.verifier.skip=" - + this.skip + ", spring.cloud.contract.verifier.publish-stubs-to-scm.skip=" + this.taskSkip); - return; - } - if (!StringUtils.hasText(this.contractsRepositoryUrl) - || !ScmStubDownloaderBuilder.isProtocolAccepted(this.contractsRepositoryUrl)) { - getLog().info("Skipping pushing stubs to scm since your " - + "[contractsRepositoryUrl] property doesn't match any of the accepted protocols"); - return; - } - String projectName = this.project.getGroupId() + ":" + this.project.getArtifactId() + ":" - + this.project.getVersion(); - getLog().info("Pushing Stubs to SCM for project [" + projectName + "]"); - new ContractProjectUpdater(buildOptions()).updateContractProject(projectName, this.outputDirectory.toPath()); - } - - StubRunnerOptions buildOptions() { - StubRunnerOptionsBuilder builder = new StubRunnerOptionsBuilder() - .withOptions(StubRunnerOptions.fromSystemProps()).withStubRepositoryRoot(this.contractsRepositoryUrl) - .withStubsMode(this.contractsMode).withUsername(this.contractsRepositoryUsername) - .withPassword(this.contractsRepositoryPassword).withDeleteStubsAfterTest(this.deleteStubsAfterTest) - .withProperties(this.contractsProperties); - return builder.build(); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/RunMojo.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/RunMojo.java deleted file mode 100644 index 879ff584af..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/RunMojo.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.maven.verifier; - -import java.io.File; -import java.io.IOException; -import java.util.Collections; - -import javax.inject.Inject; - -import org.apache.maven.execution.MavenSession; -import org.apache.maven.plugin.AbstractMojo; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.MojoFailureException; -import org.apache.maven.plugins.annotations.Mojo; -import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.plugins.annotations.ResolutionScope; -import org.eclipse.aether.RepositorySystemSession; - -import org.springframework.cloud.contract.maven.verifier.stubrunner.LocalStubRunner; -import org.springframework.cloud.contract.maven.verifier.stubrunner.RemoteStubRunner; -import org.springframework.cloud.contract.stubrunner.BatchStubRunner; -import org.springframework.cloud.contract.stubrunner.StubRunner; -import org.springframework.cloud.contract.stubrunner.StubRunnerOptions; -import org.springframework.cloud.contract.stubrunner.StubRunnerOptionsBuilder; -import org.springframework.util.StringUtils; - -/** - * Mojo for running stubs. - * - * @author Mariusz Smykula - * @author Eddú Meléndez - */ -@Mojo(name = "run", requiresProject = false, requiresDependencyResolution = ResolutionScope.RUNTIME) -public class RunMojo extends AbstractMojo { - - private final LocalStubRunner localStubRunner; - - private final RemoteStubRunner remoteStubRunner; - - @Parameter(defaultValue = "${repositorySystemSession}", readonly = true) - private RepositorySystemSession repoSession; - - @Parameter(defaultValue = ConvertMojo.DEFAULT_STUBS_DIR) - private File stubsDirectory; - - @Parameter(property = "stubsDirectory", defaultValue = "${basedir}") - private File destination; - - /** - * HTTP port for the WireMock server that serves stubs. - */ - @Parameter(property = "spring.cloud.contract.verifier.http.port", defaultValue = "8080") - private int httpPort; - - /** - * Set this to "true" to bypass verifier execution. - */ - @Parameter(property = "spring.cloud.contract.verifier.skip", defaultValue = "false") - private boolean skip; - - /** - * Set this to "true" to bypass verifier test generation. - */ - @Parameter(property = "spring.cloud.contract.verifier.skipTestOnly", defaultValue = "false") - private boolean skipTestOnly; - - /** - * List of stubs to be downloaded and ran in a colon separated Ivy notation. - */ - @Parameter(property = "spring.cloud.contract.verifier.stubs") - private String stubs; - - /** - * Minimal port at which the stub should start. - */ - @Parameter(property = "spring.cloud.contract.verifier.http.minPort", defaultValue = "10000") - private int minPort; - - /** - * Maximal port at which the stub should start. - */ - @Parameter(property = "spring.cloud.contract.verifier.http.maxPort", defaultValue = "15000") - private int maxPort; - - /** - * Should the plugin wait for the user to press the key after starting the stubs. - */ - @Parameter(property = "spring.cloud.contract.verifier.wait-for-key-pressed", defaultValue = "true") - private boolean waitForKeyPressed; - - /** - * Classifier used by stubs artifacts. - */ - @Parameter(defaultValue = "stubs") - private String stubsClassifier = "stubs"; - - @Parameter(defaultValue = "${session}", readonly = true) - private MavenSession mavenSession; - - /** - * - */ - @Parameter(property = "spring.cloud.contract.verifier.server-id") - private String serverId; - - @Inject - public RunMojo(LocalStubRunner localStubRunner, RemoteStubRunner remoteStubRunner) { - this.localStubRunner = localStubRunner; - this.remoteStubRunner = remoteStubRunner; - } - - @Override - public void execute() throws MojoExecutionException, MojoFailureException { - if (this.skip || this.skipTestOnly) { - getLog().info("Skipping verifier execution: spring.cloud.contract.verifier.skip=" + this.skip); - return; - } - BatchStubRunner batchStubRunner = null; - StubRunnerOptionsBuilder optionsBuilder = new StubRunnerOptionsBuilder() - .withStubsClassifier(this.stubsClassifier); - if (!StringUtils.hasText(this.stubs)) { - StubRunnerOptions options = optionsBuilder.withMinMaxPort(this.httpPort, this.httpPort).build(); - StubRunner stubRunner = this.localStubRunner.run(resolveStubsDirectory().getAbsolutePath(), options); - batchStubRunner = new BatchStubRunner(Collections.singleton(stubRunner)); - } - else { - StubRunnerOptions options = optionsBuilder.withStubs(this.stubs).withMinMaxPort(this.minPort, this.maxPort) - .withServerId(this.serverId).build(); - batchStubRunner = this.remoteStubRunner.run(options, this.repoSession); - } - pressAnyKeyToContinue(); - if (batchStubRunner != null) { - try { - batchStubRunner.close(); - } - catch (IOException e) { - throw new MojoExecutionException("Fail to close batch stub runner", e); - } - } - } - - private File resolveStubsDirectory() { - if (isInsideProject()) { - return this.stubsDirectory; - } - else { - return this.destination; - } - } - - private void pressAnyKeyToContinue() { - if (!this.waitForKeyPressed) { - return; - } - getLog().info("Press ENTER to continue..."); - try { - System.in.read(); - } - catch (Exception ignored) { - } - } - - private boolean isInsideProject() { - return this.mavenSession.getRequest().isProjectPresent(); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/stubrunner/AetherStubDownloaderFactory.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/stubrunner/AetherStubDownloaderFactory.java deleted file mode 100644 index b548b18372..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/stubrunner/AetherStubDownloaderFactory.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.maven.verifier.stubrunner; - -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.maven.project.MavenProject; -import org.eclipse.aether.RepositorySystem; -import org.eclipse.aether.RepositorySystemSession; -import shaded.org.apache.maven.settings.Settings; - -import org.springframework.cloud.contract.stubrunner.AetherStubDownloader; -import org.springframework.cloud.contract.stubrunner.StubDownloader; -import org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder; -import org.springframework.cloud.contract.stubrunner.StubRunnerOptions; -import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; - -/** - * Builds {@link StubDownloaderBuilder} for a Maven project. - * - * @author Mariusz Smykula - * @author Eddú Meléndez - */ -@Named -@Singleton -public class AetherStubDownloaderFactory { - - private static final Log log = LogFactory.getLog(AetherStubDownloaderFactory.class); - - private final MavenProject project; - - private final RepositorySystem repoSystem; - - private final Settings settings; - - @Inject - public AetherStubDownloaderFactory(RepositorySystem repoSystem, MavenProject project, Settings settings) { - this.repoSystem = repoSystem; - this.project = project; - this.settings = settings; - } - - public StubDownloaderBuilder build(final RepositorySystemSession repoSession) { - return new StubDownloaderBuilder() { - @Override - public StubDownloader build(StubRunnerOptions stubRunnerOptions) { - log.info("Will download contracts using current build's Maven repository setup"); - return new AetherStubDownloader(AetherStubDownloaderFactory.this.repoSystem, - AetherStubDownloaderFactory.this.project.getRemoteProjectRepositories(), repoSession, - AetherStubDownloaderFactory.this.settings); - } - - @Override - public Resource resolve(String location, ResourceLoader resourceLoader) { - return null; - } - }; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/stubrunner/LocalStubRunner.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/stubrunner/LocalStubRunner.java deleted file mode 100644 index fd09515534..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/stubrunner/LocalStubRunner.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.maven.verifier.stubrunner; - -import javax.inject.Named; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.stubrunner.StubConfiguration; -import org.springframework.cloud.contract.stubrunner.StubRunner; -import org.springframework.cloud.contract.stubrunner.StubRunnerOptions; - -/** - * Allows running stubs from the given directory. - * - * @author Mariusz Smykula - */ -@Named -public class LocalStubRunner { - - private static final Log log = LogFactory.getLog(LocalStubRunner.class); - - public StubRunner run(final String contractsDir, StubRunnerOptions options) { - log.info("Launching StubRunner with contracts from " + contractsDir); - StubRunner stubRunner = new StubRunner(options, contractsDir, new StubConfiguration(contractsDir)); - stubRunner.runStubs(); - return stubRunner; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/stubrunner/RemoteStubRunner.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/stubrunner/RemoteStubRunner.java deleted file mode 100644 index fbeedcd86b..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/stubrunner/RemoteStubRunner.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.maven.verifier.stubrunner; - -import javax.inject.Inject; -import javax.inject.Named; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.eclipse.aether.RepositorySystemSession; - -import org.springframework.cloud.contract.stubrunner.BatchStubRunner; -import org.springframework.cloud.contract.stubrunner.BatchStubRunnerFactory; -import org.springframework.cloud.contract.stubrunner.RunningStubs; -import org.springframework.cloud.contract.stubrunner.StubDownloader; -import org.springframework.cloud.contract.stubrunner.StubRunnerOptions; - -/** - * Fetches stubs from a remote location. - * - * @author Mariusz Smykula - */ -@Named -public class RemoteStubRunner { - - private static final Log log = LogFactory.getLog(RemoteStubRunner.class); - - private final AetherStubDownloaderFactory aetherStubDownloaderFactory; - - @Inject - public RemoteStubRunner(AetherStubDownloaderFactory aetherStubDownloaderFactory) { - this.aetherStubDownloaderFactory = aetherStubDownloaderFactory; - } - - public BatchStubRunner run(StubRunnerOptions options, RepositorySystemSession repositorySystemSession) { - StubDownloader stubDownloader = this.aetherStubDownloaderFactory.build(repositorySystemSession).build(options); - try { - if (log.isDebugEnabled()) { - log.debug("Launching StubRunner with args: " + options); - } - BatchStubRunner stubRunner = new BatchStubRunnerFactory(options, stubDownloader).buildBatchStubRunner(); - RunningStubs runningCollaborators = stubRunner.runStubs(); - log.info(runningCollaborators.toString()); - return stubRunner; - } - catch (Exception e) { - log.error("An exception occurred while trying to execute the stubs: " + e.getMessage()); - throw e; - } - - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml deleted file mode 100644 index bd46ddf1c2..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - convert - run - generateTests - generateStubs - pushStubsToScm - - - - - true - false - - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/resources/META-INF/plexus/components.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/resources/META-INF/plexus/components.xml deleted file mode 100644 index 99fdf6bfc9..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/resources/META-INF/plexus/components.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - org.apache.maven.lifecycle.Lifecycle - org.apache.maven.lifecycle.Lifecycle - spring-cloud-contract-verifier - - spring-cloud-contract-verifier - - spring-cloud-contract-verifier-not-used-phase - - - - org.springframework.cloud:spring-cloud-contract-maven-plugin:${project.version}:convert - - - org.springframework.cloud:spring-cloud-contract-maven-plugin:${project.version}:generateTests - - - org.springframework.cloud:spring-cloud-contract-maven-plugin:${project.version}:generateStubs - - - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/asciidoc/complex.adoc b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/asciidoc/complex.adoc deleted file mode 100644 index 354c94c672..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/asciidoc/complex.adoc +++ /dev/null @@ -1,45 +0,0 @@ -:root_folder: ../../.. - -== More Complex Plugin Configuration - -Sample more complex configuration for Java Project with JUnit tests. - - -=== Project configuration for Spring Cloud Contract Verifier with JUnit tests and stub publishing - -[source,xml] ----- -include::{root_folder}/src/test/projects/complex-configuration/pom.xml[tags=plugin] ----- - -=== Base Test class - -[source,java] ----- -include::{root_folder}/src/test/projects/complex-configuration/src/test/java/com/blogspot/toomuchcoding/frauddetection/BaseAccurest.java[] ----- - - -=== Sample additional matcher - -[source,java] ----- -include::{root_folder}/src/test/projects/complex-configuration/src/test/java/com/blogspot/toomuchcoding/frauddetection/matchers/CustomMatchers.java[] ----- - -=== Sample contract using matcher - -[source,java] ----- -include::{root_folder}/src/test/projects/complex-configuration/src/test/contracts/shouldMarkClientAsNotFraud.groovy[] ----- - - -=== Project source code - -https://github.com/spring-cloud/spring-cloud-contract/tree/main/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration - -=== More samples - -You can check out the https://github.com/spring-cloud-samples/spring-cloud-contract-samples[Spring Cloud Contract Samples project] for -more examples of Maven plugin setup. \ No newline at end of file diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/asciidoc/configs.adoc b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/asciidoc/configs.adoc deleted file mode 100644 index f1c3dc2e50..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/asciidoc/configs.adoc +++ /dev/null @@ -1,45 +0,0 @@ -== Configuration snippets - -Here you'll be able to see different Spring Cloud Contract Maven plugin configuration - -=== Base class from mappings - -Define regular expression mappings to map a contract to its base class. - -[source,xml] ----- -include::../../../src/test/projects/basic-baseclass-from-mappings/pom.xml[tags=mapping] ----- - -=== Convention based mappings - -Define a package in which base classes are placed. In this case we define -a package called `hello`. If there's a contract under /contracts/hello/V1/Contract.groovy` then -we'll search for a `HelloV1Base` base class. We're taking two last folders -from the path and combine them into a class name. - -[source,xml] ----- -include::../../../src/test/projects/basic-generated-baseclass/pom.xml[tags=convention] ----- - -=== Remote contracts - -Here you can see a setup where we point to a repository where the JAR with the -contracts got deployed. - -[source,xml] ----- -include::../../../src/test/projects/basic-remote-contracts/pom-with-repo.xml[tags=remote_config] ----- - -=== Setting up repo with common contracts - -A setup of a repo that contains all common contracts. It can exclude the target / build -folder that gets created when you're installing stubs locally as a consumer. - -[source,xml] ----- -include::../../../src/test/projects/common-repo/pom.xml[tags=common_repo] ----- - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/asciidoc/index.adoc b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/asciidoc/index.adoc deleted file mode 100644 index 9746951136..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/asciidoc/index.adoc +++ /dev/null @@ -1,24 +0,0 @@ -:samples_branch: 2.2.x - -= Spring Cloud Contract Maven Plugin - -Just to make long story short - Spring Cloud Contract Verifier is a tool that enables Consumer Driven Contract (CDC) development of JVM-based applications. - - * Stubs mappings to be used by WireMock when doing integration testing on the client code (client tests). - - * Acceptance tests used to verify if server-side implementation of the API is compliant with the contract (server tests). - -Spring Cloud Contract Verifier moves TDD to the level of software architecture. - -This plugin allows you to: - -- generate tests from the provided contracts -- run the stubs from the stubs - -== Samples - -You can check out the https://github.com/spring-cloud-samples/spring-cloud-contract-samples[Spring Cloud Contract Samples project] for -examples of Maven plugin setup. - -- https://github.com/spring-cloud-samples/spring-cloud-contract-samples/blob/{samples_branch}/producer/pom.xml[Producer application with a test dependency added to the plugin] -- https://github.com/spring-cloud-samples/spring-cloud-contract-samples/blob/{samples_branch}/producer/pom.xml[Producer application referencing a repo with contracts and regular expression based base class mapping] diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/asciidoc/junit.adoc b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/asciidoc/junit.adoc deleted file mode 100644 index e14de9bdce..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/asciidoc/junit.adoc +++ /dev/null @@ -1,31 +0,0 @@ -:branch: main - -== Java Project with JUnit Tests - -Sample minimal configuration for Java Project with JUnit tests. - -=== Test dependencies for generated contract verification tests - -[source,xml] ----- -include::../../../src/test/projects/spring-boot-java/pom.xml[tags=dependencies] ----- - -=== Project configuration for Spring Cloud Contract Verifier with JUnit tests and stub publishing - -[source,xml] ----- -include::../../../src/test/projects/spring-boot-java/pom.xml[tags=plugin] ----- - -=== Base Test class - -[source,java] ----- -include::../../../src/test/projects/spring-boot-java/src/test/java/hello/BaseAccurest.java[] ----- - - -=== Project source code - -https://github.com/spring-cloud/spring-cloud-contract/tree/{github-tag}/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java \ No newline at end of file diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/asciidoc/spock.adoc b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/asciidoc/spock.adoc deleted file mode 100644 index 421d468789..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/asciidoc/spock.adoc +++ /dev/null @@ -1,31 +0,0 @@ -:branch: main - -== Groovy Project with Spock Specifications - -Sample minimal configuration for Groovy Project with Spock Specification - -=== Test dependencies for generated contract verification tests - -[source,xml] ----- -include::../../../src/test/projects/spring-boot-groovy/pom.xml[tags=dependencies] ----- - -=== Project configuration for Spring Cloud Contract Verifier, Groovy, Spock specifications and stub publishing - - -[source,xml] ----- -include::../../../src/test/projects/spring-boot-groovy/pom.xml[tags=plugin] ----- - -=== Base Specification class - -[source,java] ----- -include::../../../src/test/projects/spring-boot-groovy/src/test/groovy/hello/BaseAccurest.groovy[] ----- - -=== Project source code - -https://github.com/spring-cloud/spring-cloud-contract/tree/{github-tag}/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/asciidoc/usage.adoc b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/asciidoc/usage.adoc deleted file mode 100644 index dba83a6cde..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/asciidoc/usage.adoc +++ /dev/null @@ -1,38 +0,0 @@ -= Usage - -== Converting Spring Cloud Contract DSL into WireMock stub mappings - - mvn org.springframework.cloud:spring-cloud-contract-maven-plugin:convert - -or shortly footnoteref:[prefix,Additional configuration inside `~/.m2/settings.xml` is required: `org.springframework.cloud`.] - - mvn spring-cloud-contract:convert - -For more information please go to the Spring Cloud Contract Wiki or Plugin Documentation Site. - -== Spring Cloud Contract Stub Runner - -Run stubs mappings from current directory: - - mvn org.springframework.cloud:spring-cloud-contract-maven-plugin:run - -or shortly footnoteref:[prefix] - - mvn spring-cloud-contract:run - -== Running stubs from repository - - mvn spring-cloud-contract:run -Dstubs="org.springframework:gs-rest-service" - -where `org.springframework:gs-rest-service` is artifact with stubs classifier contains WireMock mappings. - -In order for the goal to be executed correctly, `target/stubs` subdirectory should be added in the directory from which -the command will be executed. - -== Project configuration - -[source,xml] ----- -include::../../../src/test/projects/spring-boot-java/pom.xml[tags=plugin] ----- - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/site.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/site.xml deleted file mode 100644 index e4c2527ce2..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/site/site.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - ${project.name} - - - - - - org.apache.maven.skins - maven-fluido-skin - 1.5 - - - - true - true - - spring-cloud/spring-cloud-contract - right - orange - - » - - - - -

- - - - - - - - - - - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/maven/verifier/AbstractMojoTest.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/maven/verifier/AbstractMojoTest.java deleted file mode 100644 index 964f2802e8..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/maven/verifier/AbstractMojoTest.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.maven.verifier; - -import java.io.File; -import java.io.IOException; - -import org.apache.maven.execution.MavenSession; -import org.apache.maven.plugin.testing.MojoRule; -import org.apache.maven.project.MavenProject; -import org.assertj.core.api.BDDAssertions; -import org.codehaus.plexus.util.xml.Xpp3Dom; -import org.junit.Before; -import org.junit.Rule; -import org.junit.rules.TemporaryFolder; - -import org.springframework.boot.test.system.OutputCaptureRule; -import org.springframework.util.FileSystemUtils; - -public abstract class AbstractMojoTest { - - @Rule - public MojoRule rule = new MojoRule() { - @Override - protected void before() throws Throwable { - } - - @Override - protected void after() { - } - }; - - @Rule - public TemporaryFolder tmp = new TemporaryFolder(); - - @Rule - public OutputCaptureRule capture = new OutputCaptureRule(); - - File tmpFolder; - - @Before - public void setupTemp() throws IOException { - this.tmpFolder = this.tmp.newFolder(); - File projects = new File("src/test/projects"); - FileSystemUtils.copyRecursively(projects, this.tmpFolder); - } - - protected File getBasedir(String name) { - return new File(this.tmpFolder, name); - } - - protected MavenSession prepareMavenSession(File baseDir) throws Exception { - MavenProject mavenProject = rule.readMavenProject(baseDir); - return rule.newMavenSession(mavenProject); - } - - protected void executeMojo(File baseDir, String goal, Xpp3Dom... parameters) throws Exception { - MavenSession mavenSession = prepareMavenSession(baseDir); - executeMojo(mavenSession, goal, parameters); - } - - protected void executeMojo(MavenSession mavenSession, String goal, Xpp3Dom... parameters) throws Exception { - rule.executeMojo(mavenSession, mavenSession.getCurrentProject(), goal, parameters); - } - - protected void assertFilesPresent(File file, String name) { - BDDAssertions.then(new File(file, name)).exists(); - } - - protected void assertFilesNotPresent(File file, String name) { - BDDAssertions.then(new File(file, name)).doesNotExist(); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/maven/verifier/ChangeDetectorTests.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/maven/verifier/ChangeDetectorTests.java deleted file mode 100644 index 7ba05966a9..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/maven/verifier/ChangeDetectorTests.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.maven.verifier; - -import java.io.File; -import java.util.Arrays; - -import org.apache.maven.execution.MavenSession; -import org.apache.maven.plugin.MojoExecutionException; -import org.junit.jupiter.api.Test; -import org.mockito.BDDMockito; - -import static org.assertj.core.api.BDDAssertions.then; -import static org.mockito.BDDMockito.given; - -class ChangeDetectorTests { - - @Test - void should_mark_that_input_files_have_changed_when_goal_clean_was_called() throws MojoExecutionException { - MavenSession session = BDDMockito.mock(MavenSession.class); - given(session.getGoals()).willReturn(Arrays.asList("clean", "install")); - - then(ChangeDetector.inputFilesChangeDetected(new File("."), null, session)).isTrue(); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/maven/verifier/MavenContractsDownloaderTests.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/maven/verifier/MavenContractsDownloaderTests.java deleted file mode 100644 index 6159455f97..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/maven/verifier/MavenContractsDownloaderTests.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.maven.verifier; - -import java.io.File; -import java.util.HashMap; - -import org.apache.maven.model.Dependency; -import org.apache.maven.plugin.testing.SilentLog; -import org.apache.maven.project.MavenProject; -import org.assertj.core.api.BDDAssertions; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -import org.springframework.cloud.contract.stubrunner.ContractDownloader; -import org.springframework.cloud.contract.stubrunner.InclusionPropertiesAccessor; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties; - -class MavenContractsDownloaderTests { - - @TempDir - File defaultFolder; - - @TempDir - File fileForDependencyOne; - - @TempDir - File fileForDependencyTwo; - - @Test - void shouldNotReadFolderFromCacheWhenExecutedTwiceFor2DifferentArtifactsInTheSameProject() { - MavenProject mavenProject = new MavenProject(); - - Dependency one = dependency(1); - MavenContractsDownloader mavenContractsDownloader = contractsDownloader(mavenProject, one, - this.fileForDependencyOne); - File dependencyOneFile = mavenContractsDownloader - .downloadAndUnpackContractsIfRequired(new ContractVerifierConfigProperties(), this.defaultFolder); - BDDAssertions.then(dependencyOneFile).as("Location for dependency 1 should be computed since it's not cached") - .isEqualTo(this.fileForDependencyOne); - - mavenContractsDownloader = contractsDownloader(mavenProject, one, this.fileForDependencyOne); - File fileForDependencyOneAgain = mavenContractsDownloader - .downloadAndUnpackContractsIfRequired(new ContractVerifierConfigProperties(), this.defaultFolder); - BDDAssertions.then(dependencyOneFile).as("Location for dependency 1 should be taken from cache") - .isEqualTo(fileForDependencyOneAgain); - - Dependency two = dependency(2); - mavenContractsDownloader = contractsDownloader(mavenProject, two, this.fileForDependencyTwo); - File dependencyTwoFile = mavenContractsDownloader - .downloadAndUnpackContractsIfRequired(new ContractVerifierConfigProperties(), this.defaultFolder); - - BDDAssertions.then(dependencyTwoFile).as("Location for dependency 2 should be computed again") - .isNotEqualTo(dependencyOneFile).isEqualTo(this.fileForDependencyTwo); - } - - private MavenContractsDownloader contractsDownloader(MavenProject mavenProject, Dependency one, File file) { - return new MavenContractsDownloader(mavenProject, one, "", "", StubRunnerProperties.StubsMode.LOCAL, - new SilentLog(), "", "", "", null, false, new HashMap<>(), false) { - @Override - ContractDownloader contractDownloader() { - return new ContractDownloader(null, null, null, null, null, null) { - - int counterForDependencyOne; - - @Override - public File unpackAndDownloadContracts() { - if (file == fileForDependencyOne) { - this.counterForDependencyOne = this.counterForDependencyOne + 1; - } - if (file == fileForDependencyOne && this.counterForDependencyOne == 2) { - throw new AssertionError("Second call for dependency 1 should come from cache"); - } - return file; - } - - @Override - public InclusionProperties createNewInclusionProperties(File contractsDirectory) { - return new InclusionPropertiesAccessor("a", "b"); - } - }; - } - }; - } - - private Dependency dependency(int number) { - Dependency dependency = new Dependency(); - dependency.setGroupId("a" + number); - dependency.setArtifactId("b" + number); - dependency.setVersion("c" + number); - dependency.setClassifier("d" + number); - return dependency; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/maven/verifier/PluginUnitTest.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/maven/verifier/PluginUnitTest.java deleted file mode 100644 index 171197af0b..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/maven/verifier/PluginUnitTest.java +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.maven.verifier; - -import java.io.File; - -import org.apache.maven.artifact.Artifact; -import org.apache.maven.artifact.DefaultArtifact; -import org.apache.maven.execution.MavenSession; -import org.apache.maven.project.MavenProject; -import org.codehaus.plexus.util.xml.Xpp3Dom; -import org.junit.Test; - -import static java.nio.charset.Charset.defaultCharset; -import static org.apache.commons.io.FileUtils.readFileToString; -import static org.apache.maven.plugin.testing.MojoParameters.newParameter; -import static org.assertj.core.api.BDDAssertions.then; - -public class PluginUnitTest extends AbstractMojoTest { - - @Test - public void shouldGenerateWireMockStubsInDefaultLocation() throws Exception { - File basedir = getBasedir("basic"); - executeMojo(basedir, "convert"); - assertFilesPresent(basedir, - "target/stubs/META-INF/org.springframework.cloud.verifier.sample/sample-project/0.1/mappings/Sample.json" - .replace("/", File.separator)); - assertFilesNotPresent(basedir, - "target/stubs/META-INF/org.springframework.cloud.verifier.sample/sample-project/0.1/mappings/Messaging.json" - .replace("/", File.separator)); - } - - private Xpp3Dom defaultPackageForTests() { - return newParameter("basePackageForTests", "org.springframework.cloud.contract.verifier.tests"); - } - - @Test - public void shouldGenerateWireMockFromStubsDirectory() throws Exception { - File basedir = getBasedir("withStubs"); - executeMojo(basedir, "convert", newParameter("contractsDirectory", "src/test/resources/stubs")); - assertFilesPresent(basedir, - "target/stubs/META-INF/org.springframework.cloud.verifier.sample/sample-project/0.1/mappings/Sample.json" - .replace("/", File.separator)); - } - - @Test - public void shouldCopyContracts() throws Exception { - File basedir = getBasedir("basic"); - executeMojo(basedir, "convert"); - assertFilesPresent(basedir, - "target/stubs/META-INF/org.springframework.cloud.verifier.sample/sample-project/0.1/contracts/Sample.groovy" - .replace("/", File.separator)); - assertFilesPresent(basedir, - "target/stubs/META-INF/org.springframework.cloud.verifier.sample/sample-project/0.1/contracts/Messaging.groovy" - .replace("/", File.separator)); - } - - @Test - public void shouldGenerateWireMockStubsInSelectedLocation() throws Exception { - File basedir = getBasedir("basic"); - executeMojo(basedir, "convert", newParameter("stubsDirectory", "target/foo")); - assertFilesPresent(basedir, - "target/foo/META-INF/org.springframework.cloud.verifier.sample/sample-project/0.1/mappings/Sample.json"); - } - - @Test - public void shouldGenerateContractSpecificationInDefaultLocation() throws Exception { - File basedir = getBasedir("basic"); - executeMojo(basedir, "generateTests", defaultPackageForTests(), newParameter("testFramework", "SPOCK")); - String path = "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/ContractVerifierSpec.groovy"; - assertFilesPresent(basedir, path); - File test = new File(basedir, path); - then(readFileToString(test, defaultCharset())).contains("spock.lang.Ignore"); - } - - @Test - public void shouldGenerateContractTestsInDefaultLocation() throws Exception { - File basedir = getBasedir("basic"); - executeMojo(basedir, "generateTests", defaultPackageForTests()); - assertFilesPresent(basedir, - "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/ContractVerifierTest.java"); - } - - @Test - public void shouldGenerateContractTestsWithCustomImports() throws Exception { - File basedir = getBasedir("basic"); - executeMojo(basedir, "generateTests", defaultPackageForTests(), newParameter("imports", "")); - assertFilesPresent(basedir, - "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/ContractVerifierTest.java"); - } - - @Test - public void shouldGenerateContractTestsWithoutArraySize() throws Exception { - File basedir = getBasedir("basic"); - executeMojo(basedir, "generateTests", defaultPackageForTests()); - assertFilesPresent(basedir, - "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/ContractVerifierTest.java"); - File test = new File(basedir, - "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/ContractVerifierTest.java"); - then(readFileToString(test, defaultCharset())).doesNotContain("hasSize(4)"); - } - - @Test - public void shouldGenerateContractTestsWithArraySize() throws Exception { - File basedir = getBasedir("basic"); - executeMojo(basedir, "generateTests", defaultPackageForTests(), newParameter("assertJsonSize", "true")); - assertFilesPresent(basedir, - "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/ContractVerifierTest.java"); - File test = new File(basedir, - "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/ContractVerifierTest.java"); - then(readFileToString(test, defaultCharset())).contains("hasSize(4)"); - } - - @Test - public void shouldGenerateStubs() throws Exception { - File basedir = getBasedir("generatedStubs"); - executeMojo(basedir, "generateStubs"); - assertFilesPresent(basedir, "target/sample-project-stubs.jar"); - } - - @Test - public void shouldGenerateStubsWithMappingsOnly() throws Exception { - File basedir = getBasedir("generatedStubs"); - executeMojo(basedir, "generateStubs"); - assertFilesPresent(basedir, "target/sample-project-stubs.jar"); - // FIXME: add assertion for jar content - } - - @Test - public void shouldGenerateStubsWithCustomClassifier() throws Exception { - File basedir = getBasedir("generatedStubs"); - executeMojo(basedir, "generateStubs", newParameter("classifier", "foo")); - assertFilesPresent(basedir, "target/sample-project-foo.jar"); - } - - @Test - public void shouldGenerateStubsByDownloadingContractsFromARepo() throws Exception { - File basedir = getBasedir("basic-remote-contracts"); - executeMojo(basedir, "convert", newParameter("contractsRepositoryUrl", "file://" + PluginUnitTest.class - .getClassLoader().getResource("m2repo/repository").getFile().replace("/", File.separator))); - assertFilesPresent(basedir, - "target/stubs/META-INF/com.example/server/0.1.BUILD-SNAPSHOT/mappings/com/example/server/client1/contracts/shouldMarkClientAsFraud.json"); - } - - @Test - public void shouldGenerateStubsByDownloadingContractsFromARepoWhenCustomPathIsProvided() throws Exception { - File basedir = getBasedir("complex-remote-contracts"); - executeMojo(basedir, "convert", newParameter("contractsRepositoryUrl", "file://" + PluginUnitTest.class - .getClassLoader().getResource("m2repo/repository").getFile().replace("/", File.separator))); - assertFilesPresent(basedir, - "target/stubs/META-INF/com.example.foo.bar.baz/someartifact/0.1.BUILD-SNAPSHOT/mappings/com/example/server/client1/contracts/shouldMarkClientAsFraud.json"); - assertFilesNotPresent(basedir, - "target/stubs/META-INF/com.example.foo.bar.baz/someartifact/0.1.BUILD-SNAPSHOT/mappings/com/foo/bar/baz/shouldBeIgnoredByPlugin.json"); - assertFilesNotPresent(basedir, - "target/stubs/META-INF/com.example.foo.bar.baz/someartifact/0.1.BUILD-SNAPSHOT/contracts/com/foo/bar/baz/shouldBeIgnoredByPlugin.groovy"); - } - - @Test - public void shouldGenerateOutputWhenCalledConvertFromRootProject() throws Exception { - File basedir = getBasedir("different-module-configuration"); - executeMojo(basedir, "convert"); - assertFilesPresent(basedir, - "target/stubs/META-INF/com.blogspot.toomuchcoding.frauddetection/frauddetection-parent/0.1.0/mappings/shouldMarkClientAsFraud.json"); - } - - @Test - public void shouldGenerateOutputWhenCalledGenerateTestsFromRootProject() throws Exception { - File basedir = getBasedir("different-module-configuration"); - executeMojo(basedir, "generateTests", defaultPackageForTests()); - assertFilesPresent(basedir, - "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/ContractVerifierTest.java"); - } - - @Test - public void shouldGenerateTestsByDownloadingContractsFromARepo() throws Exception { - File basedir = getBasedir("basic-remote-contracts"); - executeMojo(basedir, "generateTests", defaultPackageForTests(), - newParameter("contractsRepositoryUrl", "file://" + PluginUnitTest.class.getClassLoader() - .getResource("m2repo/repository").getFile().replace("/", File.separator))); - assertFilesPresent(basedir, - "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/com/example/server/client1/ContractsTest.java"); - } - - @Test - public void shouldGenerateTestsByDownloadingContractsFromARepoWhenCustomPathIsProvided() throws Exception { - File basedir = getBasedir("complex-remote-contracts"); - executeMojo(basedir, "generateTests", defaultPackageForTests(), - newParameter("contractsRepositoryUrl", "file://" + PluginUnitTest.class.getClassLoader() - .getResource("m2repo/repository").getFile().replace("/", File.separator))); - assertFilesPresent(basedir, - "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/com/example/server/client1/ContractsTest.java"); - assertFilesNotPresent(basedir, - "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/com/foo/bar/BazTest.java"); - assertFilesNotPresent(basedir, "target/stubs/contracts/com/foo/bar/baz/shouldBeIgnoredByPlugin.groovy"); - } - - @Test - public void shouldGenerateContractTestsWithBaseClassResolvedFromConvention() throws Exception { - File basedir = getBasedir("basic-generated-baseclass"); - - executeMojo(basedir, "generateTests", defaultPackageForTests(), newParameter("testFramework", "JUNIT")); - - String path = "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/hello/V1Test.java"; - assertFilesPresent(basedir, path); - File test = new File(basedir, path); - then(readFileToString(test, defaultCharset())).contains("extends HelloV1Base") - .contains("import hello.HelloV1Base"); - } - - @Test - public void shouldGenerateContractTestsWithBaseClassResolvedFromConventionForSpock() throws Exception { - File basedir = getBasedir("basic-generated-baseclass"); - - executeMojo(basedir, "generateTests", defaultPackageForTests(), newParameter("testFramework", "SPOCK")); - - String path = "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/hello/V1Spec.groovy"; - assertFilesPresent(basedir, path); - File test = new File(basedir, path); - then(readFileToString(test, defaultCharset())).contains("extends HelloV1Base") - .contains("import hello.HelloV1Base"); - } - - @Test - public void shouldGenerateContractTestsWithBaseClassResolvedFromMapping() throws Exception { - File basedir = getBasedir("basic-baseclass-from-mappings"); - - executeMojo(basedir, "generateTests", defaultPackageForTests(), newParameter("testFramework", "JUNIT")); - - String path = "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/com/hello/V1Test.java"; - assertFilesPresent(basedir, path); - File test = new File(basedir, path); - then(readFileToString(test, defaultCharset())).contains("extends TestBase") - .contains("import com.example.TestBase"); - } - - @Test - public void shouldGenerateContractTestsWithBaseClassResolvedFromMappingNameForSpock() throws Exception { - File basedir = getBasedir("basic-baseclass-from-mappings"); - - executeMojo(basedir, "generateTests", defaultPackageForTests(), newParameter("testFramework", "SPOCK")); - - String path = "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/com/hello/V1Spec.groovy"; - assertFilesPresent(basedir, path); - File test = new File(basedir, path); - then(readFileToString(test, defaultCharset())).contains("extends TestBase") - .contains("import com.example.TestBase"); - } - - @Test - public void shouldGenerateContractTestsWithAFileContainingAListOfContracts() throws Exception { - File basedir = getBasedir("multiple-contracts"); - - executeMojo(basedir, "generateTests", defaultPackageForTests(), newParameter("testFramework", "JUNIT")); - - String path = "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/com/hello/V1Test.java"; - assertFilesPresent(basedir, path); - File test = new File(basedir, path); - then(readFileToString(test, defaultCharset())) - .contains("public void validate_should_post_a_user() throws Exception {") - .contains("public void validate_withList_1() throws Exception {"); - } - - @Test - public void shouldGenerateStubsWithAFileContainingAListOfContracts() throws Exception { - File basedir = getBasedir("multiple-contracts"); - - executeMojo(basedir, "convert", newParameter("stubsDirectory", "target/foo")); - - String firstFile = "target/foo/META-INF/org.springframework.cloud.verifier.sample/sample-project/0.1/mappings/com/hello/v1/should post a user.json"; - File test = new File(basedir, firstFile); - assertFilesPresent(basedir, - "target/foo/META-INF/org.springframework.cloud.verifier.sample/sample-project/0.1/mappings/com/hello/v1/WithList_1.json"); - then(readFileToString(test, defaultCharset())).contains("/users/1"); - String secondFile = "target/foo/META-INF/org.springframework.cloud.verifier.sample/sample-project/0.1/mappings/com/hello/v1/WithList_1.json"; - File test2 = new File(basedir, secondFile); - assertFilesPresent(basedir, - "target/foo/META-INF/org.springframework.cloud.verifier.sample/sample-project/0.1/mappings/com/hello/v1/should post a user.json"); - then(readFileToString(test2, defaultCharset())).contains("/users/2"); - } - - @Test - public void shouldGenerateStubsForCommonRepoWithTargetFolder() throws Exception { - File basedir = getBasedir("common-repo"); - - executeMojo(basedir, "convert"); - - assertFilesNotPresent(basedir, "target/generated-test-sources/contracts/"); - // there will be no stubs cause all files are copied to `target` folder - assertFilesPresent(basedir, - "target/stubs/META-INF/org.springframework.cloud.verifier.sample/common-repo/0.1/mappings/consumer1"); - assertFilesPresent(basedir, - "target/stubs/META-INF/org.springframework.cloud.verifier.sample/common-repo/0.1/contracts/consumer1/Messaging.groovy"); - assertFilesPresent(basedir, - "target/stubs/META-INF/org.springframework.cloud.verifier.sample/common-repo/0.1/contracts/pom.xml"); - } - - @Test - public void shouldRunPushStubsToScm() throws Exception { - File basedir = getBasedir("git-basic-remote-contracts"); - - executeMojo(basedir, "pushStubsToScm"); - - then(this.capture.toString()).contains("Skipping pushing stubs to scm since your"); - } - - @Test - public void shouldGenerateContractTestsForIncludedFilesPattern() throws Exception { - File basedir = getBasedir("complex-common-repo-with-messaging"); - - executeMojo(basedir, "generateTests", defaultPackageForTests(), - newParameter("contractsRepositoryUrl", "file://" + PluginUnitTest.class.getClassLoader() - .getResource("m2repo/repository").getFile().replace("/", File.separator))); - assertFilesPresent(basedir, - "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/common_repo_with_inclusion/kafka_topics/coupon_sent/src/main/resources/contracts/rule_engine_daemon/MessagingTest.java"); - assertFilesPresent(basedir, - "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/common_repo_with_inclusion/reward_rules/src/main/resources/contracts/reward_rules/rest/admin/V1Test.java"); - } - - @Test - public void shouldAttachUpToDateStubs() throws Exception { - File basedir = getBasedir("generatedStubs"); - - MavenSession firstSession = prepareMavenSession(basedir); - MavenProject firstProject = firstSession.getCurrentProject(); - Artifact stubArtifact = new DefaultArtifact(firstProject.getGroupId(), firstProject.getArtifactId(), - firstProject.getVersion(), "", "jar", "stubs", firstProject.getArtifact().getArtifactHandler()); - - executeMojo(firstSession, "generateStubs"); - then(firstSession.getCurrentProject().getAttachedArtifacts()).contains(stubArtifact); - - MavenSession secondSession = prepareMavenSession(basedir); - executeMojo(secondSession, "generateStubs"); - then(secondSession.getCurrentProject().getAttachedArtifacts()).contains(stubArtifact); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/stubrunner/InclusionPropertiesAccessor.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/stubrunner/InclusionPropertiesAccessor.java deleted file mode 100644 index f6408f9424..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/java/org/springframework/cloud/contract/stubrunner/InclusionPropertiesAccessor.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -public class InclusionPropertiesAccessor extends ContractDownloader.InclusionProperties { - - public InclusionPropertiesAccessor(String includedContracts, String includedRootFolderAntPattern) { - super(includedContracts, includedRootFolderAntPattern); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-baseclass-from-mappings/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-baseclass-from-mappings/pom.xml deleted file mode 100644 index 1d13c6b642..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-baseclass-from-mappings/pom.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - 4.0.0 - - org.springframework.cloud.verifier.sample - sample-project - 0.1 - - - - - - org.springframework.cloud - spring-cloud-contract-maven-plugin - - com.example.FooBase - - - .*com.* - com.example.TestBase - - - - - - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-baseclass-from-mappings/src/test/resources/contracts/com/hello/v1/Messaging.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-baseclass-from-mappings/src/test/resources/contracts/com/hello/v1/Messaging.groovy deleted file mode 100644 index dbbfb72a06..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-baseclass-from-mappings/src/test/resources/contracts/com/hello/v1/Messaging.groovy +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - label 'some_label' - input { - triggeredBy("hashCode()") - } - outputMessage { - sentTo('jms:output') - body([ - bookName: 'foo' - ]) - headers { - header('BOOK-NAME', 'foo') - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-baseclass-from-mappings/src/test/resources/contracts/com/hello/v1/Sample.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-baseclass-from-mappings/src/test/resources/contracts/com/hello/v1/Sample.groovy deleted file mode 100644 index b1c68007a9..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-baseclass-from-mappings/src/test/resources/contracts/com/hello/v1/Sample.groovy +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - request { - method 'POST' - url('/users') { - - } - headers { - header 'Content-Type': 'application/json' - } - body '''{ "login" : "john", "name": "John The Contract" }''' - } - response { - status OK() - headers { - header 'Location': '/users/john' - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-baseclass-from-mappings/src/test/resources/contracts/com/hello/v1/WithList.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-baseclass-from-mappings/src/test/resources/contracts/com/hello/v1/WithList.groovy deleted file mode 100644 index fca30d4729..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-baseclass-from-mappings/src/test/resources/contracts/com/hello/v1/WithList.groovy +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - request { - method 'POST' - url('/users') { - - } - headers { - header 'Content-Type': 'application/json' - } - } - response { - status OK() - headers { - header 'Location': '/users/john' - } - body '''{ "list" : [ "login", "john", "name", "John The Contract" ] }''' - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-generated-baseclass/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-generated-baseclass/pom.xml deleted file mode 100644 index b28edff5a9..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-generated-baseclass/pom.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - 4.0.0 - - org.springframework.cloud.verifier.sample - sample-project - 0.1 - - - - - - org.springframework.cloud - spring-cloud-contract-maven-plugin - - hello - - - - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-generated-baseclass/src/test/resources/contracts/hello/v1/Messaging.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-generated-baseclass/src/test/resources/contracts/hello/v1/Messaging.groovy deleted file mode 100644 index dbbfb72a06..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-generated-baseclass/src/test/resources/contracts/hello/v1/Messaging.groovy +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - label 'some_label' - input { - triggeredBy("hashCode()") - } - outputMessage { - sentTo('jms:output') - body([ - bookName: 'foo' - ]) - headers { - header('BOOK-NAME', 'foo') - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-generated-baseclass/src/test/resources/contracts/hello/v1/Sample.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-generated-baseclass/src/test/resources/contracts/hello/v1/Sample.groovy deleted file mode 100644 index b1c68007a9..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-generated-baseclass/src/test/resources/contracts/hello/v1/Sample.groovy +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - request { - method 'POST' - url('/users') { - - } - headers { - header 'Content-Type': 'application/json' - } - body '''{ "login" : "john", "name": "John The Contract" }''' - } - response { - status OK() - headers { - header 'Location': '/users/john' - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-generated-baseclass/src/test/resources/contracts/hello/v1/WithList.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-generated-baseclass/src/test/resources/contracts/hello/v1/WithList.groovy deleted file mode 100644 index fca30d4729..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-generated-baseclass/src/test/resources/contracts/hello/v1/WithList.groovy +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - request { - method 'POST' - url('/users') { - - } - headers { - header 'Content-Type': 'application/json' - } - } - response { - status OK() - headers { - header 'Location': '/users/john' - } - body '''{ "list" : [ "login", "john", "name", "John The Contract" ] }''' - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-remote-contracts/pom-with-repo.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-remote-contracts/pom-with-repo.xml deleted file mode 100644 index d286faad7d..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-remote-contracts/pom-with-repo.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - 4.0.0 - - com.example - server - 0.1.BUILD-SNAPSHOT - - - - - - org.springframework.cloud - spring-cloud-contract-maven-plugin - - REMOTE - - https://link/to/your/nexus/or/artifactory/or/sth - - - com.example.standalone - contracts - - - - - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-remote-contracts/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-remote-contracts/pom.xml deleted file mode 100644 index eb2f40c6ae..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic-remote-contracts/pom.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - 4.0.0 - - com.example - server - 0.1.BUILD-SNAPSHOT - - - - - org.springframework.cloud - spring-cloud-contract-maven-plugin - - REMOTE - - com.example - contracts - - - - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic/pom.xml deleted file mode 100644 index b1f5b63fd5..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic/pom.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - 4.0.0 - - org.springframework.cloud.verifier.sample - sample-project - 0.1 - - - - - org.springframework.cloud - spring-cloud-contract-maven-plugin - - - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic/src/test/resources/contracts/Messaging.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic/src/test/resources/contracts/Messaging.groovy deleted file mode 100644 index dbbfb72a06..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic/src/test/resources/contracts/Messaging.groovy +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - label 'some_label' - input { - triggeredBy("hashCode()") - } - outputMessage { - sentTo('jms:output') - body([ - bookName: 'foo' - ]) - headers { - header('BOOK-NAME', 'foo') - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic/src/test/resources/contracts/Sample.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic/src/test/resources/contracts/Sample.groovy deleted file mode 100644 index b1c68007a9..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic/src/test/resources/contracts/Sample.groovy +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - request { - method 'POST' - url('/users') { - - } - headers { - header 'Content-Type': 'application/json' - } - body '''{ "login" : "john", "name": "John The Contract" }''' - } - response { - status OK() - headers { - header 'Location': '/users/john' - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic/src/test/resources/contracts/WithList.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic/src/test/resources/contracts/WithList.groovy deleted file mode 100644 index dd98a1ee82..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/basic/src/test/resources/contracts/WithList.groovy +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - ignored() - request { - method 'POST' - url('/users') { - - } - headers { - header 'Content-Type': 'application/json' - } - } - response { - status OK() - headers { - header 'Location': '/users/john' - } - body '''{ "list" : [ "login", "john", "name", "John The Contract" ] }''' - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/common-repo/consumer1/Messaging.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/common-repo/consumer1/Messaging.groovy deleted file mode 100644 index dbbfb72a06..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/common-repo/consumer1/Messaging.groovy +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - label 'some_label' - input { - triggeredBy("hashCode()") - } - outputMessage { - sentTo('jms:output') - body([ - bookName: 'foo' - ]) - headers { - header('BOOK-NAME', 'foo') - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/common-repo/consumer1/Sample.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/common-repo/consumer1/Sample.groovy deleted file mode 100644 index b1c68007a9..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/common-repo/consumer1/Sample.groovy +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - request { - method 'POST' - url('/users') { - - } - headers { - header 'Content-Type': 'application/json' - } - body '''{ "login" : "john", "name": "John The Contract" }''' - } - response { - status OK() - headers { - header 'Location': '/users/john' - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/common-repo/consumer1/WithList.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/common-repo/consumer1/WithList.groovy deleted file mode 100644 index fca30d4729..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/common-repo/consumer1/WithList.groovy +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - request { - method 'POST' - url('/users') { - - } - headers { - header 'Content-Type': 'application/json' - } - } - response { - status OK() - headers { - header 'Location': '/users/john' - } - body '''{ "list" : [ "login", "john", "name", "John The Contract" ] }''' - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/common-repo/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/common-repo/pom.xml deleted file mode 100644 index 200c4384c5..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/common-repo/pom.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - 4.0.0 - - org.springframework.cloud.verifier.sample - common-repo - 0.1 - - - - - true - - true - - - - - - org.springframework.cloud - spring-cloud-contract-maven-plugin - - - ${project.basedir} - - - - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-common-repo-with-messaging/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-common-repo-with-messaging/pom.xml deleted file mode 100644 index 4a2c331704..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-common-repo-with-messaging/pom.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - 4.0.0 - - com.example - social-service - 0.1.BUILD-SNAPSHOT - - - - - org.springframework.cloud - spring-cloud-contract-maven-plugin - 2.0.0.BUILD-SNAPSHOT - - REMOTE - - com.example - services-contracts - + - - / - - - .*messaging.* - com.example.services.TestBase - - - .*rest.* - com.example.services.TestBase - - - - **/coupon-sent/** - **/reward-rules/** - - - - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-common-repo-with-messaging/src/test/java/com/example/services/TestBase.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-common-repo-with-messaging/src/test/java/com/example/services/TestBase.java deleted file mode 100644 index 2d6e5c2815..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-common-repo-with-messaging/src/test/java/com/example/services/TestBase.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package com.example.services; - -import io.restassured.module.mockmvc.RestAssuredMockMvc; -import org.junit.Before; - -public class TestBase { - - @Before - public void setup() { - RestAssuredMockMvc.standaloneSetup(new FraudDetectionController()); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/.gitignore b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/.gitignore deleted file mode 100644 index 1de565933b..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target \ No newline at end of file diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/pom.xml deleted file mode 100644 index 83e75a9e17..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/pom.xml +++ /dev/null @@ -1,142 +0,0 @@ - - - - 4.0.0 - - com.blogspot.toomuchcoding.frauddetection - frauddetection - 0.1.0 - - - org.springframework.boot - spring-boot-starter-parent - 3.2.0-SNAPSHOT - - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-test - test - - - ch.qos.logback - logback-classic - - - - - - io.rest-assured - rest-assured - 3.0.2 - test - - - io.rest-assured - spring-mock-mvc - 3.0.2 - test - - - com.toomuchcoding.jsonassert - jsonassert - 0.6.2 - test - - - org.assertj - assertj-core - 2.4.1 - test - - - - - - 17 - ${it-plugin.version} - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.springframework.cloud - spring-cloud-contract-maven-plugin - ${spring-cloud-verifier-plugin.version} - - - - convert - generateStubs - generateTests - - - src/test/contracts - - com.blogspot.toomuchcoding.frauddetection - - MOCKMVC - JUNIT - stubs - Test - org.junit.rules.ErrorCollector - - - - com.blogspot.toomuchcoding.frauddetection.matchers.CustomMatchers.* - - - - - com.blogspot.toomuchcoding.frauddetection.matchers.CustomMatchers - - - - broken** - - - shouldMarkClientAsFraud.groovy - - - - - - - com.blogspot.toomuchcoding.frauddetection.BaseAccurest - - - - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/main/java/com/blogspot/toomuchcoding/frauddetection/Application.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/main/java/com/blogspot/toomuchcoding/frauddetection/Application.java deleted file mode 100644 index a110d3548a..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/main/java/com/blogspot/toomuchcoding/frauddetection/Application.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package com.blogspot.toomuchcoding.frauddetection; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/main/java/com/blogspot/toomuchcoding/frauddetection/FraudDetectionController.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/main/java/com/blogspot/toomuchcoding/frauddetection/FraudDetectionController.java deleted file mode 100644 index 276c19bb13..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/main/java/com/blogspot/toomuchcoding/frauddetection/FraudDetectionController.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package com.blogspot.toomuchcoding.frauddetection; - -import java.math.BigDecimal; - -import com.blogspot.toomuchcoding.frauddetection.model.FraudCheck; -import com.blogspot.toomuchcoding.frauddetection.model.FraudCheckResult; - -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import static com.blogspot.toomuchcoding.frauddetection.model.FraudCheckStatus.FRAUD; -import static com.blogspot.toomuchcoding.frauddetection.model.FraudCheckStatus.OK; -import static org.springframework.web.bind.annotation.RequestMethod.PUT; - -@RestController -public class FraudDetectionController { - - private static final String FRAUD_SERVICE_JSON_VERSION_1 = "application/vnd.fraud.v1+json"; - - private static final String NO_REASON = null; - - private static final String AMOUNT_TOO_HIGH = "Amount too high"; - - private static final BigDecimal MAX_AMOUNT = new BigDecimal("5000"); - - @RequestMapping(value = "/fraudcheck", method = PUT, consumes = FRAUD_SERVICE_JSON_VERSION_1, produces = FRAUD_SERVICE_JSON_VERSION_1) - public FraudCheckResult fraudCheck(@RequestBody FraudCheck fraudCheck) { - if (amountGreaterThanThreshold(fraudCheck)) { - return new FraudCheckResult(FRAUD, AMOUNT_TOO_HIGH); - } - return new FraudCheckResult(OK, NO_REASON); - } - - private boolean amountGreaterThanThreshold(FraudCheck fraudCheck) { - return MAX_AMOUNT.compareTo(fraudCheck.getLoanAmount()) < 0; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheck.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheck.java deleted file mode 100644 index d40366b376..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheck.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package com.blogspot.toomuchcoding.frauddetection.model; - -import java.math.BigDecimal; - -public class FraudCheck { - - private String clientPesel; - - private BigDecimal loanAmount; - - public FraudCheck() { - } - - public String getClientPesel() { - return clientPesel; - } - - public void setClientPesel(String clientPesel) { - this.clientPesel = clientPesel; - } - - public BigDecimal getLoanAmount() { - return loanAmount; - } - - public void setLoanAmount(BigDecimal loanAmount) { - this.loanAmount = loanAmount; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheckResult.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheckResult.java deleted file mode 100644 index 373511afc5..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheckResult.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package com.blogspot.toomuchcoding.frauddetection.model; - -public class FraudCheckResult { - - private FraudCheckStatus fraudCheckStatus; - - private String rejectionReason; - - public FraudCheckResult() { - } - - public FraudCheckResult(FraudCheckStatus fraudCheckStatus, String rejectionReason) { - this.fraudCheckStatus = fraudCheckStatus; - this.rejectionReason = rejectionReason; - } - - public FraudCheckStatus getFraudCheckStatus() { - return fraudCheckStatus; - } - - public void setFraudCheckStatus(FraudCheckStatus fraudCheckStatus) { - this.fraudCheckStatus = fraudCheckStatus; - } - - public String getRejectionReason() { - return rejectionReason; - } - - public void setRejectionReason(String rejectionReason) { - this.rejectionReason = rejectionReason; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheckStatus.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheckStatus.java deleted file mode 100644 index 920466b190..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheckStatus.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package com.blogspot.toomuchcoding.frauddetection.model; - -public enum FraudCheckStatus { - - OK, FRAUD - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/test/contracts/brokenContract.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/test/contracts/brokenContract.groovy deleted file mode 100644 index b6181cac29..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/test/contracts/brokenContract.groovy +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - request { - method 'PUT' - url '/fraudcheck' - body(""" - { - "clientPesel":"${ - value(consumer(regex('[0-9]{10}')), producer('1234567890')) - }", - "loanAmount":123.123 - } - """ - ) - headers { - header('Content-Type', 'application/vnd.fraud.v1+json') - } - - } - response { - status 999 - body( - fraudCheckStatus: "OK", - rejectionReason: $(consumer(null), - producer(execute('assertThatRejectionReasonIsNull($it)'))) - ) - headers { - header('Content-Type': 'application/vnd.fraud.v1+json') - } - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/test/contracts/shouldMarkClientAsFraud.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/test/contracts/shouldMarkClientAsFraud.groovy deleted file mode 100644 index 14275c90b1..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/test/contracts/shouldMarkClientAsFraud.groovy +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - request { - method """PUT""" - url """/fraudcheck""" - body(""" - { - "clientPesel":"${ - value(consumer(regex('[0-9]{10}')), producer('1234567890')) - }", - "loanAmount":99999} - """ - ) - headers { - header("""Content-Type""", """application/vnd.fraud.v1+json""") - } - - } - response { - status OK() - body("""{ - "fraudCheckStatus": "${value(consumer('FRAUD'), producer(regex('[A-Z]{5}')))}", - "rejectionReason": "Amount too high" -}""") - headers { - header('Content-Type': 'application/vnd.fraud.v1+json') - } - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/test/contracts/shouldMarkClientAsNotFraud.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/test/contracts/shouldMarkClientAsNotFraud.groovy deleted file mode 100644 index 5b96fba77b..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/test/contracts/shouldMarkClientAsNotFraud.groovy +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - request { - method 'PUT' - url '/fraudcheck' - body(""" - { - "clientPesel":"${ - value(consumer(regex('[0-9]{10}')), producer('1234567890')) - }", - "loanAmount":123.123 - } - """ - ) - headers { - header('Content-Type', 'application/vnd.fraud.v1+json') - } - - } - response { - status OK() - body( - fraudCheckStatus: "OK", - rejectionReason: $(consumer(null), - producer(execute('assertThatRejectionReasonIsNull($it)'))) - ) - headers { - header('Content-Type': 'application/vnd.fraud.v1+json') - } - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/test/java/com/blogspot/toomuchcoding/frauddetection/BaseAccurest.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/test/java/com/blogspot/toomuchcoding/frauddetection/BaseAccurest.java deleted file mode 100644 index 899a2aed4a..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/test/java/com/blogspot/toomuchcoding/frauddetection/BaseAccurest.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package com.blogspot.toomuchcoding.frauddetection; - -import io.restassured.module.mockmvc.RestAssuredMockMvc; -import org.junit.Before; - -public class BaseAccurest { - - @Before - public void setup() { - RestAssuredMockMvc.standaloneSetup(new FraudDetectionController()); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/test/java/com/blogspot/toomuchcoding/frauddetection/matchers/CustomMatchers.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/test/java/com/blogspot/toomuchcoding/frauddetection/matchers/CustomMatchers.java deleted file mode 100644 index 0a4343f46f..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-configuration/src/test/java/com/blogspot/toomuchcoding/frauddetection/matchers/CustomMatchers.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package com.blogspot.toomuchcoding.frauddetection.matchers; - -import org.junit.Assert; - -public class CustomMatchers { - - public static void assertThatRejectionReasonIsNull(String rejectionReason) { - Assert.assertNull(rejectionReason); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-remote-contracts/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-remote-contracts/pom.xml deleted file mode 100644 index 3f77df1de0..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/complex-remote-contracts/pom.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - 4.0.0 - - com.example.foo.bar.baz - someartifact - 0.1.BUILD-SNAPSHOT - - - - - org.springframework.cloud - spring-cloud-contract-maven-plugin - - REMOTE - com/example/server - - com.example - contracts - + - - - - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/.gitignore b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/.gitignore deleted file mode 100644 index 1de565933b..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target \ No newline at end of file diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/pom.xml deleted file mode 100644 index f7e651cf8b..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/pom.xml +++ /dev/null @@ -1,140 +0,0 @@ - - - - 4.0.0 - - com.blogspot.toomuchcoding.frauddetection - frauddetection - 0.1.0 - - - org.springframework.boot - spring-boot-starter-parent - 3.2.0-SNAPSHOT - - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-test - test - - - ch.qos.logback - logback-classic - - - - - com.jayway.restassured - rest-assured - 2.9.0 - test - - - com.jayway.restassured - spring-mock-mvc - 2.9.0 - test - - - com.toomuchcoding.jsonassert - jsonassert - 0.6.2 - test - - - org.assertj - assertj-core - 2.4.1 - test - - - - - 17 - ${it-plugin.version} - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.springframework.cloud - spring-cloud-contract-maven-plugin - ${spring-cloud-verifier-plugin.version} - - - - convert - generateStubs - generateTests - - - src/test/contracts - - com.blogspot.toomuchcoding.frauddetection - - MOCKMVC - JUNIT - stubs - Test - org.junit.rules.ErrorCollector - - - - com.blogspot.toomuchcoding.frauddetection.matchers.CustomMatchers.* - - - - - com.blogspot.toomuchcoding.frauddetection.matchers.CustomMatchers - - - - broken** - - - shouldMarkClientAsFraud.groovy - - - - - - - com.blogspot.toomuchcoding.frauddetection.BaseAccurest - - - - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/main/java/com/blogspot/toomuchcoding/frauddetection/Application.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/main/java/com/blogspot/toomuchcoding/frauddetection/Application.java deleted file mode 100644 index a110d3548a..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/main/java/com/blogspot/toomuchcoding/frauddetection/Application.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package com.blogspot.toomuchcoding.frauddetection; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/main/java/com/blogspot/toomuchcoding/frauddetection/FraudDetectionController.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/main/java/com/blogspot/toomuchcoding/frauddetection/FraudDetectionController.java deleted file mode 100644 index 276c19bb13..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/main/java/com/blogspot/toomuchcoding/frauddetection/FraudDetectionController.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package com.blogspot.toomuchcoding.frauddetection; - -import java.math.BigDecimal; - -import com.blogspot.toomuchcoding.frauddetection.model.FraudCheck; -import com.blogspot.toomuchcoding.frauddetection.model.FraudCheckResult; - -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import static com.blogspot.toomuchcoding.frauddetection.model.FraudCheckStatus.FRAUD; -import static com.blogspot.toomuchcoding.frauddetection.model.FraudCheckStatus.OK; -import static org.springframework.web.bind.annotation.RequestMethod.PUT; - -@RestController -public class FraudDetectionController { - - private static final String FRAUD_SERVICE_JSON_VERSION_1 = "application/vnd.fraud.v1+json"; - - private static final String NO_REASON = null; - - private static final String AMOUNT_TOO_HIGH = "Amount too high"; - - private static final BigDecimal MAX_AMOUNT = new BigDecimal("5000"); - - @RequestMapping(value = "/fraudcheck", method = PUT, consumes = FRAUD_SERVICE_JSON_VERSION_1, produces = FRAUD_SERVICE_JSON_VERSION_1) - public FraudCheckResult fraudCheck(@RequestBody FraudCheck fraudCheck) { - if (amountGreaterThanThreshold(fraudCheck)) { - return new FraudCheckResult(FRAUD, AMOUNT_TOO_HIGH); - } - return new FraudCheckResult(OK, NO_REASON); - } - - private boolean amountGreaterThanThreshold(FraudCheck fraudCheck) { - return MAX_AMOUNT.compareTo(fraudCheck.getLoanAmount()) < 0; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheck.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheck.java deleted file mode 100644 index d40366b376..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheck.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package com.blogspot.toomuchcoding.frauddetection.model; - -import java.math.BigDecimal; - -public class FraudCheck { - - private String clientPesel; - - private BigDecimal loanAmount; - - public FraudCheck() { - } - - public String getClientPesel() { - return clientPesel; - } - - public void setClientPesel(String clientPesel) { - this.clientPesel = clientPesel; - } - - public BigDecimal getLoanAmount() { - return loanAmount; - } - - public void setLoanAmount(BigDecimal loanAmount) { - this.loanAmount = loanAmount; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheckResult.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheckResult.java deleted file mode 100644 index 373511afc5..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheckResult.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package com.blogspot.toomuchcoding.frauddetection.model; - -public class FraudCheckResult { - - private FraudCheckStatus fraudCheckStatus; - - private String rejectionReason; - - public FraudCheckResult() { - } - - public FraudCheckResult(FraudCheckStatus fraudCheckStatus, String rejectionReason) { - this.fraudCheckStatus = fraudCheckStatus; - this.rejectionReason = rejectionReason; - } - - public FraudCheckStatus getFraudCheckStatus() { - return fraudCheckStatus; - } - - public void setFraudCheckStatus(FraudCheckStatus fraudCheckStatus) { - this.fraudCheckStatus = fraudCheckStatus; - } - - public String getRejectionReason() { - return rejectionReason; - } - - public void setRejectionReason(String rejectionReason) { - this.rejectionReason = rejectionReason; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheckStatus.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheckStatus.java deleted file mode 100644 index 920466b190..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheckStatus.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package com.blogspot.toomuchcoding.frauddetection.model; - -public enum FraudCheckStatus { - - OK, FRAUD - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/test/contracts/brokenContract.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/test/contracts/brokenContract.groovy deleted file mode 100644 index b6181cac29..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/test/contracts/brokenContract.groovy +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - request { - method 'PUT' - url '/fraudcheck' - body(""" - { - "clientPesel":"${ - value(consumer(regex('[0-9]{10}')), producer('1234567890')) - }", - "loanAmount":123.123 - } - """ - ) - headers { - header('Content-Type', 'application/vnd.fraud.v1+json') - } - - } - response { - status 999 - body( - fraudCheckStatus: "OK", - rejectionReason: $(consumer(null), - producer(execute('assertThatRejectionReasonIsNull($it)'))) - ) - headers { - header('Content-Type': 'application/vnd.fraud.v1+json') - } - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/test/contracts/shouldMarkClientAsFraud.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/test/contracts/shouldMarkClientAsFraud.groovy deleted file mode 100644 index 14275c90b1..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/test/contracts/shouldMarkClientAsFraud.groovy +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - request { - method """PUT""" - url """/fraudcheck""" - body(""" - { - "clientPesel":"${ - value(consumer(regex('[0-9]{10}')), producer('1234567890')) - }", - "loanAmount":99999} - """ - ) - headers { - header("""Content-Type""", """application/vnd.fraud.v1+json""") - } - - } - response { - status OK() - body("""{ - "fraudCheckStatus": "${value(consumer('FRAUD'), producer(regex('[A-Z]{5}')))}", - "rejectionReason": "Amount too high" -}""") - headers { - header('Content-Type': 'application/vnd.fraud.v1+json') - } - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/test/contracts/shouldMarkClientAsNotFraud.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/test/contracts/shouldMarkClientAsNotFraud.groovy deleted file mode 100644 index 5b96fba77b..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/test/contracts/shouldMarkClientAsNotFraud.groovy +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - request { - method 'PUT' - url '/fraudcheck' - body(""" - { - "clientPesel":"${ - value(consumer(regex('[0-9]{10}')), producer('1234567890')) - }", - "loanAmount":123.123 - } - """ - ) - headers { - header('Content-Type', 'application/vnd.fraud.v1+json') - } - - } - response { - status OK() - body( - fraudCheckStatus: "OK", - rejectionReason: $(consumer(null), - producer(execute('assertThatRejectionReasonIsNull($it)'))) - ) - headers { - header('Content-Type': 'application/vnd.fraud.v1+json') - } - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/test/java/com/blogspot/toomuchcoding/frauddetection/BaseAccurest.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/test/java/com/blogspot/toomuchcoding/frauddetection/BaseAccurest.java deleted file mode 100644 index 724646f0f8..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/test/java/com/blogspot/toomuchcoding/frauddetection/BaseAccurest.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package com.blogspot.toomuchcoding.frauddetection; - -import com.jayway.restassured.module.mockmvc.RestAssuredMockMvc; -import org.junit.Before; - -public class BaseAccurest { - - @Before - public void setup() { - RestAssuredMockMvc.standaloneSetup(new FraudDetectionController()); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/test/java/com/blogspot/toomuchcoding/frauddetection/matchers/CustomMatchers.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/test/java/com/blogspot/toomuchcoding/frauddetection/matchers/CustomMatchers.java deleted file mode 100644 index 0a4343f46f..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/module/src/test/java/com/blogspot/toomuchcoding/frauddetection/matchers/CustomMatchers.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package com.blogspot.toomuchcoding.frauddetection.matchers; - -import org.junit.Assert; - -public class CustomMatchers { - - public static void assertThatRejectionReasonIsNull(String rejectionReason) { - Assert.assertNull(rejectionReason); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/pom.xml deleted file mode 100644 index 5d6a6dbe28..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/different-module-configuration/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - 4.0.0 - - com.blogspot.toomuchcoding.frauddetection - frauddetection-parent - 0.1.0 - pom - - - module/src/test/contracts - - - - module - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/generatedStubs/.gitignore b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/generatedStubs/.gitignore deleted file mode 100644 index 8dc6c7308d..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/generatedStubs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!target \ No newline at end of file diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/generatedStubs/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/generatedStubs/pom.xml deleted file mode 100644 index 76b78fefbf..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/generatedStubs/pom.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - 4.0.0 - - org.springframework.cloud.verifier.sample - sample-project - 0.1 - - - ${project.name} - - - org.springframework.cloud - spring-cloud-contract-maven-plugin - - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/generatedStubs/target/stubs/contracts/Sample.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/generatedStubs/target/stubs/contracts/Sample.groovy deleted file mode 100644 index 3b306b02e5..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/generatedStubs/target/stubs/contracts/Sample.groovy +++ /dev/null @@ -1,18 +0,0 @@ -io.codearte.accurest.dsl.GroovyDsl.make { - request { - method 'POST' - url('/users') { - - } - headers { - header 'Content-Type': 'application/json' - } - body '''{ "login" : "john", "name": "John The Contract" }''' - } - response { - status OK() - headers { - header 'Location': '/users/john' - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/generatedStubs/target/stubs/mappings/Sample.json b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/generatedStubs/target/stubs/mappings/Sample.json deleted file mode 100644 index 460a6a7928..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/generatedStubs/target/stubs/mappings/Sample.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "request": { - "url": "/users", - "method": "POST", - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.login == 'john')]" - }, - { - "matchesJsonPath": "$[?(@.name == 'John The Contract')]" - } - ], - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - } - }, - "response": { - "status": 200, - "headers": { - "Location": "/users/john" - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/generatedStubsOnly/.gitignore b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/generatedStubsOnly/.gitignore deleted file mode 100644 index 8dc6c7308d..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/generatedStubsOnly/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!target \ No newline at end of file diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/generatedStubsOnly/target/stubs/Sample.json b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/generatedStubsOnly/target/stubs/Sample.json deleted file mode 100644 index 460a6a7928..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/generatedStubsOnly/target/stubs/Sample.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "request": { - "url": "/users", - "method": "POST", - "bodyPatterns": [ - { - "matchesJsonPath": "$[?(@.login == 'john')]" - }, - { - "matchesJsonPath": "$[?(@.name == 'John The Contract')]" - } - ], - "headers": { - "Content-Type": { - "equalTo": "application/json" - } - } - }, - "response": { - "status": 200, - "headers": { - "Location": "/users/john" - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/git-basic-remote-contracts/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/git-basic-remote-contracts/pom.xml deleted file mode 100644 index 947c0457fc..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/git-basic-remote-contracts/pom.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - 4.0.0 - - com.example - server - 0.1.BUILD-SNAPSHOT - - - - - org.springframework.cloud - spring-cloud-contract-maven-plugin - - REMOTE - https://foo.bar - - - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/multiple-contracts/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/multiple-contracts/pom.xml deleted file mode 100644 index 935cb5d985..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/multiple-contracts/pom.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - 4.0.0 - - org.springframework.cloud.verifier.sample - sample-project - 0.1 - - - - - org.springframework.cloud - spring-cloud-contract-maven-plugin - - - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/multiple-contracts/src/test/resources/contracts/com/hello/v1/WithList.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/multiple-contracts/src/test/resources/contracts/com/hello/v1/WithList.groovy deleted file mode 100644 index 606d72a43c..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/multiple-contracts/src/test/resources/contracts/com/hello/v1/WithList.groovy +++ /dev/null @@ -1,40 +0,0 @@ -/** - * - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.springframework.cloud.contract.spec.Contract - -[ - Contract.make { - name("should post a user") - request { - method 'POST' - url('/users/1') - } - response { - status OK() - } - }, - Contract.make { - request { - method 'POST' - url('/users/2') - } - response { - status OK() - } - } -] diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/pom.xml deleted file mode 100644 index 913c10fe24..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/pom.xml +++ /dev/null @@ -1,146 +0,0 @@ - - - - 4.0.0 - - org.springframework - gs-rest-service - 0.1.0 - - - org.springframework.boot - spring-boot-starter-parent - 3.2.0-SNAPSHOT - - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-test - test - - - ch.qos.logback - logback-classic - - - - - - org.springframework.cloud - spring-cloud-starter-contract-verifier - ${it-plugin.version} - test - - - - - - 17 - ${it-plugin.version} - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.springframework.cloud - spring-cloud-contract-maven-plugin - ${spring-cloud-verifier-plugin.version} - true - - hello.BaseAccurest - - - - - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - false - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - false - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/src/main/java/hello/Application.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/src/main/java/hello/Application.java deleted file mode 100644 index 2e98d6e788..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/src/main/java/hello/Application.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package hello; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/src/main/java/hello/Greeting.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/src/main/java/hello/Greeting.java deleted file mode 100644 index 1bfe96bdb3..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/src/main/java/hello/Greeting.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package hello; - -public class Greeting { - - private final long id; - - private final String content; - - public Greeting(long id, String content) { - this.id = id; - this.content = content; - } - - public long getId() { - return id; - } - - public String getContent() { - return content; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/src/main/java/hello/GreetingController.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/src/main/java/hello/GreetingController.java deleted file mode 100644 index 30f64e0b28..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/src/main/java/hello/GreetingController.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package hello; - -import java.util.concurrent.atomic.AtomicLong; - -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class GreetingController { - - private static final String template = "Hello, %s!"; - - private final AtomicLong counter = new AtomicLong(); - - @RequestMapping("/greeting") - public Greeting greeting( - @RequestParam(value = "name", defaultValue = "World") String name) { - return new Greeting(counter.incrementAndGet(), String.format(template, name)); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/src/test/java/hello/BaseAccurest.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/src/test/java/hello/BaseAccurest.java deleted file mode 100644 index 75500c27c3..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/src/test/java/hello/BaseAccurest.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package hello; - -import io.restassured.module.mockmvc.RestAssuredMockMvc; -import org.junit.Before; - -public class BaseAccurest { - - @Before - public void setup() { - RestAssuredMockMvc.standaloneSetup(new GreetingController()); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/src/test/resources/contracts/greetings_ok.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/src/test/resources/contracts/greetings_ok.groovy deleted file mode 100644 index 8db5dde3e3..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/src/test/resources/contracts/greetings_ok.groovy +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - priority 2 - request { - method 'GET' - urlPath('/greeting') { - queryParameters { - parameter 'name': 'Something' - } - } - headers { - header 'Content-Type': 'application/json' - } - } - response { - status OK() - body( - id: 1, - content: "Hello, Something!" - ) - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/src/test/resources/contracts/greetings_with_default_value.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/src/test/resources/contracts/greetings_with_default_value.groovy deleted file mode 100644 index 9f38616bc4..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/plugin-extension/src/test/resources/contracts/greetings_with_default_value.groovy +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - priority 2 - request { - method 'GET' - url('/greeting') - headers { - header 'Content-Type': 'application/json' - } - } - response { - status OK() - body( - id: 1, - content: "Hello, World!" - ) - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/pomless/Sample.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/pomless/Sample.groovy deleted file mode 100644 index b1c68007a9..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/pomless/Sample.groovy +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - request { - method 'POST' - url('/users') { - - } - headers { - header 'Content-Type': 'application/json' - } - body '''{ "login" : "john", "name": "John The Contract" }''' - } - response { - status OK() - headers { - header 'Location': '/users/john' - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/pom.xml deleted file mode 100644 index 67b973b833..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/pom.xml +++ /dev/null @@ -1,191 +0,0 @@ - - - - 4.0.0 - - org.springframework - gs-rest-service - 0.1.0 - - - org.springframework.boot - spring-boot-starter-parent - 3.2.0-SNAPSHOT - - - - - org.apache.groovy - groovy - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - org.spockframework - spock-core - 1.0-groovy-2.4 - test - - - org.springframework.cloud - spring-cloud-starter-contract-verifier - ${it-plugin.version} - test - - - - - - 17 - ${it-plugin.version} - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.springframework.cloud - spring-cloud-contract-maven-plugin - ${spring-cloud-verifier-plugin.version} - true - - hello.BaseAccurest - SPOCK - - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - - - compileTests - - - - - - - ${project.basedir}/src/test/groovy - - **/*.groovy - - - - - ${project.build.directory}/generated-test-sources/contracts - - - **/*.groovy - - - - - - - maven-surefire-plugin - - - **/*Spec.java - - - - - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - false - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - false - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/main/java/hello/Application.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/main/java/hello/Application.java deleted file mode 100644 index 2e98d6e788..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/main/java/hello/Application.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package hello; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/main/java/hello/Greeting.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/main/java/hello/Greeting.java deleted file mode 100644 index 1bfe96bdb3..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/main/java/hello/Greeting.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package hello; - -public class Greeting { - - private final long id; - - private final String content; - - public Greeting(long id, String content) { - this.id = id; - this.content = content; - } - - public long getId() { - return id; - } - - public String getContent() { - return content; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/main/java/hello/GreetingController.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/main/java/hello/GreetingController.java deleted file mode 100644 index bfa89018c8..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/main/java/hello/GreetingController.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package hello; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import java.util.ArrayList; -import java.util.concurrent.atomic.AtomicLong; - -import static java.util.Arrays.asList; - -@RestController -public class GreetingController { - - private static final String template = "Hello, %s!"; - - private final AtomicLong counter = new AtomicLong(); - - @GetMapping("/greeting") - public Greeting greeting( - @RequestParam(value = "name", defaultValue = "World") String name) { - return new Greeting(counter.incrementAndGet(), String.format(template, name)); - } - - @GetMapping(value = "/accounts") - public GreetingResponse accounts( - @RequestParam(value = "name", defaultValue = "World") String name) { - return new GreetingResponse( - name, - new ArrayList<>( - asList( - new GreetingResponse.Account("account1"), - new GreetingResponse.Account("account2")) - ) - ); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/main/java/hello/GreetingResponse.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/main/java/hello/GreetingResponse.java deleted file mode 100644 index 5510787a85..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/main/java/hello/GreetingResponse.java +++ /dev/null @@ -1,47 +0,0 @@ -package hello; - -import java.util.List; - -public class GreetingResponse { - String name; - List accounts; - - public GreetingResponse(String name, List accounts) { - this.name = name; - this.accounts = accounts; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public List getAccounts() { - return accounts; - } - - public void setAccounts(List accounts) { - this.accounts = accounts; - } - - static class Account { - - String key; - - public Account(String key) { - this.key = key; - } - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - } - - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/test/groovy/hello/BaseAccurest.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/test/groovy/hello/BaseAccurest.groovy deleted file mode 100644 index 3a195c8d8d..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/test/groovy/hello/BaseAccurest.groovy +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package hello - -import io.restassured.module.mockmvc.RestAssuredMockMvc -import spock.lang.Specification - -class BaseAccurest extends Specification { - - def setup() { - RestAssuredMockMvc.standaloneSetup(new GreetingController()) - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/test/resources/contracts/greetings_ok.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/test/resources/contracts/greetings_ok.groovy deleted file mode 100644 index 8db5dde3e3..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/test/resources/contracts/greetings_ok.groovy +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - priority 2 - request { - method 'GET' - urlPath('/greeting') { - queryParameters { - parameter 'name': 'Something' - } - } - headers { - header 'Content-Type': 'application/json' - } - } - response { - status OK() - body( - id: 1, - content: "Hello, Something!" - ) - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/test/resources/contracts/greetings_post_ok.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/test/resources/contracts/greetings_post_ok.groovy deleted file mode 100644 index f77fa9dbc0..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/test/resources/contracts/greetings_post_ok.groovy +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - priority 2 - request { - method 'GET' - urlPath('/accounts') { - queryParameters { - parameter 'name': 'Something' - } - } - headers { - header 'Content-Type': 'application/json' - } - } - response { - status OK() - body ( - name: fromRequest().query('name'), - accounts: [ - [ - key: 'account1' - ], - [ - key: 'account2' - ] - ] - ) - bodyMatchers { - jsonPath('$.accounts[*].key', byRegex('account.*')) - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/test/resources/contracts/greetings_with_default_value.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/test/resources/contracts/greetings_with_default_value.groovy deleted file mode 100644 index 9f38616bc4..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-groovy/src/test/resources/contracts/greetings_with_default_value.groovy +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - priority 2 - request { - method 'GET' - url('/greeting') - headers { - header 'Content-Type': 'application/json' - } - } - response { - status OK() - body( - id: 1, - content: "Hello, World!" - ) - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/pom.xml deleted file mode 100644 index 913c10fe24..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/pom.xml +++ /dev/null @@ -1,146 +0,0 @@ - - - - 4.0.0 - - org.springframework - gs-rest-service - 0.1.0 - - - org.springframework.boot - spring-boot-starter-parent - 3.2.0-SNAPSHOT - - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-test - test - - - ch.qos.logback - logback-classic - - - - - - org.springframework.cloud - spring-cloud-starter-contract-verifier - ${it-plugin.version} - test - - - - - - 17 - ${it-plugin.version} - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.springframework.cloud - spring-cloud-contract-maven-plugin - ${spring-cloud-verifier-plugin.version} - true - - hello.BaseAccurest - - - - - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - false - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - false - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/src/main/java/hello/Application.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/src/main/java/hello/Application.java deleted file mode 100644 index 2e98d6e788..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/src/main/java/hello/Application.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package hello; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/src/main/java/hello/Greeting.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/src/main/java/hello/Greeting.java deleted file mode 100644 index 1bfe96bdb3..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/src/main/java/hello/Greeting.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package hello; - -public class Greeting { - - private final long id; - - private final String content; - - public Greeting(long id, String content) { - this.id = id; - this.content = content; - } - - public long getId() { - return id; - } - - public String getContent() { - return content; - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/src/main/java/hello/GreetingController.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/src/main/java/hello/GreetingController.java deleted file mode 100644 index 30f64e0b28..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/src/main/java/hello/GreetingController.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package hello; - -import java.util.concurrent.atomic.AtomicLong; - -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class GreetingController { - - private static final String template = "Hello, %s!"; - - private final AtomicLong counter = new AtomicLong(); - - @RequestMapping("/greeting") - public Greeting greeting( - @RequestParam(value = "name", defaultValue = "World") String name) { - return new Greeting(counter.incrementAndGet(), String.format(template, name)); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/src/test/java/hello/BaseAccurest.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/src/test/java/hello/BaseAccurest.java deleted file mode 100644 index 75500c27c3..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/src/test/java/hello/BaseAccurest.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */package hello; - -import io.restassured.module.mockmvc.RestAssuredMockMvc; -import org.junit.Before; - -public class BaseAccurest { - - @Before - public void setup() { - RestAssuredMockMvc.standaloneSetup(new GreetingController()); - } - -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/src/test/resources/contracts/greetings_ok.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/src/test/resources/contracts/greetings_ok.groovy deleted file mode 100644 index 8db5dde3e3..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/src/test/resources/contracts/greetings_ok.groovy +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - priority 2 - request { - method 'GET' - urlPath('/greeting') { - queryParameters { - parameter 'name': 'Something' - } - } - headers { - header 'Content-Type': 'application/json' - } - } - response { - status OK() - body( - id: 1, - content: "Hello, Something!" - ) - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/src/test/resources/contracts/greetings_with_default_value.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/src/test/resources/contracts/greetings_with_default_value.groovy deleted file mode 100644 index 9f38616bc4..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/spring-boot-java/src/test/resources/contracts/greetings_with_default_value.groovy +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - priority 2 - request { - method 'GET' - url('/greeting') - headers { - header 'Content-Type': 'application/json' - } - } - response { - status OK() - body( - id: 1, - content: "Hello, World!" - ) - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/withStubs/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/withStubs/pom.xml deleted file mode 100644 index 0a8ae63e91..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/withStubs/pom.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - 4.0.0 - - org.springframework.cloud.verifier.sample - sample-project - 0.1 - - - - - org.springframework.cloud - spring-cloud-contract-maven-plugin - - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/withStubs/src/test/resources/stubs/Sample.groovy b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/withStubs/src/test/resources/stubs/Sample.groovy deleted file mode 100644 index b1c68007a9..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/projects/withStubs/src/test/resources/stubs/Sample.groovy +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ org.springframework.cloud.contract.spec.Contract.make { - request { - method 'POST' - url('/users') { - - } - headers { - header 'Content-Type': 'application/json' - } - body '''{ "login" : "john", "name": "John The Contract" }''' - } - response { - status OK() - headers { - header 'Location': '/users/john' - } - } -} diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/logback.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/logback.xml deleted file mode 100644 index 96d75b755b..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/logback.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/contracts/0.0.1-SNAPSHOT/contracts-0.0.1-SNAPSHOT.jar b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/contracts/0.0.1-SNAPSHOT/contracts-0.0.1-SNAPSHOT.jar deleted file mode 100644 index 6c47639c606361a8cbe9f40d39454e58ae6fdbff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3880 zcmWIWW@h1HVBp|j&|{wF!2kqIAOZ+Df!NnI#8KDN&rP41Apk|;rh2A#(m(~0KrDi+ z(AUw=)6F$FM9 zDNZdaOD!VPFlp?DCFf+O=9L(dX{aiGLzDCKN{SMbONt2^4+>5Wa4;@adv5&i;&j2EN=FjbhQ_4yW^xJW!+;}^l+yko8;Gra~+>-k94h#ci7exs3~0OLJ0u6N|E)!7=Yx>{gUm znnFaF)lLlbKV%@%I{)VS45`Vyt%d<170MFxIS+NWwcm=}zVYI@ZL=q({=d8Jwu|Q$ ze&2U{&+dF)bC%QBlcl3*8OuU1D?agw`o$AByzrgCTvIUdm&s$-7v=q5Bv$Nyvx?c1 zG1Sjrp7A}a$JH?Q07HJkV-;KPzPN41J#pqak8W|r-o|BjpG<9cU$0%&>%xCohjCe$ zg5u%gn!u?l+6S_C&1>MWv;D3rajxvD#frOi^$jW=LM_kx)UTUgzPNrQ+w_ zU;0Y>6d%Rk%71m|zxVly{A<^FZI_qrLn>U3bd;kMO&rj;PRq~N$Ck(o_L)Y2Frs)u zHvv{WflNqBEF#ks0VH>TOi4|g2Dt^jtOoB7Txc`#Ww@E4u#c%(E1Bj?6nYuCV>V@ZX6ndWInI@G-f9~1(&aiFDW{0&~ z9TLhWYe+qvZ7U_voiuTyWwJ#Z$Gij8srI#Jnz_?O{>=W+u~F)*ie8{fXRIWDUQwNU zkMo;Z9c)t=Kh1BNFIW>EdOUQet?Z9a-s(kun?Fk<3g{SMSZqA6!&(mvhv`6U4#c4L z1W{q(lA4oRk_s!7P0u)T9aa!vy-;f7dctk(j8*;44Fsan2Xv*c&x z|N2J>ua9N&`nR#hAGx{9Y4`TNu*8B(5_9MN%WUlV>t4#5rnC23M8F3_;ncOew&d-e zbBlAiz=VtO_tH879=ph$wdgs!AS`94tH9#(4`p9{Eq{D=MfAgf-EyAPLuo)NTWrAP2S>vw_9JAOY45viN{w z8ITQWtg%8GYiPwHK9hJ*Oxgl92^LMEA*7oqjAG(1G!x;CIMNN4MlskOSoPycQRKK> z6~%%%_$@$WU;I`f8Z4+yJ4gfq?OZRhjVyCBmop zTTl2M0?I)Q4Cqxc2TG6&vO*jJs+hs1f$B6oi5cBA)WjT&WE!Y~CdWhp6!*7dw$rj-29PbrYyOfmwsCphsA9jDrMg YP>cNlZ&o&tLHs~i0Suv8ppGyD03w62MgRZ+ diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/contracts/0.0.1-SNAPSHOT/contracts-0.0.1-SNAPSHOT.pom b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/contracts/0.0.1-SNAPSHOT/contracts-0.0.1-SNAPSHOT.pom deleted file mode 100644 index fa8a29a15d..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/contracts/0.0.1-SNAPSHOT/contracts-0.0.1-SNAPSHOT.pom +++ /dev/null @@ -1,27 +0,0 @@ - - - - - 4.0.0 - com.example - contracts - 0.0.1-SNAPSHOT - pom - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/contracts/0.0.1-SNAPSHOT/maven-metadata-local.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/contracts/0.0.1-SNAPSHOT/maven-metadata-local.xml deleted file mode 100644 index 3b4511d3ba..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/contracts/0.0.1-SNAPSHOT/maven-metadata-local.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - com.example - contracts - 0.0.1-SNAPSHOT - - - true - - 20160916125313 - - - jar - 0.0.1-SNAPSHOT - 20160916125313 - - - pom - 0.0.1-SNAPSHOT - 20160916125313 - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/contracts/1.0.4-SNAPSHOT/contracts-0.0.1-SNAPSHOT.pom b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/contracts/1.0.4-SNAPSHOT/contracts-0.0.1-SNAPSHOT.pom deleted file mode 100644 index fa8a29a15d..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/contracts/1.0.4-SNAPSHOT/contracts-0.0.1-SNAPSHOT.pom +++ /dev/null @@ -1,27 +0,0 @@ - - - - - 4.0.0 - com.example - contracts - 0.0.1-SNAPSHOT - pom - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/contracts/maven-metadata.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/contracts/maven-metadata.xml deleted file mode 100644 index a261017302..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/contracts/maven-metadata.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - com.example - contracts - 0.0.1-SNAPSHOT - - - 0.0.1-SNAPSHOT - - 20160409062112 - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/services-contracts/1.0.4-SNAPSHOT/maven-metadata-local.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/services-contracts/1.0.4-SNAPSHOT/maven-metadata-local.xml deleted file mode 100644 index 0e106b3860..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/services-contracts/1.0.4-SNAPSHOT/maven-metadata-local.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - com.example - services-contracts - 1.0.4-SNAPSHOT - - - true - - 20160916125313 - - - jar - 1.0.4-SNAPSHOT - 20160916125313 - - - pom - 1.0.4-SNAPSHOT - 20160916125313 - - - - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/services-contracts/1.0.4-SNAPSHOT/services-contracts-1.0.4-SNAPSHOT.jar b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/services-contracts/1.0.4-SNAPSHOT/services-contracts-1.0.4-SNAPSHOT.jar deleted file mode 100644 index 54c268d26c3bea4ea8dc2102758ec53352294585..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15718 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 L(Ks%#ZT$Ctm)=;) diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/services-contracts/1.0.4-SNAPSHOT/services-contracts-1.0.4-SNAPSHOT.pom b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/services-contracts/1.0.4-SNAPSHOT/services-contracts-1.0.4-SNAPSHOT.pom deleted file mode 100644 index 680aba29ac..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/services-contracts/1.0.4-SNAPSHOT/services-contracts-1.0.4-SNAPSHOT.pom +++ /dev/null @@ -1,27 +0,0 @@ - - - - - 4.0.0 - com.example - services-contracts - 1.0.4-SNAPSHOT - pom - diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/services-contracts/maven-metadata.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/services-contracts/maven-metadata.xml deleted file mode 100644 index f70a55a8d8..0000000000 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/test/resources/m2repo/repository/com/example/services-contracts/maven-metadata.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - com.example - services-contracts - 1.0.4-SNAPSHOT - - - 1.0.4-SNAPSHOT - - 20160409062112 - - diff --git a/spring-cloud-contract-verifier/pom.xml b/spring-cloud-contract-verifier/pom.xml deleted file mode 100644 index f1629fba72..0000000000 --- a/spring-cloud-contract-verifier/pom.xml +++ /dev/null @@ -1,344 +0,0 @@ - - - 4.0.0 - - 2.1.1 - - - org.springframework.cloud - spring-cloud-contract-parent - 4.1.0-SNAPSHOT - .. - - spring-cloud-contract-verifier - jar - Spring Cloud Contract Verifier - Spring Cloud Contract Verifier - - - org.springframework.cloud - spring-cloud-contract-spec - - - org.springframework.cloud - spring-cloud-contract-shade - - - org.springframework.boot - spring-boot-test-autoconfigure - - - com.fasterxml.jackson.core - jackson-databind - - - com.squareup.okhttp3 - okhttp - true - - - org.springframework - spring-messaging - true - - - org.springframework - spring-jms - true - - - org.springframework.kafka - spring-kafka - true - - - org.springframework.kafka - spring-kafka-test - true - - - org.slf4j - slf4j-log4j12 - - - - - jakarta.jms - jakarta.jms-api - true - - - org.apache.commons - commons-text - - - org.apache.camel.springboot - camel-spring-boot-starter - true - - - org.apache.camel - camel-spring - true - - - org.apache.camel - camel-core - true - - - org.apache.camel - camel-kafka - true - - - org.springframework.cloud - spring-cloud-stream - true - compile - - - org.springframework.cloud - spring-cloud-stream-test-binder - true - compile - - - org.springframework.amqp - spring-rabbit - true - - - javax.inject - javax.inject - - - com.github.tomakehurst - wiremock-jre8-standalone - - - com.toomuchcoding.jsonassert - jsonassert - - - org.apache.maven.resolver - maven-resolver-api - - - com.rackspace.eclipse.webtools.sourceediting - org.eclipse.wst.xml.xpath2.processor - - - org.apache.groovy - groovy - - - org.apache.groovy - groovy-nio - - - org.apache.groovy - groovy-json - - - org.apache.groovy - groovy-xml - - - org.skyscreamer - jsonassert - - - com.github.jknack - handlebars - - - commons-beanutils - commons-beanutils - ${commons-beanutils.version} - - - org.yaml - snakeyaml - - - com.fasterxml.jackson.dataformat - jackson-dataformat-yaml - - - org.springframework.boot - spring-boot-autoconfigure-processor - true - - - org.springframework.cloud - spring-cloud-test-support - test - - - cglib - cglib - test - - - org.spockframework - spock-core - test - - - org.springframework.boot - spring-boot-starter-test - - - org.junit.vintage - junit-vintage-engine - - - - - org.mockito - mockito-core - compile - - - net.javacrumbs.json-unit - json-unit-assertj - ${json-unit-assertj.version} - compile - - - org.slf4j - slf4j-simple - test - - - io.rest-assured - rest-assured - test - - - io.rest-assured - spring-mock-mvc - test - - - io.rest-assured - spring-web-test-client - test - - - org.springframework - spring-webflux - test - - - org.junit.jupiter - junit-jupiter-api - - - org.apache.groovy - groovy-testng - test - - - - org.mdkt.compiler - InMemoryJavaCompiler - ${InMemoryJavaCompiler.version} - test - - - jetty-ee10-servlet - org.eclipse.jetty.ee10 - test - - - jetty-ee10-servlet - org.eclipse.jetty.ee10 - test - - - jetty-ee10-servlets - org.eclipse.jetty.ee10 - test - - - javax.ws.rs-api - javax.ws.rs - ${javax.ws.rs-api.version} - test - - - xerces - xercesImpl - test - - - org.spockframework - spock-junit4 - test - - - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - - - - addSources - addTestSources - generateStubs - compile - generateTestStubs - compileTests - removeStubs - removeTestStubs - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - none:none - - - - org.codehaus.mojo - build-helper-maven-plugin - - - attach-zip - none - - - add-source - generate-test-sources - - add-test-source - - - - src/test/resources/contractsToCompile - - - - - - - - diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/BodyExtractor.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/BodyExtractor.groovy deleted file mode 100644 index 519d849d41..0000000000 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/BodyExtractor.groovy +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util - -import java.util.regex.Pattern - -import groovy.json.JsonOutput -import groovy.json.StringEscapeUtils -import groovy.transform.CompileStatic - -import org.springframework.cloud.contract.spec.internal.CanBeDynamic -import org.springframework.cloud.contract.spec.internal.DslProperty -import org.springframework.cloud.contract.spec.internal.FromFileProperty -import org.springframework.cloud.contract.spec.internal.RegexProperty - -import static ContentUtils.extractValue - -/** - * Class that constructs a String from a body. The body can be a GString - * or a map. - * - * @author Marcin Grzejszczak - * - * @since 1.0.0 - */ -@CompileStatic -class BodyExtractor { - - private BodyExtractor() {} - - /** - * @return the string representation of the body for the server side. - * That means that all the interpolations etc. will be resolved for the - * server side. - */ - static String extractTestValueFrom(Object body) { - Object bodyValue = extractServerValueFromBody(body) - String json = new JsonOutput().toJson(bodyValue) - json = StringEscapeUtils.unescapeJavaScript(json) - return trimRepeatedQuotes(json) - } - - /** - * @return the string representation of the body for the client side. - * That means that all the interpolations etc. will be resolved for the - * client side. - */ - static String extractStubValueFrom(Object body) { - Object bodyValue = extractClientValueFromBody(body) - String json = new JsonOutput().toJson(bodyValue) - json = StringEscapeUtils.unescapeJavaScript(json) - return trimRepeatedQuotes(json) - } - - private static String trimRepeatedQuotes(String toTrim) { - return toTrim.startsWith('"') ? toTrim.replaceAll('"', '') : toTrim - } - - static Object extractServerValueFromBody(bodyValue) { - if (bodyValue instanceof GString) { - bodyValue = - extractValue(bodyValue, { DslProperty dslProperty -> dslProperty.serverValue }) - } - else { - bodyValue = MapConverter.transformValues(bodyValue, { - it instanceof DslProperty ? it.serverValue : it - }) - } - return bodyValue - } - - static Object extractClientValueFromBody(bodyValue) { - if (bodyValue instanceof GString) { - return extractValue(bodyValue, { DslProperty dslProperty -> dslProperty.clientValue }) - } - else if (bodyValue instanceof DslProperty) { - return extractClientValueFromBody(bodyValue.clientValue) - } - else if (bodyValue instanceof FromFileProperty && bodyValue.isString()) { - return MapConverter.transformValues(bodyValue.asString(), Closure.IDENTITY) - } - else { - return MapConverter.transformValues(bodyValue, { - Object prop = it instanceof DslProperty ? it.clientValue : it - if (prop instanceof CanBeDynamic || prop instanceof Pattern) { - return new RegexProperty(prop).generateConcreteValue() - } - return prop - }) - } - } -} diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/ContentUtils.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/ContentUtils.groovy deleted file mode 100644 index 3c94859745..0000000000 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/ContentUtils.groovy +++ /dev/null @@ -1,697 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util - - -import java.util.function.Function -import java.util.regex.Matcher -import java.util.regex.Pattern - -import groovy.json.JsonException -import groovy.json.JsonOutput -import groovy.json.JsonSlurper -import groovy.transform.CompileStatic -import groovy.xml.XmlSlurper -import org.apache.commons.logging.Log -import org.apache.commons.logging.LogFactory -import org.codehaus.groovy.runtime.GStringImpl -import org.xml.sax.helpers.DefaultHandler - -import org.springframework.cloud.contract.spec.internal.DslProperty -import org.springframework.cloud.contract.spec.internal.ExecutionProperty -import org.springframework.cloud.contract.spec.internal.FromFileProperty -import org.springframework.cloud.contract.spec.internal.Header -import org.springframework.cloud.contract.spec.internal.Headers -import org.springframework.cloud.contract.spec.internal.MatchingStrategy -import org.springframework.cloud.contract.spec.internal.NamedProperty -import org.springframework.cloud.contract.spec.internal.OptionalProperty -import org.springframework.cloud.contract.verifier.template.HandlebarsTemplateProcessor -import org.springframework.util.StringUtils - -import static org.apache.commons.text.StringEscapeUtils.escapeJava -import static org.apache.commons.text.StringEscapeUtils.escapeJson -import static org.apache.commons.text.StringEscapeUtils.escapeXml11 -import static org.apache.commons.text.StringEscapeUtils.unescapeXml -import static org.springframework.cloud.contract.verifier.util.ContentType.DEFINED -import static org.springframework.cloud.contract.verifier.util.ContentType.JSON -import static org.springframework.cloud.contract.verifier.util.ContentType.UNKNOWN -import static org.springframework.cloud.contract.verifier.util.ContentType.XML - -/** - * A utility class that can operate on a message body basing on the provided Content Type. - * - * @author Marcin Grzejszczak - * @author Olga Maciaszek-Sharma - * @author Konstantin Shevchuk - * - * @since 1.0.0 - */ -@CompileStatic -class ContentUtils { - - private static final Log log = LogFactory.getLog(ContentUtils) - - public static final Closure GET_STUB_SIDE = { - it instanceof DslProperty ? it.clientValue : it - } - - public static final Closure GET_TEST_SIDE = { - it instanceof DslProperty ? it.serverValue : it - } - - public static final Function GET_STUB_SIDE_FUNCTION = new Function() { - @Override - Object apply(Object it) { - return it instanceof DslProperty ? it.clientValue : it - } - } - - public static final Function GET_TEST_SIDE_FUNCTION = new Function() { - @Override - Object apply(Object it) { - return it instanceof DslProperty ? it.serverValue : it - } - } - - private static final Pattern TEMPORARY_PATTERN_HOLDER = Pattern. - compile('.*REGEXP>>(.*)<<.*') - private static final Pattern TEMPORARY_EXECUTION_PATTERN_HOLDER = Pattern. - compile('["]?EXECUTION>>(.*)<<["]?') - private static final Pattern TEMPORARY_OPTIONAL_PATTERN_HOLDER = Pattern. - compile('OPTIONAL>>(.*)<<') - private static final String JSON_VALUE_PATTERN_FOR_REGEX = 'REGEXP>>%s<<' - private static final String JSON_VALUE_PATTERN_FOR_OPTIONAL = 'OPTIONAL>>%s<<' - private static final String JSON_VALUE_PATTERN_FOR_EXECUTION = '"EXECUTION>>%s<<"' - - /** - * Due to the fact that we allow users to have a body with GString and different values inside - * we need to be prepared that they pass regexps around both on client and server side. - * - * In order to preserve the original JSON structure we need to convert the passed Regex patterns - * to a temporary string, then convert all to a legitimate JSON structure and then finally - * convert it back from string to a pattern. - * - * @param bodyAsValue - GString with passed values - * @param valueProvider - provider of values either for server or client side - * @return JSON structure with replaced client / server side parts - */ - static Object extractValue(GString bodyAsValue, ContentType contentType, Closure valueProvider) { - if (!StringUtils.hasText(bodyAsValue.toString())) { - return bodyAsValue - } - if (contentType == ContentType.TEXT || contentType == ContentType.FORM) { - return extractValueForText(bodyAsValue, valueProvider) - } - if (JSON == contentType) { - return extractValueForJSON(bodyAsValue, valueProvider) - } - if (contentType == XML) { - return extractValueForXML(bodyAsValue, valueProvider) - } - // else Brute force :( - try { - log.trace("No content type provided so trying to parse as JSON") - return extractValueForJSON(bodyAsValue, valueProvider) - } - catch (JsonException e) { - // Not a JSON format - log.trace("Failed to parse as JSON - trying to parse as XML", e) - try { - return extractValueForXML(bodyAsValue, valueProvider) - } - catch (Exception exception) { - log.trace("No content type provided and failed to parse as XML - returning the value back to the user", exception) - return extractValueForGString(bodyAsValue, valueProvider) - } - } - } - - static Object extractValue(GString bodyAsValue, ContentType contentType, Function valueProvider) { - return extractValue(bodyAsValue, contentType, { valueProvider.apply(it) }) - } - - static ContentType getClientContentType(GString bodyAsValue) { - try { - extractValueForJSON(bodyAsValue, GET_STUB_SIDE) - return JSON - } - catch (JsonException e) { - try { - getXmlSlurperWithDefaultErrorHandler() - .parseText( - extractValueForXML(bodyAsValue, GET_STUB_SIDE).toString()) - return XML - } - catch (Exception ignored) { - extractValueForGString(bodyAsValue, GET_STUB_SIDE) - return UNKNOWN - } - } - } - - static ContentType getClientContentType(String bodyAsValue) { - try { - new JsonSlurper().parseText(bodyAsValue) - return JSON - } - catch (JsonException e) { - try { - getXmlSlurperWithDefaultErrorHandler() - .parseText(bodyAsValue) - return XML - } - catch (Exception ignored) { - return UNKNOWN - } - } - } - - static ContentType getClientContentType(Object bodyAsValue) { - if (bodyAsValue instanceof GString) { - return getClientContentType((GString) bodyAsValue) - } - else if (bodyAsValue instanceof String) { - return getClientContentType((String) bodyAsValue) - } - else if (bodyAsValue instanceof Map) { - return getClientContentType((Map) bodyAsValue) - } - else if (bodyAsValue instanceof List) { - return getClientContentType((List) bodyAsValue) - } - else if (bodyAsValue instanceof MatchingStrategy) { - return UNKNOWN - } - else if (bodyAsValue instanceof FromFileProperty) { - return UNKNOWN - } - return tryToGuessContentType(bodyAsValue) - } - - private static ContentType tryToGuessContentType(Object bodyAsValue) { - try { - if (log.isDebugEnabled()) { - log.debug("No content type passed, will try to guess the type of payload") - } - return getClientContentType(JsonOutput.toJson(bodyAsValue)) - } - catch (Exception ignored) { - if (log.isTraceEnabled()) { - log.trace("Failed to assume that body [" + bodyAsValue + "] is json") - } - } - return UNKNOWN - } - - static ContentType getClientContentType(Object bodyAsValue, Headers headers) { - ContentType contentType = recognizeContentTypeFromHeader(headers) - if (contentType == UNKNOWN) { - return getClientContentType(bodyAsValue) - } - return contentType - } - - static ContentType getClientContentType(Map bodyAsValue) { - try { - JsonOutput.toJson(bodyAsValue) - return JSON - } - catch (Exception ignore) { - return UNKNOWN - } - } - - static ContentType getClientContentType(List bodyAsValue) { - try { - JsonOutput.toJson(bodyAsValue) - return JSON - } - catch (Exception ignore) { - return UNKNOWN - } - } - - static GStringImpl extractValueForGString(GString bodyAsValue, Closure valueProvider) { - return new GStringImpl( - bodyAsValue.values.collect { - it instanceof DslProperty ? valueProvider(it) : it - } as String[], - CloneUtils.clone(bodyAsValue.strings) as String[] - ) - } - - static Object extractValue(GString bodyAsValue, Function valueProvider) { - return extractValue(bodyAsValue, UNKNOWN, { valueProvider.apply(it) }) - } - - static Object extractValue(GString bodyAsValue, Closure valueProvider) { - return extractValue(bodyAsValue, UNKNOWN, valueProvider) - } - - private static String extractValueForText(GString bodyAsValue, Closure valueProvider) { - GString transformedString = new GStringImpl( - bodyAsValue.values.collect { valueProvider(it) } as String[], - CloneUtils.clone(bodyAsValue.strings) as String[] - ) - return transformedString.toString() - } - - private static Object extractValueForJSON(GString bodyAsValue, Closure valueProvider) { - GString transformedString = new GStringImpl( - bodyAsValue.values. - collect { - transformJSONStringValue(it, valueProvider) - } as String[], - CloneUtils.clone(bodyAsValue.strings) as String[] - ) - def parsedJson = new JsonSlurper(). - parseText(transformedString.toString().replace('\\', '\\\\')) - return convertAllTemporaryRegexPlaceholdersBackToPatterns(parsedJson) - } - - private static GStringImpl extractValueForXML(GString bodyAsValue, Closure valueProvider) { - GStringImpl impl = new GStringImpl( - bodyAsValue.values. - collect { - transformXMLStringValue(it, valueProvider) - } as String[], - CloneUtils.clone(bodyAsValue.strings) as String[] - ) - // try to convert it to XML - getXmlSlurperWithDefaultErrorHandler() - .parseText(impl.toString()) - return impl - } - - protected static Object transformJSONStringValue(Object obj, Closure valueProvider) { - if (obj instanceof DslProperty) { - return transformJSONStringValue((DslProperty) obj, valueProvider) - } - else if (obj instanceof Pattern) { - return transformJSONStringValue((Pattern) obj, valueProvider) - } - else if (obj instanceof OptionalProperty) { - return transformJSONStringValue((OptionalProperty) obj, valueProvider) - } - else if (obj instanceof ExecutionProperty) { - return transformJSONStringValue((ExecutionProperty) obj, valueProvider) - } - return obj - } - - protected static Object transformJSONStringValue(DslProperty dslProperty, Closure valueProvider) { - return transformJSONStringValue(valueProvider(dslProperty), valueProvider) - } - - protected static Object transformJSONStringValue(Pattern pattern, Closure valueProvider) { - return String.format(JSON_VALUE_PATTERN_FOR_REGEX, pattern.pattern()) - } - - protected static Object transformJSONStringValue(OptionalProperty optional, Closure valueProvider) { - return String.format(JSON_VALUE_PATTERN_FOR_OPTIONAL, optional.value()) - } - - protected static Object transformJSONStringValue(ExecutionProperty property, Closure valueProvider) { - return String.format(JSON_VALUE_PATTERN_FOR_EXECUTION, property.executionCommand) - } - - private static String transformXMLStringValue(Object obj, Closure valueProvider) { - if (obj instanceof DslProperty) { - return transformJSONStringValue((DslProperty) obj, valueProvider) - } - return escapeXml11(unescapeXml(obj.toString())) - } - - private static String transformXMLStringValue(DslProperty dslProperty, Closure valueProvider) { - return transformXMLStringValue(valueProvider(dslProperty), valueProvider) - } - - protected static Object convertDslPropsToTemporaryRegexPatterns(Object parsedJson, - Closure parsingClosure = MapConverter.JSON_PARSING_CLOSURE) { - MapConverter.transformValues(parsedJson, { Object value -> - return transformJSONStringValue(value, GET_TEST_SIDE) - }, parsingClosure) - } - - private static Object convertAllTemporaryRegexPlaceholdersBackToPatterns(parsedJson) { - MapConverter.transformValues(parsedJson, { Object value -> - if (value instanceof String) { - String string = (String) value - return returnParsedObject(string) - } - return value - }) - } - - /** - *

- * If you wonder why there is val[1] without null-check then take a look at this: - *

- *

- * Example: - *

- *

- * Our string equals: {@code EXECUTION>>assertThatRejectionReasonIsNull($it)<<} - * The matcher matches this group with the pattern {@code EXECUTION>>(.*)<<} - *

- *

- * So {@code executionMatcher[0]} returns 2 elements: - *

    - *
  • index0: EXECUTION>>assertThatRejectionReasonIsNull($it)<<
  • - *
  • index1: assertThatRejectionReasonIsNull($it)<<
  • - *
- *

- *

- * Thus one can safely write {@code executionMatcher[0][1]} to retrieve the matched group - *

- * @param string to match the regexps against - * @return object converted from temporary holders - */ - static Object returnParsedObject(Object object) { - if (!(object instanceof String)) { - return object - } - String string = (String) object - Matcher matcher = TEMPORARY_PATTERN_HOLDER.matcher(string.trim()) - if (matcher.matches()) { - return Pattern.compile(patternFromMatchingGroup(matcher)) - } - Matcher executionMatcher = TEMPORARY_EXECUTION_PATTERN_HOLDER. - matcher(string.trim()) - if (executionMatcher.matches()) { - return new ExecutionProperty(patternFromMatchingGroup(executionMatcher)) - } - Matcher optionalMatcher = TEMPORARY_OPTIONAL_PATTERN_HOLDER.matcher(string.trim()) - if (optionalMatcher.matches()) { - String patternToMatch = patternFromMatchingGroup(optionalMatcher) - return Pattern.compile(new OptionalProperty(patternToMatch).optionalPattern()) - } - return string - } - - private static String patternFromMatchingGroup(Matcher matcher) { - List val = matcher[0] as List - return val[1] - } - - static ContentType recognizeContentTypeFromHeader(Headers headers, Closure closure) { - Header header = headers?.entries?.find { - it.name == "Content-Type" || - it.name == "contentType" - } - String content = closure(header)?.toString() - if (content?.contains("json")) { - return JSON - } - if (content?.contains("xml")) { - return XML - } - if (content?.contains("text")) { - return ContentType.TEXT - } - if (content?.contains("form-urlencoded")) { - return ContentType.FORM - } - if (content?.contains("octet-stream")) { - return UNKNOWN - } - if (content && isNotTemplate(content)) { - return DEFINED - } - return UNKNOWN - } - - static ContentType recognizeContentTypeFromHeader(Headers headers) { - return recognizeContentTypeFromHeader(headers, - { Header header -> header?.clientValue }) - } - - static ContentType recognizeContentTypeFromTestHeader(Headers headers) { - return recognizeContentTypeFromHeader(headers, - { Header header -> header?.serverValue }) - } - - static MatchingStrategy.Type getEqualsTypeFromContentType(ContentType contentType) { - switch (contentType) { - case JSON: - return MatchingStrategy.Type.EQUAL_TO_JSON - case XML: - return MatchingStrategy.Type.EQUAL_TO_XML - } - return MatchingStrategy.Type.EQUAL_TO - } - - static ContentType recognizeContentTypeFromContent(GString gstring) { - if (isJsonType(gstring)) { - return JSON - } - if (isXmlType(gstring)) { - return XML - } - return UNKNOWN - } - - static ContentType recognizeContentTypeFromContent(Map jsonMap) { - return JSON - } - - static ContentType recognizeContentTypeFromContent(byte[] bytes) { - return UNKNOWN - } - - static ContentType recognizeContentTypeFromContent(List jsonList) { - return JSON - } - - static ContentType recognizeContentTypeFromContent(String string) { - try { - new JsonSlurper().parseText(string) - return JSON - } - catch (Exception ignored) { - if (isXmlType("$string")) { - return XML - } - return UNKNOWN - } - } - - static ContentType recognizeContentTypeFromContent(Number number) { - return ContentType.TEXT - } - - static ContentType recognizeContentTypeFromContent(Object object) { - if (object instanceof FromFileProperty) { - FromFileProperty property = (FromFileProperty) object; - if (property.isJson()) { - return JSON - } else if (property.isXml()) { - return XML - } - object = object.isByte() ? object.asBytes() : object.asString() - } - if (object instanceof GString) { - return recognizeContentTypeFromContent((GString) object) - } - else if (object instanceof Map) { - return recognizeContentTypeFromContent((Map) object) - } - else if (object instanceof byte[]) { - return recognizeContentTypeFromContent((byte[]) object) - } - else if (object instanceof List) { - return recognizeContentTypeFromContent((List) object) - } - else if (object instanceof String) { - return recognizeContentTypeFromContent((String) object) - } - else if (object instanceof Number) { - return recognizeContentTypeFromContent((Number) object) - } - return UNKNOWN - } - - static boolean isJsonType(GString gstring) { - if (gstring.isEmpty()) { - return false - } - GString stringWithoutValues = new GStringImpl( - gstring.values.collect({ - it instanceof String || it instanceof GString ? it.toString() : - escapeJson(it.toString()) - }) as Object[], - CloneUtils.clone(gstring.strings) as String[] - ) - try { - new JsonSlurper().parseText(stringWithoutValues.toString()) - return true - } - catch (JsonException e) { - // Not JSON - } - return false - } - - static boolean isXmlType(GString gString) { - GString stringWithoutValues = new GStringImpl( - gString.values.collect({ - it instanceof String || it instanceof GString ? it.toString() : - escapeXml11(it.toString()) - }) as Object[], - CloneUtils.clone(gString.strings) as String[] - ) - try { - getXmlSlurperWithDefaultErrorHandler() - .parseText(stringWithoutValues.toString()) - return true - } - catch (Exception ignored) { - // Not XML - } - return false - } - - static ContentType recognizeContentTypeFromMatchingStrategy(MatchingStrategy.Type type) { - switch (type) { - case MatchingStrategy.Type.EQUAL_TO_XML: - return XML - case MatchingStrategy.Type.EQUAL_TO_JSON: - return JSON - } - return UNKNOWN - } - - static String getGroovyMultipartFileParameterContent(String propertyName, NamedProperty propertyValue, - Closure bytesFromFile) { - return "'$propertyName', ${namedPropertyName(propertyValue, "'")}, " + - "${groovyNamedPropertyValue(propertyValue, "'", bytesFromFile)}" + - namedContentTypeNameIfPresent(propertyValue, "'") - } - - static String getGroovyMultipartFileParameterContent(String propertyName, NamedProperty propertyValue, - Function bytesFromFile) { - return "'$propertyName', ${namedPropertyName(propertyValue, "'")}, " + - "${groovyNamedPropertyValue(propertyValue, "'", { FromFileProperty property -> bytesFromFile.apply(property) })}" + - namedContentTypeNameIfPresent(propertyValue, "'") - } - - static String getJavaMultipartFileParameterContent(String propertyName, NamedProperty propertyValue, - Function bytesFromFile) { - return getJavaMultipartFileParameterContent(propertyName, propertyValue, { FromFileProperty property -> bytesFromFile.apply(property) }) - } - - static String getJavaMultipartFileParameterContent(String propertyName, NamedProperty propertyValue, - Closure bytesFromFile) { - return """"${escapeJava(propertyName)}", ${ - namedPropertyName(propertyValue, '"') - }, """ + - """${ - javaNamedPropertyValue(propertyValue, '"', bytesFromFile) - }${ - namedContentTypeNameIfPresent(propertyValue, '"') - }""" - } - - static String namedPropertyName(NamedProperty property, String quote) { - return property.name.serverValue instanceof ExecutionProperty ? - property.name.serverValue.toString() : quote + - escapeJava(property.name.serverValue.toString()) + quote - } - - static String namedContentTypeNameIfPresent(NamedProperty property, String quote) { - if (!property.contentType) { - return "" - } - String contentType = property.contentType.serverValue instanceof ExecutionProperty ? - property.contentType.serverValue.toString() : quote + - escapeJava(property.contentType.serverValue.toString()) + quote - return ", " + contentType - } - - static String groovyNamedPropertyValue(NamedProperty property, String quote, Closure bytesFromFile) { - if (property.value.serverValue instanceof ExecutionProperty) { - return property.value.serverValue.toString() - } - else if (property.value.serverValue instanceof byte[]) { - byte[] bytes = (byte[]) property.value.serverValue - return "[" + bytes.collect { it }.join(", ") + "] as byte[]" - } - else if (property.value.serverValue instanceof FromFileProperty) { - FromFileProperty fromFileProperty = (FromFileProperty) property.value.serverValue - if (fromFileProperty.isByte()) { - return bytesFromFile(fromFileProperty) - } - return "[" + fromFileProperty.asBytes().collect { it }. - join(", ") + "] as byte[]" - } - return quote + - escapeJava(property.value.serverValue.toString()) + quote + ".bytes" - } - - static String javaNamedPropertyValue(NamedProperty property, String quote, Closure bytesFromFile) { - if (property.value.serverValue instanceof ExecutionProperty) { - return property.value.serverValue.toString() - } - else if (property.value.serverValue instanceof byte[]) { - byte[] bytes = (byte[]) property.value.serverValue - return "new byte[] {" + bytes.collect { it }.join(", ") + "}" - } - else if (property.value.serverValue instanceof FromFileProperty) { - FromFileProperty fromFileProperty = (FromFileProperty) property.value.serverValue - if (fromFileProperty.isByte()) { - return bytesFromFile(fromFileProperty) - } - return "new byte[] {" + fromFileProperty.asBytes().collect { it }. - join(", ") + "}" - } - return quote + - escapeJava(property.value.serverValue.toString()) + quote + ".getBytes()" - } - - static ContentType evaluateClientSideContentType(Headers contractHeaders, Object body) { - ContentType contentType = recognizeContentTypeFromHeader(contractHeaders) - if (UNKNOWN == contentType) { - contentType = recognizeContentTypeFromContent(body) - } - return contentType - } - - static ContentType evaluateServerSideContentType(Headers contractHeaders, Object body) { - ContentType contentType = recognizeContentTypeFromTestHeader(contractHeaders) - if (UNKNOWN == contentType) { - contentType = recognizeContentTypeFromContent(body) - } - return contentType - } - - /** - * Creates new {@link XmlSlurper} with default error handler. - * - * @return XmlSlurper with default error handler - */ - static XmlSlurper getXmlSlurperWithDefaultErrorHandler() { - XmlSlurper xmlSlurper = new XmlSlurper() - xmlSlurper.setErrorHandler(new DefaultHandler()) - return xmlSlurper - } - - private static boolean isNotTemplate(String content) { - return !new HandlebarsTemplateProcessor().containsTemplateEntry(content) - } - - -} diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/JsonToJsonPathsConverter.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/JsonToJsonPathsConverter.groovy deleted file mode 100644 index b7c3a3ba1b..0000000000 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/JsonToJsonPathsConverter.groovy +++ /dev/null @@ -1,634 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util - -import java.util.function.Function -import java.util.regex.Matcher -import java.util.regex.Pattern - -import com.jayway.jsonpath.DocumentContext -import com.jayway.jsonpath.JsonPath -import com.jayway.jsonpath.PathNotFoundException -import com.toomuchcoding.jsonassert.JsonAssertion -import groovy.json.JsonOutput -import groovy.transform.CompileStatic -import groovy.util.logging.Commons - -import org.springframework.cloud.contract.spec.internal.BodyMatcher -import org.springframework.cloud.contract.spec.internal.BodyMatchers -import org.springframework.cloud.contract.spec.internal.ExecutionProperty -import org.springframework.cloud.contract.spec.internal.MatchingType -import org.springframework.cloud.contract.spec.internal.OptionalProperty -import org.springframework.cloud.contract.spec.internal.RegexProperty -import org.springframework.util.SerializationUtils -/** - * I would like to apologize to anyone who is reading this class. Since JSON is a hectic structure - * this class is also hectic. The idea is to traverse the JSON structure and build a set of - * JSON Paths together with methods needed to be called to build them. - * - * @author Marcin Grzejszczak - * @author Tim Ysewyn - * @author Olga Maciaszek-Sharma - */ -@Commons -class JsonToJsonPathsConverter { - - /** - * In case of issues with size assertion just provide this property as system property - * equal to "false" and then size assertion will be disabled - */ - private static final String SIZE_ASSERTION_SYSTEM_PROP = "spring.cloud.contract.verifier.assert.size" - - private static final Boolean SERVER_SIDE = false - private static final Boolean CLIENT_SIDE = true - private static final Pattern ANY_ARRAY_NOTATION_IN_JSONPATH = ~/\[(.*?)\]/ - private static final String DESCENDANT_OPERATOR = ".." - - private final boolean assertJsonSize - - JsonToJsonPathsConverter(boolean assertJsonSize) { - this.assertJsonSize = assertJsonSize - } - - JsonToJsonPathsConverter() { - this(false) - if (log.isTraceEnabled()) { - log.trace("Creating JsonToJsonPaths converter with default properties") - } - } - - /** - * Removes from the parsed json any JSON path matching entries. - * That way we remain with values that should be checked in the auto-generated - * fashion. - * - * @param json - parsed JSON - * @param bodyMatchers - the part of request / response that contains matchers - * @return json with removed entries - */ - static def removeMatchingJsonPaths(def json, BodyMatchers bodyMatchers) { - def jsonCopy = cloneBody(json) - DocumentContext context = JsonPath.parse(jsonCopy) - if (bodyMatchers?.hasMatchers()) { - List pathsToDelete = [] - List paths = bodyMatchers.matchers().collect { it.path() } - paths.each { String path -> - try { - def entry = entry(context, path) - if (entry != null) { - context.delete(path) - pathsToDelete.add(path) - } - } - catch (RuntimeException e) { - if (log.isTraceEnabled()) { - log.trace("Exception occurred while trying to delete path [${matcher.path()}]", e) - } - } - } - pathsToDelete.sort(Collections.reverseOrder()) - pathsToDelete.each { - removeTrailingContainers(it, context) - } - } - return jsonCopy - } - - private static def entry(DocumentContext context, String path) { - try { - return context.read(path) - } - catch (Exception ex) { - if (log.isTraceEnabled()) { - log.trace("Exception occurred while trying to retrieve element via path [${path}]", ex) - } - return null - } - } - - /** - * Retrieves the value from JSON via json path - * - * @param json - parsed JSON - * @param jsonPath - json path - * @return matching part of the json - */ - static def readElement(def json, String jsonPath) { - DocumentContext context = JsonPath.parse(json) - return context.read(jsonPath) - } - - /** - * Related to #391 and #1091 and #1414. The converted body looks different when done via the String notation than - * it does when done via a map notation. When working with String body and when matchers - * are provided, even when all entries of a map / list got removed, the map / list itself - * remains. That leads to unnecessary creation of checks for empty collection. With this method - * we're checking if the JSON path matcher is related to array checking and we're trying to - * remove that trailing collection. All in all it's better to use the Groovy based notation for - * defining body... - */ - private static boolean removeTrailingContainers(String matcherPath, DocumentContext context) { - try { - Matcher matcher = ANY_ARRAY_NOTATION_IN_JSONPATH.matcher(matcherPath) - boolean containsArray = matcher.find() - String pathWithoutAnyArray = containsArray ? matcherPath. - substring(0, matcherPath.lastIndexOf(lastMatch(matcher))) : matcherPath - def object = entry(context, pathWithoutAnyArray) - // object got removed and it was the only element - // let's get its parent and see if it contains an empty element - if (isIterable(object) - && - containsOnlyEmptyElements(object) - && isNotRootArray(matcherPath)) { - String pathToDelete = pathToDelete(pathWithoutAnyArray) - if (pathToDelete.contains(DESCENDANT_OPERATOR)) { - Object root = context.read('$') - if (rootContainsEmptyContainers(root)) { - // now root contains only empty elements, we should remove the trailing containers - context.delete('$[*]') - return false - } - return false - } else { - context.delete(pathToDelete) - } - return removeTrailingContainers(pathToDelete, context) - } - else { - int lastIndexOfDot = matcherPath.lastIndexOf(".") - if (lastIndexOfDot == -1) { - return false - } - String lastParent = matcherPath.substring(0, lastIndexOfDot) - def lastParentObject = context.read(lastParent) - if (isIterable(lastParentObject) - && - containsOnlyEmptyElements(lastParentObject) - && isNotRoot(lastParent)) { - context.delete(lastParent) - return removeTrailingContainers(lastParent, context) - } - } - return false - } - catch (RuntimeException e) { - if (log.isTraceEnabled()) { - log.trace("Exception occurred while trying to delete path [${matcherPath}]", e) - } - return false - } - } - - private static boolean rootContainsEmptyContainers(root) { - root instanceof Iterable && root.every { containsOnlyEmptyElements(it) } - } - - private static String lastMatch(Matcher matcher) { - List matches = [] - while ({ - matches << matcher.group() - matcher.find() - }()) { - continue - } - return matches[matches.size() - 1] - } - - private static boolean isIterable(Object object) { - return object instanceof Iterable || object instanceof Map - } - - private static boolean isEmpty(Object object) { - return isIterable(object) && object instanceof Iterable ? object.isEmpty() : ((Map) object).isEmpty() - } - - private static String pathToDelete(String pathWithoutAnyArray) { - // we can't remove root - return pathWithoutAnyArray == '$' ? '$[*]' : pathWithoutAnyArray - } - - private static boolean isNotRoot(String path) { - // we can't remove root - return path != '$' - } - - private static boolean isNotRootArray(String path) { - // we can't remove root - return path != '$[*]' - } - - private static boolean containsOnlyEmptyElements(Object object) { - return object.every { - if (it instanceof Map) { - return it.isEmpty() - } - else if (it instanceof List) { - return it.isEmpty() - } - return false - } - } - - // Doing a clone doesn't work for nested lists... - private static Object cloneBody(Object object) { - byte[] serializedObject = SerializationUtils.serialize(object) - return SerializationUtils.deserialize(serializedObject) - } - - /** - * For the given matcher converts it into a JSON path - * that checks the regex pattern or equality - * - * @param bodyMatcher - * @return JSON path that checks the regex for its last element - */ - static String convertJsonPathAndRegexToAJsonPath(BodyMatcher bodyMatcher, def body = null) { - String path = bodyMatcher.path() - Object value = bodyMatcher.value() - if (value == null && bodyMatcher.matchingType() != MatchingType.EQUALITY - && - bodyMatcher.matchingType() != MatchingType.TYPE) { - return path - } - int lastIndexOfDot = lastIndexOfDot(path) - String fromLastDot = path.substring(lastIndexOfDot + 1) - String toLastDot = lastIndexOfDot == -1 ? '$' : path.substring(0, lastIndexOfDot) - String propertyName = lastIndexOfDot == -1 ? '@' : "@.${fromLastDot}" - String comparison = createComparison(propertyName, bodyMatcher, value, body) - return "${toLastDot}[?(${comparison})]" - } - - private static int lastIndexOfDot(String path) { - if (pathContainsDotSeparatedKey(path)) { - int lastIndexOfBracket = path.lastIndexOf("['") - return path.substring(0, lastIndexOfBracket).lastIndexOf(".") - } - return path.lastIndexOf(".") - } - - private static boolean pathContainsDotSeparatedKey(String path) { - return path.contains("['") - } - - - @CompileStatic - static Object generatedValueIfNeeded(Object value) { - if (value instanceof RegexProperty) { - return ((RegexProperty) value).generateAndEscapeJavaStringIfNeeded() - } - return value - } - - private static String createComparison(String propertyName, BodyMatcher bodyMatcher, Object value, def body) { - if (bodyMatcher.matchingType() == MatchingType.EQUALITY) { - Object convertedBody = body - if (!body) { - throw new IllegalStateException("Body hasn't been passed") - } - try { - convertedBody = MapConverter.transformValues(body) { - return generatedValueIfNeeded(it) - } - Object retrievedValue = JsonPath.parse(convertedBody). - read(bodyMatcher.path()) - String wrappedValue = retrievedValue instanceof Number ? retrievedValue : "'${retrievedValue.toString()}'" - return "${propertyName} == ${wrappedValue}" - } - catch (PathNotFoundException e) { - throw new IllegalStateException("Value [${bodyMatcher.path()}] not found in JSON [${JsonOutput.toJson(convertedBody)}]", e) - } - } - else if (bodyMatcher.matchingType() == MatchingType.TYPE) { - Integer min = bodyMatcher.minTypeOccurrence() - Integer max = bodyMatcher.maxTypeOccurrence() - String result = "" - if (min != null) { - result = "${propertyName}.size() >= ${min}" - } - if (max != null) { - String maxResult = "${propertyName}.size() <= ${max}" - result = result ? "${result} && ${maxResult}" : maxResult - } - return result - } - else { - String convertedValue = value.toString().replace('/', '\\\\/') - return "${propertyName} =~ /(${convertedValue})/" - } - } - - JsonPaths transformToJsonPathWithTestsSideValues(def json, Function parsingClosure, boolean includeEmptyCheck) { - return transformToJsonPathWithValues(json, SERVER_SIDE, { parsingClosure.apply(it) }, includeEmptyCheck) - } - - JsonPaths transformToJsonPathWithTestsSideValues(def json, - Closure parsingClosure = MapConverter.JSON_PARSING_CLOSURE, - boolean includeEmptyCheck = false) { - return transformToJsonPathWithValues(json, SERVER_SIDE, parsingClosure, includeEmptyCheck) - } - - JsonPaths transformToJsonPathWithStubsSideValues(def json, - Closure parsingClosure = MapConverter.JSON_PARSING_CLOSURE, - boolean includeEmptyCheck = false) { - return transformToJsonPathWithValues(json, CLIENT_SIDE, parsingClosure, includeEmptyCheck) - } - - static JsonPaths transformToJsonPathWithStubsSideValuesAndNoArraySizeCheck(def json, - Closure parsingClosure = MapConverter.JSON_PARSING_CLOSURE) { - return new JsonToJsonPathsConverter() - .transformToJsonPathWithValues(json, CLIENT_SIDE, parsingClosure) - } - - private JsonPaths transformToJsonPathWithValues(def json, boolean clientSide, - Closure parsingClosure = MapConverter.JSON_PARSING_CLOSURE, - boolean includeEmptyCheck = false) { - if (json == null || (!json && !includeEmptyCheck)) { - return new JsonPaths() - } - Object convertedJson = MapConverter. - getClientOrServerSideValues(json, clientSide, parsingClosure) - Object jsonWithPatterns = ContentUtils. - convertDslPropsToTemporaryRegexPatterns(convertedJson, parsingClosure) - MethodBufferingJsonVerifiable methodBufferingJsonPathVerifiable = - new DelegatingJsonVerifiable(JsonAssertion. - assertThat(JsonOutput.toJson(jsonWithPatterns)) - .withoutThrowingException()) - JsonPaths pathsAndValues = [] as Set - if (isRootElement(methodBufferingJsonPathVerifiable) && !json) { - pathsAndValues.add(methodBufferingJsonPathVerifiable.isEmpty()) - return pathsAndValues - } - traverseRecursivelyForKey(jsonWithPatterns, methodBufferingJsonPathVerifiable, - { MethodBufferingJsonVerifiable key, Object value -> - if (value instanceof ExecutionProperty || !(key instanceof FinishedDelegatingJsonVerifiable)) { - return - } - pathsAndValues.add(key) - }, parsingClosure) - return pathsAndValues - } - - protected def traverseRecursively(Class parentType, MethodBufferingJsonVerifiable key, def value, - Closure closure, Closure parsingClosure = MapConverter.JSON_PARSING_CLOSURE) { - value = ContentUtils.returnParsedObject(value) - if (value instanceof String && value) { - try { - def json = parsingClosure(value) - if (json instanceof Map) { - return convertWithKey(parentType, key, json, closure, parsingClosure) - } - } - catch (Exception ignore) { - return runClosure(closure, key, value) - } - } - else if (isAnEntryWithNonCollectionLikeValue(value)) { - return convertWithKey(List, key, value as Map, closure, parsingClosure) - } - else if (isAnEntryWithoutNestedStructures(value)) { - return convertWithKey(List, key, value as Map, closure, parsingClosure) - } - else if (value instanceof Map && !value.isEmpty()) { - return convertWithKey(Map, key, value as Map, closure, parsingClosure) - } - else if (value instanceof Map && value.isEmpty()) { - return runClosure(closure, key.isEmpty(), value) - // JSON with a list of primitives ["a", "b", "c"] in root issue #266 - } - else if (key.isIteratingOverNamelessArray() && value instanceof List - && - listContainsOnlyPrimitives(value)) { - addSizeVerificationForListWithPrimitives(key, closure, value) - value.each { - traverseRecursively(Object, key.arrayField(). - contains(ContentUtils.returnParsedObject(it)), - ContentUtils.returnParsedObject(it), closure, parsingClosure) - } - // JSON containing list of primitives { "partners":[ { "role":"AGENT", "payment_methods":[ "BANK", "CASH" ] } ] - } - else if (value instanceof List && listContainsOnlyPrimitives(value)) { - addSizeVerificationForListWithPrimitives(key, closure, value) - value.each { - traverseRecursively(Object, - valueToAsserter(key.arrayField(), ContentUtils. - returnParsedObject(it)), - ContentUtils.returnParsedObject(it), closure, parsingClosure) - } - } - else if (value instanceof List && !value.empty) { - MethodBufferingJsonVerifiable jsonPathVerifiable = - createAsserterFromList(key, value) - addSizeVerificationForListWithPrimitives(key, closure, value) - value.each { def element -> - traverseRecursively(List, - createAsserterFromListElement(jsonPathVerifiable, ContentUtils. - returnParsedObject(element)), - ContentUtils.returnParsedObject(element), closure, parsingClosure) - } - return value - } - else if (value instanceof List && value.empty) { - return runClosure(closure, key, value) - } - else if (key.isIteratingOverArray()) { - traverseRecursively(Object, key.arrayField(). - contains(ContentUtils.returnParsedObject(value)), - ContentUtils.returnParsedObject(value), closure, parsingClosure) - } - try { - return runClosure(closure, key, value) - } - catch (Exception ignore) { - return value - } - } - - // Size verification: https://github.com/Codearte/accurest/issues/279 - private void addSizeVerificationForListWithPrimitives(MethodBufferingJsonVerifiable key, Closure closure, List value) { - String systemPropValue = System.getProperty(SIZE_ASSERTION_SYSTEM_PROP) - Boolean configPropValue = assertJsonSize - if ((systemPropValue != null && Boolean.parseBoolean(systemPropValue)) - || - configPropValue && listContainsOnlyPrimitives(value)) { - addArraySizeCheck(key, value, closure) - } - else { - if (log.isTraceEnabled()) { - log.trace("Turning off the incubating feature of JSON array check. " - + - "System property [$systemPropValue]. Config property [$configPropValue]") - } - return - } - } - - private void addArraySizeCheck(MethodBufferingJsonVerifiable key, List value, Closure closure) { - if (log.isDebugEnabled()) { - log.debug("WARNING: Turning on the incubating feature of JSON array check") - } - if (isRootElement(key) || key.assertsConcreteValue()) { - if (value.size() > 0) { - closure(key.hasSize(value.size()), value) - } - } - } - - private boolean isRootElement(MethodBufferingJsonVerifiable key) { - return key.jsonPath() == '$' - } - - // If you have a list of not-only primitives it can contain different sets of elements (maps, lists, primitives) - private MethodBufferingJsonVerifiable createAsserterFromList(MethodBufferingJsonVerifiable key, List value) { - if (key.isIteratingOverNamelessArray()) { - return key.array() - } - else if (key.isIteratingOverArray() && isAnEntryWithLists(value)) { - if (!value.every { listContainsOnlyPrimitives(it as List) }) { - return key.array() - } - else { - return key.iterationPassingArray() - } - } - else if (key.isIteratingOverArray()) { - return key.iterationPassingArray() - } - return key - } - - private MethodBufferingJsonVerifiable createAsserterFromListElement(MethodBufferingJsonVerifiable jsonPathVerifiable, def element) { - if (jsonPathVerifiable.isAssertingAValueInArray()) { - def object = ContentUtils.returnParsedObject(element) - if (object instanceof Pattern) { - return jsonPathVerifiable.matches((object as Pattern).pattern()) - } - return jsonPathVerifiable.contains(object) - } - else if (element instanceof List) { - if (listContainsOnlyPrimitives(element)) { - return jsonPathVerifiable.array() - } - } - return jsonPathVerifiable - } - - private def runClosure(Closure closure, MethodBufferingJsonVerifiable key, def value) { - if (key. - isAssertingAValueInArray() - && !(value instanceof List || value instanceof Map)) { - return closure(valueToAsserter(key, value), value) - } - return closure(key, value) - } - - private boolean isAnEntryWithNonCollectionLikeValue(def value) { - if (!(value instanceof Map)) { - return false - } - Map valueAsMap = ((Map) value) - boolean mapHasOneEntry = valueAsMap.size() == 1 - if (!mapHasOneEntry) { - return false - } - Object valueOfEntry = valueAsMap.entrySet().first().value - return !(valueOfEntry instanceof Map || valueOfEntry instanceof List) - } - - private boolean isAnEntryWithoutNestedStructures(def value) { - if (!(value instanceof Map)) { - return false - } - Map valueAsMap = ((Map) value) - if (valueAsMap.isEmpty()) { - return false - } - return valueAsMap.entrySet().every { Map.Entry entry -> - [String, Number, Boolean].any { it.isAssignableFrom(entry.value.getClass()) } - } - } - - private boolean listContainsOnlyPrimitives(List list) { - if (list.empty) { - return false - } - return list.every { def element -> - [String, Number, Boolean].any { - it.isAssignableFrom(element.getClass()) - } - } - } - - private boolean isAnEntryWithLists(def value) { - if (!(value instanceof Iterable)) { - return false - } - return value.every { def entry -> - entry instanceof List - } - } - - private Map convertWithKey(Class parentType, MethodBufferingJsonVerifiable parentKey, Map map, - Closure closureToExecute, Closure parsingClosure) { - return map.collectEntries { - Object entrykey, value -> - def convertedValue = ContentUtils.returnParsedObject(value) - [entrykey, traverseRecursively(parentType, - convertedValue instanceof List ? - list(convertedValue, entrykey, parentKey) : - convertedValue instanceof Map ? parentKey. - field(new ShouldTraverse(entrykey)) : - valueToAsserter(parentKey.field(entrykey), convertedValue) - , convertedValue, closureToExecute, parsingClosure)] - } - } - - protected MethodBufferingJsonVerifiable list(List convertedValue, Object entrykey, MethodBufferingJsonVerifiable parentKey) { - if (convertedValue.empty) { - return parentKey.array(entrykey).isEmpty() - } - return listContainsOnlyPrimitives(convertedValue) ? - parentKey.arrayField(entrykey) : - parentKey.array(entrykey) - } - - private void traverseRecursivelyForKey(def json, MethodBufferingJsonVerifiable rootKey, - Closure closure, Closure parsingClosure = MapConverter.JSON_PARSING_CLOSURE) { - traverseRecursively(Map, rootKey, json, closure, parsingClosure) - } - - protected MethodBufferingJsonVerifiable valueToAsserter(MethodBufferingJsonVerifiable key, Object value) { - def convertedValue = ContentUtils.returnParsedObject(value) - if (key instanceof FinishedDelegatingJsonVerifiable) { - return key - } - if (convertedValue instanceof Pattern) { - return key.matches((convertedValue as Pattern).pattern()) - } - else if (convertedValue instanceof OptionalProperty) { - return key.matches((convertedValue as OptionalProperty).optionalPattern()) - } - else if (convertedValue instanceof GString) { - return key. - matches(RegexpBuilders.buildGStringRegexpForTestSide(convertedValue)) - } - else if (convertedValue instanceof ExecutionProperty) { - return key - } - return key.isEqualTo(convertedValue) - } - -} diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/xml/XmlToXPathsConverter.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/xml/XmlToXPathsConverter.groovy deleted file mode 100644 index 9c1bb2392f..0000000000 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/xml/XmlToXPathsConverter.groovy +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Copyright 2018-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util.xml - -import java.util.stream.IntStream - -import javax.xml.parsers.DocumentBuilder -import javax.xml.parsers.DocumentBuilderFactory -import javax.xml.transform.Transformer -import javax.xml.transform.TransformerFactory -import javax.xml.transform.dom.DOMSource -import javax.xml.transform.stream.StreamResult -import javax.xml.xpath.XPath -import javax.xml.xpath.XPathFactory - -import groovy.transform.CompileDynamic -import org.w3c.dom.Attr -import org.w3c.dom.Document -import org.w3c.dom.NamedNodeMap -import org.w3c.dom.Node -import org.w3c.dom.NodeList -import org.xml.sax.InputSource - -import org.springframework.cloud.contract.spec.internal.BodyMatcher -import org.springframework.cloud.contract.spec.internal.BodyMatchers -import org.springframework.cloud.contract.spec.internal.MatchingType -import org.springframework.cloud.contract.spec.internal.MatchingTypeValue -import org.springframework.cloud.contract.spec.internal.PathBodyMatcher - -import static java.util.stream.Collectors.toList -import static javax.xml.xpath.XPathConstants.NODESET -import static org.apache.commons.lang3.StringUtils.isBlank -import static org.w3c.dom.Node.ATTRIBUTE_NODE -import static org.w3c.dom.Node.CDATA_SECTION_NODE -import static org.w3c.dom.Node.COMMENT_NODE -import static org.w3c.dom.Node.DOCUMENT_NODE -import static org.w3c.dom.Node.DOCUMENT_TYPE_NODE -import static org.w3c.dom.Node.NOTATION_NODE -import static org.w3c.dom.Node.PROCESSING_INSTRUCTION_NODE -import static org.w3c.dom.Node.TEXT_NODE -/** - * @author Olga Maciaszek-Sharma - * @author Chris Bono - * @since 2.1.0 - */ -class XmlToXPathsConverter { - - static Object removeMatchingXPaths(Object body, BodyMatchers bodyMatchers) { - XPath xPath = XPathFactory.newInstance().newXPath() - DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance() - builderFactory.setNamespaceAware(true) - DocumentBuilder documentBuilder = builderFactory - .newDocumentBuilder() - Document parsedXml = documentBuilder - .parse(new InputSource(new StringReader(body as String))) - xPath.setNamespaceContext(new DOMNamespaceContext(parsedXml.documentElement)) - bodyMatchers?.matchers()?.each({ - NodeList nodes = xPath.evaluate(it.path(), parsedXml.documentElement, NODESET) as NodeList - nodes.each {removeNode(it)} - }) - parsedXml.normalizeDocument() - return xmlToString(parsedXml) - } - - static String retrieveValue(BodyMatcher matcher, Object body) { - if (matcher.matchingType() == MatchingType.EQUALITY || !matcher.value()) { - return retrieveValueFromBody(matcher.path(), body) - } - return matcher.value() - } - - static String retrieveValueFromBody(String path, Object body) { - return getNodeValue(path, body) - } - - private static String getNodeValue(String path, Object body) { - XPath xPath = XPathFactory.newInstance().newXPath() - DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance() - builderFactory.setNamespaceAware(true) - DocumentBuilder documentBuilder = builderFactory - .newDocumentBuilder() - Document parsedXml = documentBuilder. - parse(new InputSource(new StringReader(body as String))) - xPath.setNamespaceContext(new DOMNamespaceContext(parsedXml.documentElement)) - return xPath.evaluate(path, parsedXml.documentElement) - } - - private static void removeNode(Node node) { - Optional.ofNullable(node).ifPresent() { - if (isValueNode(node as Node)) { - node.getParentNode().removeChild(node) - } - else { - removeNode(node.getParentNode()) - } - } - } - - private static boolean isValueNode(Node node) { - return [TEXT_NODE, - CDATA_SECTION_NODE, - COMMENT_NODE, - DOCUMENT_TYPE_NODE, - PROCESSING_INSTRUCTION_NODE, - NOTATION_NODE].contains(node.nodeType) - } - - private static boolean isAttributeNode(Node node) { - return ATTRIBUTE_NODE == node.nodeType - } - - private static String xmlToString(Node parsedXml) { - Transformer transformer = TransformerFactory.newInstance().newTransformer() - StringWriter writer = new StringWriter() - StreamResult result = new StreamResult(writer) - transformer.transform(new DOMSource(parsedXml), result) - return writer.toString() - } - - static List mapToMatchers(Object xml) { - DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance() - builderFactory.setNamespaceAware(true) - DocumentBuilder documentBuilder = builderFactory.newDocumentBuilder() - Document parsedXml = documentBuilder.parse(new InputSource(new StringReader(xml as String))) - List> valueNodes = getValueNodesWithParents(parsedXml) - List matchers = [] - List valueNodePaths = transformListEntries(valueNodes) - valueNodePaths.findAll{ !isPathToDefaultXmlnsAttributeNode(it) }.each { - matchers << new PathBodyMatcher( - buildXPath(it.fromChildToParents(), it.index), - new MatchingTypeValue(MatchingType.EQUALITY, it.path.get(0).nodeValue)) - } - return matchers - } - - static boolean isPathToDefaultXmlnsAttributeNode(NodePath nodePath) { - Node node = nodePath?.path?.first() - return node && isAttributeNode(node) && node.getNodeName() == 'xmlns' - } - - static List transformListEntries(List> nodeLists) { - List pathOccurrenceCounters = [] - List nodePaths = [] - nodeLists.each { nodeList -> - List parentNodesList = nodeList.subList(1, nodeList.size()) - int elementIndex = pathOccurrenceCounters.stream() - .map({ it }) - .filter({ - nodeNames(it.path) == nodeNames(parentNodesList) - }).findFirst() - .map({ ++it.counter }) - .orElseGet({ - PathOccurrenceCounter pathCounter = new PathOccurrenceCounter(parentNodesList) - pathOccurrenceCounters << pathCounter - return pathCounter.counter - }) - nodePaths << new NodePath(nodeList, elementIndex) - } - return nodePaths - } - - private static List nodeNames(List nodes) { - return nodes.stream() - .map({ it.getNodeName() }) - .collect(toList()) - } - - static String buildXPath(List nodes, int index = 1) { - XmlVerifiable xmlVerifiable = XPathBuilder.builder() - if (!nodes) { - return xmlVerifiable.xPath() - } - nodes.subList(0, nodes.size() - 1).each { - xmlVerifiable = processNode(xmlVerifiable, it) - } - Node closingNode = nodes.get(nodes.size() - 1) - xmlVerifiable = processClosingNode(xmlVerifiable, closingNode, index) - return xmlVerifiable.xPath() - } - - private static XmlVerifiable processNode(XmlVerifiable xmlVerifiable, Node node) { - // If node has explicit namespace (eg '') no special processing needed - if (nodeUsesExplicitNamespace(node)) { - return xmlVerifiable.node(node.nodeName) - } - // If node directly declares default ns (eg. 'xmlns=') then use local name and namespace uri syntax - String defaultXmlns = getDefaultXmlnsDeclarationOnNodeIfExists(node) - if (defaultXmlns != null) { - return xmlVerifiable.nodeWithDefaultNamespace(node.nodeName, defaultXmlns) - } - // If node indirectly declares (via ancestor) default ns then use local name syntax - if (getDefaultXmlnsDeclarationOnAncestorsIfExists(node) != null) { - return xmlVerifiable.nodeWithDefaultNamespace(node.nodeName, null) - } - return xmlVerifiable.node(node.nodeName) - } - - private static boolean nodeUsesExplicitNamespace(Node node) { - return node?.getNodeName()?.contains(":") - } - - private static String getDefaultXmlnsDeclarationOnNodeIfExists(Node node) { - return node?.getAttributes()?.getNamedItem("xmlns")?.getTextContent() - } - - private static String getDefaultXmlnsDeclarationOnAncestorsIfExists(Node node) { - while ((node = node?.getParentNode()) != null) { - String defaultXmlns = getDefaultXmlnsDeclarationOnNodeIfExists(node) - if (defaultXmlns != null) { - return defaultXmlns - } - } - return null - } - - private static XmlVerifiable processNode(XmlVerifiable xmlVerifiable, Attr attribute) { - return xmlVerifiable.withAttribute(attribute.nodeName) - } - - private static XmlVerifiable processClosingNode(XmlVerifiable xmlVerifiable, Node node, int index) { - return index != 1 ? xmlVerifiable.index(index).text() : xmlVerifiable.text() - } - - private static XmlVerifiable processClosingNode(XmlVerifiable xmlVerifiable, Attr attribute, int index) { - if (index != 1) { - xmlVerifiable.index(index) - } - return processNode(xmlVerifiable, attribute) - } - - private static List> getValueNodesWithParents(Node node) { - List> valueNodes = [] - List attributes = [] - addValueNodes(node, valueNodes, attributes) - attributes.each { - valueNodes << withParents(it) - } - return valueNodes - } - - private static List addValueNodes(Node node, List> valueNodes, List attributes) { - getChildNodesAsList(node).each { - attributes.addAll(getAttributesAsList(it)) - if (isValueNode(it) && !isBlank(it.nodeValue)) { - valueNodes << withParents(it) - } - else { - addValueNodes(it, valueNodes, attributes) - } - } - } - - private static List getChildNodesAsList(Node node) { - NodeList nodeList = node.getChildNodes() - return getNodeCollectionElements(nodeList) - } - - @CompileDynamic - private static List getAttributesAsList(Node node) { - NamedNodeMap nodeMap = node.getAttributes() - return nodeMap != null ? getNodeCollectionElements(nodeMap) : [] - } - - @CompileDynamic - private static List getNodeCollectionElements(def nodeCollection) { - return IntStream.range(0, nodeCollection.getLength()) - .mapToObj({ nodeCollection.item(it) as Node }) - .collect(toList()) - } - - private static List withParents(Node node) { - List nodeList = new ArrayList<>() - nodeList << node - return addParents(node, nodeList) - } - - private static List withParents(Attr attribute) { - List nodeList = new ArrayList<>() - nodeList << attribute - Node ownerNode = attribute.getOwnerElement() - nodeList << ownerNode - return addParents(ownerNode, nodeList) - } - - private static List addParents(Node node, List nodeList) { - Node parentNode = node.getParentNode() - if (parentNode != null && DOCUMENT_NODE != parentNode.nodeType) { - nodeList << parentNode - return addParents(parentNode, nodeList) - } - return nodeList - } - - private static class NodePath { - final List path - final int index - - NodePath(List path, int index) { - this.path = path - this.index = index - } - - List fromChildToParents() { - return path.reverse() - } - } - - private static class PathOccurrenceCounter { - final List path - int counter - - PathOccurrenceCounter(List path) { - this.path = path - counter = 1 - } - } -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/FileSaver.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/FileSaver.java deleted file mode 100644 index cdc0b2f11b..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/FileSaver.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import static java.nio.file.StandardOpenOption.CREATE; -import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; -import static org.springframework.cloud.contract.verifier.util.NamesUtil.beforeLast; -import static org.springframework.cloud.contract.verifier.util.NamesUtil.capitalize; -import static org.springframework.cloud.contract.verifier.util.NamesUtil.packageToDirectory; - -class FileSaver { - - private static final Logger log = LoggerFactory.getLogger(FileSaver.class); - - private final File targetDirectory; - - private final String fileExtension; - - FileSaver(File targetDirectory, String fileExtension) { - this.targetDirectory = targetDirectory; - this.fileExtension = fileExtension; - } - - public void saveClassFile(Path classPath, byte[] classBytes) { - log.info("Creating new class file [{}]", classPath); - try { - Files.write(classPath, classBytes, CREATE, TRUNCATE_EXISTING); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - - protected Path pathToClass(Path testBaseDir, String fileName) { - return Paths.get(testBaseDir.toString(), capitalize(fileName) + fileExtension).toAbsolutePath(); - } - - protected Path generateTestBaseDir(String basePackageClass, String includedDirectoryRelativePath) { - Path testBaseDir = Paths.get(targetDirectory.getAbsolutePath(), packageToDirectory(basePackageClass), - beforeLast(includedDirectoryRelativePath, File.separator)); - try { - Files.createDirectories(testBaseDir); - } - catch (IOException e) { - throw new RuntimeException(e); - } - return testBaseDir; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/TestGenerator.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/TestGenerator.java deleted file mode 100755 index 45082ebe64..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/TestGenerator.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier; - -import java.io.File; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; - -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.cloud.contract.spec.ContractVerifierException; -import org.springframework.cloud.contract.verifier.builder.JavaTestGenerator; -import org.springframework.cloud.contract.verifier.builder.SingleTestGenerator; -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties; -import org.springframework.cloud.contract.verifier.file.ContractFileScanner; -import org.springframework.cloud.contract.verifier.file.ContractMetadata; -import org.springframework.core.io.support.SpringFactoriesLoader; -import org.springframework.util.MultiValueMap; - -import static org.springframework.cloud.contract.verifier.util.NamesUtil.afterLast; -import static org.springframework.cloud.contract.verifier.util.NamesUtil.beforeLast; -import static org.springframework.cloud.contract.verifier.util.NamesUtil.convertIllegalPackageChars; -import static org.springframework.cloud.contract.verifier.util.NamesUtil.directoryToPackage; -import static org.springframework.cloud.contract.verifier.util.NamesUtil.recrusiveDirectoryToPackage; -import static org.springframework.cloud.contract.verifier.util.NamesUtil.toLastDot; - -/** - * @author Jakub Kubrynski, codearte.io - */ -public class TestGenerator { - - private static final Logger log = LoggerFactory.getLogger(TestGenerator.class); - - private static final String DEFAULT_CLASS_PREFIX = "ContractVerifier"; - - private static final String DEFAULT_TEST_PACKAGE = "org.springframework.cloud.contract.verifier.tests"; - - private final ContractVerifierConfigProperties configProperties; - - private final AtomicInteger counter = new AtomicInteger(); - - private final SingleTestGenerator generator; - - private final FileSaver saver; - - private final ContractFileScanner contractFileScanner; - - public TestGenerator(ContractVerifierConfigProperties configProperties) { - this(configProperties, singleTestGenerator(), new FileSaver(configProperties.getGeneratedTestSourcesDir(), - configProperties.getTestFramework().getClassExtension())); - } - - private static SingleTestGenerator singleTestGenerator() { - List factories = SpringFactoriesLoader.loadFactories(SingleTestGenerator.class, null); - if (factories.isEmpty()) { - return new JavaTestGenerator(); - } - return factories.get(0); - } - - public TestGenerator(ContractVerifierConfigProperties configProperties, SingleTestGenerator generator, - FileSaver saver) { - this(configProperties, generator, saver, ContractFileScanner.builder() - .baseDir(configProperties.getContractsDslDir()).excluded(toSet(configProperties.getExcludedFiles())) - .ignored(toSet(configProperties.getIgnoredFiles())).included(toSet(configProperties.getIncludedFiles())) - .includeMatcher(configProperties.getIncludedContracts()).build()); - } - - private static Set toSet(List files) { - return Optional.ofNullable(files).map(HashSet::new).orElseGet(HashSet::new); - } - - protected TestGenerator(ContractVerifierConfigProperties configProperties, SingleTestGenerator generator, - FileSaver saver, ContractFileScanner contractFileScanner) { - this.configProperties = configProperties; - if (configProperties.getContractsDslDir() == null) { - throw new ContractVerifierException( - "Stubs directory not found under " + configProperties.getContractsDslDir()); - } - - this.generator = generator; - this.saver = saver; - this.contractFileScanner = contractFileScanner; - } - - public int generate() { - generateTestClasses(basePackageName()); - recrusiveDirectoryToPackage(configProperties.getGeneratedTestSourcesDir()); - recrusiveDirectoryToPackage(configProperties.getGeneratedTestResourcesDir()); - return counter.get(); - } - - private String basePackageName() { - if (StringUtils.isNotEmpty(configProperties.getBasePackageForTests())) { - return configProperties.getBasePackageForTests(); - } - else if (StringUtils.isNotEmpty(configProperties.getBaseClassForTests())) { - return toLastDot(configProperties.getBaseClassForTests()); - } - else if (StringUtils.isNotEmpty(configProperties.getPackageWithBaseClasses())) { - return configProperties.getPackageWithBaseClasses(); - } - return DEFAULT_TEST_PACKAGE; - } - - void generateTestClasses(final String basePackageName) { - MultiValueMap contracts = contractFileScanner.findContractsRecursively(); - log.debug("Found the following contracts {}", contracts.keySet()); - - Set>> inProgress = inProgress(contracts); - if (!inProgress.isEmpty() && configProperties.isFailOnInProgress()) { - String inProgressContractsPaths = inProgress.stream().map(Map.Entry::getKey).map(Path::toString) - .collect(Collectors.joining(",")); - throw new IllegalStateException("In progress contracts found in paths [" + inProgressContractsPaths - + "] and the switch [failOnInProgress] is set to [true]. Either unmark those contracts as in progress, or set the switch to [false]."); - } - processAll(contracts, basePackageName); - } - - private Set>> inProgress(MultiValueMap contracts) { - return contracts.entrySet().stream() - .filter(entry -> entry.getValue().stream().anyMatch(ContractMetadata::anyInProgress)) - .collect(Collectors.toSet()); - } - - void processAll(MultiValueMap contracts, final String basePackageName) { - contracts.entrySet().stream().forEach( - entry -> processIncludedDirectory(relativizeContractPath(entry), entry.getValue(), basePackageName)); - } - - private String relativizeContractPath(Map.Entry> entry) { - Path relativePath = configProperties.getContractsDslDir().toPath().relativize(entry.getKey()); - return StringUtils.defaultIfEmpty(relativePath.toString(), DEFAULT_CLASS_PREFIX); - } - - private void processIncludedDirectory(final String includedDirectoryRelativePath, - final Collection contracts, final String basePackageNameForClass) { - log.debug("Collected contracts with metadata {} relative path is [{}]", contracts, - includedDirectoryRelativePath); - if (!contracts.isEmpty()) { - String className = afterLast(includedDirectoryRelativePath, File.separator) + resolveNameSuffix(); - String convertedClassName = ensureNameDoesNotStartWithNumber(convertIllegalPackageChars(className)); - String packageName = buildPackage(basePackageNameForClass, includedDirectoryRelativePath); - Path dir = saver.generateTestBaseDir(basePackageNameForClass, - convertIllegalPackageChars(includedDirectoryRelativePath)); - Path classPath = saver.pathToClass(dir, convertedClassName); - byte[] classBytes = generator - .buildClass(configProperties, contracts, includedDirectoryRelativePath, - new SingleTestGenerator.GeneratedClassData(convertedClassName, packageName, classPath)) - .getBytes(StandardCharsets.UTF_8); - saver.saveClassFile(classPath, classBytes); - counter.incrementAndGet(); - } - } - - private String ensureNameDoesNotStartWithNumber(String convertedClassName) { - return convertedClassName.matches("[0-9]+.*") ? ("_" + convertedClassName) : convertedClassName; - } - - private String resolveNameSuffix() { - return StringUtils.defaultIfEmpty(configProperties.getNameSuffixForTests(), - configProperties.getTestFramework().getClassNameSuffix()); - } - - protected static String buildPackage(final String packageNameForClass, final String includedDirectoryRelativePath) { - String directory = beforeLast(includedDirectoryRelativePath, File.separator); - String convertedPackage = packageNameForClass + "." + directoryToPackage(convertIllegalPackageChars(directory)); - return !directory.isEmpty() ? convertedPackage : packageNameForClass; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/TestGeneratorApplication.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/TestGeneratorApplication.java deleted file mode 100644 index 52b4c6eaf4..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/TestGeneratorApplication.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; - -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties; - -public final class TestGeneratorApplication { - - private TestGeneratorApplication() { - } - - public static void main(String[] args) throws JsonProcessingException { - if (args.length != 1) { - throw new RuntimeException("Invalid number of arguments"); - } - - ObjectMapper objectMapper = new ObjectMapper(); - - ContractVerifierConfigProperties configProperties = objectMapper.readValue(args[0], - ContractVerifierConfigProperties.class); - - TestGenerator generator = new TestGenerator(configProperties); - generator.generate(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/assertion/CollectionAssert.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/assertion/CollectionAssert.java deleted file mode 100644 index 0523f15ab7..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/assertion/CollectionAssert.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.assertion; - -import java.util.Iterator; -import java.util.Map; - -import org.assertj.core.api.IterableAssert; -import org.assertj.core.util.Streams; - -import static java.util.stream.Collectors.toList; - -/** - * Extension to {@link Iterable} assertions. - * - * @param type to assert - * @author Marcin Grzejszczak - * @since 1.1.0 - */ -public class CollectionAssert extends IterableAssert { - - public CollectionAssert(Iterable actual) { - super(actual); - } - - public CollectionAssert(Iterator actual) { - super(toIterable(actual)); - } - - private static Iterable toIterable(Iterator iterator) { - return Streams.stream(iterator).collect(toList()); - } - - /** - * Asserts all elements of the collection whether they match a regular expression. - * @param regex - regular expression to check against - * @return this - */ - public CollectionAssert allElementsMatch(String regex) { - isNotNull(); - isNotEmpty(); - for (Object anActual : this.actual) { - if (anActual == null) { - failWithMessageRelatedToRegex(regex, anActual); - } - String value = anActual.toString(); - if (!value.matches(regex)) { - failWithMessageRelatedToRegex(regex, value); - } - } - return this; - } - - private void failWithMessageRelatedToRegex(String regex, Object value) { - failWithMessage("The value <%s> doesn't match the regex <%s>", value, regex); - } - - /** - * Flattens the collection and checks whether size is greater than or equal to the - * provided value. - * @param size - the flattened collection should have size greater than or equal to - * this value - * @return this - */ - public CollectionAssert hasFlattenedSizeGreaterThanOrEqualTo(int size) { - isNotNull(); - int flattenedSize = flattenedSize(0, this.actual); - if (!(flattenedSize >= size)) { - failWithMessage("The flattened size <%s> is not greater or equal to <%s>", flattenedSize, size); - } - return this; - } - - /** - * Flattens the collection and checks whether size is less than or equal to the - * provided value. - * @param size - the flattened collection should have size less than or equal to this - * value - * @return this - */ - public CollectionAssert hasFlattenedSizeLessThanOrEqualTo(int size) { - isNotNull(); - int flattenedSize = flattenedSize(0, this.actual); - if (!(flattenedSize <= size)) { - failWithMessage("The flattened size <%s> is not less or equal to <%s>", flattenedSize, size); - } - return this; - } - - /** - * Flattens the collection and checks whether size is between the provided value. - * @param lowerBound - the flattened collection should have size greater than or equal - * to this value - * @param higherBound - the flattened collection should have size less than or equal - * to this value - * @return this - */ - public CollectionAssert hasFlattenedSizeBetween(int lowerBound, int higherBound) { - isNotNull(); - int flattenedSize = flattenedSize(0, this.actual); - if (!(flattenedSize >= lowerBound && flattenedSize <= higherBound)) { - failWithMessage("The flattened size <%s> is not between <%s> and <%s>", flattenedSize, lowerBound, - higherBound); - } - return this; - } - - /** - * Checks whether size is greater than or equal to the provided value. - * @param size - the collection should have size greater than or equal to this value - * @return this - */ - public CollectionAssert hasSizeGreaterThanOrEqualTo(int size) { - isNotNull(); - int actualSize = size(this.actual); - if (!(actualSize >= size)) { - failWithMessage("The size <%s> is not greater or equal to <%s>", actualSize, size); - } - return this; - } - - /** - * Checks whether size is less than or equal to the provided value. - * @param size - the collection should have size less than or equal to this value - * @return this - */ - public CollectionAssert hasSizeLessThanOrEqualTo(int size) { - isNotNull(); - int actualSize = size(this.actual); - if (!(actualSize <= size)) { - failWithMessage("The size <%s> is not less or equal to <%s>", actualSize, size); - } - return this; - } - - /** - * Checks whether size is between the provided value. - * @param lowerBound - the collection should have size greater than or equal to this - * value - * @param higherBound - the collection should have size less than or equal to this - * value - * @return this - */ - public CollectionAssert hasSizeBetween(int lowerBound, int higherBound) { - isNotNull(); - int size = size(this.actual); - if (!(size >= lowerBound && size <= higherBound)) { - failWithMessage("The size <%s> is not between <%s> and <%s>", size, lowerBound, higherBound); - } - return this; - } - - @Override - public CollectionAssert as(String description, Object... args) { - return (CollectionAssert) super.as(description, args); - } - - private int flattenedSize(int counter, Object object) { - if (object instanceof Map) { - return counter + ((Map) object).size(); - } - if (object instanceof Iterator) { - Iterator iterator = ((Iterator) object); - while (iterator.hasNext()) { - Object next = iterator.next(); - counter = flattenedSize(counter, next); - } - return counter; - } - if (object instanceof Iterable) { - return flattenedSize(counter, ((Iterable) object).iterator()); - } - return ++counter; - } - - private int size(Iterable iterable) { - int size = 0; - for (Object value : iterable) { - size++; - } - return size; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/assertion/ContractCollectionAssert.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/assertion/ContractCollectionAssert.java deleted file mode 100644 index 7a7ee28fb9..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/assertion/ContractCollectionAssert.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.assertion; - -import java.util.Collection; - -/** - * Extension to {@link Iterable} assertions. - * - * @param type to assert - * @author Marcin Grzejszczak - * @since 3.1.0 - */ -public class ContractCollectionAssert extends org.assertj.core.api.CollectionAssert { - - private final CollectionAssert collectionAssert; - - public ContractCollectionAssert(Collection actual) { - super(actual); - this.collectionAssert = new CollectionAssert<>(actual); - } - - /** - * Asserts all elements of the collection whether they match a regular expression. - * @param regex - regular expression to check against - * @return this - */ - public ContractCollectionAssert allElementsMatch(String regex) { - this.collectionAssert.allElementsMatch(regex); - return this; - } - - /** - * Flattens the collection and checks whether size is greater than or equal to the - * provided value. - * @param size - the flattened collection should have size greater than or equal to - * this value - * @return this - */ - public ContractCollectionAssert hasFlattenedSizeGreaterThanOrEqualTo(int size) { - this.collectionAssert.hasFlattenedSizeGreaterThanOrEqualTo(size); - return this; - } - - /** - * Flattens the collection and checks whether size is less than or equal to the - * provided value. - * @param size - the flattened collection should have size less than or equal to this - * value - * @return this - */ - public ContractCollectionAssert hasFlattenedSizeLessThanOrEqualTo(int size) { - this.collectionAssert.hasFlattenedSizeLessThanOrEqualTo(size); - return this; - } - - /** - * Flattens the collection and checks whether size is between the provided value. - * @param lowerBound - the flattened collection should have size greater than or equal - * to this value - * @param higherBound - the flattened collection should have size less than or equal - * to this value - * @return this - */ - public ContractCollectionAssert hasFlattenedSizeBetween(int lowerBound, int higherBound) { - this.collectionAssert.hasFlattenedSizeBetween(lowerBound, higherBound); - return this; - } - - /** - * Checks whether size is greater than or equal to the provided value. - * @param size - the collection should have size greater than or equal to this value - * @return this - */ - public ContractCollectionAssert hasSizeGreaterThanOrEqualTo(int size) { - this.collectionAssert.hasSizeGreaterThanOrEqualTo(size); - return this; - } - - /** - * Checks whether size is less than or equal to the provided value. - * @param size - the collection should have size less than or equal to this value - * @return this - */ - public ContractCollectionAssert hasSizeLessThanOrEqualTo(int size) { - this.collectionAssert.hasSizeLessThanOrEqualTo(size); - return this; - } - - /** - * Checks whether size is between the provided value. - * @param lowerBound - the collection should have size greater than or equal to this - * value - * @param higherBound - the collection should have size less than or equal to this - * value - * @return this - */ - public ContractCollectionAssert hasSizeBetween(int lowerBound, int higherBound) { - this.collectionAssert.hasSizeBetween(lowerBound, higherBound); - return this; - } - - @Override - public ContractCollectionAssert as(String description, Object... args) { - return (ContractCollectionAssert) super.as(description, args); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/assertion/SpringCloudContractAssertions.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/assertion/SpringCloudContractAssertions.java deleted file mode 100644 index f37760e408..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/assertion/SpringCloudContractAssertions.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.assertion; - -import java.util.Collection; - -import org.assertj.core.api.Assertions; - -public class SpringCloudContractAssertions extends Assertions { - - /** - * Creates a new instance of {@link CollectionAssert}. - * @param type to assert - * @param actual the actual value. - * @return the created assertion object. - */ - public static CollectionAssert assertThat(Iterable actual) { - return new CollectionAssert<>(actual); - } - - /** - * Creates a new instance of {@link ContractCollectionAssert}. - * @param type to assert - * @param actual the actual value. - * @return the created assertion object. - */ - public static ContractCollectionAssert assertThat(Collection actual) { - return new ContractCollectionAssert<>(actual); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/Acceptor.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/Acceptor.java deleted file mode 100644 index 191369938c..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/Acceptor.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -interface Acceptor { - - boolean accept(); - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BaseClassProvider.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BaseClassProvider.java deleted file mode 100644 index 7b64ade095..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BaseClassProvider.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.io.File; -import java.util.Map; -import java.util.Optional; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.cloud.contract.verifier.util.NamesUtil; -import org.springframework.util.StringUtils; - -class BaseClassProvider { - - private static final Log log = LogFactory.getLog(BaseClassProvider.class); - - private static final String SEPARATOR = "_REPLACEME_"; - - String retrieveBaseClass(Map baseClassMappings, String packageWithBaseClasses, - String baseClassForTests, String includedDirectoryRelativePath) { - String contractPathAsPackage = includedDirectoryRelativePath.replace(File.separator, "."); - String contractPackage = includedDirectoryRelativePath.replace(File.separator, SEPARATOR); - // package mapping takes super precedence - if (baseClassMappings != null && !baseClassMappings.isEmpty()) { - Optional> mapping = baseClassMappings.entrySet().stream().filter(entry -> { - String pattern = entry.getKey(); - return contractPathAsPackage.matches(pattern); - }).findFirst(); - if (log.isDebugEnabled()) { - log.debug("Matching pattern for contract package [" + contractPathAsPackage + "] with setup " - + baseClassMappings + " is [" + mapping + "]"); - } - if (mapping.isPresent()) { - return mapping.get().getValue(); - } - } - if (!StringUtils.hasText(packageWithBaseClasses)) { - return baseClassForTests; - } - String generatedClassName = generateDefaultBaseClassName(contractPackage, packageWithBaseClasses); - return generatedClassName + "Base"; - } - - private String generateDefaultBaseClassName(String classPackage, String packageWithBaseClasses) { - String[] splitPackage = NamesUtil.convertIllegalPackageChars(classPackage).split(SEPARATOR); - if (splitPackage.length > 1) { - String last = NamesUtil.capitalize(splitPackage[splitPackage.length - 1]); - String butLast = NamesUtil.capitalize(splitPackage[splitPackage.length - 2]); - return packageWithBaseClasses + "." + butLast + last; - } - return packageWithBaseClasses + "." + NamesUtil.capitalize(splitPackage[0]); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BlockBuilder.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BlockBuilder.java deleted file mode 100644 index e04f3d823f..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BlockBuilder.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.apache.commons.lang3.StringUtils; - -/** - * Builds a block of code. Allows to start, end, indent etc. pieces of code. - * - * @author Jakub Kubrynski, codearte.io - * @since 1.0.0 - */ -public class BlockBuilder { - - private final StringBuilder builder; - - private final String spacer; - - private int indents; - - private String lineEnding = ""; - - private String labelPrefix = ""; - - /** - * @param spacer - char used for spacing - */ - public BlockBuilder(String spacer) { - this.spacer = spacer; - builder = new StringBuilder(); - } - - /** - * Setup line ending - */ - public BlockBuilder setupLineEnding(String lineEnding) { - this.lineEnding = lineEnding; - return this; - } - - /** - * Setup label prefix - */ - public BlockBuilder setupLabelPrefix(String labelPrefix) { - this.labelPrefix = labelPrefix; - return this; - } - - public String getLineEnding() { - return this.lineEnding; - } - - /** - * Adds indents to start a new block - */ - public BlockBuilder appendWithLabelPrefix(String label) { - return append(this.labelPrefix).append(label); - } - - /** - * Adds indents to start a new block - */ - public BlockBuilder startBlock() { - indents++; - return this; - } - - /** - * Ends block by removing indents - */ - public BlockBuilder endBlock() { - indents--; - return this; - } - - /** - * Creates a block and adds indents - */ - public BlockBuilder indent() { - startBlock().startBlock(); - return this; - } - - /** - * Removes indents and closes the block - */ - public BlockBuilder unindent() { - endBlock().endBlock(); - return this; - } - - public BlockBuilder addLine(String line) { - return addIndented(line).append("\n"); - } - - public BlockBuilder addIndented(String line) { - return addIndentation().append(line); - } - - public BlockBuilder addIndented(Runnable runnable) { - addIndentation(); - runnable.run(); - return this; - } - - public BlockBuilder addLineWithEnding(String line) { - addIndentation(); - append(line).addEndingIfNotPresent().addEmptyLine(); - return this; - } - - public BlockBuilder addEndingIfNotPresent() { - addAtTheEnd(lineEnding); - return this; - } - - public BlockBuilder addEmptyLine() { - builder.append("\n"); - return this; - } - - public BlockBuilder appendWithSpace(String text) { - return addAtTheEnd(" ").append(text); - } - - public BlockBuilder appendWithSpace(Runnable runnable) { - addAtTheEnd(" "); - runnable.run(); - return this; - } - - public BlockBuilder append(Runnable runnable) { - runnable.run(); - return this; - } - - public BlockBuilder append(String string) { - builder.append(string); - return this; - } - - public BlockBuilder addIndentation() { - for (int i = 0; i < indents; i++) { - builder.append(spacer); - } - return this; - } - - BlockBuilder inBraces(Runnable runnable) { - builder.append("{\n"); - startBlock(); - runnable.run(); - endBlock(); - addAtTheEnd("\n"); - addLine("}"); - return this; - } - - public boolean endsWith(String text) { - return builder.toString().endsWith(text); - } - - public BlockBuilder addAtTheEndIfEndsWithAChar(String toAdd) { - char lastChar = builder.charAt(builder.length() - 1); - if (Character.isLetter(lastChar)) { - builder.append(toAdd); - } - return this; - } - - /** - * Adds the given text at the end of the line - * @return updated BlockBuilder - */ - public BlockBuilder addAtTheEnd(String toAdd) { - String lastChar = String.valueOf(builder.charAt(builder.length() - 1)); - String secondLastChar = builder.length() >= 2 ? String.valueOf(builder.charAt(builder.length() - 2)) : ""; - boolean isEndWithNewLine = endsWithNewLine(lastChar); - boolean lastCharSpecial = aSpecialSign(lastChar, toAdd); - boolean secondLastCharSpecial = aSpecialSign(secondLastChar, toAdd); - boolean lineEndingToAdd = toAdd.equals(lineEnding); - // lastChar = [;] , toAdd = [;] - if (lastChar.equals(toAdd)) { - return this; - } - // secondLastChar = [ ], lastChar = [{] , toAdd = [;] - else if ((!isEndWithNewLine && lastCharSpecial) && lineEndingToAdd) { - return this; - } - // secondLastChar = [{], lastChar = [\n] , toAdd = [;] - else if (isEndWithNewLine && secondLastCharSpecial) { - return this; - } - else if (isEndWithNewLine && !secondLastCharSpecial) { - builder.replace(builder.length() - 1, builder.length(), toAdd); - builder.append("\n"); - } - else { - builder.append(toAdd); - } - return this; - } - - private boolean endsWithNewLine(String character) { - return character.equals("\n"); - } - - private boolean aSpecialSign(String character, String toAdd) { - if (StringUtils.isEmpty(character)) { - return false; - } - return character.equals("{") || (character.equals(spacer) && toAdd.equals(spacer)) - || (character.equals(spacer) && toAdd.equals(" ")) || character.equals(toAdd) - || (endsWithNewLine(character) && StringUtils.equalsAny(toAdd, "\n", " ", lineEnding)); - } - - /** - * Updates the current text with the provided one - * @param contents - text to replace the current content with - * @return updated Block Builder - */ - public BlockBuilder updateContents(String contents) { - this.builder.replace(0, this.builder.length(), contents); - return this; - } - - @Override - public String toString() { - return builder.toString(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BodyAssertionLineCreator.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BodyAssertionLineCreator.java deleted file mode 100644 index 0051f75a5c..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BodyAssertionLineCreator.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.regex.Pattern; - -import org.springframework.cloud.contract.spec.internal.DslProperty; -import org.springframework.cloud.contract.spec.internal.ExecutionProperty; -import org.springframework.cloud.contract.spec.internal.FromFileProperty; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class BodyAssertionLineCreator { - - private final BlockBuilder blockBuilder; - - private final BodyReader bodyReader; - - private final String byteArrayString; - - private final ComparisonBuilder comparisonBuilder; - - BodyAssertionLineCreator(BlockBuilder blockBuilder, GeneratedClassMetaData metaData, String byteArrayString, - ComparisonBuilder comparisonBuilder) { - this.blockBuilder = blockBuilder; - this.bodyReader = new BodyReader(metaData); - this.byteArrayString = byteArrayString; - this.comparisonBuilder = comparisonBuilder; - } - - void appendBodyAssertionLine(SingleContractMetadata metadata, String property, Object value) { - if (value instanceof String && ((String) value).startsWith("$")) { - String newValue = stripFirstChar((String) value).replaceAll("\\$value", "responseBody" + property); - this.blockBuilder.addLineWithEnding(newValue); - } - else { - this.blockBuilder.addLineWithEnding(getResponseBodyPropertyComparisonString(metadata, property, value)); - } - } - - /** - * Builds the code that for the given {@code property} will compare it to the given - * Object {@code value} - */ - private String getResponseBodyPropertyComparisonString(SingleContractMetadata singleContractMetadata, - String property, Object value) { - if (value instanceof FromFileProperty) { - return getResponseBodyPropertyComparisonString(singleContractMetadata, property, (FromFileProperty) value); - } - else if (value instanceof Pattern) { - return getResponseBodyPropertyComparisonString(property, (Pattern) value); - } - else if (value instanceof ExecutionProperty) { - return getResponseBodyPropertyComparisonString(property, (ExecutionProperty) value); - } - else if (value instanceof DslProperty) { - return getResponseBodyPropertyComparisonString(singleContractMetadata, property, - ((DslProperty) value).getServerValue()); - } - return getResponseBodyPropertyComparisonString(property, value.toString()); - } - - /** - * Builds the code that for the given {@code property} will compare it to the given - * byte[] {@code value} - */ - private String getResponseBodyPropertyComparisonString(SingleContractMetadata singleContractMetadata, - String property, FromFileProperty value) { - if (value.isByte()) { - return this.comparisonBuilder.assertThat(this.byteArrayString) + this.comparisonBuilder.isEqualToUnquoted( - this.bodyReader.readBytesFromFileString(singleContractMetadata, value, CommunicationType.RESPONSE)); - } - return getResponseBodyPropertyComparisonString(property, value.asString()); - } - - /** - * Builds the code that for the given {@code property} will compare it to the given - * String {@code value} - */ - private String getResponseBodyPropertyComparisonString(String property, String value) { - return this.comparisonBuilder.assertThatUnescaped("responseBody" + property, value); - } - - /** - * Builds the code that for the given {@code property} will match it to the given - * regular expression {@code value} - */ - private String getResponseBodyPropertyComparisonString(String property, Pattern value) { - return this.comparisonBuilder.assertThat("responseBody" + property, value); - } - - /** - * Builds the code that for the given {@code property} will match it to the given - * {@link ExecutionProperty} value - */ - private String getResponseBodyPropertyComparisonString(String property, ExecutionProperty value) { - return value.insertValue("responseBody" + property); - } - - private String stripFirstChar(String s) { - return s.substring(1); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BodyMethodGeneration.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BodyMethodGeneration.java deleted file mode 100644 index a7747b7266..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BodyMethodGeneration.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.List; -import java.util.Optional; - -import org.apache.commons.text.StringEscapeUtils; - -import org.springframework.cloud.contract.spec.internal.BodyMatcher; -import org.springframework.cloud.contract.spec.internal.MatchingType; -import org.springframework.util.SerializationUtils; - -/** - * @author Marcin Grzejszczak - * @author Olga Maciaszek-Sharma - * @since 2.1.0 - */ -interface BodyMethodGeneration { - - default Object cloneBody(Object object) { - byte[] serializedObject = SerializationUtils.serialize(object); - return SerializationUtils.deserialize(serializedObject); - } - - default void addColonIfRequired(Optional lineSuffix, BlockBuilder blockBuilder) { - lineSuffix.ifPresent(s -> blockBuilder.addAtTheEnd(lineSuffix.get())); - } - - default void addBodyMatchingBlock(List matchers, BlockBuilder blockBuilder, Object responseBody, - boolean shouldCommentOutBDDBlocks) { - blockBuilder.endBlock(); - blockBuilder.addLine(getAssertionJoiner(shouldCommentOutBDDBlocks)); - blockBuilder.startBlock(); - matchers.forEach(it -> { - if (it.matchingType() == MatchingType.NULL) { - methodForNullCheck(it, blockBuilder); - } - else if (MatchingType.regexRelated(it.matchingType()) || it.matchingType() == MatchingType.EQUALITY) { - methodForEqualityCheck(it, blockBuilder, responseBody); - } - else if (it.matchingType() == MatchingType.COMMAND) { - methodForCommandExecution(it, blockBuilder, responseBody); - } - else { - methodForTypeCheck(it, blockBuilder, responseBody); - } - }); - } - - default String quotedAndEscaped(String string) { - return '"' + StringEscapeUtils.escapeJava(string) + '"'; - } - - void methodForNullCheck(BodyMatcher bodyMatcher, BlockBuilder bb); - - void methodForEqualityCheck(BodyMatcher bodyMatcher, BlockBuilder bb, Object body); - - void methodForCommandExecution(BodyMatcher bodyMatcher, BlockBuilder bb, Object body); - - void methodForTypeCheck(BodyMatcher bodyMatcher, BlockBuilder bb, Object body); - - default String getAssertionJoiner(boolean shouldCommentOutBDDBlocks) { - return shouldCommentOutBDDBlocks ? "// and:" : "and:"; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BodyMethodVisitor.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BodyMethodVisitor.java deleted file mode 100644 index d45d36bd25..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BodyMethodVisitor.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Iterator; -import java.util.List; -import java.util.stream.Collectors; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -/** - * Adds a label, proper indents and line endings for the body of a method. - */ -interface BodyMethodVisitor { - - /** - * Adds a starting body method block. E.g. //given: together with all indents - * @param blockBuilder - * @param label - * @return - */ - default BlockBuilder startBodyBlock(BlockBuilder blockBuilder, String label) { - return blockBuilder.addIndentation().appendWithLabelPrefix(label).addEmptyLine().startBlock(); - } - - /** - * Picks matching elements, visits them and applies indents. - * @param blockBuilder - * @param methodVisitors - * @param singleContractMetadata - */ - default void indentedBodyBlock(BlockBuilder blockBuilder, List methodVisitors, - SingleContractMetadata singleContractMetadata) { - List visitors = filterVisitors(methodVisitors, singleContractMetadata); - if (visitors.isEmpty()) { - blockBuilder.addEndingIfNotPresent().addEmptyLine(); - blockBuilder.endBlock(); - return; - } - blockBuilder.addEmptyLine().indent(); - applyVisitors(blockBuilder, singleContractMetadata, visitors); - endIndentedBodyBlock(blockBuilder); - } - - /** - * Picks matching visitors. - * @param methodVisitors - * @param singleContractMetadata - * @return - */ - default List filterVisitors(List methodVisitors, - SingleContractMetadata singleContractMetadata) { - return methodVisitors.stream().filter(given -> given.accept(singleContractMetadata)) - .collect(Collectors.toList()); - } - - /** - * Picks matching elements, visits them. Doesn't apply indents. Useful for the // - * then: block where there is no method chaining. - * @param blockBuilder - * @param methodVisitors - * @param singleContractMetadata - */ - default void bodyBlock(BlockBuilder blockBuilder, List methodVisitors, - SingleContractMetadata singleContractMetadata) { - List visitors = filterVisitors(methodVisitors, singleContractMetadata); - if (visitors.isEmpty()) { - blockBuilder.addEndingIfNotPresent().addEmptyLine(); - return; - } - applyVisitorsWithEnding(blockBuilder, singleContractMetadata, visitors); - endBodyBlock(blockBuilder); - } - - /** - * Executes logic for all the matching visitors. - * @param blockBuilder - * @param singleContractMetadata - * @param visitors - */ - default void applyVisitors(BlockBuilder blockBuilder, SingleContractMetadata singleContractMetadata, - List visitors) { - Iterator iterator = visitors.iterator(); - while (iterator.hasNext()) { - MethodVisitor visitor = iterator.next(); - visitor.apply(singleContractMetadata); - if (iterator.hasNext()) { - blockBuilder.addEmptyLine(); - } - } - blockBuilder.addEndingIfNotPresent(); - } - - /** - * Executes logic for all the matching visitors. - * @param blockBuilder - * @param singleContractMetadata - * @param visitors - */ - default void applyVisitorsWithEnding(BlockBuilder blockBuilder, SingleContractMetadata singleContractMetadata, - List visitors) { - Iterator iterator = visitors.iterator(); - while (iterator.hasNext()) { - MethodVisitor visitor = iterator.next(); - visitor.apply(singleContractMetadata); - blockBuilder.addEndingIfNotPresent(); - if (iterator.hasNext()) { - blockBuilder.addEmptyLine(); - } - } - } - - default void endIndentedBodyBlock(BlockBuilder blockBuilder) { - blockBuilder.addEndingIfNotPresent().unindent().endBlock(); - } - - default void endBodyBlock(BlockBuilder blockBuilder) { - blockBuilder.addEndingIfNotPresent().endBlock(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BodyParser.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BodyParser.java deleted file mode 100644 index 20f9f7cb95..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BodyParser.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; - -import groovy.json.JsonOutput; -import groovy.lang.GString; -import org.apache.commons.text.StringEscapeUtils; - -import org.springframework.cloud.contract.spec.internal.DslProperty; -import org.springframework.cloud.contract.spec.internal.FromFileProperty; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.ContentType; -import org.springframework.cloud.contract.verifier.util.ContentUtils; -import org.springframework.cloud.contract.verifier.util.MapConverter; - -import static org.apache.commons.text.StringEscapeUtils.escapeJava; -import static org.springframework.cloud.contract.verifier.util.ContentType.DEFINED; -import static org.springframework.cloud.contract.verifier.util.ContentType.FORM; -import static org.springframework.cloud.contract.verifier.util.ContentType.JSON; -import static org.springframework.cloud.contract.verifier.util.ContentType.TEXT; -import static org.springframework.cloud.contract.verifier.util.ContentUtils.extractValue; - -interface BodyParser extends BodyThen { - - String byteArrayString(); - - default String convertUnicodeEscapesIfRequired(String json) { - String unescapedJson = StringEscapeUtils.unescapeEcmaScript(json); - return escapeJava(unescapedJson); - } - - default String convertToJsonString(Object bodyValue) { - String json = JsonOutput.toJson(bodyValue); - json = convertUnicodeEscapesIfRequired(json); - return trimRepeatedQuotes(json); - } - - default String trimRepeatedQuotes(String toTrim) { - if (toTrim.startsWith("\"")) { - return toTrim.replaceAll("\"", ""); - // #261 - } - else if (toTrim.startsWith("\\\"") && toTrim.endsWith("\\\"")) { - return toTrim.substring(2, toTrim.length() - 2); - } - return toTrim; - } - - default Object convertResponseBody(SingleContractMetadata metadata) { - ContentType contentType = metadata.getOutputTestContentType(); - DslProperty body = responseBody(metadata); - Object responseBody = extractServerValueFromBody(contentType, body.getServerValue()); - if (responseBody instanceof FromFileProperty) { - responseBody = ((FromFileProperty) responseBody).asString(); - } - else if (responseBody instanceof GString) { - responseBody = extractValue((GString) responseBody, contentType, - o -> o instanceof DslProperty ? ((DslProperty) o).getServerValue() : o); - } - else if (responseBody instanceof DslProperty) { - responseBody = MapConverter.getTestSideValues(responseBody); - } - return responseBody; - } - - String responseAsString(); - - @SuppressWarnings("unchecked") - default String requestBodyAsString(SingleContractMetadata metadata) { - ContentType contentType = metadata.getInputTestContentType(); - DslProperty body = requestBody(metadata); - Object bodyValue = extractServerValueFromBody(contentType, body.getServerValue()); - if (contentType == ContentType.FORM) { - if (bodyValue instanceof Map) { - // [a:3, b:4] == "a=3&b=4" - return ((Map) bodyValue).entrySet().stream().map(o -> { - Map.Entry entry = (Map.Entry) o; - return convertUnicodeEscapesIfRequired( - entry.getKey().toString() + "=" + MapConverter.getTestSideValuesForText(entry.getValue())); - }).collect(Collectors.joining("&")).toString(); - } - else if (bodyValue instanceof List) { - // ["a=3", "b=4"] == "a=3&b=4" - return ((List) bodyValue).stream() - .map(o -> convertUnicodeEscapesIfRequired(MapConverter.getTestSideValuesForText(o).toString())) - .collect(Collectors.joining("&")).toString(); - } - else if (bodyValue instanceof String) { - return (String) bodyValue; - } - } - else { - return convertToJsonString(bodyValue); - } - return ""; - } - - /** - * Converts the passed body into ints server side representation. All - * {@link DslProperty} will return their server side values - */ - default Object extractServerValueFromBody(ContentType contentType, Object bodyValue) { - if (bodyValue instanceof GString) { - return extractValue((GString) bodyValue, contentType, ContentUtils.GET_TEST_SIDE_FUNCTION); - } - else if (bodyValue instanceof FromFileProperty) { - return MapConverter.transformValues(bodyValue, ContentUtils.GET_TEST_SIDE_FUNCTION); - } - else if (TEXT != contentType && FORM != contentType && DEFINED != contentType) { - boolean dontParseStrings = contentType == JSON && bodyValue instanceof Map; - Function parsingClosure = dontParseStrings ? MapConverter.IDENTITY - : MapConverter.JSON_PARSING_FUNCTION; - return MapConverter.getTestSideValues(bodyValue, parsingClosure); - } - return bodyValue; - } - - default String escape(String text) { - return StringEscapeUtils.escapeJava(text); - } - - default String escapeForSimpleTextAssertion(String text) { - return text; - } - - default String postProcessJsonPath(String jsonPath) { - return jsonPath; - } - - default String quotedLongText(Object text) { - return quotedEscapedLongText(escape(text.toString())); - } - - default String quotedEscapedLongText(Object text) { - return "\"" + text.toString() + "\""; - } - - default String quotedShortText(Object text) { - return quotedLongText(text); - } - - default String quotedEscapedShortText(Object text) { - return quotedEscapedLongText(text); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BodyReader.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BodyReader.java deleted file mode 100644 index 2ce5a040b6..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BodyReader.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.internal.FromFileProperty; -import org.springframework.cloud.contract.verifier.converter.YamlContract; -import org.springframework.cloud.contract.verifier.converter.YamlContractConverter; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.util.Assert; - -class BodyReader { - - private static final Log log = LogFactory.getLog(BodyReader.class); - - private final GeneratedClassMetaData generatedClassMetaData; - - private final YamlContractConverter converter = new YamlContractConverter(); - - BodyReader(GeneratedClassMetaData generatedClassMetaData) { - this.generatedClassMetaData = generatedClassMetaData; - } - - String readBytesFromFileString(SingleContractMetadata metadata, FromFileProperty property, CommunicationType side) { - String fileName = byteBodyToAFileForTestMethod(metadata, property, side); - return "fileToBytes(this, \"" + fileName + "\")"; - } - - String readStringFromFileString(SingleContractMetadata metadata, FromFileProperty property, - CommunicationType side) { - if (!Charset.defaultCharset().toString().equals(property.getCharset())) { - return "new String(" + readBytesFromFileString(metadata, property, side) + ", \"" + property.getCharset() - + "\")"; - } - return "new String(" + readBytesFromFileString(metadata, property, side) + ")"; - } - - void storeContractAsYaml(SingleContractMetadata metadata) { - Contract contract = metadata.getContract(); - List contracts = this.converter.convertTo(Collections.singleton(contract)); - Map store = this.converter.store(contracts); - store.forEach((name, bytes) -> writeFileForBothIdeAndBuildTool(metadata, bytes, name)); - } - - private String byteBodyToAFileForTestMethod(SingleContractMetadata metadata, FromFileProperty property, - CommunicationType side) { - GeneratedClassDataForMethod classDataForMethod = classDataForMethod(metadata); - String newFileName = classDataForMethod.getMethodName() + "_" + side.name().toLowerCase() + "_" - + property.fileName(); - writeFileForBothIdeAndBuildTool(metadata, property.asBytes(), newFileName); - return newFileName; - } - - private GeneratedClassDataForMethod classDataForMethod(SingleContractMetadata metadata) { - return new GeneratedClassDataForMethod(this.generatedClassMetaData.generatedClassData, metadata.methodName()); - } - - private void writeFileForBothIdeAndBuildTool(SingleContractMetadata metadata, byte[] bytes, String newFileName) { - GeneratedClassDataForMethod classDataForMethod = classDataForMethod(metadata); - java.nio.file.Path parent = classDataForMethod.testClassPath().getParent(); - if (parent == null) { - parent = classDataForMethod.testClassPath(); - } - File newFile = new File(parent.toFile(), newFileName); - if (newFile.exists()) { - return; - } - // for IDE - try { - Path path = newFile.toPath(); - if (log.isDebugEnabled()) { - log.debug("Writing file for [" + path + "] for body reading in generated test (for IDE)"); - } - Files.write(path, bytes); - // for plugin - generatedTestResourcesFileBytes(bytes, newFile); - } - catch (IOException ex) { - throw new IllegalStateException(ex); - } - } - - private void generatedTestResourcesFileBytes(byte[] bytes, File newFile) throws IOException { - Assert.notNull(this.generatedClassMetaData.configProperties.getGeneratedTestSourcesDir(), - "No generated test sources directory set"); - Assert.notNull(this.generatedClassMetaData.configProperties.getGeneratedTestResourcesDir(), - "No generated test resources directory set"); - Path path = this.generatedClassMetaData.configProperties.getGeneratedTestSourcesDir().toPath(); - Path relativePath = path.relativize(newFile.toPath()); - File newFileInGeneratedTestSources = new File( - this.generatedClassMetaData.configProperties.getGeneratedTestResourcesDir(), relativePath.toString()); - newFileInGeneratedTestSources.getParentFile().mkdirs(); - Path generatedTestSourceFilePath = newFileInGeneratedTestSources.toPath(); - if (log.isDebugEnabled()) { - log.debug("Writing file for [" + generatedTestSourceFilePath - + "] for body reading in generated test (Build tool)"); - } - Files.write(generatedTestSourceFilePath, bytes); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BodyThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BodyThen.java deleted file mode 100644 index 4cb3736025..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/BodyThen.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.spec.internal.BodyMatchers; -import org.springframework.cloud.contract.spec.internal.DslProperty; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -interface BodyThen { - - default DslProperty requestBody(SingleContractMetadata metadata) { - return metadata.getContract().getRequest().getBody(); - } - - default DslProperty responseBody(SingleContractMetadata metadata) { - return metadata.getContract().getResponse().getBody(); - } - - default BodyMatchers responseBodyMatchers(SingleContractMetadata metadata) { - return metadata.getContract().getResponse().getBodyMatchers(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ClassAnnotation.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ClassAnnotation.java deleted file mode 100644 index a8b78d72d0..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ClassAnnotation.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -interface ClassAnnotation extends Visitor { - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ClassAnnotationsBuilder.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ClassAnnotationsBuilder.java deleted file mode 100644 index 8a87054097..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ClassAnnotationsBuilder.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -class ClassAnnotationsBuilder { - - private final GeneratedTestClassBuilder parentBuilder; - - private final BlockBuilder builder; - - private final GeneratedClassMetaData metaData; - - ClassAnnotationsBuilder(GeneratedTestClassBuilder generatedTestClassBuilder) { - this.parentBuilder = generatedTestClassBuilder; - this.builder = generatedTestClassBuilder.blockBuilder; - this.metaData = generatedTestClassBuilder.generatedClassMetaData; - } - - ClassAnnotationsBuilder defaultAnnotations() { - this.parentBuilder.classAnnotations(new SuppressWarningsClassAnnotation(builder)); - return this; - } - - ClassAnnotationsBuilder jUnit4() { - this.parentBuilder.classAnnotations(new JUnit4OrderClassAnnotation(builder, metaData)); - return this; - } - - ClassAnnotationsBuilder jUnit5() { - this.parentBuilder.classAnnotations(new JUnit5OrderClassAnnotation(builder, metaData)); - return this; - } - - ClassAnnotationsBuilder spock() { - this.parentBuilder.classAnnotations(new SpockOrderClassAnnotation(builder, metaData)); - return this; - } - - GeneratedTestClassBuilder build() { - return this.parentBuilder; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ClassBodyBuilder.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ClassBodyBuilder.java deleted file mode 100644 index 837462f570..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ClassBodyBuilder.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.stream.Collectors; - -/** - * Builds the body of the class. Sets fields, methods. - * - * @author Olga Maciaszek-Sharma - * @author Marcin Grzejszczak - * @since 2.2.0 - */ -class ClassBodyBuilder { - - private List fields = new LinkedList<>(); - - private SingleMethodBuilder methodBuilder; - - final BlockBuilder blockBuilder; - - final GeneratedClassMetaData generatedClassMetaData; - - private ClassBodyBuilder(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - static ClassBodyBuilder builder(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - return new ClassBodyBuilder(blockBuilder, generatedClassMetaData); - } - - FieldBuilder field() { - return new FieldBuilder(this); - } - - ClassBodyBuilder field(Field field) { - this.fields.add(field); - return this; - } - - ClassBodyBuilder methodBuilder(SingleMethodBuilder methodBuilder) { - this.methodBuilder = methodBuilder; - return this; - } - - /** - * Mutates the {@link BlockBuilder} to generate methods and fields. - * @return block builder with contents of built methods - */ - BlockBuilder build() { - this.blockBuilder.inBraces(() -> { - // @Rule ... - visit(this.fields); - // new line if fields added - this.methodBuilder.build(); - }); - return this.blockBuilder; - } - - void visit(List list) { - List visitors = list.stream().filter(Acceptor::accept).collect(Collectors.toList()); - Iterator iterator = visitors.iterator(); - while (iterator.hasNext()) { - Visitor visitor = iterator.next(); - visitor.call(); - this.blockBuilder.addEndingIfNotPresent(); - if (iterator.hasNext()) { - this.blockBuilder.addEmptyLine(); - } - } - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ClassMetaData.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ClassMetaData.java deleted file mode 100644 index 1b10929458..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ClassMetaData.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -interface ClassMetaData extends Acceptor { - - ClassMetaData setupLineEnding(); - - ClassMetaData setupLabelPrefix(); - - ClassMetaData packageDefinition(); - - ClassMetaData modifier(); - - ClassMetaData suffix(); - - ClassMetaData parentClass(); - - ClassMetaData className(); - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ClassVerifier.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ClassVerifier.java deleted file mode 100644 index 6797119d57..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ClassVerifier.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.springframework.cloud.contract.verifier.builder; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Used to return the {@link Class} against which the type of the element should be - * verified using instanceof in generated response assertions. - * - * @author Marcin Grzejszczak - * @author Olga Maciaszek-Sharma - * @since 2.1.0 - */ -public interface ClassVerifier { - - default Class classToCheck(Object elementFromBody) { - if (elementFromBody instanceof List) { - return List.class; - } - else if (elementFromBody instanceof Set) { - return Set.class; - } - else if (elementFromBody instanceof Map) { - return Map.class; - } - return elementFromBody.getClass(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CommunicationType.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CommunicationType.java deleted file mode 100644 index ff872f5c9d..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CommunicationType.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -/** - * Describes the type of communication. - * - * @author Marcin Grzejszczak - * @since 2.1.0 - */ -public enum CommunicationType { - - REQUEST, RESPONSE, INPUT, OUTPUT; - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ComparisonBuilder.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ComparisonBuilder.java deleted file mode 100644 index f39f21cb92..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ComparisonBuilder.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.regex.Pattern; - -import org.apache.commons.text.StringEscapeUtils; - -import static org.apache.commons.text.StringEscapeUtils.escapeJava; - -interface ComparisonBuilder { - - ComparisonBuilder JAVA_HTTP_INSTANCE = () -> RestAssuredBodyParser.INSTANCE; - - ComparisonBuilder JAVA_MESSAGING_INSTANCE = () -> JavaMessagingBodyParser.INSTANCE; - - default String createComparison(Object headerValue) { - if (headerValue instanceof Pattern) { - return matches((Pattern) headerValue); - } - else if (headerValue instanceof Number) { - return isEqualTo((Number) headerValue); - } - String escapedHeader = convertUnicodeEscapesIfRequired(headerValue.toString()); - return isEqualTo(escapedHeader); - } - - default String createUnescapedComparison(Object headerValue) { - if (headerValue instanceof Pattern) { - return createComparison((Pattern) headerValue); - } - else if (headerValue instanceof Number) { - return isEqualTo((Number) headerValue); - } - return isEqualTo(headerValue.toString()); - } - - default String assertThat(String object) { - return "assertThat(" + object + ")"; - } - - default String assertThatIsNotNull(String object) { - return assertThat(object) + isNotNull(); - } - - default String assertThat(String object, Object valueToCompareAgainst) { - return assertThat(object) + createComparison(valueToCompareAgainst); - } - - default String assertThatUnescaped(String object, Object valueToCompareAgainst) { - return assertThat(object) + createUnescapedComparison(valueToCompareAgainst); - } - - default String isEqualTo(String escapedHeaderValue) { - return isEqualToUnquoted(bodyParser().quotedShortText(escapedHeaderValue)); - } - - default String isEqualToUnquoted(String unquoted) { - return ".isEqualTo(" + unquoted + ")"; - } - - default String isEqualTo(Number number) { - String numberString = number instanceof Long ? number.toString() + "L" : number.toString(); - return ".isEqualTo(" + numberString + ")"; - } - - default String isNotNull() { - return ".isNotNull()"; - } - - default String matches(Pattern pattern) { - String escapedPattern = StringEscapeUtils.escapeJava(pattern.pattern()); - return ".matches(" + bodyParser().quotedEscapedShortText(escapedPattern) + ")"; - } - - default String matches(String pattern) { - return ".matches(" + bodyParser().quotedShortText(pattern) + ")"; - } - - default String matchesEscaped(String pattern) { - return ".matches(" + bodyParser().quotedEscapedShortText(pattern) + ")"; - } - - default String convertUnicodeEscapesIfRequired(String json) { - String unescapedJson = StringEscapeUtils.unescapeJson(json); - return escapeJava(unescapedJson); - } - - BodyParser bodyParser(); - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ContentHelper.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ContentHelper.java deleted file mode 100644 index 8d339c0ce9..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ContentHelper.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.apache.commons.text.StringEscapeUtils; - -import org.springframework.cloud.contract.spec.internal.ExecutionProperty; -import org.springframework.cloud.contract.verifier.util.MapConverter; - -final class ContentHelper { - - /** - * Depending on the object type extracts the test side values and combines them into a - * String representation. Will not try to guess the type of the value of the header - * (e.g. if it's a JSON). - */ - static String getTestSideForNonBodyValue(Object object) { - if (object instanceof ExecutionProperty) { - return getTestSideValue(object); - } - return quotedAndEscaped(MapConverter.getTestSideValuesForNonBody(object).toString()); - } - - /** - * Depending on the object type extracts the test side values and combines them into a - * String representation - */ - private static String getTestSideValue(Object object) { - if (object instanceof ExecutionProperty) { - return object.toString(); - } - return '"' + MapConverter.getTestSideValues(object).toString() + '"'; - } - - private static String quotedAndEscaped(String string) { - return '"' + StringEscapeUtils.escapeJava(string) + '"'; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CookieElementProcessor.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CookieElementProcessor.java deleted file mode 100644 index 1072373b26..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CookieElementProcessor.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Iterator; -import java.util.regex.Pattern; - -import org.springframework.cloud.contract.spec.internal.Cookie; -import org.springframework.cloud.contract.spec.internal.Cookies; -import org.springframework.cloud.contract.spec.internal.ExecutionProperty; -import org.springframework.cloud.contract.spec.internal.NotToEscapePattern; -import org.springframework.cloud.contract.spec.internal.Response; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.MapConverter; - -interface CookieElementProcessor { - - ComparisonBuilder comparisonBuilder(); - - default void processCookies(SingleContractMetadata metadata) { - Response response = metadata.getContract().getResponse(); - Cookies cookies = response.getCookies(); - Iterator iterator = cookies.getEntries().iterator(); - while (iterator.hasNext()) { - Cookie cookie = iterator.next(); - String text = processCookieElement(cookie.getKey(), cookie.getServerValue() instanceof NotToEscapePattern - ? cookie.getServerValue() : MapConverter.getTestSideValues(cookie.getServerValue())); - if (iterator.hasNext()) { - blockBuilder().addLine(text).addEndingIfNotPresent(); - } - else { - blockBuilder().addIndented(text).addEndingIfNotPresent(); - } - } - } - - BlockBuilder blockBuilder(); - - default String processCookieElement(String property, Object value) { - if (value instanceof NotToEscapePattern) { - verifyCookieNotNull(property); - return comparisonBuilder().assertThat(cookieValue(property)) + comparisonBuilder() - .matches(((NotToEscapePattern) value).getServerValue().pattern().replace("\\", "\\\\")); - } - else if (value instanceof String || value instanceof Pattern) { - verifyCookieNotNull(property); - return comparisonBuilder().assertThat(cookieValue(property), value); - } - else if (value instanceof Number) { - verifyCookieNotNull(property); - return comparisonBuilder().assertThat(cookieValue(property), value); - } - else if (value instanceof ExecutionProperty) { - verifyCookieNotNull(property); - return ((ExecutionProperty) value).insertValue(cookieValue(property)); - - } - else { - // fallback - return processCookieElement(property, value.toString()); - } - } - - default void verifyCookieNotNull(String key) { - blockBuilder().addLineWithEnding(comparisonBuilder().assertThatIsNotNull(cookieKey(key))); - } - - String cookieKey(String key); - - default String cookieValue(String key) { - return cookieKey(key); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeAcceptor.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeAcceptor.java deleted file mode 100644 index 66f3b7e663..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeAcceptor.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestMode; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -interface CustomModeAcceptor { - - default boolean acceptType(GeneratedClassMetaData generatedClassMetaData, - SingleContractMetadata singleContractMetadata) { - return generatedClassMetaData.configProperties.getTestMode() == TestMode.CUSTOM - && acceptType(singleContractMetadata); - } - - default boolean acceptType(GeneratedClassMetaData generatedClassMetaData) { - return generatedClassMetaData.configProperties.getTestMode() == TestMode.CUSTOM - && generatedClassMetaData.isAnyHttp(); - } - - default boolean acceptType(SingleContractMetadata singleContractMetadata) { - return singleContractMetadata.isHttp(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeBodyGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeBodyGiven.java deleted file mode 100644 index 0d2b38eb10..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeBodyGiven.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.spec.internal.ExecutionProperty; -import org.springframework.cloud.contract.spec.internal.FromFileProperty; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.ContentType; - -class CustomModeBodyGiven implements Given { - - private final BlockBuilder blockBuilder; - - private final BodyReader bodyReader; - - private final BodyParser bodyParser; - - CustomModeBodyGiven(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData, - BodyParser bodyParser) { - this.blockBuilder = blockBuilder; - this.bodyReader = new BodyReader(generatedClassMetaData); - this.bodyParser = bodyParser; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - processInput(this.blockBuilder, metadata); - return this; - } - - private void processInput(BlockBuilder bb, SingleContractMetadata metadata) { - Object body; - Request request = metadata.getContract().getRequest(); - Object serverValue = request.getBody().getServerValue(); - if (serverValue instanceof ExecutionProperty || serverValue instanceof FromFileProperty) { - body = request.getBody().getServerValue(); - } - else { - body = this.bodyParser.requestBodyAsString(metadata); - } - bb.addIndented(getBodyString(metadata, body)); - } - - private String getBodyString(SingleContractMetadata metadata, Object body) { - String value; - if (body instanceof ExecutionProperty) { - value = body.toString(); - } - else if (body instanceof FromFileProperty) { - FromFileProperty fileProperty = (FromFileProperty) body; - value = fileProperty.isByte() - ? this.bodyReader.readBytesFromFileString(metadata, fileProperty, CommunicationType.REQUEST) - : this.bodyReader.readStringFromFileString(metadata, fileProperty, CommunicationType.REQUEST); - } - else { - String escaped = escapeRequestSpecialChars(metadata, body.toString()); - value = this.bodyParser.quotedEscapedLongText(escaped); - } - return ".body(" + value + ")"; - } - - private String escapeRequestSpecialChars(SingleContractMetadata metadata, String string) { - if (metadata.getInputTestContentType() == ContentType.JSON) { - return string.replaceAll("\\\\n", "\\\\\\\\n"); - } - return string; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - Request request = metadata.getContract().getRequest(); - return request != null && request.getBody() != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeBodyParser.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeBodyParser.java deleted file mode 100644 index 621a6d03b2..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeBodyParser.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -interface CustomModeBodyParser extends BodyParser { - - BodyParser INSTANCE = new CustomModeBodyParser() { - }; - - @Override - default String responseAsString() { - return "response.getBody().asString()"; - } - - @Override - default String byteArrayString() { - return "response.getBody().asByteArray()"; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeCookiesGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeCookiesGiven.java deleted file mode 100644 index c7f0d2afb9..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeCookiesGiven.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Iterator; - -import org.springframework.cloud.contract.spec.internal.Cookie; -import org.springframework.cloud.contract.spec.internal.MatchingStrategy; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class CustomModeCookiesGiven implements Given { - - private final BlockBuilder blockBuilder; - - CustomModeCookiesGiven(BlockBuilder blockBuilder) { - this.blockBuilder = blockBuilder; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - processInput(metadata.getContract().getRequest()); - return this; - } - - private void processInput(Request request) { - Iterator iterator = request.getCookies().getEntries().iterator(); - while (iterator.hasNext()) { - Cookie cookie = iterator.next(); - if (ofAbsentType(cookie)) { - return; - } - if (iterator.hasNext()) { - this.blockBuilder.addLine(string(cookie)); - } - else { - this.blockBuilder.addIndented(string(cookie)); - } - } - } - - private String string(Cookie cookie) { - return ".cookie(" + ContentHelper.getTestSideForNonBodyValue(cookie.getKey()) + ", " - + ContentHelper.getTestSideForNonBodyValue(cookie.getServerValue()) + ")"; - } - - private boolean ofAbsentType(Cookie cookie) { - return cookie.getServerValue() instanceof MatchingStrategy - && MatchingStrategy.Type.ABSENT.equals(((MatchingStrategy) cookie.getServerValue()).getType()); - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - Request request = metadata.getContract().getRequest(); - return request != null && request.getCookies() != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeCookiesThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeCookiesThen.java deleted file mode 100644 index fe3bf35a67..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeCookiesThen.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.spec.internal.Response; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class CustomModeCookiesThen implements Then, CustomModeAcceptor, CookieElementProcessor { - - private final BlockBuilder blockBuilder; - - private final ComparisonBuilder comparisonBuilder; - - CustomModeCookiesThen(BlockBuilder blockBuilder, ComparisonBuilder comparisonBuilder) { - this.blockBuilder = blockBuilder; - this.comparisonBuilder = comparisonBuilder; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - processCookies(metadata); - return this; - } - - @Override - public ComparisonBuilder comparisonBuilder() { - return this.comparisonBuilder; - } - - @Override - public BlockBuilder blockBuilder() { - return this.blockBuilder; - } - - @Override - public String cookieKey(String key) { - return "response.cookie(\"" + key + "\")"; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - Response response = metadata.getContract().getResponse(); - return response.getCookies() != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeFields.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeFields.java deleted file mode 100644 index 685d0aeb2c..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeFields.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -class CustomModeFields implements Field, CustomModeAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] FIELDS = { "@Inject HttpVerifier httpVerifier" }; - - CustomModeFields(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Field call() { - Arrays.stream(FIELDS).forEach(this.blockBuilder::addLineWithEnding); - return this; - } - - @Override - public boolean accept() { - return acceptType(this.generatedClassMetaData); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeGiven.java deleted file mode 100644 index da720b7748..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeGiven.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class CustomModeGiven implements Given, BodyMethodVisitor, CustomModeAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private final List requestGivens = new LinkedList<>(); - - private final List bodyGivens = new LinkedList<>(); - - CustomModeGiven(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData, BodyParser bodyParser) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - this.requestGivens - .addAll(Collections.singletonList(new CustomModeRequestGiven(blockBuilder, generatedClassMetaData))); - this.bodyGivens.addAll(Arrays.asList(new CustomModeMethodWithUrlGiven(blockBuilder, bodyParser), - new CustomModeQueryParamsGiven(blockBuilder, bodyParser), - new CustomModeSchemeProtocolGiven(blockBuilder), new CustomModeHeadersGiven(blockBuilder), - new CustomModeCookiesGiven(blockBuilder), - new CustomModeBodyGiven(blockBuilder, generatedClassMetaData, bodyParser), - new CustomMultipartGiven(generatedClassMetaData), new CustomModeRequestBuildGiven(blockBuilder))); - } - - @Override - public MethodVisitor apply(SingleContractMetadata singleContractMetadata) { - startBodyBlock(this.blockBuilder, "given:"); - addRequestGivenLine(singleContractMetadata); - indentedBodyBlock(this.blockBuilder, this.bodyGivens, singleContractMetadata); - this.blockBuilder.addEmptyLine(); - return this; - } - - private void addRequestGivenLine(SingleContractMetadata singleContractMetadata) { - this.requestGivens.stream().filter(given -> given.accept(singleContractMetadata)).findFirst() - .orElseThrow(() -> new IllegalStateException( - "No matching request building Given implementation for a custom test mode")) - .apply(singleContractMetadata); - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return acceptType(generatedClassMetaData, singleContractMetadata); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeHeadersGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeHeadersGiven.java deleted file mode 100644 index 85095daf34..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeHeadersGiven.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Iterator; - -import org.springframework.cloud.contract.spec.internal.Header; -import org.springframework.cloud.contract.spec.internal.Headers; -import org.springframework.cloud.contract.spec.internal.MatchingStrategy; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.MapConverter; - -class CustomModeHeadersGiven implements Given { - - private final BlockBuilder blockBuilder; - - CustomModeHeadersGiven(BlockBuilder blockBuilder) { - this.blockBuilder = blockBuilder; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - processInput(this.blockBuilder, metadata.getContract().getRequest().getHeaders()); - return this; - } - - private void processInput(BlockBuilder bb, Headers headers) { - Iterator
iterator = headers.getEntries().iterator(); - while (iterator.hasNext()) { - Header header = iterator.next(); - if (ofAbsentType(header)) { - return; - } - if (iterator.hasNext()) { - bb.addLine(string(header)); - } - else { - bb.addIndented(string(header)); - } - } - } - - private String string(Header header) { - return ".header(" - + ContentHelper.getTestSideForNonBodyValue(header.getName()) + ", " + ContentHelper - .getTestSideForNonBodyValue(MapConverter.getTestSideValuesForNonBody(header.getServerValue())) - + ")"; - } - - private boolean ofAbsentType(Header header) { - return header.getServerValue() instanceof MatchingStrategy - && MatchingStrategy.Type.ABSENT.equals(((MatchingStrategy) header.getServerValue()).getType()); - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - Request request = metadata.getContract().getRequest(); - return request != null && request.getHeaders() != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeHeadersThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeHeadersThen.java deleted file mode 100644 index 61cc5bc59d..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeHeadersThen.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Iterator; - -import org.springframework.cloud.contract.spec.internal.ExecutionProperty; -import org.springframework.cloud.contract.spec.internal.Header; -import org.springframework.cloud.contract.spec.internal.Headers; -import org.springframework.cloud.contract.spec.internal.NotToEscapePattern; -import org.springframework.cloud.contract.spec.internal.Response; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.MapConverter; - -class CustomModeHeadersThen implements Then, CustomModeAcceptor { - - private final BlockBuilder blockBuilder; - - private final ComparisonBuilder comparisonBuilder; - - CustomModeHeadersThen(BlockBuilder blockBuilder, ComparisonBuilder comparisonBuilder) { - this.blockBuilder = blockBuilder; - this.comparisonBuilder = comparisonBuilder; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - Response response = metadata.getContract().getResponse(); - Headers headers = response.getHeaders(); - Iterator
iterator = headers.getEntries().iterator(); - while (iterator.hasNext()) { - Header header = iterator.next(); - String text = processHeaderElement(header.getName(), header.getServerValue() instanceof NotToEscapePattern - ? header.getServerValue() : MapConverter.getTestSideValues(header.getServerValue())); - if (iterator.hasNext()) { - this.blockBuilder.addLineWithEnding(text); - } - else { - this.blockBuilder.addIndented(text); - } - } - this.blockBuilder.addEndingIfNotPresent(); - return this; - } - - private String processHeaderElement(String property, Object value) { - if (value instanceof NotToEscapePattern) { - return this.comparisonBuilder.assertThat("response.header(\"" + property + "\")") - + matchesManuallyEscapedPattern((NotToEscapePattern) value); - } - else if (value instanceof ExecutionProperty) { - return ((ExecutionProperty) value).insertValue("response.header(\"" + property + "\")"); - - } - return this.comparisonBuilder.assertThat("response.header(\"" + property + "\")", value); - } - - private String matchesManuallyEscapedPattern(NotToEscapePattern value) { - return this.comparisonBuilder.matchesEscaped(value.getServerValue().pattern().replace("\\", "\\\\")); - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - Response response = metadata.getContract().getResponse(); - return response.getHeaders() != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeImports.java deleted file mode 100644 index 523d5da445..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeImports.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -class CustomModeImports implements Imports, CustomModeAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] IMPORTS = { "javax.inject.Inject", - "org.springframework.cloud.contract.verifier.http.HttpVerifier", - "org.springframework.cloud.contract.verifier.http.Request", - "org.springframework.cloud.contract.verifier.http.Response;" }; - - CustomModeImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - Arrays.stream(IMPORTS).forEach(s -> this.blockBuilder.addLineWithEnding("import " + s)); - return this; - } - - @Override - public boolean accept() { - return acceptType(this.generatedClassMetaData); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeMethodWithUrlGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeMethodWithUrlGiven.java deleted file mode 100644 index ca91eaab39..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeMethodWithUrlGiven.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.spec.internal.ExecutionProperty; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.spec.internal.Url; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.MapConverter; - -class CustomModeMethodWithUrlGiven implements Given { - - private final BlockBuilder blockBuilder; - - private final BodyParser bodyParser; - - CustomModeMethodWithUrlGiven(BlockBuilder blockBuilder, BodyParser bodyParser) { - this.blockBuilder = blockBuilder; - this.bodyParser = bodyParser; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - addUrl(getUrl(metadata.getContract().getRequest()), metadata.getContract().getRequest()); - return this; - } - - private Url getUrl(Request request) { - if (request.getUrl() != null) { - return request.getUrl(); - } - if (request.getUrlPath() != null) { - return request.getUrlPath(); - } - throw new IllegalStateException("URL is not set!"); - } - - private void addUrl(Url buildUrl, Request request) { - Object testSideUrl = MapConverter.getTestSideValues(buildUrl); - String method = request.getMethod().getServerValue().toString().toLowerCase(); - String url = testSideUrl.toString(); - if (!(testSideUrl instanceof ExecutionProperty)) { - url = this.bodyParser.quotedShortText(testSideUrl.toString()); - } - this.blockBuilder.addIndented("." + method + "(" + url + ")"); - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - Request request = metadata.getContract().getRequest(); - return request != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeQueryParamsGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeQueryParamsGiven.java deleted file mode 100644 index f86210fb49..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeQueryParamsGiven.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Iterator; -import java.util.List; -import java.util.stream.Collectors; - -import org.springframework.cloud.contract.spec.internal.MatchingStrategy; -import org.springframework.cloud.contract.spec.internal.QueryParameter; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.spec.internal.Url; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.MapConverter; - -class CustomModeQueryParamsGiven implements Given, CustomModeAcceptor, QueryParamsResolver { - - private final BlockBuilder blockBuilder; - - private final BodyParser bodyParser; - - CustomModeQueryParamsGiven(BlockBuilder blockBuilder, BodyParser bodyParser) { - this.blockBuilder = blockBuilder; - this.bodyParser = bodyParser; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - Request request = metadata.getContract().getRequest(); - Url url = getUrl(request); - addQueryParameters(url); - return this; - } - - private Url getUrl(Request request) { - if (request.getUrl() != null) { - return request.getUrl(); - } - if (request.getUrlPath() != null) { - return request.getUrlPath(); - } - throw new IllegalStateException("URL is not set!"); - } - - private void addQueryParameters(Url buildUrl) { - List queryParameters = buildUrl.getQueryParameters().getParameters().stream() - .filter(this::allowedQueryParameter).collect(Collectors.toList()); - Iterator iterator = queryParameters.iterator(); - while (iterator.hasNext()) { - QueryParameter parameter = iterator.next(); - String text = addQueryParameter(parameter); - if (iterator.hasNext()) { - this.blockBuilder.addLine(text); - } - else { - this.blockBuilder.addIndented(text); - } - } - } - - private boolean allowedQueryParameter(Object o) { - if (o instanceof QueryParameter) { - return allowedQueryParameter(((QueryParameter) o).getServerValue()); - } - else if (o instanceof MatchingStrategy) { - return !MatchingStrategy.Type.ABSENT.equals(((MatchingStrategy) o).getType()); - } - return true; - } - - private String addQueryParameter(QueryParameter queryParam) { - return "." + "queryParam(" + this.bodyParser.quotedLongText(queryParam.getName()) + "," + this.bodyParser - .quotedLongText(resolveParamValue(MapConverter.getTestSideValuesForNonBody(queryParam))) + ")"; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return acceptType(metadata) && metadata.getContract().getRequest() != null - && getUrl(metadata.getContract().getRequest()).getQueryParameters() != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeRequestBuildGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeRequestBuildGiven.java deleted file mode 100644 index 6118d01e45..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeRequestBuildGiven.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class CustomModeRequestBuildGiven implements Given { - - private final BlockBuilder blockBuilder; - - CustomModeRequestBuildGiven(BlockBuilder blockBuilder) { - this.blockBuilder = blockBuilder; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - this.blockBuilder.addLineWithEnding(".build()"); - return this; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - Request request = metadata.getContract().getRequest(); - return request != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeRequestGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeRequestGiven.java deleted file mode 100644 index d3e899d82c..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeRequestGiven.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class CustomModeRequestGiven implements Given, CustomModeAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - CustomModeRequestGiven(BlockBuilder blockBuilder, GeneratedClassMetaData metaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = metaData; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - this.blockBuilder.addIndented("Request request = given()"); - return this; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return acceptType(this.generatedClassMetaData); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeResponseWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeResponseWhen.java deleted file mode 100644 index 91a32886d8..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeResponseWhen.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class CustomModeResponseWhen implements When, CustomModeAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - CustomModeResponseWhen(BlockBuilder blockBuilder, GeneratedClassMetaData metaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = metaData; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - this.blockBuilder.addLineWithEnding("Response response = httpVerifier.exchange(request)").endBlock(); - return this; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return acceptType(this.generatedClassMetaData, metadata); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeSchemeProtocolGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeSchemeProtocolGiven.java deleted file mode 100644 index d247298fab..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeSchemeProtocolGiven.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.http.ContractVerifierHttpMetaData; - -class CustomModeSchemeProtocolGiven implements Given { - - private final BlockBuilder blockBuilder; - - CustomModeSchemeProtocolGiven(BlockBuilder blockBuilder) { - this.blockBuilder = blockBuilder; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - Contract contract = metadata.getContract(); - ContractVerifierHttpMetaData httpMetadata = ContractVerifierHttpMetaData.fromMetadata(contract.getMetadata()); - this.blockBuilder.addIndented(".scheme(\"" + httpMetadata.getScheme().name() + "\")").addEmptyLine(); - this.blockBuilder.addIndented(".protocol(\"" + httpMetadata.getProtocol().toString() + "\")"); - return this; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - Request request = metadata.getContract().getRequest(); - return request != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeStaticImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeStaticImports.java deleted file mode 100644 index 2b646efb83..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeStaticImports.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -class CustomModeStaticImports implements Imports, CustomModeAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] IMPORTS = { "org.springframework.cloud.contract.verifier.http.Request.given" }; - - CustomModeStaticImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - Arrays.stream(IMPORTS).forEach(s -> this.blockBuilder.addLineWithEnding("import static " + s)); - return this; - } - - @Override - public boolean accept() { - return acceptType(this.generatedClassMetaData); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeStatusCodeThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeStatusCodeThen.java deleted file mode 100644 index b71189da76..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeStatusCodeThen.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.spec.internal.Response; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class CustomModeStatusCodeThen implements Then { - - private final BlockBuilder blockBuilder; - - private final ComparisonBuilder comparisonBuilder; - - CustomModeStatusCodeThen(BlockBuilder blockBuilder, ComparisonBuilder comparisonBuilder) { - this.blockBuilder = blockBuilder; - this.comparisonBuilder = comparisonBuilder; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - Response response = metadata.getContract().getResponse(); - this.blockBuilder.addIndented( - this.comparisonBuilder.assertThat("response.statusCode()", response.getStatus().getServerValue())) - .addEndingIfNotPresent(); - return this; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return true; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeThen.java deleted file mode 100644 index 3272c3bab5..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeThen.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class CustomModeThen implements Then, BodyMethodVisitor, CustomModeAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private final List thens = new LinkedList<>(); - - CustomModeThen(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData, BodyParser bodyParser, - ComparisonBuilder comparisonBuilder) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - this.thens.addAll(Arrays.asList(new CustomModeStatusCodeThen(this.blockBuilder, comparisonBuilder), - new CustomModeHeadersThen(this.blockBuilder, comparisonBuilder), - new CustomModeCookiesThen(this.blockBuilder, comparisonBuilder), - new GenericHttpBodyThen(this.blockBuilder, generatedClassMetaData, bodyParser, comparisonBuilder))); - } - - @Override - public MethodVisitor apply(SingleContractMetadata singleContractMetadata) { - startBodyBlock(this.blockBuilder, "then:"); - bodyBlock(this.blockBuilder, this.thens, singleContractMetadata); - return this; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return acceptType(this.generatedClassMetaData, singleContractMetadata); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeWhen.java deleted file mode 100644 index 910ce758b3..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeWhen.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class CustomModeWhen implements When, BodyMethodVisitor, CustomModeAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private final List responseWhens = new LinkedList<>(); - - CustomModeWhen(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - this.responseWhens.addAll(Arrays.asList(new CustomModeResponseWhen(blockBuilder, this.generatedClassMetaData))); - } - - @Override - public MethodVisitor apply(SingleContractMetadata singleContractMetadata) { - startBodyBlock(this.blockBuilder, "when:"); - addResponseWhenLine(singleContractMetadata); - this.blockBuilder.addEmptyLine(); - return this; - } - - private void addResponseWhenLine(SingleContractMetadata singleContractMetadata) { - this.responseWhens.stream().filter(when -> when.accept(singleContractMetadata)).findFirst().orElseThrow( - () -> new IllegalStateException("No matching request building When implementation for Rest Assured")) - .apply(singleContractMetadata); - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return acceptType(this.generatedClassMetaData, singleContractMetadata); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomMultipartGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomMultipartGiven.java deleted file mode 100644 index 34e5acb6b0..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomMultipartGiven.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class CustomMultipartGiven implements Given, CustomModeAcceptor { - - private final GeneratedClassMetaData generatedClassMetaData; - - CustomMultipartGiven(GeneratedClassMetaData generatedClassMetaData) { - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - throw new UnsupportedOperationException("Multipart is not yet supported"); - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - Request request = metadata.getContract().getRequest(); - return request != null && request.getMultipart() != null && acceptType(this.generatedClassMetaData, metadata); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/DefaultBaseClassProvider.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/DefaultBaseClassProvider.java deleted file mode 100644 index fb52c5c347..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/DefaultBaseClassProvider.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties; - -interface DefaultBaseClassProvider { - - GeneratedClassMetaData generatedClassMetaData(); - - BaseClassProvider baseClassProvider(); - - default String fqnBaseClass() { - ContractVerifierConfigProperties properties = generatedClassMetaData().configProperties; - String includedDirectoryRelativePath = generatedClassMetaData().includedDirectoryRelativePath; - return baseClassProvider().retrieveBaseClass(properties.getBaseClassMappings(), - properties.getPackageWithBaseClasses(), properties.getBaseClassForTests(), - includedDirectoryRelativePath); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/DefaultClassMetadata.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/DefaultClassMetadata.java deleted file mode 100644 index 866fa6bf35..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/DefaultClassMetadata.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import static org.springframework.cloud.contract.verifier.util.NamesUtil.capitalize; - -interface DefaultClassMetadata extends ClassMetaData, DefaultBaseClassProvider { - - @Override - default ClassMetaData packageDefinition() { - blockBuilder().addLineWithEnding("package " + generatedClassMetaData().generatedClassData.classPackage); - return this; - } - - GeneratedClassMetaData generatedClassMetaData(); - - BaseClassProvider baseClassProvider(); - - BlockBuilder blockBuilder(); - - @Override - default ClassMetaData className() { - String className = capitalize(generatedClassMetaData().generatedClassData.className); - blockBuilder().addAtTheEnd(className); - return this; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/DefaultImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/DefaultImports.java deleted file mode 100644 index bf234302c4..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/DefaultImports.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.util.StringUtils; - -class DefaultImports implements Imports, DefaultBaseClassProvider { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private final BaseClassProvider baseClassProvider; - - DefaultImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - this.baseClassProvider = new BaseClassProvider(); - } - - @Override - public Imports call() { - String fqnBaseClass = fqnBaseClass(); - if (StringUtils.hasText(fqnBaseClass)) { - this.blockBuilder.addLineWithEnding("import " + fqnBaseClass); - } - return this; - } - - @Override - public boolean accept() { - return true; - } - - @Override - public GeneratedClassMetaData generatedClassMetaData() { - return this.generatedClassMetaData; - } - - @Override - public BaseClassProvider baseClassProvider() { - return this.baseClassProvider; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/DefaultJsonStaticImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/DefaultJsonStaticImports.java deleted file mode 100644 index cd87ba8303..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/DefaultJsonStaticImports.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class DefaultJsonStaticImports implements Imports { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] IMPORTS = { "com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson" }; - - DefaultJsonStaticImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - Arrays.stream(IMPORTS).forEach(s -> this.blockBuilder.addLineWithEnding("import static " + s)); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.listOfFiles.stream().anyMatch(metadata -> metadata - .getConvertedContractWithMetadata().stream().anyMatch(SingleContractMetadata::isJson)); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/DefaultStaticImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/DefaultStaticImports.java deleted file mode 100644 index 7ba8b0eb75..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/DefaultStaticImports.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -class DefaultStaticImports implements Imports { - - private final BlockBuilder blockBuilder; - - private static final String[] IMPORTS = { - "org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat", - "org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.*" }; - - DefaultStaticImports(BlockBuilder blockBuilder) { - this.blockBuilder = blockBuilder; - } - - @Override - public Imports call() { - Arrays.stream(IMPORTS).forEach(s -> this.blockBuilder.addLineWithEnding("import static " + s)); - return this; - } - - @Override - public boolean accept() { - return true; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ExplicitAcceptor.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ExplicitAcceptor.java deleted file mode 100644 index 6bcd4b08c7..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ExplicitAcceptor.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestMode; - -interface ExplicitAcceptor { - - default boolean acceptType(GeneratedClassMetaData generatedClassMetaData) { - return generatedClassMetaData.configProperties.getTestMode() == TestMode.EXPLICIT; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ExplicitRequestGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ExplicitRequestGiven.java deleted file mode 100644 index 2c429d0979..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ExplicitRequestGiven.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class ExplicitRequestGiven implements Given, ExplicitAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - ExplicitRequestGiven(BlockBuilder blockBuilder, GeneratedClassMetaData metaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = metaData; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - this.blockBuilder.addIndented("RequestSpecification request = given()"); - return this; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return acceptType(this.generatedClassMetaData); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ExplicitResponseWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ExplicitResponseWhen.java deleted file mode 100644 index d4acf6153e..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ExplicitResponseWhen.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class ExplicitResponseWhen implements When, ExplicitAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - ExplicitResponseWhen(BlockBuilder blockBuilder, GeneratedClassMetaData metaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = metaData; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - this.blockBuilder.addIndented("Response response = given().spec(request)"); - return this; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return acceptType(this.generatedClassMetaData); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ExplicitRestAssuredImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ExplicitRestAssuredImports.java deleted file mode 100644 index d8a75b7f1d..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ExplicitRestAssuredImports.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.config.TestMode; - -class ExplicitRestAssuredImports implements Imports { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] REST_ASSURED_3_IMPORTS = { "io.restassured.specification.RequestSpecification", - "io.restassured.response.Response" }; - - ExplicitRestAssuredImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - Arrays.stream(REST_ASSURED_3_IMPORTS).forEach(s -> this.blockBuilder.addLineWithEnding("import " + s)); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.configProperties.getTestMode() == TestMode.EXPLICIT - && this.generatedClassMetaData.isAnyHttp(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ExplicitRestAssuredStaticImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ExplicitRestAssuredStaticImports.java deleted file mode 100644 index cfee4ccda9..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ExplicitRestAssuredStaticImports.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.config.TestMode; - -class ExplicitRestAssuredStaticImports implements Imports { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] REST_ASSURED_3_IMPORTS = { "io.restassured.RestAssured.*" }; - - ExplicitRestAssuredStaticImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - Arrays.stream(REST_ASSURED_3_IMPORTS).forEach(s -> this.blockBuilder.addLineWithEnding("import static " + s)); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.configProperties.getTestMode() == TestMode.EXPLICIT - && this.generatedClassMetaData.isAnyHttp(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/Field.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/Field.java deleted file mode 100644 index 8f133eca0f..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/Field.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -interface Field extends Visitor { - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/FieldBuilder.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/FieldBuilder.java deleted file mode 100644 index d597e8f136..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/FieldBuilder.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -class FieldBuilder { - - private final ClassBodyBuilder parentBuilder; - - private final BlockBuilder builder; - - private final GeneratedClassMetaData metaData; - - FieldBuilder(ClassBodyBuilder parentBuilder) { - this.parentBuilder = parentBuilder; - this.builder = parentBuilder.blockBuilder; - this.metaData = parentBuilder.generatedClassMetaData; - } - - FieldBuilder messaging() { - this.parentBuilder.field(new MessagingFields(this.builder, this.metaData)); - return this; - } - - FieldBuilder customMode() { - this.parentBuilder.field(new CustomModeFields(this.builder, this.metaData)); - return this; - } - - ClassBodyBuilder build() { - return this.parentBuilder; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GeneratedClassDataForMethod.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GeneratedClassDataForMethod.java deleted file mode 100644 index 36a0c41dd8..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GeneratedClassDataForMethod.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.nio.file.Path; - -/** - * POJO that wraps data for a given generated method. - * - * @author Marcin Grzejszczak - * @since 2.1.0 - */ -public class GeneratedClassDataForMethod { - - private final SingleTestGenerator.GeneratedClassData generatedClassData; - - private final String methodName; - - public GeneratedClassDataForMethod(SingleTestGenerator.GeneratedClassData generatedClassData, String methodName) { - this.generatedClassData = generatedClassData; - this.methodName = methodName; - } - - private SingleTestGenerator.GeneratedClassData assertClassData() { - if (this.generatedClassData == null) { - throw new IllegalStateException("No metadata was found for the generated test class"); - } - return this.generatedClassData; - } - - public String className() { - return assertClassData().className; - } - - public Path testClassPath() { - return assertClassData().testClassPath; - } - - public final SingleTestGenerator.GeneratedClassData getGeneratedClassData() { - return generatedClassData; - } - - public final String getMethodName() { - return methodName; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GeneratedClassMetaData.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GeneratedClassMetaData.java deleted file mode 100644 index d10efbdab5..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GeneratedClassMetaData.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Collection; -import java.util.stream.Collectors; - -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties; -import org.springframework.cloud.contract.verifier.file.ContractMetadata; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -/** - * All meta data required to generate a test class. - * - * @author Olga Maciaszek-Sharma - * @author Marcin Grzejszczak - * @since 2.2.0 - */ -class GeneratedClassMetaData { - - final ContractVerifierConfigProperties configProperties; - - final Collection listOfFiles; - - final String includedDirectoryRelativePath; - - final SingleTestGenerator.GeneratedClassData generatedClassData; - - GeneratedClassMetaData(ContractVerifierConfigProperties configProperties, Collection listOfFiles, - String includedDirectoryRelativePath, SingleTestGenerator.GeneratedClassData generatedClassData) { - this.configProperties = configProperties; - this.listOfFiles = listOfFiles; - this.includedDirectoryRelativePath = includedDirectoryRelativePath; - this.generatedClassData = generatedClassData; - } - - Collection toSingleContractMetadata() { - return this.listOfFiles.stream().flatMap(metadata -> metadata.getConvertedContractWithMetadata().stream()) - .collect(Collectors.toList()); - } - - boolean isAnyJson() { - return toSingleContractMetadata().stream().anyMatch(SingleContractMetadata::isJson); - } - - boolean isAnyIgnored() { - return toSingleContractMetadata().stream().anyMatch(SingleContractMetadata::isIgnored); - } - - boolean isAnyXml() { - return toSingleContractMetadata().stream().anyMatch(SingleContractMetadata::isXml); - } - - boolean isAnyHttp() { - return toSingleContractMetadata().stream().anyMatch(SingleContractMetadata::isHttp); - } - - boolean isAnyMessaging() { - return toSingleContractMetadata().stream().anyMatch(SingleContractMetadata::isMessaging); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GeneratedTestClass.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GeneratedTestClass.java deleted file mode 100644 index a925c927c5..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GeneratedTestClass.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -/** - * Contents of the generated test. - * - * @author Olga Maciaszek-Sharma - * @author Marcin Grzejszczak - * @since 2.2.0 - */ -public class GeneratedTestClass { - - final BlockBuilder blockBuilder; - - GeneratedTestClass(BlockBuilder blockBuilder) { - this.blockBuilder = blockBuilder; - } - - public String asClassString() { - return this.blockBuilder.toString(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GeneratedTestClassBuilder.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GeneratedTestClassBuilder.java deleted file mode 100644 index 9aef2d4702..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GeneratedTestClassBuilder.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; -import java.util.stream.Collectors; - -/** - * A generated test class consists of the class meta data (e.g. packages, imports) fields - * and methods. The latter are generated via the {@link ClassBodyBuilder}. - * - * @author Olga Maciaszek-Sharma - * @author Marcin Grzejszczak - * @since 2.2.0 - */ -class GeneratedTestClassBuilder { - - private List metaData = new LinkedList<>(); - - private List imports = new LinkedList<>(); - - private List staticImports = new LinkedList<>(); - - private List annotations = new LinkedList<>(); - - private ClassBodyBuilder classBodyBuilder; - - final BlockBuilder blockBuilder; - - final GeneratedClassMetaData generatedClassMetaData; - - private GeneratedTestClassBuilder(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - static GeneratedTestClassBuilder builder(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - return new GeneratedTestClassBuilder(blockBuilder, generatedClassMetaData); - } - - GeneratedTestClassBuilder metaData(ClassMetaData metaData) { - this.metaData.add(metaData); - return this; - } - - MetaDataBuilder metaData() { - return new MetaDataBuilder(this); - } - - GeneratedTestClassBuilder metaData(ClassMetaData... metaData) { - return metaData(Arrays.asList(metaData)); - } - - GeneratedTestClassBuilder metaData(List metaData) { - this.metaData.addAll(metaData); - return this; - } - - ImportsBuilder imports() { - return new ImportsBuilder(this); - } - - GeneratedTestClassBuilder imports(Imports imports) { - this.imports.add(imports); - return this; - } - - GeneratedTestClassBuilder imports(Imports... imports) { - return imports(Arrays.asList(imports)); - } - - GeneratedTestClassBuilder imports(List imports) { - this.imports.addAll(imports); - return this; - } - - GeneratedTestClassBuilder staticImports(Imports imports) { - this.staticImports.add(imports); - return this; - } - - GeneratedTestClassBuilder staticImports(Imports... imports) { - return staticImports(Arrays.asList(imports)); - } - - GeneratedTestClassBuilder staticImports(List imports) { - this.staticImports.addAll(imports); - return this; - } - - ClassAnnotationsBuilder classAnnotations() { - return new ClassAnnotationsBuilder(this); - } - - GeneratedTestClassBuilder classAnnotations(ClassAnnotation... annotations) { - List classAnnotations = Arrays.asList(annotations); - this.annotations.addAll(classAnnotations); - return this; - } - - GeneratedTestClassBuilder classBodyBuilder(ClassBodyBuilder classBodyBuilder) { - this.classBodyBuilder = classBodyBuilder; - return this; - } - - /** - * From a matching {@link ClassMetaData} given the present input data, builds a - * generated test class. - * @return generated test class - */ - GeneratedTestClass build() { - // picks a matching class meta data - ClassMetaData classMetaData = this.metaData.stream().filter(Acceptor::accept).findFirst() - .orElseThrow(() -> new IllegalStateException("There is no matching class meta data")); - classMetaData.setupLineEnding().setupLabelPrefix() - // package com.example - .packageDefinition(); - // \n - this.blockBuilder.addEmptyLine(); - // import ... \n - visitSeparated(this.imports); - // import static ... \n - visitSeparated(this.staticImports); - // @Test ... \n - visitWithNoEnding(this.annotations); - // @formatter:off - // public - this.blockBuilder.append(classMetaData::modifier) - .addAtTheEndIfEndsWithAChar(" ") - // class - .append("class") - // Foo - .appendWithSpace(classMetaData::className) - // Spec - .append(classMetaData::suffix) - // extends Parent - .appendWithSpace(classMetaData::parentClass); - // public class FooSpec extends Parent - // @formatter:on - this.classBodyBuilder.build(); - return new GeneratedTestClass(this.blockBuilder); - } - - void visitSeparated(List list) { - visit(list, true, true); - } - - void visitWithNoEnding(List list) { - visit(list, false, false); - } - - private void visit(List list, boolean addEnding, boolean separated) { - List elements = list.stream().filter(Acceptor::accept).collect(Collectors.toList()); - elements.forEach(OurCallable::call); - if (addEnding) { - this.blockBuilder.addEndingIfNotPresent(); - } - if (!elements.isEmpty() && separated) { - this.blockBuilder.addEmptyLine(); - } - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GenericBinaryBodyThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GenericBinaryBodyThen.java deleted file mode 100644 index 61c96b74c9..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GenericBinaryBodyThen.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.spec.internal.FromFileProperty; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class GenericBinaryBodyThen implements Then { - - private final BlockBuilder blockBuilder; - - private final BodyAssertionLineCreator bodyAssertionLineCreator; - - private final BodyParser bodyParser; - - private final ComparisonBuilder comparisonBuilder; - - GenericBinaryBodyThen(BlockBuilder blockBuilder, GeneratedClassMetaData metaData, BodyParser bodyParser, - ComparisonBuilder comparisonBuilder) { - this.blockBuilder = blockBuilder; - this.comparisonBuilder = comparisonBuilder; - this.bodyAssertionLineCreator = new BodyAssertionLineCreator(blockBuilder, metaData, - bodyParser.byteArrayString(), this.comparisonBuilder); - this.bodyParser = bodyParser; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - Object responseBody = this.bodyParser.responseBody(metadata).getServerValue(); - byteResponseBodyCheck(metadata, (FromFileProperty) responseBody); - return this; - } - - private void byteResponseBodyCheck(SingleContractMetadata metadata, FromFileProperty convertedResponseBody) { - this.bodyAssertionLineCreator.appendBodyAssertionLine(metadata, "", convertedResponseBody); - this.blockBuilder.addEndingIfNotPresent(); - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - Object responseBody = this.bodyParser.responseBody(metadata).getServerValue(); - if (!(responseBody instanceof FromFileProperty)) { - return false; - } - return ((FromFileProperty) responseBody).isByte(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GenericHttpBodyThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GenericHttpBodyThen.java deleted file mode 100644 index 41207d5a00..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GenericHttpBodyThen.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.template.HandlebarsTemplateProcessor; -import org.springframework.cloud.contract.verifier.template.TemplateProcessor; - -class GenericHttpBodyThen implements Then, BodyMethodVisitor { - - private final BlockBuilder blockBuilder; - - private final BodyParser bodyParser; - - private final TemplateProcessor templateProcessor; - - private final ComparisonBuilder comparisonBuilder; - - private final List thens = new LinkedList<>(); - - GenericHttpBodyThen(BlockBuilder blockBuilder, GeneratedClassMetaData metaData, BodyParser bodyParser, - ComparisonBuilder comparisonBuilder) { - this.blockBuilder = blockBuilder; - this.bodyParser = bodyParser; - this.comparisonBuilder = comparisonBuilder; - this.templateProcessor = new HandlebarsTemplateProcessor(); - this.thens.addAll( - Arrays.asList(new GenericBinaryBodyThen(blockBuilder, metaData, this.bodyParser, comparisonBuilder), - new GenericTextBodyThen(blockBuilder, metaData, this.bodyParser, this.comparisonBuilder), - new GenericJsonBodyThen(blockBuilder, metaData, this.bodyParser, this.comparisonBuilder), - new GenericXmlBodyThen(blockBuilder, this.bodyParser))); - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - endBodyBlock(this.blockBuilder); - this.blockBuilder.addEmptyLine(); - startBodyBlock(this.blockBuilder, "and:"); - this.thens.stream().filter(then -> then.accept(metadata)).forEach(then -> then.apply(metadata)); - return this; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return metadata.getContract().getResponse().getBody() != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GenericJsonBodyThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GenericJsonBodyThen.java deleted file mode 100644 index 435e0be37a..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GenericJsonBodyThen.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.Function; - -import org.apache.commons.text.StringEscapeUtils; - -import org.springframework.cloud.contract.spec.ContractTemplate; -import org.springframework.cloud.contract.spec.internal.BodyMatchers; -import org.springframework.cloud.contract.spec.internal.ExecutionProperty; -import org.springframework.cloud.contract.spec.internal.FromFileProperty; -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.template.HandlebarsTemplateProcessor; -import org.springframework.cloud.contract.verifier.template.TemplateProcessor; -import org.springframework.cloud.contract.verifier.util.ContentType; -import org.springframework.cloud.contract.verifier.util.MapConverter; -import org.springframework.util.StringUtils; - -import static org.springframework.cloud.contract.verifier.util.ContentType.DEFINED; -import static org.springframework.cloud.contract.verifier.util.ContentType.FORM; -import static org.springframework.cloud.contract.verifier.util.ContentType.JSON; -import static org.springframework.cloud.contract.verifier.util.ContentType.TEXT; - -class GenericJsonBodyThen implements Then { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private final BodyParser bodyParser; - - private final BodyAssertionLineCreator bodyAssertionLineCreator; - - private final TemplateProcessor templateProcessor; - - private final ContractTemplate contractTemplate; - - private final ComparisonBuilder comparisonBuilder; - - GenericJsonBodyThen(BlockBuilder blockBuilder, GeneratedClassMetaData metaData, BodyParser bodyParser, - ComparisonBuilder comparisonBuilder) { - this.blockBuilder = blockBuilder; - this.bodyParser = bodyParser; - this.comparisonBuilder = comparisonBuilder; - this.bodyAssertionLineCreator = new BodyAssertionLineCreator(blockBuilder, metaData, - this.bodyParser.byteArrayString(), this.comparisonBuilder); - this.generatedClassMetaData = metaData; - this.templateProcessor = new HandlebarsTemplateProcessor(); - this.contractTemplate = new HandlebarsTemplateProcessor(); - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - BodyMatchers bodyMatchers = this.bodyParser.responseBodyMatchers(metadata); - Object convertedResponseBody = this.bodyParser.convertResponseBody(metadata); - ContentType contentType = metadata.getOutputTestContentType(); - if (TEXT != contentType && FORM != contentType && DEFINED != contentType) { - boolean dontParseStrings = contentType == JSON && convertedResponseBody instanceof Map; - Function parsingClosure = dontParseStrings ? Function.identity() : MapConverter.JSON_PARSING_FUNCTION; - convertedResponseBody = MapConverter.getTestSideValues(convertedResponseBody, parsingClosure); - } - else { - convertedResponseBody = StringEscapeUtils.escapeJava(convertedResponseBody.toString()); - } - addJsonBodyVerification(metadata, convertedResponseBody, bodyMatchers); - return this; - } - - private void addJsonBodyVerification(SingleContractMetadata contractMetadata, Object responseBody, - BodyMatchers bodyMatchers) { - JsonBodyVerificationBuilder jsonBodyVerificationBuilder = new JsonBodyVerificationBuilder( - this.generatedClassMetaData.configProperties.getAssertJsonSize(), this.templateProcessor, - this.contractTemplate, contractMetadata.getContract(), Optional.of(this.blockBuilder.getLineEnding()), - bodyParser::postProcessJsonPath); - // TODO: Refactor spock from should comment out bdd blocks - Object convertedResponseBody = jsonBodyVerificationBuilder.addJsonResponseBodyCheck(this.blockBuilder, - responseBody, bodyMatchers, this.bodyParser.responseAsString(), - this.generatedClassMetaData.configProperties.getTestFramework() != TestFramework.SPOCK); - if (!(convertedResponseBody instanceof Map || convertedResponseBody instanceof List - || convertedResponseBody instanceof ExecutionProperty)) { - simpleTextResponseBodyCheck(contractMetadata, convertedResponseBody); - } - processBodyElement("", "", convertedResponseBody); - } - - private void processBodyElement(String oldProp, String property, Object value) { - String propDiff = subtract(property, oldProp); - String prop = wrappedWithBracketsForDottedProp(propDiff); - String mergedProp = StringUtils.hasText(property) ? oldProp + "." + prop : ""; - if (value instanceof ExecutionProperty) { - processBodyElement(mergedProp, (ExecutionProperty) value); - } - else if (value instanceof Map.Entry) { - processBodyElement(mergedProp, (Map.Entry) value); - } - else if (value instanceof Map) { - processBodyElement(mergedProp, (Map) value); - } - else if (value instanceof List) { - processBodyElement(mergedProp, (List) value); - } - } - - private void processBodyElement(String property, ExecutionProperty exec) { - this.blockBuilder.addLineWithEnding( - exec.insertValue(this.bodyParser.postProcessJsonPath("parsedJson.read(\"$" + property + "\")"))); - } - - private void processBodyElement(String property, Map.Entry entry) { - processBodyElement(property, getMapKeyReferenceString(property, entry), entry.getValue()); - } - - private void processBodyElement(String property, Map map) { - map.entrySet().forEach(o -> processBodyElement(property, (Map.Entry) o)); - } - - private void processBodyElement(String property, List list) { - Iterator iterator = list.iterator(); - int index = -1; - while (iterator.hasNext()) { - Object listElement = iterator.next(); - index = index + 1; - String prop = getPropertyInListString(property, index); - processBodyElement(property, prop, listElement); - } - } - - private String getPropertyInListString(String property, Integer listIndex) { - return property + "[" + listIndex + "]"; - } - - private String getMapKeyReferenceString(String property, Map.Entry entry) { - return provideProperJsonPathNotation(property) + "." + entry.getKey(); - } - - private String provideProperJsonPathNotation(String property) { - return property.replaceAll("(get\\(\\\\\")(.*)(\\\\\"\\))", "$2"); - } - - private String wrappedWithBracketsForDottedProp(String key) { - String remindingKey = trailingKey(key); - if (remindingKey.contains(".")) { - return "['" + remindingKey + "']"; - } - return remindingKey; - } - - private String trailingKey(String key) { - if (key.startsWith(".")) { - return key.substring(1); - } - return key; - } - - private String subtract(String self, String text) { - int index = self.indexOf(text); - if (index == -1) { - return self; - } - int end = index + text.length(); - if (self.length() > end) { - return self.substring(0, index) + self.substring(end); - } - return self.substring(0, index); - } - - private void simpleTextResponseBodyCheck(SingleContractMetadata metadata, Object convertedResponseBody) { - this.blockBuilder.addLineWithEnding(getSimpleResponseBodyString(this.bodyParser.responseAsString())); - this.bodyAssertionLineCreator.appendBodyAssertionLine(metadata, "", convertedResponseBody); - this.blockBuilder.addEndingIfNotPresent(); - } - - private String getSimpleResponseBodyString(String responseString) { - return "String responseBody = " + responseString + this.blockBuilder.getLineEnding(); - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - Object responseBody = this.bodyParser.responseBody(metadata).getServerValue(); - if (responseBody instanceof FromFileProperty) { - return !((FromFileProperty) responseBody).isByte(); - } - ContentType outputTestContentType = metadata.getOutputTestContentType(); - return JSON == outputTestContentType || mostLikelyJson(outputTestContentType, metadata); - } - - private boolean mostLikelyJson(ContentType outputTestContentType, SingleContractMetadata metadata) { - return DEFINED == outputTestContentType && metadata.evaluatesToJson(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GenericTextBodyThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GenericTextBodyThen.java deleted file mode 100644 index b412bf0d0a..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GenericTextBodyThen.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.spec.internal.FromFileProperty; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.ContentType; - -import static org.springframework.cloud.contract.verifier.util.ContentType.JSON; -import static org.springframework.cloud.contract.verifier.util.ContentType.XML; - -class GenericTextBodyThen implements Then { - - private final BlockBuilder blockBuilder; - - private final BodyAssertionLineCreator bodyAssertionLineCreator; - - private final BodyParser bodyParser; - - private final ComparisonBuilder comparisonBuilder; - - GenericTextBodyThen(BlockBuilder blockBuilder, GeneratedClassMetaData metaData, BodyParser bodyParser, - ComparisonBuilder comparisonBuilder) { - this.blockBuilder = blockBuilder; - this.bodyParser = bodyParser; - this.comparisonBuilder = comparisonBuilder; - this.bodyAssertionLineCreator = new BodyAssertionLineCreator(blockBuilder, metaData, - this.bodyParser.byteArrayString(), this.comparisonBuilder); - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - Object convertedResponseBody = this.bodyParser.convertResponseBody(metadata); - if (convertedResponseBody instanceof String) { - convertedResponseBody = this.bodyParser.escapeForSimpleTextAssertion(convertedResponseBody.toString()); - } - simpleTextResponseBodyCheck(metadata, convertedResponseBody); - return this; - } - - private void simpleTextResponseBodyCheck(SingleContractMetadata metadata, Object convertedResponseBody) { - this.blockBuilder.addLineWithEnding(getSimpleResponseBodyString(this.bodyParser.responseAsString())); - this.bodyAssertionLineCreator.appendBodyAssertionLine(metadata, "", convertedResponseBody); - this.blockBuilder.addEndingIfNotPresent(); - } - - private String getSimpleResponseBodyString(String responseString) { - return "String responseBody = " + responseString + this.blockBuilder.getLineEnding(); - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - ContentType outputTestContentType = metadata.getOutputTestContentType(); - return outputTestContentType != JSON && outputTestContentType != XML - && this.bodyParser.responseBody(metadata) != null - && !(this.bodyParser.responseBody(metadata).getServerValue() instanceof FromFileProperty); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GenericXmlBodyThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GenericXmlBodyThen.java deleted file mode 100644 index dbb11e3533..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GenericXmlBodyThen.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Optional; - -import org.springframework.cloud.contract.spec.internal.BodyMatchers; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.ContentType; - -import static org.springframework.cloud.contract.verifier.util.ContentType.XML; - -class GenericXmlBodyThen implements Then { - - private final BlockBuilder blockBuilder; - - private final BodyParser bodyParser; - - GenericXmlBodyThen(BlockBuilder blockBuilder, BodyParser bodyParser) { - this.blockBuilder = blockBuilder; - this.bodyParser = bodyParser; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - BodyMatchers bodyMatchers = this.bodyParser.responseBodyMatchers(metadata); - Object convertedResponseBody = this.bodyParser.convertResponseBody(metadata); - XmlBodyVerificationBuilder xmlBodyVerificationBuilder = new XmlBodyVerificationBuilder(metadata.getContract(), - Optional.of(this.blockBuilder.getLineEnding())); - xmlBodyVerificationBuilder.addXmlResponseBodyCheck(this.blockBuilder, convertedResponseBody, bodyMatchers, - this.bodyParser.responseAsString(), true); - return this; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - ContentType outputTestContentType = metadata.getOutputTestContentType(); - return XML == outputTestContentType; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/Given.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/Given.java deleted file mode 100644 index d2e6e0088a..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/Given.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -interface Given extends MethodVisitor { - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GroovyBodyParser.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GroovyBodyParser.java deleted file mode 100644 index 9c2919c6b5..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GroovyBodyParser.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.apache.commons.text.StringEscapeUtils; - -import org.springframework.cloud.contract.verifier.template.TemplateProcessor; - -interface GroovyBodyParser extends BodyParser { - - @Override - default String convertUnicodeEscapesIfRequired(String json) { - return StringEscapeUtils.unescapeEcmaScript(json); - } - - @Override - default String postProcessJsonPath(String jsonPath) { - if (templateProcessor().containsTemplateEntry(jsonPath)) { - return jsonPath; - } - return jsonPath.replace("$", "\\$"); - } - - TemplateProcessor templateProcessor(); - - @Override - default String escape(String text) { - return text.replaceAll("\\n", "\\\\n"); - } - - @Override - default String escapeForSimpleTextAssertion(String text) { - return escape(text); - } - - @Override - default String quotedShortText(Object text) { - String string = text.toString(); - if (text instanceof Number) { - return string; - } - else if (string.contains("'") || string.contains("\"")) { - return quotedLongText(text); - } - return "'" + groovyEscapedString(text.toString()) + "'"; - } - - @Override - default String quotedEscapedShortText(Object text) { - String string = text.toString(); - if (text instanceof Number) { - return string; - } - else if (string.contains("'") || string.contains("\"")) { - return quotedEscapedLongText(text); - } - return "'" + text.toString() + "'"; - } - - @Override - default String quotedEscapedLongText(Object text) { - return "'''" + text.toString() + "'''"; - } - - @Override - default String quotedLongText(Object text) { - String escapedString = groovyEscapedString(text); - if (escapedString.startsWith("'")) { - escapedString = "\\'" + escapedString.substring(1); - } - if (escapedString.endsWith("'")) { - escapedString = escapedString.substring(0, escapedString.length() - 1) + "\\'"; - } - return "'''" + escapedString + "'''"; - } - - default String groovyEscapedString(Object text) { - return escape(text.toString()).replaceAll("\\\\\"", "\""); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GroovyClassMetaData.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GroovyClassMetaData.java deleted file mode 100644 index b66759d335..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GroovyClassMetaData.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties; -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.util.StringUtils; - -class GroovyClassMetaData implements ClassMetaData, DefaultClassMetadata { - - private final BlockBuilder blockBuilder; - - private final BaseClassProvider baseClassProvider = new BaseClassProvider(); - - private final GeneratedClassMetaData generatedClassMetaData; - - GroovyClassMetaData(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public ClassMetaData setupLineEnding() { - return this; - } - - @Override - public ClassMetaData setupLabelPrefix() { - return this; - } - - @Override - public ClassMetaData suffix() { - String suffix = StringUtils.hasText(this.generatedClassMetaData.configProperties.getNameSuffixForTests()) - ? this.generatedClassMetaData.configProperties.getNameSuffixForTests() : "Spec"; - if (!this.blockBuilder.endsWith(suffix)) { - this.blockBuilder.addAtTheEnd(suffix); - } - return this; - } - - @Override - public ClassMetaData modifier() { - return this; - } - - @Override - public ClassMetaData packageDefinition() { - this.blockBuilder.addLineWithEnding("package " + this.generatedClassMetaData.generatedClassData.classPackage); - return this; - } - - @Override - public ClassMetaData parentClass() { - ContractVerifierConfigProperties properties = generatedClassMetaData().configProperties; - String includedDirectoryRelativePath = generatedClassMetaData().includedDirectoryRelativePath; - String baseClass = baseClassProvider().retrieveBaseClass(properties.getBaseClassMappings(), - properties.getPackageWithBaseClasses(), properties.getBaseClassForTests(), - includedDirectoryRelativePath); - baseClass = StringUtils.hasText(baseClass) ? baseClass : "Specification"; - int lastIndexOf = baseClass.lastIndexOf("."); - if (lastIndexOf > 0) { - baseClass = baseClass.substring(lastIndexOf + 1); - } - blockBuilder().append("extends ").append(baseClass).append(" "); - return this; - } - - @Override - public GeneratedClassMetaData generatedClassMetaData() { - return this.generatedClassMetaData; - } - - @Override - public BaseClassProvider baseClassProvider() { - return this.baseClassProvider; - } - - @Override - public BlockBuilder blockBuilder() { - return this.blockBuilder; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.SPOCK; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GroovyComparisonBuilder.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GroovyComparisonBuilder.java deleted file mode 100644 index cb0793e865..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/GroovyComparisonBuilder.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.regex.Pattern; - -import org.apache.commons.text.StringEscapeUtils; - -interface GroovyComparisonBuilder extends ComparisonBuilder { - - ComparisonBuilder SPOCK_HTTP_INSTANCE = (GroovyComparisonBuilder) () -> SpockRestAssuredBodyParser.INSTANCE; - - ComparisonBuilder JAXRS_HTTP_INSTANCE = (GroovyComparisonBuilder) () -> JaxRsBodyParser.INSTANCE; - - ComparisonBuilder SPOCK_MESSAGING_INSTANCE = (GroovyComparisonBuilder) () -> SpockMessagingBodyParser.INSTANCE; - - @Override - default String assertThat(String object) { - return object; - } - - @Override - default String isEqualToUnquoted(String unquoted) { - return " == " + unquoted; - } - - @Override - default String isEqualTo(Number number) { - String numberString = number instanceof Long ? number.toString() + "L" : number.toString(); - return " == " + numberString; - } - - @Override - default String matches(String pattern) { - return matchesEscaped(bodyParser().quotedShortText(pattern)); - } - - @Override - default String matches(Pattern pattern) { - String escapedPattern = StringEscapeUtils.escapeJava(pattern.pattern()); - return matchesEscaped(escapedPattern); - } - - @Override - default String matchesEscaped(String pattern) { - return " ==~ java.util.regex.Pattern.compile(" + bodyParser().quotedEscapedShortText(pattern) + ")"; - } - - @Override - default String isNotNull() { - return " != null"; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/Imports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/Imports.java deleted file mode 100644 index 51b2b0ce1b..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/Imports.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -interface Imports extends Visitor { - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ImportsBuilder.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ImportsBuilder.java deleted file mode 100644 index 9a9b405008..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ImportsBuilder.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -class ImportsBuilder { - - private final GeneratedTestClassBuilder parentBuilder; - - private final BlockBuilder builder; - - private final GeneratedClassMetaData metaData; - - ImportsBuilder(GeneratedTestClassBuilder generatedTestClassBuilder) { - this.parentBuilder = generatedTestClassBuilder; - this.builder = generatedTestClassBuilder.blockBuilder; - this.metaData = generatedTestClassBuilder.generatedClassMetaData; - } - - ImportsBuilder defaultImports() { - this.parentBuilder.imports(new DefaultImports(builder, metaData)); - this.parentBuilder.staticImports(new DefaultStaticImports(builder)); - return this; - } - - ImportsBuilder userImports() { - this.parentBuilder.imports(new UserImports(builder, metaData)); - this.parentBuilder.staticImports(new UserStaticImports(builder, metaData)); - return this; - } - - ImportsBuilder customMode() { - this.parentBuilder.imports(new CustomModeImports(builder, metaData)); - this.parentBuilder.staticImports(new CustomModeStaticImports(builder, metaData)); - return this; - } - - ImportsBuilder json() { - this.parentBuilder.imports(new JsonPathImports(builder, metaData)); - this.parentBuilder.staticImports(new DefaultJsonStaticImports(builder, metaData)); - return this; - } - - ImportsBuilder xml() { - this.parentBuilder.imports(new XmlImports(builder, metaData)); - return this; - } - - ImportsBuilder jUnit4() { - this.parentBuilder.imports(new JUnit4Imports(builder, metaData), new JUnit4IgnoreImports(builder, metaData), - new JUnit4OrderImports(builder, metaData)); - return this; - } - - ImportsBuilder jUnit5() { - this.parentBuilder.imports(new JUnit5Imports(builder, metaData), new JUnit5IgnoreImports(builder, metaData), - new JUnit5OrderImports(builder, metaData)); - return this; - } - - ImportsBuilder testNG() { - this.parentBuilder.imports(new TestNGImports(builder, metaData)); - return this; - } - - ImportsBuilder spock() { - this.parentBuilder.imports(new SpockImports(builder, metaData), new SpockIgnoreImports(builder, metaData), - new SpockOrderImports(builder, metaData)); - return this; - } - - ImportsBuilder messaging() { - this.parentBuilder.imports(new MessagingImports(builder, metaData)); - this.parentBuilder.staticImports(new MessagingStaticImports(builder, metaData)); - return this; - } - - ImportsBuilder restAssured() { - this.parentBuilder.imports(new MockMvcRestAssuredImports(builder, metaData), - new ExplicitRestAssuredImports(builder, metaData), - new WebTestClientRestAssuredImports(builder, metaData)); - this.parentBuilder.staticImports(new MockMvcRestAssuredStaticImports(builder, metaData), - new ExplicitRestAssuredStaticImports(builder, metaData), - new WebTestClientRestAssured3StaticImports(builder, metaData)); - return this; - } - - ImportsBuilder jaxRs() { - this.parentBuilder.imports(new JaxRsImports(builder, metaData)); - this.parentBuilder.staticImports(new JaxRsStaticImports(builder, metaData)); - return this; - } - - GeneratedTestClassBuilder build() { - return this.parentBuilder; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit4IgnoreImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit4IgnoreImports.java deleted file mode 100644 index 04b399bd72..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit4IgnoreImports.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestFramework; - -class JUnit4IgnoreImports implements Imports { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - JUnit4IgnoreImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - this.blockBuilder.addLineWithEnding("import org.junit.Ignore"); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.JUNIT - && this.generatedClassMetaData.listOfFiles.stream() - .anyMatch(metadata -> metadata.isIgnored() || metadata.getConvertedContractWithMetadata() - .stream().anyMatch(m -> m.isIgnored() || m.isInProgress())); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit4IgnoreMethodAnnotation.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit4IgnoreMethodAnnotation.java deleted file mode 100644 index f8aa54b292..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit4IgnoreMethodAnnotation.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class JUnit4IgnoreMethodAnnotation implements MethodAnnotations { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] ANNOTATIONS = { "@Ignore" }; - - JUnit4IgnoreMethodAnnotation(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public MethodVisitor apply(SingleContractMetadata singleContractMetadata) { - Arrays.stream(ANNOTATIONS).forEach(this.blockBuilder::addIndented); - return this; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.JUNIT - && (singleContractMetadata.getContractMetadata().isIgnored() - || singleContractMetadata.getContract().isIgnored() - || singleContractMetadata.getContract().isInProgress()); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit4Imports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit4Imports.java deleted file mode 100644 index bf0b07a777..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit4Imports.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.config.TestFramework; - -class JUnit4Imports implements Imports { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] IMPORTS = { "org.junit.Test", "org.junit.Rule" }; - - JUnit4Imports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - Arrays.stream(IMPORTS).forEach(s -> this.blockBuilder.addLineWithEnding("import " + s)); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.JUNIT; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit4MethodAnnotation.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit4MethodAnnotation.java deleted file mode 100644 index 1fe3610bfb..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit4MethodAnnotation.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class JUnit4MethodAnnotation implements MethodAnnotations { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] ANNOTATIONS = { "@Test" }; - - JUnit4MethodAnnotation(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.JUNIT; - } - - @Override - public MethodVisitor apply(SingleContractMetadata singleContractMetadata) { - Arrays.stream(ANNOTATIONS).forEach(this.blockBuilder::addIndented); - return this; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit4OrderClassAnnotation.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit4OrderClassAnnotation.java deleted file mode 100644 index b2b3d74851..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit4OrderClassAnnotation.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.config.TestFramework; - -class JUnit4OrderClassAnnotation implements ClassAnnotation { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] ANNOTATIONS = { "@FixMethodOrder(MethodSorters.NAME_ASCENDING)" }; - - JUnit4OrderClassAnnotation(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public ClassAnnotation call() { - Arrays.stream(ANNOTATIONS).forEach(this.blockBuilder::addLine); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.JUNIT - && this.generatedClassMetaData.listOfFiles.stream().anyMatch(meta -> meta.getOrder() != null); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit4OrderImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit4OrderImports.java deleted file mode 100644 index 825e751089..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit4OrderImports.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.config.TestFramework; - -class JUnit4OrderImports implements Imports { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] IMPORTS = { "org.junit.FixMethodOrder", "org.junit.runners.MethodSorters" }; - - JUnit4OrderImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - Arrays.stream(IMPORTS).forEach(s -> this.blockBuilder.addLineWithEnding("import " + s)); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.JUNIT - && this.generatedClassMetaData.listOfFiles.stream().anyMatch(meta -> meta.getOrder() != null); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit5IgnoreImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit5IgnoreImports.java deleted file mode 100644 index 901bfba735..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit5IgnoreImports.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestFramework; - -class JUnit5IgnoreImports implements Imports { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - JUnit5IgnoreImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - this.blockBuilder.addLineWithEnding("import org.junit.jupiter.api.Disabled"); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.JUNIT5 - && this.generatedClassMetaData.listOfFiles.stream() - .anyMatch(metadata -> metadata.isIgnored() || metadata.getConvertedContractWithMetadata() - .stream().anyMatch(m -> m.isIgnored() || m.isInProgress())); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit5IgnoreMethodAnnotation.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit5IgnoreMethodAnnotation.java deleted file mode 100644 index 8d3d169dd5..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit5IgnoreMethodAnnotation.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class JUnit5IgnoreMethodAnnotation implements MethodAnnotations { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] ANNOTATIONS = { "@Disabled" }; - - JUnit5IgnoreMethodAnnotation(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public MethodVisitor apply(SingleContractMetadata singleContractMetadata) { - Arrays.stream(ANNOTATIONS).forEach(this.blockBuilder::addIndented); - return this; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.JUNIT5 - && (singleContractMetadata.getContractMetadata().isIgnored() - || singleContractMetadata.getContract().isIgnored() - || singleContractMetadata.getContract().isInProgress()); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit5Imports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit5Imports.java deleted file mode 100644 index 9e544be6f7..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit5Imports.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.config.TestFramework; - -class JUnit5Imports implements Imports { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] IMPORTS = { "org.junit.jupiter.api.Test", - "org.junit.jupiter.api.extension.ExtendWith" }; - - JUnit5Imports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - Arrays.stream(IMPORTS).forEach(s -> this.blockBuilder.addLineWithEnding("import " + s)); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.JUNIT5; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit5MethodAnnotation.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit5MethodAnnotation.java deleted file mode 100644 index 4f9eba82c6..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit5MethodAnnotation.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class JUnit5MethodAnnotation implements MethodAnnotations { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] ANNOTATIONS = { "@Test" }; - - JUnit5MethodAnnotation(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public MethodVisitor apply(SingleContractMetadata singleContractMetadata) { - Arrays.stream(ANNOTATIONS).forEach(this.blockBuilder::addIndented); - return this; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.JUNIT5; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit5OrderClassAnnotation.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit5OrderClassAnnotation.java deleted file mode 100644 index 5b02293412..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit5OrderClassAnnotation.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.config.TestFramework; - -class JUnit5OrderClassAnnotation implements ClassAnnotation { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] ANNOTATIONS = { "@TestMethodOrder(MethodOrderer.Alphanumeric.class)" }; - - JUnit5OrderClassAnnotation(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public ClassAnnotation call() { - Arrays.stream(ANNOTATIONS).forEach(this.blockBuilder::addIndented); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.JUNIT5 - && this.generatedClassMetaData.listOfFiles.stream().anyMatch(meta -> meta.getOrder() != null); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit5OrderImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit5OrderImports.java deleted file mode 100644 index d91721166e..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnit5OrderImports.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.config.TestFramework; - -class JUnit5OrderImports implements Imports { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] IMPORTS = { "org.junit.jupiter.api.TestMethodOrder", - "org.junit.jupiter.api.MethodOrderer" }; - - JUnit5OrderImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - Arrays.stream(IMPORTS).forEach(s -> this.blockBuilder.addLineWithEnding("import " + s)); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.JUNIT5 - && this.generatedClassMetaData.listOfFiles.stream().anyMatch(meta -> meta.getOrder() != null); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnitMethodMetadata.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnitMethodMetadata.java deleted file mode 100644 index 9897ba602b..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JUnitMethodMetadata.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class JUnitMethodMetadata implements MethodMetadata { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData metaData; - - private final NameProvider nameProvider = new NameProvider(); - - JUnitMethodMetadata(BlockBuilder blockBuilder, GeneratedClassMetaData metaData) { - this.blockBuilder = blockBuilder; - this.metaData = metaData; - } - - @Override - public MethodMetadata name(SingleContractMetadata metaData) { - this.blockBuilder.addAtTheEnd(this.nameProvider.methodName(metaData)); - return this; - } - - @Override - public MethodMetadata modifier() { - this.blockBuilder.addIndented("public"); - return this; - } - - @Override - public MethodMetadata returnType() { - this.blockBuilder.append("void"); - return this; - } - - @Override - public boolean accept() { - return this.metaData.configProperties.getTestFramework() != TestFramework.SPOCK; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaClassMetaData.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaClassMetaData.java deleted file mode 100644 index 2f7a447fe3..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaClassMetaData.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.util.StringUtils; - -class JavaClassMetaData implements ClassMetaData, DefaultClassMetadata { - - private final BlockBuilder blockBuilder; - - private final BaseClassProvider baseClassProvider = new BaseClassProvider(); - - private final GeneratedClassMetaData generatedClassMetaData; - - JavaClassMetaData(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public ClassMetaData modifier() { - this.blockBuilder.append("public"); - return this; - } - - @Override - public ClassMetaData suffix() { - String suffix = StringUtils.hasText(this.generatedClassMetaData.configProperties.getNameSuffixForTests()) - ? this.generatedClassMetaData.configProperties.getNameSuffixForTests() : "Test"; - if (!this.blockBuilder.endsWith(suffix)) { - this.blockBuilder.addAtTheEnd(suffix); - } - return this; - } - - @Override - public ClassMetaData setupLineEnding() { - this.blockBuilder.setupLineEnding(";"); - return this; - } - - @Override - public ClassMetaData setupLabelPrefix() { - this.blockBuilder.setupLabelPrefix("// "); - return this; - } - - @Override - public GeneratedClassMetaData generatedClassMetaData() { - return this.generatedClassMetaData; - } - - @Override - public BaseClassProvider baseClassProvider() { - return this.baseClassProvider; - } - - @Override - public BlockBuilder blockBuilder() { - return this.blockBuilder; - } - - @Override - public ClassMetaData parentClass() { - String baseClass = fqnBaseClass(); - if (StringUtils.hasText(baseClass)) { - int lastIndexOf = baseClass.lastIndexOf("."); - if (lastIndexOf > 0) { - baseClass = baseClass.substring(lastIndexOf + 1); - } - blockBuilder().append("extends ").append(baseClass).append(" "); - } - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.JUNIT - || this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.JUNIT5 - || this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.TESTNG; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaJaxRsThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaJaxRsThen.java deleted file mode 100644 index 8388ae6da5..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaJaxRsThen.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class JavaJaxRsThen extends JaxRsThen { - - private final GeneratedClassMetaData metaData; - - JavaJaxRsThen(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - super(blockBuilder, generatedClassMetaData, JaxRsBodyParser.INSTANCE, ComparisonBuilder.JAVA_HTTP_INSTANCE); - this.metaData = generatedClassMetaData; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return super.accept(singleContractMetadata) - && this.metaData.configProperties.getTestFramework() != TestFramework.SPOCK; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaJaxRsWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaJaxRsWhen.java deleted file mode 100644 index 76e50347bd..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaJaxRsWhen.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class JavaJaxRsWhen extends JaxRsWhen { - - private final GeneratedClassMetaData metaData; - - JavaJaxRsWhen(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - super(blockBuilder, generatedClassMetaData, JaxRsBodyParser.INSTANCE); - this.metaData = generatedClassMetaData; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return super.accept(singleContractMetadata) - && this.metaData.configProperties.getTestFramework() != TestFramework.SPOCK; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaMessagingBodyParser.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaMessagingBodyParser.java deleted file mode 100644 index a62ca1cfc1..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaMessagingBodyParser.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -interface JavaMessagingBodyParser extends MessagingBodyParser { - - BodyParser INSTANCE = new JavaMessagingBodyParser() { - }; - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaMessagingWithBodyThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaMessagingWithBodyThen.java deleted file mode 100644 index d9cb72c9b5..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaMessagingWithBodyThen.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class JavaMessagingWithBodyThen extends MessagingWithBodyThen { - - private final GeneratedClassMetaData metaData; - - JavaMessagingWithBodyThen(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - super(blockBuilder, generatedClassMetaData, ComparisonBuilder.JAVA_MESSAGING_INSTANCE); - this.metaData = generatedClassMetaData; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return super.accept(singleContractMetadata) - && this.metaData.configProperties.getTestFramework() != TestFramework.SPOCK; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaMultipartGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaMultipartGiven.java deleted file mode 100644 index 9595ccb61d..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaMultipartGiven.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Map; - -import org.springframework.cloud.contract.spec.internal.NamedProperty; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.MapConverter; - -import static org.springframework.cloud.contract.verifier.util.ContentUtils.getJavaMultipartFileParameterContent; - -class JavaMultipartGiven implements Given, RestAssuredAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private final BodyReader bodyReader; - - private final BodyParser bodyParser; - - JavaMultipartGiven(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData, - BodyParser bodyParser) { - this.blockBuilder = blockBuilder; - this.bodyReader = new BodyReader(generatedClassMetaData); - this.bodyParser = bodyParser; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - getMultipartParameters(metadata).entrySet() - .forEach(entry -> this.blockBuilder.addLine(getMultipartParameterLine(metadata, entry))); - return this; - } - - private String getMultipartParameterLine(SingleContractMetadata metadata, Map.Entry parameter) { - if (parameter.getValue() instanceof NamedProperty) { - return ".multiPart(" + getMultipartFileParameterContent(metadata, parameter.getKey(), - (NamedProperty) parameter.getValue()) + ")"; - } - return getParameterString(parameter); - } - - @SuppressWarnings("unchecked") - private Map getMultipartParameters(SingleContractMetadata metadata) { - return (Map) metadata.getContract().getRequest().getMultipart().getServerValue(); - } - - private String getMultipartFileParameterContent(SingleContractMetadata metadata, String propertyName, - NamedProperty propertyValue) { - return getJavaMultipartFileParameterContent(propertyName, propertyValue, - fileProp -> this.bodyReader.readBytesFromFileString(metadata, fileProp, CommunicationType.REQUEST)); - } - - private String getParameterString(Map.Entry parameter) { - return ".param(" + this.bodyParser.quotedShortText(parameter.getKey()) + ", " - + this.bodyParser.quotedShortText(MapConverter.getTestSideValuesForNonBody(parameter.getValue())) + ")"; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - Request request = metadata.getContract().getRequest(); - return request != null && request.getMultipart() != null && acceptType(this.generatedClassMetaData, metadata) - && this.generatedClassMetaData.configProperties.getTestFramework() != TestFramework.SPOCK; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaRestAssuredGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaRestAssuredGiven.java deleted file mode 100644 index 8bff074083..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaRestAssuredGiven.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class JavaRestAssuredGiven extends RestAssuredGiven { - - private final GeneratedClassMetaData metaData; - - JavaRestAssuredGiven(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - super(blockBuilder, generatedClassMetaData, RestAssuredBodyParser.INSTANCE); - this.metaData = generatedClassMetaData; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return super.accept(singleContractMetadata) - && this.metaData.configProperties.getTestFramework() != TestFramework.SPOCK; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaRestAssuredThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaRestAssuredThen.java deleted file mode 100644 index 29c469440e..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaRestAssuredThen.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class JavaRestAssuredThen extends RestAssuredThen { - - private final GeneratedClassMetaData metaData; - - JavaRestAssuredThen(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - super(blockBuilder, generatedClassMetaData, RestAssuredBodyParser.INSTANCE, - ComparisonBuilder.JAVA_HTTP_INSTANCE); - this.metaData = generatedClassMetaData; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return super.accept(singleContractMetadata) - && this.metaData.configProperties.getTestFramework() != TestFramework.SPOCK; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaRestAssuredWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaRestAssuredWhen.java deleted file mode 100644 index 2c7970ca93..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaRestAssuredWhen.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class JavaRestAssuredWhen extends RestAssuredWhen { - - private final GeneratedClassMetaData metaData; - - JavaRestAssuredWhen(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - super(blockBuilder, generatedClassMetaData, RestAssuredBodyParser.INSTANCE); - this.metaData = generatedClassMetaData; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return super.accept(singleContractMetadata) - && this.metaData.configProperties.getTestFramework() != TestFramework.SPOCK; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaTestGenerator.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaTestGenerator.java deleted file mode 100644 index 0eb7749ca6..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaTestGenerator.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Collection; - -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties; -import org.springframework.cloud.contract.verifier.file.ContractMetadata; - -/** - * Builds a single test for the given {@link ContractVerifierConfigProperties properties} - * - * @since 1.1.0 - */ -public class JavaTestGenerator implements SingleTestGenerator { - - @Override - public String buildClass(ContractVerifierConfigProperties properties, Collection listOfFiles, - String includedDirectoryRelativePath, GeneratedClassData generatedClassData) { - BlockBuilder builder = new BlockBuilder("\t"); - GeneratedClassMetaData metaData = new GeneratedClassMetaData(properties, listOfFiles, - includedDirectoryRelativePath, generatedClassData); - return classAsString(builder, metaData); - } - - private String classAsString(BlockBuilder builder, GeneratedClassMetaData metaData) { - SingleMethodBuilder methodBuilder = singleMethodBuilder(builder, metaData); - ClassBodyBuilder bodyBuilder = classBodyBuilder(builder, metaData, methodBuilder); - GeneratedTestClass generatedTestClass = generatedTestClass(builder, metaData, bodyBuilder); - return generatedTestClass.asClassString(); - } - - GeneratedTestClass generatedTestClass(BlockBuilder builder, GeneratedClassMetaData metaData, - ClassBodyBuilder bodyBuilder) { - // @formatter:off - return GeneratedTestClassBuilder.builder(builder, metaData) - .classBodyBuilder(bodyBuilder) - .metaData() - .java() - .groovy() - .build() - .imports() - .defaultImports() - .userImports() - .customMode() - .json() - .jUnit4() - .jUnit5() - .testNG() - .spock() - .xml() - .messaging() - .restAssured() - .jaxRs() - .build() - .classAnnotations() - .defaultAnnotations() - .jUnit4() - .jUnit5() - .spock() - .build() - .build(); - // @formatter:on - } - - ClassBodyBuilder classBodyBuilder(BlockBuilder builder, GeneratedClassMetaData metaData, - SingleMethodBuilder methodBuilder) { - // @formatter:off - return ClassBodyBuilder.builder(builder, metaData) - .field() - .messaging() - .customMode() - .build() - .methodBuilder(methodBuilder); - // @formatter:on - } - - SingleMethodBuilder singleMethodBuilder(BlockBuilder builder, GeneratedClassMetaData metaData) { - // @formatter:off - return SingleMethodBuilder.builder(builder, metaData) - .methodAnnotation() - .jUnit4() - .jUnit5() - .testNG() - .spock() - .build() - .methodMetadata() - .jUnit() - .spock() - .build() - .restAssured() - .customMode() - .jaxRs() - .messaging(); - // @formatter:on - } - -} \ No newline at end of file diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsAcceptor.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsAcceptor.java deleted file mode 100644 index 937112dc59..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsAcceptor.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestMode; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -interface JaxRsAcceptor { - - default boolean acceptType(GeneratedClassMetaData generatedClassMetaData, - SingleContractMetadata singleContractMetadata) { - return generatedClassMetaData.configProperties.getTestMode() == TestMode.JAXRSCLIENT - && singleContractMetadata.isHttp(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsBodyParser.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsBodyParser.java deleted file mode 100644 index 1a5e6dcd8e..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsBodyParser.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -interface JaxRsBodyParser extends BodyParser { - - JaxRsBodyParser INSTANCE = new JaxRsBodyParser() { - }; - - default String readEntity() { - return "response.readEntity(String.class)"; - } - - default String responseAsString() { - return "responseAsString"; - } - - default String byteArrayString() { - return "response.readEntity(byte[].class)"; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsGiven.java deleted file mode 100644 index 4ffc81662d..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsGiven.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class JaxRsGiven implements Given, JaxRsAcceptor { - - private final GeneratedClassMetaData generatedClassMetaData; - - JaxRsGiven(GeneratedClassMetaData metaData) { - this.generatedClassMetaData = metaData; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - return this; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return acceptType(this.generatedClassMetaData, metadata); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsImports.java deleted file mode 100644 index 7be7334c97..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsImports.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.config.TestMode; - -class JaxRsImports implements Imports { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] IMPORTS = { "javax.ws.rs.client.Entity", "javax.ws.rs.core.Response" }; - - JaxRsImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - Arrays.stream(IMPORTS).forEach(s -> this.blockBuilder.addLineWithEnding("import " + s)); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.configProperties.getTestMode() == TestMode.JAXRSCLIENT; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsRequestCookiesWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsRequestCookiesWhen.java deleted file mode 100644 index aaa4b54ff9..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsRequestCookiesWhen.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Iterator; -import java.util.Set; - -import org.springframework.cloud.contract.spec.internal.Cookie; -import org.springframework.cloud.contract.spec.internal.MatchingStrategy; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.MapConverter; - -class JaxRsRequestCookiesWhen implements When { - - private final BlockBuilder blockBuilder; - - private final BodyParser bodyParser; - - JaxRsRequestCookiesWhen(BlockBuilder blockBuilder, BodyParser bodyParser) { - this.blockBuilder = blockBuilder; - this.bodyParser = bodyParser; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - appendCookies(metadata.getContract().getRequest()); - return this; - } - - private void appendCookies(Request request) { - Iterator iterator = request.getCookies().getEntries().stream() - .filter(cookie -> !cookieOfAbsentType(cookie)).iterator(); - while (iterator.hasNext()) { - Cookie cookie = iterator.next(); - String value = ".cookie(" + this.bodyParser.quotedShortText(cookie.getKey()) + ", " - + this.bodyParser.quotedShortText(MapConverter.getTestSideValuesForNonBody(cookie.getServerValue())) - + ")"; - if (iterator.hasNext()) { - this.blockBuilder.addLine(value); - } - else { - this.blockBuilder.addIndented(value); - } - } - } - - private boolean cookieOfAbsentType(Cookie cookie) { - return cookie.getServerValue() instanceof MatchingStrategy - && ((MatchingStrategy) cookie.getServerValue()).getType() == MatchingStrategy.Type.ABSENT; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return metadata.getContract().getRequest().getCookies() != null - && !metadata.getContract().getRequest().getCookies().getEntries().isEmpty() - && !hasOnlyAbsentCookies(metadata); - } - - private boolean hasOnlyAbsentCookies(SingleContractMetadata metadata) { - Set entries = metadata.getContract().getRequest().getCookies().getEntries(); - long filteredOut = entries.stream().filter(this::cookieOfAbsentType).count(); - return filteredOut == entries.size(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsRequestHeadersWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsRequestHeadersWhen.java deleted file mode 100644 index 98b478d313..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsRequestHeadersWhen.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Iterator; -import java.util.Set; - -import org.springframework.cloud.contract.spec.internal.ExecutionProperty; -import org.springframework.cloud.contract.spec.internal.Header; -import org.springframework.cloud.contract.spec.internal.MatchingStrategy; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.MapConverter; - -class JaxRsRequestHeadersWhen implements When { - - private final BlockBuilder blockBuilder; - - private final BodyParser bodyParser; - - JaxRsRequestHeadersWhen(BlockBuilder blockBuilder, BodyParser bodyParser) { - this.blockBuilder = blockBuilder; - this.bodyParser = bodyParser; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - appendHeaders(metadata.getContract().getRequest()); - return this; - } - - private void appendHeaders(Request request) { - Iterator
iterator = request.getHeaders().getEntries().stream().filter(header -> !headerToIgnore(header)) - .iterator(); - while (iterator.hasNext()) { - Header header = iterator.next(); - String text = ".header(\"" + header.getName() + "\", " + headerValue(header) + ")"; - if (iterator.hasNext()) { - this.blockBuilder.addLine(text); - } - else { - this.blockBuilder.addIndented(text); - } - } - } - - private String headerValue(Header header) { - Object headerServerValue = header.getServerValue(); - if (headerServerValue instanceof ExecutionProperty) { - return ((ExecutionProperty) headerServerValue).getExecutionCommand(); - } - return this.bodyParser.quotedLongText(MapConverter.getTestSideValuesForNonBody(header.getServerValue())); - } - - private boolean headerToIgnore(Header header) { - return contentTypeOrAccept(header) || headerOfAbsentType(header); - } - - private boolean contentTypeOrAccept(Header header) { - return "Content-Type".equalsIgnoreCase(header.getName()) || "Accept".equalsIgnoreCase(header.getName()); - } - - private boolean headerOfAbsentType(Header header) { - return header.getServerValue() instanceof MatchingStrategy - && ((MatchingStrategy) header.getServerValue()).getType() == MatchingStrategy.Type.ABSENT; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return metadata.getContract().getRequest().getHeaders() != null - && !metadata.getContract().getRequest().getHeaders().getEntries().isEmpty() - && !hasHeaderOnlyContentTypeOrAccept(metadata); - } - - private boolean hasHeaderOnlyContentTypeOrAccept(SingleContractMetadata metadata) { - Set
entries = metadata.getContract().getRequest().getHeaders().getEntries(); - long filteredOut = entries.stream().filter(this::headerToIgnore).count(); - return filteredOut == entries.size(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsRequestInvokerWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsRequestInvokerWhen.java deleted file mode 100644 index d0af973db9..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsRequestInvokerWhen.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class JaxRsRequestInvokerWhen implements When, JaxRsBodyParser { - - private final BlockBuilder blockBuilder; - - JaxRsRequestInvokerWhen(BlockBuilder blockBuilder) { - this.blockBuilder = blockBuilder; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - this.blockBuilder.addIndented(".invoke()").addEndingIfNotPresent(); - return this; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return true; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsRequestMethodWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsRequestMethodWhen.java deleted file mode 100644 index 82580a5bd3..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsRequestMethodWhen.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.spec.internal.ExecutionProperty; -import org.springframework.cloud.contract.spec.internal.FromFileProperty; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.ContentType; -import org.springframework.util.StringUtils; - -class JaxRsRequestMethodWhen implements When, JaxRsBodyParser { - - private final BlockBuilder blockBuilder; - - private final BodyReader bodyReader; - - JaxRsRequestMethodWhen(BlockBuilder blockBuilder, GeneratedClassMetaData metaData) { - this.blockBuilder = blockBuilder; - this.bodyReader = new BodyReader(metaData); - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - appendMethodAndBody(metadata); - return this; - } - - void appendMethodAndBody(SingleContractMetadata metadata) { - Request request = metadata.getContract().getRequest(); - ContentType type = metadata.getInputTestContentType(); - String method = request.getMethod().getServerValue().toString().toLowerCase(); - if (request.getBody() != null) { - String contentType = StringUtils.hasText(metadata.getDefinedInputTestContentType()) - ? metadata.getDefinedInputTestContentType() : type.getMimeType(); - Object body = request.getBody().getServerValue(); - String value; - if (body instanceof ExecutionProperty) { - value = body.toString(); - } - else if (body instanceof FromFileProperty) { - FromFileProperty fileProperty = (FromFileProperty) body; - value = fileProperty.isByte() - ? this.bodyReader.readBytesFromFileString(metadata, fileProperty, CommunicationType.REQUEST) - : this.bodyReader.readStringFromFileString(metadata, fileProperty, CommunicationType.REQUEST); - } - else { - value = "\"" + requestBodyAsString(metadata) + "\""; - } - this.blockBuilder.addIndented( - ".build(\"" + method.toUpperCase() + "\", entity(" + value + ", \"" + contentType + "\"))"); - } - else { - this.blockBuilder.addIndented(".build(\"" + method.toUpperCase() + "\")"); - } - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return true; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsRequestWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsRequestWhen.java deleted file mode 100644 index 0951472e8d..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsRequestWhen.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.spec.internal.Header; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.MapConverter; -import org.springframework.util.StringUtils; - -class JaxRsRequestWhen implements When, JaxRsAcceptor, QueryParamsResolver { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - JaxRsRequestWhen(BlockBuilder blockBuilder, GeneratedClassMetaData metaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = metaData; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - appendRequestWithRequiredResponseContentType(metadata.getContract().getRequest()); - return this; - } - - void appendRequestWithRequiredResponseContentType(Request request) { - String acceptHeader = getHeader(request, "Accept"); - if (StringUtils.hasText(acceptHeader)) { - this.blockBuilder.addIndented(".request(\"" + acceptHeader + "\")"); - } - else { - this.blockBuilder.addIndented(".request()"); - } - } - - private String getHeader(Request request, String name) { - if (request.getHeaders() == null || request.getHeaders().getEntries() == null) { - return ""; - } - Header foundHeader = request.getHeaders().getEntries().stream().filter(header -> name.equals(header.getName())) - .findFirst().orElse(null); - if (foundHeader == null) { - return ""; - } - return MapConverter.getTestSideValuesForNonBody(foundHeader.getServerValue()).toString(); - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return acceptType(this.generatedClassMetaData, metadata); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsResponseCookiesThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsResponseCookiesThen.java deleted file mode 100644 index afacb04750..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsResponseCookiesThen.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.spec.internal.Response; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class JaxRsResponseCookiesThen implements Then, MockMvcAcceptor, CookieElementProcessor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private final ComparisonBuilder comparisonBuilder; - - private final BodyParser bodyParser; - - JaxRsResponseCookiesThen(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData, - ComparisonBuilder comparisonBuilder) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - this.comparisonBuilder = comparisonBuilder; - this.bodyParser = comparisonBuilder.bodyParser(); - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - processCookies(metadata); - return this; - } - - @Override - public ComparisonBuilder comparisonBuilder() { - return this.comparisonBuilder; - } - - @Override - public BlockBuilder blockBuilder() { - return this.blockBuilder; - } - - @Override - public String cookieKey(String key) { - return "response.getCookies().get(" + this.bodyParser.quotedShortText(key) + ")"; - } - - @Override - public String cookieValue(String key) { - return cookieKey(key) + ".getValue()"; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - Response response = metadata.getContract().getResponse(); - return response.getCookies() != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsResponseHeadersThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsResponseHeadersThen.java deleted file mode 100644 index b037888299..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsResponseHeadersThen.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Iterator; - -import org.springframework.cloud.contract.spec.internal.ExecutionProperty; -import org.springframework.cloud.contract.spec.internal.Header; -import org.springframework.cloud.contract.spec.internal.Headers; -import org.springframework.cloud.contract.spec.internal.NotToEscapePattern; -import org.springframework.cloud.contract.spec.internal.Response; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.MapConverter; - -class JaxRsResponseHeadersThen implements Then { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private final ComparisonBuilder comparisonBuilder; - - JaxRsResponseHeadersThen(BlockBuilder blockBuilder, GeneratedClassMetaData metaData, - ComparisonBuilder comparisonBuilder) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = metaData; - this.comparisonBuilder = comparisonBuilder; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - validateResponseHeadersBlock(metadata); - return this; - } - - private void validateResponseHeadersBlock(SingleContractMetadata metadata) { - Response response = metadata.getContract().getResponse(); - Headers headers = response.getHeaders(); - Iterator
iterator = headers.getEntries().iterator(); - while (iterator.hasNext()) { - Header header = iterator.next(); - String text = processHeaderElement(header.getName(), header.getServerValue() instanceof NotToEscapePattern - ? header.getServerValue() : MapConverter.getTestSideValues(header.getServerValue())); - if (iterator.hasNext()) { - this.blockBuilder.addLineWithEnding(text); - } - else { - this.blockBuilder.addIndented(text); - } - } - } - - private String processHeaderElement(String property, Object value) { - if (value instanceof NotToEscapePattern) { - return this.comparisonBuilder.assertThat("response.getHeaderString(\"" + property + "\")") - + this.comparisonBuilder.createComparison(((NotToEscapePattern) value).getServerValue()); - } - else if (value instanceof Number) { - return this.comparisonBuilder.assertThat("response.getHeaderString(\"" + property + "\")", value); - } - else if (value instanceof ExecutionProperty) { - return ((ExecutionProperty) value).insertValue("response.getHeaderString(\"" + property + "\")"); - } - else { - return this.comparisonBuilder.assertThat("response.getHeaderString(\"" + property + "\")") - + this.comparisonBuilder.createComparison(value); - } - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return metadata.getContract().getResponse().getHeaders() != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsStaticImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsStaticImports.java deleted file mode 100644 index 1cbf87b7e7..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsStaticImports.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.config.TestMode; - -class JaxRsStaticImports implements Imports { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] IMPORTS = { "javax.ws.rs.client.Entity.*" }; - - JaxRsStaticImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - Arrays.stream(IMPORTS).forEach(s -> this.blockBuilder.addLineWithEnding("import static " + s)); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.configProperties.getTestMode() == TestMode.JAXRSCLIENT; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsStatusCodeThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsStatusCodeThen.java deleted file mode 100644 index 6d5c8e6759..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsStatusCodeThen.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.spec.internal.Response; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class JaxRsStatusCodeThen implements Then { - - private final BlockBuilder blockBuilder; - - private final ComparisonBuilder comparisonBuilder; - - JaxRsStatusCodeThen(BlockBuilder blockBuilder, ComparisonBuilder comparisonBuilder) { - this.blockBuilder = blockBuilder; - this.comparisonBuilder = comparisonBuilder; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - Response response = metadata.getContract().getResponse(); - this.blockBuilder.addIndented( - this.comparisonBuilder.assertThat("response.getStatus()", response.getStatus().getServerValue())) - .addEndingIfNotPresent(); - return this; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return true; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsThen.java deleted file mode 100644 index b592a34417..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsThen.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class JaxRsThen implements Then, BodyMethodVisitor, JaxRsAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private final List thens = new LinkedList<>(); - - JaxRsThen(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData, BodyParser bodyParser, - ComparisonBuilder comparisonBuilder) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - this.thens.addAll(Arrays.asList(new JaxRsStatusCodeThen(this.blockBuilder, comparisonBuilder), - new JaxRsResponseHeadersThen(this.blockBuilder, generatedClassMetaData, comparisonBuilder), - new JaxRsResponseCookiesThen(this.blockBuilder, generatedClassMetaData, comparisonBuilder), - new GenericHttpBodyThen(this.blockBuilder, generatedClassMetaData, bodyParser, comparisonBuilder))); - } - - @Override - public MethodVisitor apply(SingleContractMetadata singleContractMetadata) { - startBodyBlock(this.blockBuilder, "then:"); - bodyBlock(this.blockBuilder, this.thens, singleContractMetadata); - return this; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return acceptType(this.generatedClassMetaData, singleContractMetadata); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsUrlPathWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsUrlPathWhen.java deleted file mode 100644 index c0d6268190..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsUrlPathWhen.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Iterator; - -import org.springframework.cloud.contract.spec.internal.DslProperty; -import org.springframework.cloud.contract.spec.internal.ExecutionProperty; -import org.springframework.cloud.contract.spec.internal.MatchingStrategy; -import org.springframework.cloud.contract.spec.internal.QueryParameter; -import org.springframework.cloud.contract.spec.internal.QueryParameters; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.MapConverter; - -class JaxRsUrlPathWhen implements When, JaxRsAcceptor, QueryParamsResolver { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private final BodyParser bodyParser; - - JaxRsUrlPathWhen(BlockBuilder blockBuilder, GeneratedClassMetaData metaData, BodyParser bodyParser) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = metaData; - this.bodyParser = bodyParser; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - appendUrlPathAndQueryParameters(metadata.getContract().getRequest()); - return this; - } - - private void appendUrlPathAndQueryParameters(Request request) { - if (request.getUrl() != null) { - this.blockBuilder.addIndented(".path(" + concreteUrl(request.getUrl()) + ")"); - appendQueryParams(request.getUrl().getQueryParameters()); - } - else if (request.getUrlPath() != null) { - this.blockBuilder.addIndented(".path(" + concreteUrl(request.getUrlPath()) + ")"); - appendQueryParams(request.getUrlPath().getQueryParameters()); - } - } - - private String concreteUrl(DslProperty url) { - Object testSideUrl = MapConverter.getTestSideValues(url); - if (!(testSideUrl instanceof ExecutionProperty)) { - return '"' + testSideUrl.toString() + '"'; - } - return testSideUrl.toString(); - } - - private void appendQueryParams(QueryParameters queryParameters) { - if (queryParameters == null || queryParameters.getParameters().isEmpty()) { - return; - } - this.blockBuilder.addEmptyLine(); - Iterator iterator = queryParameters.getParameters().stream().filter(this::allowedQueryParameter) - .iterator(); - while (iterator.hasNext()) { - QueryParameter param = iterator.next(); - String queryParamValue = getQueryParamValue(param); - String text = ".queryParam(\"" + param.getName() + "\", " + queryParamValue + ")"; - if (iterator.hasNext()) { - this.blockBuilder.addLine(text); - } - else { - this.blockBuilder.addIndented(text); - } - } - } - - private String getQueryParamValue(QueryParameter param) { - Object serverValue = param.getServerValue(); - if (serverValue instanceof ExecutionProperty) { - return ((ExecutionProperty) serverValue).getExecutionCommand(); - } - return this.bodyParser.quotedShortText(resolveParamValue(param)); - } - - /** - * @return {@code true} if the query parameter is allowed - */ - private boolean allowedQueryParameter(QueryParameter param) { - return allowedQueryParameter(param.getServerValue()); - } - - /** - * @return {@code true} if the query parameter is allowed - */ - private boolean allowedQueryParameter(MatchingStrategy matchingStrategy) { - return matchingStrategy.getType() != MatchingStrategy.Type.ABSENT; - } - - /** - * @return {@code true} if the query parameter is allowed - */ - private boolean allowedQueryParameter(Object o) { - if (o instanceof QueryParameter) { - return allowedQueryParameter((QueryParameter) o); - } - else if (o instanceof MatchingStrategy) { - return allowedQueryParameter((MatchingStrategy) o); - } - else if (o instanceof DslProperty) { - return allowedQueryParameter(((DslProperty) o).getServerValue()); - } - return true; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return acceptType(this.generatedClassMetaData, metadata); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsWhen.java deleted file mode 100644 index eb844faff9..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JaxRsWhen.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class JaxRsWhen implements When, BodyMethodVisitor, JaxRsAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private final JaxRsBodyParser bodyParser; - - private final List whens = new LinkedList<>(); - - JaxRsWhen(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData, JaxRsBodyParser bodyParser) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - this.bodyParser = bodyParser; - this.whens - .addAll(Arrays.asList(new JaxRsUrlPathWhen(this.blockBuilder, this.generatedClassMetaData, bodyParser), - new JaxRsRequestWhen(this.blockBuilder, this.generatedClassMetaData), - new JaxRsRequestHeadersWhen(this.blockBuilder, bodyParser), - new JaxRsRequestCookiesWhen(this.blockBuilder, bodyParser), - new JaxRsRequestMethodWhen(this.blockBuilder, this.generatedClassMetaData), - new JaxRsRequestInvokerWhen(this.blockBuilder))); - } - - @Override - public MethodVisitor apply(SingleContractMetadata singleContractMetadata) { - startBodyBlock(this.blockBuilder, "when:"); - this.blockBuilder.addIndented("Response response = webTarget"); - this.blockBuilder.indent(); - indentedBodyBlock(this.blockBuilder, this.whens, singleContractMetadata); - this.blockBuilder.addEmptyLine().endBlock(); - if (expectsResponseBody(singleContractMetadata)) { - this.blockBuilder.addLineWithEnding("String responseAsString = " + this.bodyParser.readEntity()); - } - this.blockBuilder.endBlock(); - return this; - } - - private boolean expectsResponseBody(SingleContractMetadata metadata) { - return metadata.getContract().getResponse().getBody() != null; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return acceptType(this.generatedClassMetaData, singleContractMetadata); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JsonBodyVerificationBuilder.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JsonBodyVerificationBuilder.java deleted file mode 100644 index 1868fb4858..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JsonBodyVerificationBuilder.java +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.math.BigDecimal; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.Function; - -import com.jayway.jsonpath.DocumentContext; -import com.jayway.jsonpath.JsonPath; -import com.jayway.jsonpath.PathNotFoundException; -import groovy.json.JsonOutput; -import org.apache.commons.beanutils.PropertyUtilsBean; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.ContractTemplate; -import org.springframework.cloud.contract.spec.internal.BodyMatcher; -import org.springframework.cloud.contract.spec.internal.BodyMatchers; -import org.springframework.cloud.contract.spec.internal.ExecutionProperty; -import org.springframework.cloud.contract.spec.internal.MatchingType; -import org.springframework.cloud.contract.spec.internal.RegexProperty; -import org.springframework.cloud.contract.verifier.template.TemplateProcessor; -import org.springframework.cloud.contract.verifier.util.JsonPaths; -import org.springframework.cloud.contract.verifier.util.JsonToJsonPathsConverter; -import org.springframework.cloud.contract.verifier.util.MapConverter; - -/** - * @author Marcin Grzejszczak - * @author Olga Maciaszek-Sharma - * @since 2.1.0 - */ -class JsonBodyVerificationBuilder implements BodyMethodGeneration, ClassVerifier { - - private static final String FROM_REQUEST_PREFIX = "request."; - - private static final String FROM_REQUEST_BODY = "escapejsonbody"; - - private static final String FROM_REQUEST_PATH = "path"; - - private final boolean assertJsonSize; - - private final TemplateProcessor templateProcessor; - - private final ContractTemplate contractTemplate; - - private final Contract contract; - - private final Optional lineSuffix; - - private final Function postProcessJsonPathCall; - - // FIXME - // Passing way more arguments here than I would like to, but since we are planning a - // major - // refactoring of this module for Hoxton release, leaving it this way for now - JsonBodyVerificationBuilder(boolean assertJsonSize, TemplateProcessor templateProcessor, - ContractTemplate contractTemplate, Contract contract, Optional lineSuffix, - Function postProcessJsonPathCall) { - this.assertJsonSize = assertJsonSize; - this.templateProcessor = templateProcessor; - this.contractTemplate = contractTemplate; - this.contract = contract; - this.lineSuffix = lineSuffix; - this.postProcessJsonPathCall = postProcessJsonPathCall; - } - - Object addJsonResponseBodyCheck(BlockBuilder bb, Object convertedResponseBody, BodyMatchers bodyMatchers, - String responseString, boolean shouldCommentOutBDDBlocks) { - appendJsonPath(bb, responseString); - DocumentContext parsedRequestBody = null; - boolean dontParseStrings = convertedResponseBody instanceof Map; - Function parsingFunction = dontParseStrings ? MapConverter.IDENTITY - : MapConverter.JSON_PARSING_FUNCTION; - if (hasRequestBody()) { - Object testSideRequestBody = MapConverter.getTestSideValues(contract.getRequest().getBody(), - parsingFunction); - parsedRequestBody = JsonPath.parse(testSideRequestBody); - if (convertedResponseBody instanceof String - && !textContainsJsonPathTemplate(convertedResponseBody.toString())) { - convertedResponseBody = templateProcessor.transform(contract.getRequest(), - convertedResponseBody.toString()); - } - } - Object copiedBody = cloneBody(convertedResponseBody); - convertedResponseBody = JsonToJsonPathsConverter.removeMatchingJsonPaths(convertedResponseBody, bodyMatchers); - - // If it was a map or list where all elements covered by matchers - json paths - // should not include empty check - boolean includeEmptyCheck = !mapOrListBodyReducedToEmpty(copiedBody, convertedResponseBody); - - // remove quotes from fromRequest objects before picking json paths - TestSideRequestTemplateModel templateModel = hasRequestBody() - ? TestSideRequestTemplateModel.from(contract.getRequest()) : null; - convertedResponseBody = MapConverter.transformValues(convertedResponseBody, - returnReferencedEntries(templateModel), parsingFunction); - JsonPaths jsonPaths = new JsonToJsonPathsConverter(assertJsonSize) - .transformToJsonPathWithTestsSideValues(convertedResponseBody, parsingFunction, includeEmptyCheck); - - DocumentContext finalParsedRequestBody = parsedRequestBody; - jsonPaths.forEach(it -> { - String method = it.method(); - method = processIfTemplateIsPresent(method, finalParsedRequestBody); - String postProcessedMethod = templateProcessor.containsJsonPathTemplateEntry(method) ? method - : postProcessJsonPathCall.apply(method); - bb.addLine("assertThatJson(parsedJson)" + postProcessedMethod); - addColonIfRequired(lineSuffix, bb); - }); - doBodyMatchingIfPresent(bodyMatchers, bb, copiedBody, shouldCommentOutBDDBlocks); - return convertedResponseBody; - } - - private boolean mapOrListBodyReducedToEmpty(Object originalBody, Object convertedBody) { - int origSize = originalBody instanceof Map ? ((Map) originalBody).size() : -1; - int convertedSize = convertedBody instanceof Map ? ((Map) convertedBody).size() : -1; - if (origSize > 0 && convertedSize == 0) { - return true; - } - origSize = originalBody instanceof List ? ((List) originalBody).size() : -1; - convertedSize = convertedBody instanceof List ? ((List) convertedBody).size() : -1; - return (origSize > 0 && convertedSize == 0); - } - - private boolean hasRequestBody() { - return contract.getRequest() != null && contract.getRequest().getBody() != null; - } - - private void checkType(BlockBuilder bb, BodyMatcher it, Object elementFromBody) { - String method = "assertThat((Object) parsedJson.read(" + quotedAndEscaped(it.path()) + ")).isInstanceOf(" - + classToCheck(elementFromBody).getName() + ".class)"; - bb.addLine(postProcessJsonPathCall.apply(method)); - addColonIfRequired(lineSuffix, bb); - } - - // we want to make the type more generic (e.g. not ArrayList but List) - private String sizeCheckMethod(BodyMatcher bodyMatcher, String quotedAndEscaptedPath) { - String prefix = sizeCheckPrefix(bodyMatcher, quotedAndEscaptedPath); - if (bodyMatcher.minTypeOccurrence() != null && bodyMatcher.maxTypeOccurrence() != null) { - return prefix + "Between(" + bodyMatcher.minTypeOccurrence() + ", " + bodyMatcher.maxTypeOccurrence() + ")"; - } - else if (bodyMatcher.minTypeOccurrence() != null) { - return prefix + "GreaterThanOrEqualTo(" + bodyMatcher.minTypeOccurrence() + ")"; - } - else if (bodyMatcher.maxTypeOccurrence() != null) { - return prefix + "LessThanOrEqualTo(" + bodyMatcher.maxTypeOccurrence() + ")"; - } - return prefix; - } - - protected void buildCustomMatchingConditionForEachElement(BlockBuilder bb, String path, String valueAsParam) { - String method = "assertThat((java.lang.Iterable) parsedJson.read(" + path + ", java.util.Collection.class)).as(" - + path + ").allElementsMatch(" + valueAsParam + ")"; - bb.addLine(postProcessJsonPathCall.apply(method)); - } - - @Override - public void methodForEqualityCheck(BodyMatcher bodyMatcher, BlockBuilder bb, Object copiedBody) { - String path = quotedAndEscaped(bodyMatcher.path()); - Object retrievedValue = value(copiedBody, bodyMatcher); - retrievedValue = retrievedValue instanceof RegexProperty - ? ((RegexProperty) retrievedValue).getPattern().pattern() : retrievedValue; - String valueAsParam = retrievedValue instanceof String ? quotedAndEscaped(retrievedValue.toString()) - : objectToString(retrievedValue); - if (arrayRelated(path) && MatchingType.regexRelated(bodyMatcher.matchingType())) { - buildCustomMatchingConditionForEachElement(bb, path, valueAsParam); - } - else { - String comparisonMethod = bodyMatcher.matchingType() == MatchingType.EQUALITY ? "isEqualTo" : "matches"; - String classToCastTo = className(retrievedValue) + ".class"; - String method = "assertThat(parsedJson.read(" + path + ", " + classToCastTo + "))." + comparisonMethod + "(" - + valueAsParam + ")"; - bb.addLine(postProcessJsonPathCall.apply(method)); - } - addColonIfRequired(lineSuffix, bb); - } - - private String className(Object retrievedValue) { - return retrievedValue.getClass().getName().startsWith("java.lang") ? retrievedValue.getClass().getSimpleName() - : retrievedValue.getClass().getName(); - } - - private String objectToString(Object value) { - if (value instanceof Long) { - return String.valueOf(value).concat("L"); - } - else if (value instanceof Double) { - return String.valueOf(value).concat("D"); - } - else if (value instanceof BigDecimal) { - return quotedAndEscaped(value.toString()); - } - return String.valueOf(value); - } - - protected String processIfTemplateIsPresent(String method, DocumentContext parsedRequestBody) { - if (textContainsJsonPathTemplate(method) && hasRequestBody()) { - // Unquoting the values of non strings - String jsonPathEntry = templateProcessor.jsonPathFromTemplateEntry(method); - Object object = parsedRequestBody.read(jsonPathEntry); - if (!(object instanceof String)) { - return method - .replace('"' + contractTemplate.escapedOpeningTemplate(), - contractTemplate.escapedOpeningTemplate()) - .replace(contractTemplate.escapedClosingTemplate() + '"', - contractTemplate.escapedClosingTemplate()) - .replace('"' + contractTemplate.openingTemplate(), contractTemplate.openingTemplate()) - .replace(contractTemplate.closingTemplate() + '"', contractTemplate.closingTemplate()); - } - } - return method; - } - - @Override - public void methodForCommandExecution(BodyMatcher bodyMatcher, BlockBuilder bb, Object copiedBody) { - String path = quotedAndEscaped(bodyMatcher.path()); - // assert that path exists - retrieveObjectByPath(copiedBody, bodyMatcher.path()); - ExecutionProperty property = (ExecutionProperty) bodyMatcher.value(); - bb.addLine(postProcessJsonPathCall.apply(property.insertValue("parsedJson.read(" + path + ")"))); - addColonIfRequired(lineSuffix, bb); - } - - @Override - public void methodForNullCheck(BodyMatcher bodyMatcher, BlockBuilder bb) { - String quotedAndEscapedPath = quotedAndEscaped(bodyMatcher.path()); - String method = "assertThat((Object) parsedJson.read(" + quotedAndEscapedPath + ")).isNull()"; - bb.addLine(postProcessJsonPathCall.apply(method)); - addColonIfRequired(lineSuffix, bb); - } - - private boolean arrayRelated(String path) { - return path.contains("[*]") || path.contains(".."); - } - - @Override - public void methodForTypeCheck(BodyMatcher bodyMatcher, BlockBuilder bb, Object copiedBody) { - Object elementFromBody = value(copiedBody, bodyMatcher); - if (bodyMatcher.minTypeOccurrence() != null || bodyMatcher.maxTypeOccurrence() != null) { - checkType(bb, bodyMatcher, elementFromBody); - String quotedAndEscaptedPath = quotedAndEscaped(bodyMatcher.path()); - String method = "assertThat((java.lang.Iterable) parsedJson.read(" + quotedAndEscaptedPath - + ", java.util.Collection.class))." + sizeCheckMethod(bodyMatcher, quotedAndEscaptedPath); - bb.addLine(postProcessJsonPathCall.apply(method)); - addColonIfRequired(lineSuffix, bb); - } - else { - checkType(bb, bodyMatcher, elementFromBody); - } - } - - private static Object value(Object body, BodyMatcher bodyMatcher) { - if (bodyMatcher.matchingType() == MatchingType.EQUALITY || bodyMatcher.value() == null) { - return retrieveObjectByPath(body, bodyMatcher.path()); - } - return bodyMatcher.value(); - } - - private static Object retrieveObjectByPath(Object body, String path) { - try { - return JsonPath.parse(body).read(path); - } - catch (PathNotFoundException e) { - throw new IllegalStateException("Entry for the provided JSON path <" + path - + "> doesn't exist in the body <" + JsonOutput.toJson(body) + ">", e); - } - } - - private Function returnReferencedEntries(TestSideRequestTemplateModel templateModel) { - return entry -> { - if (!(entry instanceof String) || templateModel == null) { - return entry; - } - String entryAsString = (String) entry; - if (this.templateProcessor.containsTemplateEntry(entryAsString) - && !this.templateProcessor.containsJsonPathTemplateEntry(entryAsString)) { - // TODO: HANDLEBARS LEAKING VIA request. - String justEntry = minus(entryAsString, contractTemplate.escapedOpeningTemplate()); - justEntry = minus(justEntry, contractTemplate.openingTemplate()); - justEntry = minus(justEntry, contractTemplate.escapedClosingTemplate()); - justEntry = minus(justEntry, contractTemplate.closingTemplate()); - justEntry = minus(justEntry, FROM_REQUEST_PREFIX); - if (FROM_REQUEST_BODY.equalsIgnoreCase(justEntry)) { - // the body should be transformed by standard mechanism - return contractTemplate.escapedOpeningTemplate() + FROM_REQUEST_PREFIX + "escapedBody" - + contractTemplate.escapedClosingTemplate(); - } - try { - Object result = new PropertyUtilsBean().getProperty(templateModel, justEntry); - // Path from the Test model is an object and we'd like to return its - // String representation - if (FROM_REQUEST_PATH.equals(justEntry)) { - return result.toString(); - } - return result; - } - catch (Exception ignored) { - return entry; - } - } - return entry; - }; - } - - private static String minus(CharSequence self, Object target) { - String s = self.toString(); - String text = target.toString(); - int index = s.indexOf(text); - if (index == -1) { - return s; - } - int end = index + text.length(); - if (s.length() > end) { - return s.substring(0, index) + s.substring(end); - } - return s.substring(0, index); - } - - private boolean textContainsJsonPathTemplate(String method) { - return templateProcessor.containsTemplateEntry(method) - && templateProcessor.containsJsonPathTemplateEntry(method); - } - - /** - * Appends to {@link BlockBuilder} parsing of the JSON Path document - */ - private void appendJsonPath(BlockBuilder blockBuilder, String json) { - blockBuilder.addLine("DocumentContext parsedJson = JsonPath.parse(" + json + ")"); - addColonIfRequired(lineSuffix, blockBuilder); - } - - private String sizeCheckPrefix(BodyMatcher bodyMatcher, String quotedAndEscapedPath) { - String description = "as(" + quotedAndEscapedPath + ")."; - String prefix = description + "has"; - if (arrayRelated(bodyMatcher.path())) { - prefix = prefix + "Flattened"; - } - return prefix + "Size"; - } - - private void doBodyMatchingIfPresent(BodyMatchers bodyMatchers, BlockBuilder bb, Object responseBody, - boolean shouldCommentOutBDDBlocks) { - if (bodyMatchers != null && bodyMatchers.hasMatchers()) { - bb.addEmptyLine(); - addBodyMatchingBlock(bodyMatchers.matchers(), bb, responseBody, shouldCommentOutBDDBlocks); - } - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JsonPathImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JsonPathImports.java deleted file mode 100644 index f506dcc4cf..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JsonPathImports.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class JsonPathImports implements Imports { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] IMPORTS = { "com.jayway.jsonpath.DocumentContext", "com.jayway.jsonpath.JsonPath" }; - - JsonPathImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - Arrays.stream(IMPORTS).forEach(s -> this.blockBuilder.addLineWithEnding("import " + s)); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.listOfFiles.stream().anyMatch(metadata -> metadata - .getConvertedContractWithMetadata().stream().anyMatch(SingleContractMetadata::isJson)); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingAssertThatThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingAssertThatThen.java deleted file mode 100644 index 942eb36598..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingAssertThatThen.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class MessagingAssertThatThen implements Then { - - private final BlockBuilder blockBuilder; - - MessagingAssertThatThen(BlockBuilder blockBuilder) { - this.blockBuilder = blockBuilder; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - this.blockBuilder - .addLineWithEnding(metadata.getContract().getOutputMessage().getAssertThat().getExecutionCommand()); - return this; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return metadata.getContract().getOutputMessage().getAssertThat() != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingAssertThatWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingAssertThatWhen.java deleted file mode 100644 index a70ba2e7e6..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingAssertThatWhen.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class MessagingAssertThatWhen implements When { - - private final BlockBuilder blockBuilder; - - MessagingAssertThatWhen(BlockBuilder blockBuilder) { - this.blockBuilder = blockBuilder; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - this.blockBuilder.addIndented(metadata.getContract().getInput().getAssertThat().getExecutionCommand()); - return this; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return metadata.getContract().getInput().getAssertThat() != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingBodyParser.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingBodyParser.java deleted file mode 100644 index 40cb96a5bc..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingBodyParser.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.spec.internal.BodyMatchers; -import org.springframework.cloud.contract.spec.internal.DslProperty; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -interface MessagingBodyParser extends BodyParser { - - default String responseAsString() { - return "contractVerifierObjectMapper.writeValueAsString(response.getPayload())"; - } - - default String byteArrayString() { - return "response.getPayloadAsByteArray()"; - } - - @Override - default DslProperty responseBody(SingleContractMetadata metadata) { - return metadata.getContract().getOutputMessage().getBody(); - } - - @Override - default BodyMatchers responseBodyMatchers(SingleContractMetadata metadata) { - return metadata.getContract().getOutputMessage().getBodyMatchers(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingBodyThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingBodyThen.java deleted file mode 100644 index e0f1cc4a39..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingBodyThen.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class MessagingBodyThen implements Then, BodyMethodVisitor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private final ComparisonBuilder comparisonBuilder; - - private final List thens = new LinkedList<>(); - - private final BodyParser bodyParser; - - MessagingBodyThen(BlockBuilder blockBuilder, GeneratedClassMetaData metaData, ComparisonBuilder comparisonBuilder) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = metaData; - this.comparisonBuilder = comparisonBuilder; - this.bodyParser = comparisonBuilder.bodyParser(); - this.thens.addAll(Arrays.asList( - new GenericBinaryBodyThen(blockBuilder, metaData, this.bodyParser, this.comparisonBuilder), - new GenericTextBodyThen(blockBuilder, metaData, this.bodyParser, this.comparisonBuilder), - new GenericJsonBodyThen(blockBuilder, metaData, this.bodyParser, this.comparisonBuilder), - new GenericXmlBodyThen(blockBuilder, this.bodyParser))); - } - - @Override - public MethodVisitor apply(SingleContractMetadata singleContractMetadata) { - endBodyBlock(this.blockBuilder); - startBodyBlock(this.blockBuilder, "and:"); - this.thens.stream().filter(then -> then.accept(singleContractMetadata)) - .forEach(then -> then.apply(singleContractMetadata)); - return this; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return singleContractMetadata.isMessaging() && this.bodyParser.responseBody(singleContractMetadata) != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingFields.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingFields.java deleted file mode 100644 index 80013ec133..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingFields.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class MessagingFields implements Field { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] FIELDS = { "@Inject ContractVerifierMessaging contractVerifierMessaging", - "@Inject ContractVerifierObjectMapper contractVerifierObjectMapper" }; - - MessagingFields(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Field call() { - Arrays.stream(FIELDS).forEach(this.blockBuilder::addLineWithEnding); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.listOfFiles.stream().anyMatch(metadata -> metadata - .getConvertedContractWithMetadata().stream().anyMatch(SingleContractMetadata::isMessaging)); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingHeadersThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingHeadersThen.java deleted file mode 100644 index 0c88cf5f7b..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingHeadersThen.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.regex.Pattern; - -import org.springframework.cloud.contract.spec.internal.ExecutionProperty; -import org.springframework.cloud.contract.spec.internal.NotToEscapePattern; -import org.springframework.cloud.contract.spec.internal.OutputMessage; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.MapConverter; - -class MessagingHeadersThen implements Then, BodyMethodVisitor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private final ComparisonBuilder comparisonBuilder; - - MessagingHeadersThen(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData, - ComparisonBuilder comparisonBuilder) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - this.comparisonBuilder = comparisonBuilder; - } - - @Override - public MethodVisitor apply(SingleContractMetadata singleContractMetadata) { - endBodyBlock(this.blockBuilder); - startBodyBlock(this.blockBuilder, "and:"); - OutputMessage outputMessage = singleContractMetadata.getContract().getOutputMessage(); - outputMessage.getHeaders().executeForEachHeader(header -> { - processHeaderElement(header.getName(), header.getServerValue() instanceof NotToEscapePattern - ? header.getServerValue() : MapConverter.getTestSideValues(header.getServerValue())); - }); - return this; - } - - private void appendLineWithHeaderNotNull(String property) { - this.blockBuilder.addLineWithEnding( - this.comparisonBuilder.assertThatIsNotNull("response.getHeader(\"" + property + "\")")); - } - - private void processHeaderElement(String property, Object value) { - if (value instanceof Number) { - processHeaderElement(property, (Number) value); - } - else if (value instanceof Pattern) { - processHeaderElement(property, (Pattern) value); - } - else if (value instanceof ExecutionProperty) { - processHeaderElement(property, (ExecutionProperty) value); - } - else { - processHeaderElement(property, value.toString()); - } - } - - private void processHeaderElement(String property, String value) { - appendLineWithHeaderNotNull(property); - this.blockBuilder.addLineWithEnding( - this.comparisonBuilder.assertThat("response.getHeader(\"" + property + "\").toString()", value)); - } - - private void processHeaderElement(String property, Number value) { - appendLineWithHeaderNotNull(property); - blockBuilder.addLineWithEnding( - this.comparisonBuilder.assertThat("response.getHeader(\"" + property + "\")", value)); - } - - private void processHeaderElement(String property, Pattern pattern) { - appendLineWithHeaderNotNull(property); - blockBuilder.addLineWithEnding( - this.comparisonBuilder.assertThat("response.getHeader(\"" + property + "\").toString()", pattern)); - } - - private void processHeaderElement(String property, ExecutionProperty exec) { - appendLineWithHeaderNotNull(property); - blockBuilder.addLineWithEnding(exec.insertValue("response.getHeader(\"" + property + "\").toString()")); - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return singleContractMetadata.isMessaging() - && singleContractMetadata.getContract().getOutputMessage().getHeaders() != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingImports.java deleted file mode 100644 index 7c90afcc6f..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingImports.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class MessagingImports implements Imports { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] IMPORTS = { "javax.inject.Inject", - "org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper", - "org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage", - "org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging" }; - - MessagingImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - Arrays.stream(IMPORTS).forEach(s -> this.blockBuilder.addLineWithEnding("import " + s)); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.listOfFiles.stream().anyMatch(metadata -> metadata - .getConvertedContractWithMetadata().stream().anyMatch(SingleContractMetadata::isMessaging)); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingReceiveMessageThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingReceiveMessageThen.java deleted file mode 100644 index b982c01f86..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingReceiveMessageThen.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.spec.internal.ExecutionProperty; -import org.springframework.cloud.contract.spec.internal.OutputMessage; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class MessagingReceiveMessageThen implements Then, BodyMethodVisitor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private final ComparisonBuilder comparisonBuilder; - - private final BodyReader bodyReader; - - MessagingReceiveMessageThen(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData, - ComparisonBuilder comparisonBuilder) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - this.comparisonBuilder = comparisonBuilder; - this.bodyReader = new BodyReader(generatedClassMetaData); - } - - @Override - public MethodVisitor apply(SingleContractMetadata singleContractMetadata) { - OutputMessage outputMessage = singleContractMetadata.getContract().getOutputMessage(); - this.bodyReader.storeContractAsYaml(singleContractMetadata); - this.blockBuilder - .addIndented("ContractVerifierMessage response = contractVerifierMessaging.receive(" - + sentToValue(outputMessage.getSentTo().getServerValue()) + ",") - .addEmptyLine().indent() - .addIndented("contract(this, \"" + singleContractMetadata.methodName() + ".yml\"))").unindent() - .addEndingIfNotPresent().addEmptyLine(); - this.blockBuilder.addLineWithEnding(this.comparisonBuilder.assertThatIsNotNull("response")); - return this; - } - - private String sentToValue(Object sentTo) { - if (sentTo instanceof ExecutionProperty) { - return ((ExecutionProperty) sentTo).getExecutionCommand(); - } - return '"' + sentTo.toString() + '"'; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return singleContractMetadata.isMessaging() - && singleContractMetadata.getContract().getOutputMessage().getSentTo() != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingSpockNoMessageThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingSpockNoMessageThen.java deleted file mode 100644 index 762615ddba..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingSpockNoMessageThen.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class MessagingSpockNoMessageThen implements Then, BodyMethodVisitor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - MessagingSpockNoMessageThen(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public MethodVisitor apply(SingleContractMetadata singleContractMetadata) { - this.blockBuilder.addLineWithEnding("noExceptionThrown()"); - return this; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return singleContractMetadata.isMessaging() && singleContractMetadata.getContract().getOutputMessage() == null - && this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.SPOCK; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingStaticImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingStaticImports.java deleted file mode 100644 index 2f7cfe419a..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingStaticImports.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class MessagingStaticImports implements Imports { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] IMPORTS = { - "org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers", - "org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.fileToBytes" }; - - MessagingStaticImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - Arrays.stream(IMPORTS).forEach(s -> this.blockBuilder.addLineWithEnding("import static " + s)); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.listOfFiles.stream().anyMatch(metadata -> metadata - .getConvertedContractWithMetadata().stream().anyMatch(SingleContractMetadata::isMessaging)); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingTriggeredByWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingTriggeredByWhen.java deleted file mode 100644 index 0bcebc5bbb..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingTriggeredByWhen.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class MessagingTriggeredByWhen implements When { - - private final BlockBuilder blockBuilder; - - MessagingTriggeredByWhen(BlockBuilder blockBuilder) { - this.blockBuilder = blockBuilder; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - this.blockBuilder.addIndented(metadata.getContract().getInput().getTriggeredBy().getExecutionCommand()) - .addEndingIfNotPresent(); - return this; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return metadata.getContract().getInput().getTriggeredBy() != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingWhen.java deleted file mode 100644 index fdc2365a6e..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingWhen.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class MessagingWhen implements When, BodyMethodVisitor { - - private final BlockBuilder blockBuilder; - - private final List whens = new LinkedList<>(); - - MessagingWhen(BlockBuilder blockBuilder) { - this.blockBuilder = blockBuilder; - this.whens.addAll(Arrays.asList(new MessagingTriggeredByWhen(this.blockBuilder), - new MessagingAssertThatWhen(this.blockBuilder))); - } - - @Override - public MethodVisitor apply(SingleContractMetadata singleContractMetadata) { - startBodyBlock(this.blockBuilder, "when:"); - bodyBlock(this.blockBuilder, this.whens, singleContractMetadata); - this.blockBuilder.addEmptyLine(); - return this; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return singleContractMetadata.isMessaging(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingWithBodyThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingWithBodyThen.java deleted file mode 100644 index e692d3c9a3..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MessagingWithBodyThen.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class MessagingWithBodyThen implements Then, BodyMethodVisitor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private final ComparisonBuilder comparisonBuilder; - - private final List thens = new LinkedList<>(); - - MessagingWithBodyThen(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData, - ComparisonBuilder comparisonBuilder) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - this.comparisonBuilder = comparisonBuilder; - this.thens.addAll(Arrays.asList(new MessagingSpockNoMessageThen(this.blockBuilder, generatedClassMetaData), - new MessagingReceiveMessageThen(this.blockBuilder, generatedClassMetaData, this.comparisonBuilder), - new MessagingHeadersThen(this.blockBuilder, generatedClassMetaData, this.comparisonBuilder), - new MessagingBodyThen(this.blockBuilder, generatedClassMetaData, comparisonBuilder), - new MessagingAssertThatThen(this.blockBuilder))); - } - - @Override - public MethodVisitor apply(SingleContractMetadata singleContractMetadata) { - startBodyBlock(this.blockBuilder, "then:"); - bodyBlock(this.blockBuilder, this.thens, singleContractMetadata); - return this; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return singleContractMetadata.isMessaging() && singleContractMetadata.getContract().getOutputMessage() != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MetaDataBuilder.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MetaDataBuilder.java deleted file mode 100644 index bc5c309ea6..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MetaDataBuilder.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -class MetaDataBuilder { - - private final GeneratedTestClassBuilder parentBuilder; - - private final BlockBuilder builder; - - private final GeneratedClassMetaData metaData; - - MetaDataBuilder(GeneratedTestClassBuilder generatedTestClassBuilder) { - this.parentBuilder = generatedTestClassBuilder; - this.builder = generatedTestClassBuilder.blockBuilder; - this.metaData = generatedTestClassBuilder.generatedClassMetaData; - } - - MetaDataBuilder java() { - this.parentBuilder.metaData(new JavaClassMetaData(this.builder, this.metaData)); - return this; - } - - MetaDataBuilder groovy() { - this.parentBuilder.metaData(new GroovyClassMetaData(this.builder, this.metaData)); - return this; - } - - GeneratedTestClassBuilder build() { - return this.parentBuilder; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodAcceptor.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodAcceptor.java deleted file mode 100644 index 892fc09b72..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodAcceptor.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -interface MethodAcceptor { - - boolean accept(SingleContractMetadata metadata); - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodAnnotationBuilder.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodAnnotationBuilder.java deleted file mode 100644 index be738493fe..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodAnnotationBuilder.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -class MethodAnnotationBuilder { - - private final SingleMethodBuilder singleMethodBuilder; - - private final BlockBuilder builder; - - private final GeneratedClassMetaData metaData; - - MethodAnnotationBuilder(SingleMethodBuilder singleMethodBuilder) { - this.singleMethodBuilder = singleMethodBuilder; - this.builder = singleMethodBuilder.blockBuilder; - this.metaData = singleMethodBuilder.generatedClassMetaData; - } - - MethodAnnotationBuilder jUnit4() { - this.singleMethodBuilder.methodAnnotation(new JUnit4MethodAnnotation(this.builder, this.metaData), - new JUnit4IgnoreMethodAnnotation(this.builder, this.metaData)); - return this; - } - - MethodAnnotationBuilder jUnit5() { - this.singleMethodBuilder.methodAnnotation(new JUnit5MethodAnnotation(this.builder, this.metaData), - new JUnit5IgnoreMethodAnnotation(this.builder, this.metaData)); - return this; - } - - MethodAnnotationBuilder testNG() { - this.singleMethodBuilder.methodAnnotation(new TestNGMethodAnnotation(this.builder, this.metaData)); - return this; - } - - MethodAnnotationBuilder spock() { - this.singleMethodBuilder.methodAnnotation(new SpockIgnoreMethodAnnotation(this.builder, this.metaData)); - return this; - } - - SingleMethodBuilder build() { - return this.singleMethodBuilder; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodAnnotations.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodAnnotations.java deleted file mode 100644 index 7b86fd95c1..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodAnnotations.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.springframework.cloud.contract.verifier.builder; - -interface MethodAnnotations extends MethodVisitor { - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodMetadata.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodMetadata.java deleted file mode 100644 index fef5fc115d..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodMetadata.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -/** - * Describes metadata of a single method. - */ -interface MethodMetadata extends Acceptor { - - // validate_foo() - MethodMetadata name(SingleContractMetadata metadata); - - // public - MethodMetadata modifier(); - - // void - MethodMetadata returnType(); - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodMetadataBuilder.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodMetadataBuilder.java deleted file mode 100644 index 48863c9176..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodMetadataBuilder.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -class MethodMetadataBuilder { - - private final SingleMethodBuilder singleMethodBuilder; - - private final BlockBuilder builder; - - private final GeneratedClassMetaData metaData; - - MethodMetadataBuilder(SingleMethodBuilder singleMethodBuilder) { - this.singleMethodBuilder = singleMethodBuilder; - this.builder = singleMethodBuilder.blockBuilder; - this.metaData = singleMethodBuilder.generatedClassMetaData; - } - - MethodMetadataBuilder jUnit() { - this.singleMethodBuilder.methodMetadata(new JUnitMethodMetadata(this.builder, this.metaData)); - return this; - } - - MethodMetadataBuilder spock() { - this.singleMethodBuilder.methodMetadata(new SpockMethodMetadata(this.builder, this.metaData)); - return this; - } - - SingleMethodBuilder build() { - return this.singleMethodBuilder; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodPostProcessor.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodPostProcessor.java deleted file mode 100644 index ac2cf7c32e..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodPostProcessor.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -interface MethodPostProcessor extends MethodVisitor { - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodPreProcessor.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodPreProcessor.java deleted file mode 100644 index 84fb213c9d..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodPreProcessor.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -interface MethodPreProcessor extends MethodVisitor { - - @Override - default MethodVisitor apply(SingleContractMetadata singleContractMetadata) { - return this; - } - - /** - * @return {@code true} if method should be processed - */ - default boolean shouldContinue() { - return true; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodVisitor.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodVisitor.java deleted file mode 100644 index b0c8a45b9c..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MethodVisitor.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.function.Function; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -interface MethodVisitor extends MethodAcceptor, Function> { - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcAcceptor.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcAcceptor.java deleted file mode 100644 index b8a7986b33..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcAcceptor.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestMode; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -interface MockMvcAcceptor { - - default boolean acceptType(GeneratedClassMetaData generatedClassMetaData, - SingleContractMetadata singleContractMetadata) { - return generatedClassMetaData.configProperties.getTestMode() == TestMode.MOCKMVC - && singleContractMetadata.isHttp(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcAsyncWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcAsyncWhen.java deleted file mode 100644 index ed482cd950..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcAsyncWhen.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.spec.internal.Response; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class MockMvcAsyncWhen implements When, MockMvcAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - MockMvcAsyncWhen(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - Response response = metadata.getContract().getResponse(); - addAsync(); - if (response.getDelay() != null) { - String delay = ".timeout(" + response.getDelay().getServerValue() + ")"; - this.blockBuilder.append(delay); - } - return this; - } - - private void addAsync() { - this.blockBuilder.addIndented(".when().async()"); - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - boolean accept = acceptType(this.generatedClassMetaData, metadata); - if (!accept) { - return false; - } - Response response = metadata.getContract().getResponse(); - return response.getAsync() || response.getDelay() != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcBodyGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcBodyGiven.java deleted file mode 100644 index e34bf3dcf8..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcBodyGiven.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.spec.internal.ExecutionProperty; -import org.springframework.cloud.contract.spec.internal.FromFileProperty; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.ContentType; - -class MockMvcBodyGiven implements Given { - - private final BlockBuilder blockBuilder; - - private final BodyReader bodyReader; - - private final BodyParser bodyParser; - - MockMvcBodyGiven(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData, BodyParser bodyParser) { - this.blockBuilder = blockBuilder; - this.bodyReader = new BodyReader(generatedClassMetaData); - this.bodyParser = bodyParser; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - processInput(this.blockBuilder, metadata); - return this; - } - - private void processInput(BlockBuilder bb, SingleContractMetadata metadata) { - Object body; - Request request = metadata.getContract().getRequest(); - Object serverValue = request.getBody().getServerValue(); - if (serverValue instanceof ExecutionProperty || serverValue instanceof FromFileProperty) { - body = request.getBody().getServerValue(); - } - else { - body = this.bodyParser.requestBodyAsString(metadata); - } - bb.addIndented(getBodyString(metadata, body)); - } - - private String getBodyString(SingleContractMetadata metadata, Object body) { - String value; - if (body instanceof ExecutionProperty) { - value = body.toString(); - } - else if (body instanceof FromFileProperty) { - FromFileProperty fileProperty = (FromFileProperty) body; - value = fileProperty.isByte() - ? this.bodyReader.readBytesFromFileString(metadata, fileProperty, CommunicationType.REQUEST) - : this.bodyReader.readStringFromFileString(metadata, fileProperty, CommunicationType.REQUEST); - } - else { - String escaped = escapeRequestSpecialChars(metadata, body.toString()); - value = this.bodyParser.quotedEscapedLongText(escaped); - } - return ".body(" + value + ")"; - } - - private String escapeRequestSpecialChars(SingleContractMetadata metadata, String string) { - if (metadata.getInputTestContentType() == ContentType.JSON) { - return string.replaceAll("\\\\n", "\\\\\\\\n"); - } - return string; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - Request request = metadata.getContract().getRequest(); - return request != null && request.getBody() != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcCookiesGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcCookiesGiven.java deleted file mode 100644 index 5314aec80f..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcCookiesGiven.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Iterator; - -import org.springframework.cloud.contract.spec.internal.Cookie; -import org.springframework.cloud.contract.spec.internal.MatchingStrategy; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class MockMvcCookiesGiven implements Given { - - private final BlockBuilder blockBuilder; - - MockMvcCookiesGiven(BlockBuilder blockBuilder) { - this.blockBuilder = blockBuilder; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - processInput(metadata.getContract().getRequest()); - return this; - } - - private void processInput(Request request) { - Iterator iterator = request.getCookies().getEntries().iterator(); - while (iterator.hasNext()) { - Cookie cookie = iterator.next(); - if (ofAbsentType(cookie)) { - return; - } - if (iterator.hasNext()) { - this.blockBuilder.addLine(string(cookie)); - } - else { - this.blockBuilder.addIndented(string(cookie)); - } - } - } - - private String string(Cookie cookie) { - return ".cookie(" + ContentHelper.getTestSideForNonBodyValue(cookie.getKey()) + ", " - + ContentHelper.getTestSideForNonBodyValue(cookie.getServerValue()) + ")"; - } - - private boolean ofAbsentType(Cookie cookie) { - return cookie.getServerValue() instanceof MatchingStrategy - && MatchingStrategy.Type.ABSENT.equals(((MatchingStrategy) cookie.getServerValue()).getType()); - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - Request request = metadata.getContract().getRequest(); - return request != null && request.getCookies() != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcHeadersGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcHeadersGiven.java deleted file mode 100644 index 194a4e8d53..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcHeadersGiven.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Iterator; - -import org.springframework.cloud.contract.spec.internal.Header; -import org.springframework.cloud.contract.spec.internal.Headers; -import org.springframework.cloud.contract.spec.internal.MatchingStrategy; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.MapConverter; - -class MockMvcHeadersGiven implements Given { - - private final BlockBuilder blockBuilder; - - MockMvcHeadersGiven(BlockBuilder blockBuilder) { - this.blockBuilder = blockBuilder; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - processInput(this.blockBuilder, metadata.getContract().getRequest().getHeaders()); - return this; - } - - private void processInput(BlockBuilder bb, Headers headers) { - Iterator
iterator = headers.getEntries().iterator(); - while (iterator.hasNext()) { - Header header = iterator.next(); - if (ofAbsentType(header)) { - continue; - } - if (iterator.hasNext()) { - bb.addLine(string(header)); - } - else { - bb.addIndented(string(header)); - } - } - } - - private String string(Header header) { - return ".header(" - + ContentHelper.getTestSideForNonBodyValue(header.getName()) + ", " + ContentHelper - .getTestSideForNonBodyValue(MapConverter.getTestSideValuesForNonBody(header.getServerValue())) - + ")"; - } - - private boolean ofAbsentType(Header header) { - return header.getServerValue() instanceof MatchingStrategy - && MatchingStrategy.Type.ABSENT.equals(((MatchingStrategy) header.getServerValue()).getType()); - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - Request request = metadata.getContract().getRequest(); - return request != null && request.getHeaders() != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcQueryParamsWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcQueryParamsWhen.java deleted file mode 100644 index 9439ec07bf..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcQueryParamsWhen.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Iterator; -import java.util.List; -import java.util.stream.Collectors; - -import org.springframework.cloud.contract.spec.internal.ExecutionProperty; -import org.springframework.cloud.contract.spec.internal.MatchingStrategy; -import org.springframework.cloud.contract.spec.internal.QueryParameter; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.spec.internal.Url; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.MapConverter; - -class MockMvcQueryParamsWhen implements When, MockMvcAcceptor, QueryParamsResolver { - - private static final String QUERY_PARAM_METHOD = "queryParam"; - - private final BlockBuilder blockBuilder; - - private final BodyParser bodyParser; - - MockMvcQueryParamsWhen(BlockBuilder blockBuilder, BodyParser bodyParser) { - this.blockBuilder = blockBuilder; - this.bodyParser = bodyParser; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - Request request = metadata.getContract().getRequest(); - Url url = getUrl(request); - addQueryParameters(url); - return this; - } - - private Url getUrl(Request request) { - if (request.getUrl() != null) { - return request.getUrl(); - } - if (request.getUrlPath() != null) { - return request.getUrlPath(); - } - throw new IllegalStateException("URL is not set!"); - } - - private void addQueryParameters(Url buildUrl) { - List queryParameters = buildUrl.getQueryParameters().getParameters().stream() - .filter(this::allowedQueryParameter).collect(Collectors.toList()); - Iterator iterator = queryParameters.iterator(); - while (iterator.hasNext()) { - QueryParameter parameter = iterator.next(); - String text = addQueryParameter(parameter); - if (iterator.hasNext()) { - this.blockBuilder.addLine(text); - } - else { - this.blockBuilder.addIndented(text); - } - } - } - - private boolean allowedQueryParameter(Object o) { - if (o instanceof QueryParameter) { - return allowedQueryParameter(((QueryParameter) o).getServerValue()); - } - else if (o instanceof MatchingStrategy) { - return !MatchingStrategy.Type.ABSENT.equals(((MatchingStrategy) o).getType()); - } - return true; - } - - private String addQueryParameter(QueryParameter queryParam) { - String queryParamValue = getQueryParamValue(queryParam); - return "." + QUERY_PARAM_METHOD + "(" + this.bodyParser.quotedLongText(queryParam.getName()) + "," - + queryParamValue + ")"; - } - - private String getQueryParamValue(QueryParameter queryParam) { - Object serverValue = queryParam.getServerValue(); - if (serverValue instanceof ExecutionProperty) { - return ((ExecutionProperty) serverValue).getExecutionCommand(); - } - return this.bodyParser.quotedLongText(resolveParamValue(MapConverter.getTestSideValuesForNonBody(queryParam))); - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - Request request = metadata.getContract().getRequest(); - Url url = getUrl(request); - return url.getQueryParameters() != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcRequestGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcRequestGiven.java deleted file mode 100644 index 9895ca36c4..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcRequestGiven.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class MockMvcRequestGiven implements Given, MockMvcAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - MockMvcRequestGiven(BlockBuilder blockBuilder, GeneratedClassMetaData metaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = metaData; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - this.blockBuilder.addIndented("MockMvcRequestSpecification request = given()"); - return this; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return acceptType(this.generatedClassMetaData, metadata); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcResponseWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcResponseWhen.java deleted file mode 100644 index d4f0eec88b..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcResponseWhen.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class MockMvcResponseWhen implements When, MockMvcAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - MockMvcResponseWhen(BlockBuilder blockBuilder, GeneratedClassMetaData metaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = metaData; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - this.blockBuilder.addIndented("ResponseOptions response = given().spec(request)"); - return this; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return acceptType(this.generatedClassMetaData, metadata); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcRestAssuredImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcRestAssuredImports.java deleted file mode 100644 index b6d2105797..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcRestAssuredImports.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.config.TestMode; - -class MockMvcRestAssuredImports implements Imports { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] REST_ASSURED_3_IMPORTS = { - "io.restassured.module.mockmvc.specification.MockMvcRequestSpecification", - "io.restassured.response.ResponseOptions" }; - - MockMvcRestAssuredImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - Arrays.stream(REST_ASSURED_3_IMPORTS).forEach(s -> this.blockBuilder.addLineWithEnding("import " + s)); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.configProperties.getTestMode() == TestMode.MOCKMVC - && this.generatedClassMetaData.isAnyHttp(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcRestAssuredStaticImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcRestAssuredStaticImports.java deleted file mode 100644 index 1c68248a8e..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcRestAssuredStaticImports.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.config.TestMode; - -class MockMvcRestAssuredStaticImports implements Imports { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] REST_ASSURED_3_IMPORTS = { "io.restassured.module.mockmvc.RestAssuredMockMvc.*" }; - - MockMvcRestAssuredStaticImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - Arrays.stream(REST_ASSURED_3_IMPORTS).forEach(s -> this.blockBuilder.addLineWithEnding("import static " + s)); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.configProperties.getTestMode() == TestMode.MOCKMVC - && this.generatedClassMetaData.isAnyHttp(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcUrlWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcUrlWhen.java deleted file mode 100644 index 8c873f5690..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcUrlWhen.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.spec.internal.ExecutionProperty; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.spec.internal.Url; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.MapConverter; - -class MockMvcUrlWhen implements When, MockMvcAcceptor, QueryParamsResolver { - - private final BlockBuilder blockBuilder; - - private final BodyParser bodyParser; - - MockMvcUrlWhen(BlockBuilder blockBuilder, BodyParser bodyParser) { - this.blockBuilder = blockBuilder; - this.bodyParser = bodyParser; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - Request request = metadata.getContract().getRequest(); - Url url = getUrl(request); - addUrl(url, request); - return this; - } - - private Url getUrl(Request request) { - if (request.getUrl() != null) { - return request.getUrl(); - } - if (request.getUrlPath() != null) { - return request.getUrlPath(); - } - throw new IllegalStateException("URL is not set!"); - } - - private void addUrl(Url buildUrl, Request request) { - Object testSideUrl = MapConverter.getTestSideValues(buildUrl); - String method = request.getMethod().getServerValue().toString().toLowerCase(); - String url = testSideUrl.toString(); - if (!(testSideUrl instanceof ExecutionProperty)) { - url = this.bodyParser.quotedShortText(testSideUrl.toString()); - } - this.blockBuilder.addIndented("." + method + "(" + url + ")"); - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return true; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/NameProvider.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/NameProvider.java deleted file mode 100644 index c242275197..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/NameProvider.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.io.File; -import java.util.Collection; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.verifier.file.ContractMetadata; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.ContractVerifierUtil; -import org.springframework.cloud.contract.verifier.util.NamesUtil; -import org.springframework.util.StringUtils; - -class NameProvider { - - private static final Log log = LogFactory.getLog(NameProvider.class); - - String methodName(SingleContractMetadata singleContractMetadata) { - return ContractVerifierUtil.TEST_METHOD_PREFIX + generateMethodName(singleContractMetadata); - } - - private String generateMethodName(SingleContractMetadata singleContractMetadata) { - ContractMetadata contractMetadata = singleContractMetadata.getContractMetadata(); - File stubsFile = contractMetadata.getPath().toFile(); - Contract stubContent = singleContractMetadata.getContract(); - if (StringUtils.hasText(stubContent.getName())) { - String name = NamesUtil.camelCase(NamesUtil.convertIllegalPackageChars(stubContent.getName())); - if (log.isDebugEnabled()) { - log.debug("Overriding the default test name with [" + name + "]"); - } - return name; - } - else if (contractMetadata.getConvertedContract().size() > 1) { - int index = findIndexOf(contractMetadata.getConvertedContract(), stubContent); - String name = camelCasedMethodFromFileName(stubsFile) + "_" + index; - if (log.isTraceEnabled()) { - log.trace("Scenario found. The method name will be [" + name + "]"); - } - return name; - } - String name = camelCasedMethodFromFileName(stubsFile); - if (StringUtils.hasText(name) && log.isTraceEnabled()) { - log.trace("The method name will be [" + name + "]"); - } - return name; - } - - private int findIndexOf(Collection contracts, Contract stubContent) { - int i = 0; - for (Contract contract : contracts) { - if (contract.equals(stubContent)) { - return i; - } - i++; - } - return -1; - } - - private String camelCasedMethodFromFileName(File stubsFile) { - return NamesUtil.camelCase(NamesUtil.convertIllegalMethodNameChars( - NamesUtil.toLastDot(NamesUtil.afterLast(stubsFile.getPath(), File.separator)))); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/OurCallable.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/OurCallable.java deleted file mode 100644 index 541618a067..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/OurCallable.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -interface OurCallable { - - T call(); - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/QueryParamsResolver.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/QueryParamsResolver.java deleted file mode 100644 index 367ac906fb..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/QueryParamsResolver.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.spec.internal.DslProperty; -import org.springframework.cloud.contract.spec.internal.MatchingStrategy; -import org.springframework.cloud.contract.spec.internal.OptionalProperty; -import org.springframework.cloud.contract.spec.internal.QueryParameter; - -interface QueryParamsResolver { - - /** - * Converts the query parameter value into String - */ - default String resolveParamValue(Object value) { - if (value instanceof QueryParameter) { - return resolveParamValue(((QueryParameter) value).getServerValue()); - } - else if (value instanceof OptionalProperty) { - return resolveParamValue(((OptionalProperty) value).optionalPattern()); - } - else if (value instanceof MatchingStrategy) { - return resolveParamValue(((MatchingStrategy) value).getServerValue()); - } - else if (value instanceof DslProperty) { - return resolveParamValue(((DslProperty) value).getServerValue()); - } - return value == null ? "null" : value.toString(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredAcceptor.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredAcceptor.java deleted file mode 100644 index 1386beb465..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredAcceptor.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestMode; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -interface RestAssuredAcceptor { - - default boolean acceptType(GeneratedClassMetaData generatedClassMetaData, - SingleContractMetadata singleContractMetadata) { - return generatedClassMetaData.configProperties.getTestMode() != TestMode.CUSTOM - && generatedClassMetaData.configProperties.getTestMode() != TestMode.JAXRSCLIENT - && singleContractMetadata.isHttp(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredBodyParser.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredBodyParser.java deleted file mode 100644 index 61c5b5b0b4..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredBodyParser.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -interface RestAssuredBodyParser extends BodyParser { - - BodyParser INSTANCE = new RestAssuredBodyParser() { - }; - - @Override - default String responseAsString() { - return "response.getBody().asString()"; - } - - @Override - default String byteArrayString() { - return "response.getBody().asByteArray()"; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredCookiesThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredCookiesThen.java deleted file mode 100644 index 8153908b97..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredCookiesThen.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.spec.internal.Response; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class RestAssuredCookiesThen implements Then, RestAssuredAcceptor, CookieElementProcessor { - - private final BlockBuilder blockBuilder; - - private final ComparisonBuilder comparisonBuilder; - - RestAssuredCookiesThen(BlockBuilder blockBuilder, ComparisonBuilder comparisonBuilder) { - this.blockBuilder = blockBuilder; - this.comparisonBuilder = comparisonBuilder; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - processCookies(metadata); - return this; - } - - @Override - public ComparisonBuilder comparisonBuilder() { - return this.comparisonBuilder; - } - - @Override - public BlockBuilder blockBuilder() { - return this.blockBuilder; - } - - @Override - public String cookieKey(String key) { - return "response.cookie(\"" + key + "\")"; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - Response response = metadata.getContract().getResponse(); - return response.getCookies() != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredGiven.java deleted file mode 100644 index 84e15323ba..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredGiven.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class RestAssuredGiven implements Given, BodyMethodVisitor, RestAssuredAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private final List requestGivens = new LinkedList<>(); - - private final List bodyGivens = new LinkedList<>(); - - RestAssuredGiven(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData, BodyParser bodyParser) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - this.requestGivens.addAll(Arrays.asList(new MockMvcRequestGiven(blockBuilder, generatedClassMetaData), - new SpockMockMvcRequestGiven(blockBuilder, generatedClassMetaData), - new ExplicitRequestGiven(blockBuilder, generatedClassMetaData), - new WebTestClientRequestGiven(blockBuilder, generatedClassMetaData))); - this.bodyGivens - .addAll(Arrays.asList(new MockMvcHeadersGiven(blockBuilder), new MockMvcCookiesGiven(blockBuilder), - new MockMvcBodyGiven(blockBuilder, generatedClassMetaData, bodyParser), - new JavaMultipartGiven(blockBuilder, generatedClassMetaData, bodyParser), - new SpockMockMvcMultipartGiven(blockBuilder, generatedClassMetaData, bodyParser), - new SpockExplicitMultipartGiven(blockBuilder, generatedClassMetaData, bodyParser), - new SpockWebTestClientMultipartGiven(blockBuilder, generatedClassMetaData, bodyParser))); - } - - @Override - public MethodVisitor apply(SingleContractMetadata singleContractMetadata) { - startBodyBlock(this.blockBuilder, "given:"); - addRequestGivenLine(singleContractMetadata); - indentedBodyBlock(this.blockBuilder, this.bodyGivens, singleContractMetadata); - this.blockBuilder.addEmptyLine(); - return this; - } - - private void addRequestGivenLine(SingleContractMetadata singleContractMetadata) { - this.requestGivens.stream().filter(given -> given.accept(singleContractMetadata)).findFirst().orElseThrow( - () -> new IllegalStateException("No matching request building Given implementation for Rest Assured")) - .apply(singleContractMetadata); - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return acceptType(this.generatedClassMetaData, singleContractMetadata); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredHeadersThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredHeadersThen.java deleted file mode 100644 index 659ac65d77..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredHeadersThen.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Iterator; - -import org.springframework.cloud.contract.spec.internal.ExecutionProperty; -import org.springframework.cloud.contract.spec.internal.Header; -import org.springframework.cloud.contract.spec.internal.Headers; -import org.springframework.cloud.contract.spec.internal.NotToEscapePattern; -import org.springframework.cloud.contract.spec.internal.Response; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.MapConverter; - -class RestAssuredHeadersThen implements Then, RestAssuredAcceptor { - - private final BlockBuilder blockBuilder; - - private final ComparisonBuilder comparisonBuilder; - - RestAssuredHeadersThen(BlockBuilder blockBuilder, ComparisonBuilder comparisonBuilder) { - this.blockBuilder = blockBuilder; - this.comparisonBuilder = comparisonBuilder; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - Response response = metadata.getContract().getResponse(); - Headers headers = response.getHeaders(); - Iterator
iterator = headers.getEntries().iterator(); - while (iterator.hasNext()) { - Header header = iterator.next(); - String text = processHeaderElement(header.getName(), header.getServerValue() instanceof NotToEscapePattern - ? header.getServerValue() : MapConverter.getTestSideValues(header.getServerValue())); - if (iterator.hasNext()) { - this.blockBuilder.addLineWithEnding(text); - } - else { - this.blockBuilder.addIndented(text); - } - } - this.blockBuilder.addEndingIfNotPresent(); - return this; - } - - private String processHeaderElement(String property, Object value) { - if (value instanceof NotToEscapePattern) { - return this.comparisonBuilder.assertThat("response.header(\"" + property + "\")") - + matchesManuallyEscapedPattern((NotToEscapePattern) value); - } - else if (value instanceof ExecutionProperty) { - return ((ExecutionProperty) value).insertValue("response.header(\"" + property + "\")"); - - } - return this.comparisonBuilder.assertThat("response.header(\"" + property + "\")", value); - } - - private String matchesManuallyEscapedPattern(NotToEscapePattern value) { - return this.comparisonBuilder.matchesEscaped(value.getServerValue().pattern().replace("\\", "\\\\")); - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - Response response = metadata.getContract().getResponse(); - return response.getHeaders() != null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredStatusCodeThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredStatusCodeThen.java deleted file mode 100644 index 0bf1be99c2..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredStatusCodeThen.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.spec.internal.Response; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class RestAssuredStatusCodeThen implements Then { - - private final BlockBuilder blockBuilder; - - private final ComparisonBuilder comparisonBuilder; - - RestAssuredStatusCodeThen(BlockBuilder blockBuilder, ComparisonBuilder comparisonBuilder) { - this.blockBuilder = blockBuilder; - this.comparisonBuilder = comparisonBuilder; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - Response response = metadata.getContract().getResponse(); - this.blockBuilder.addIndented( - this.comparisonBuilder.assertThat("response.statusCode()", response.getStatus().getServerValue())) - .addEndingIfNotPresent(); - return this; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return true; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredThen.java deleted file mode 100644 index b4c05c85fc..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredThen.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class RestAssuredThen implements Then, BodyMethodVisitor, RestAssuredAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private final List thens = new LinkedList<>(); - - RestAssuredThen(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData, BodyParser bodyParser, - ComparisonBuilder comparisonBuilder) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - this.thens.addAll(Arrays.asList(new RestAssuredStatusCodeThen(this.blockBuilder, comparisonBuilder), - new RestAssuredHeadersThen(this.blockBuilder, comparisonBuilder), - new RestAssuredCookiesThen(this.blockBuilder, comparisonBuilder), - new GenericHttpBodyThen(this.blockBuilder, generatedClassMetaData, bodyParser, comparisonBuilder))); - } - - @Override - public MethodVisitor apply(SingleContractMetadata singleContractMetadata) { - startBodyBlock(this.blockBuilder, "then:"); - bodyBlock(this.blockBuilder, this.thens, singleContractMetadata); - return this; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return acceptType(this.generatedClassMetaData, singleContractMetadata); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredWhen.java deleted file mode 100644 index 84dc095783..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredWhen.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class RestAssuredWhen implements When, BodyMethodVisitor, RestAssuredAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private final List responseWhens = new LinkedList<>(); - - private final List whens = new LinkedList<>(); - - RestAssuredWhen(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData, BodyParser bodyParser) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - this.responseWhens.addAll(Arrays.asList(new MockMvcResponseWhen(blockBuilder, this.generatedClassMetaData), - new SpockMockMvcResponseWhen(blockBuilder, this.generatedClassMetaData), - new ExplicitResponseWhen(blockBuilder, this.generatedClassMetaData), - new WebTestClientResponseWhen(blockBuilder, this.generatedClassMetaData))); - this.whens.addAll(Arrays.asList(new MockMvcQueryParamsWhen(this.blockBuilder, bodyParser), - new MockMvcAsyncWhen(this.blockBuilder, this.generatedClassMetaData), - new MockMvcUrlWhen(this.blockBuilder, bodyParser))); - } - - @Override - public MethodVisitor apply(SingleContractMetadata singleContractMetadata) { - startBodyBlock(this.blockBuilder, "when:"); - addResponseWhenLine(singleContractMetadata); - indentedBodyBlock(this.blockBuilder, this.whens, singleContractMetadata); - this.blockBuilder.addEmptyLine(); - return this; - } - - private void addResponseWhenLine(SingleContractMetadata singleContractMetadata) { - this.responseWhens.stream().filter(when -> when.accept(singleContractMetadata)).findFirst().orElseThrow( - () -> new IllegalStateException("No matching request building When implementation for Rest Assured")) - .apply(singleContractMetadata); - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return acceptType(this.generatedClassMetaData, singleContractMetadata); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SingleMethodBuilder.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SingleMethodBuilder.java deleted file mode 100644 index bd23b0d0a4..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SingleMethodBuilder.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.stream.Collectors; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -/** - * Builds a single method body. Must be executed per contract. - * - * @author Olga Maciaszek-Sharma - * @author Marcin Grzejszczak - * @since 2.2.0 - */ -class SingleMethodBuilder { - - private static final Log log = LogFactory.getLog(SingleMethodBuilder.class); - - private List methodAnnotations = new LinkedList<>(); - - private List methodMetadata = new LinkedList<>(); - - private List methodPreProcessors = new LinkedList<>(); - - private List methodPostProcessors = new LinkedList<>(); - - private List givens = new LinkedList<>(); - - private List whens = new LinkedList<>(); - - private List thens = new LinkedList<>(); - - final GeneratedClassMetaData generatedClassMetaData; - - final BlockBuilder blockBuilder; - - private SingleMethodBuilder(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - static SingleMethodBuilder builder(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - return new SingleMethodBuilder(blockBuilder, generatedClassMetaData); - } - - SingleMethodBuilder methodAnnotation(MethodAnnotations methodAnnotations) { - this.methodAnnotations.add(methodAnnotations); - return this; - } - - MethodAnnotationBuilder methodAnnotation() { - return new MethodAnnotationBuilder(this); - } - - SingleMethodBuilder methodAnnotation(MethodAnnotations... methodAnnotations) { - this.methodAnnotations.addAll(Arrays.asList(methodAnnotations)); - return this; - } - - MethodMetadataBuilder methodMetadata() { - return new MethodMetadataBuilder(this); - } - - SingleMethodBuilder methodMetadata(MethodMetadata... methodMetadata) { - this.methodMetadata.addAll(Arrays.asList(methodMetadata)); - return this; - } - - SingleMethodBuilder restAssured() { - return given(new JavaRestAssuredGiven(this.blockBuilder, this.generatedClassMetaData)) - .given(new SpockRestAssuredGiven(this.blockBuilder, this.generatedClassMetaData)) - .when(new JavaRestAssuredWhen(this.blockBuilder, this.generatedClassMetaData)) - .when(new SpockRestAssuredWhen(this.blockBuilder, this.generatedClassMetaData)) - .then(new JavaRestAssuredThen(this.blockBuilder, this.generatedClassMetaData)) - .then(new SpockRestAssuredThen(this.blockBuilder, this.generatedClassMetaData)) - .methodPostProcessor(new TemplateUpdatingMethodPostProcessor(this.blockBuilder)); - } - - SingleMethodBuilder customMode() { - return given(new CustomModeGiven(this.blockBuilder, this.generatedClassMetaData, CustomModeBodyParser.INSTANCE)) - .when(new CustomModeWhen(this.blockBuilder, this.generatedClassMetaData)) - .then(new CustomModeThen(this.blockBuilder, this.generatedClassMetaData, CustomModeBodyParser.INSTANCE, - ComparisonBuilder.JAVA_HTTP_INSTANCE)) - .methodPostProcessor(new TemplateUpdatingMethodPostProcessor(this.blockBuilder)); - } - - SingleMethodBuilder jaxRs() { - return given(new JaxRsGiven(this.generatedClassMetaData)) - .when(new JavaJaxRsWhen(this.blockBuilder, this.generatedClassMetaData)) - .when(new SpockJaxRsWhen(this.blockBuilder, this.generatedClassMetaData)) - .then(new JavaJaxRsThen(this.blockBuilder, this.generatedClassMetaData)) - .then(new SpockJaxRsThen(this.blockBuilder, this.generatedClassMetaData)) - .methodPostProcessor(new TemplateUpdatingMethodPostProcessor(this.blockBuilder)); - } - - SingleMethodBuilder messaging() { - // @formatter:off - return when(new MessagingWhen(this.blockBuilder)) - .then(new JavaMessagingWithBodyThen(this.blockBuilder, - this.generatedClassMetaData)) - .then(new SpockMessagingWithBodyThen(this.blockBuilder, - this.generatedClassMetaData)) - .then(new SpockMessagingEmptyThen(this.blockBuilder, - this.generatedClassMetaData)) - .methodPostProcessor(new TemplateUpdatingMethodPostProcessor(this.blockBuilder)); - // @formatter:on - } - - SingleMethodBuilder given(Given... given) { - this.givens.addAll(Arrays.asList(given)); - return this; - } - - SingleMethodBuilder when(When... when) { - this.whens.addAll(Arrays.asList(when)); - return this; - } - - SingleMethodBuilder then(Then... then) { - this.thens.addAll(Arrays.asList(then)); - return this; - } - - SingleMethodBuilder methodPreProcessor(MethodPreProcessor methodPreProcessor) { - this.methodPreProcessors.add(methodPreProcessor); - return this; - } - - SingleMethodBuilder methodPostProcessor(MethodPostProcessor methodPostProcessor) { - this.methodPostProcessors.add(methodPostProcessor); - return this; - } - - /** - * Mutates the {@link BlockBuilder} to generate a methodBuilder - * @return block builder with contents of a single methodBuilder - */ - BlockBuilder build() { - MethodMetadata methodMetadatum = pickMetadatum(); - // \n - this.blockBuilder.addEmptyLine(); - this.generatedClassMetaData.toSingleContractMetadata().forEach(metaData -> { - boolean stopProcessing = shouldStopProcessing(metaData); - if (stopProcessing) { - if (log.isDebugEnabled()) { - log.debug("The method for meta data [" + metaData - + "] will not be processed further. At least one method pre-processor declared that this method should be skipped."); - } - return; - } - // @Test - if (visit(this.methodAnnotations, metaData, false)) { - this.blockBuilder.addEmptyLine(); - } - // @formatter:off - // public void validate_foo() - this.blockBuilder.append(methodMetadatum::modifier) - .appendWithSpace(methodMetadatum::returnType) - .appendWithSpace(() -> methodMetadatum.name(metaData)) - .append("() throws Exception "); - // (space) { - this.blockBuilder.inBraces(() -> { - // (indent) given - if (visit(this.givens, metaData)) { - this.blockBuilder.addEmptyLine(); - } - // (indent) when - visit(this.whens, metaData); - this.blockBuilder.addEmptyLine(); - // (indent) then - visit(this.thens, metaData); - }); - this.blockBuilder.addEmptyLine(); - this.methodPostProcessors - .stream() - .filter(m -> m.accept(metaData)) - .forEach(m -> m.apply(metaData)); - // } - }); - // @formatter:on - return this.blockBuilder; - } - - private boolean shouldStopProcessing(SingleContractMetadata metaData) { - List matchingPreProcessors = this.methodPreProcessors.stream() - .filter(m -> m.accept(metaData)).collect(Collectors.toCollection(LinkedList::new)); - matchingPreProcessors.forEach(m -> m.apply(metaData)); - return matchingPreProcessors.stream().anyMatch(m -> !m.shouldContinue()); - } - - private MethodMetadata pickMetadatum() { - return this.methodMetadata.stream().filter(Acceptor::accept).findFirst() - .orElseThrow(() -> new IllegalStateException("No matching method metadata found")); - } - - private boolean visit(List list, SingleContractMetadata metaData) { - return visit(list, metaData, true); - } - - private boolean visit(List list, SingleContractMetadata metaData, boolean addLineEnding) { - List visitors = list.stream().filter(o -> o.accept(metaData)) - .collect(Collectors.toList()); - Iterator iterator = visitors.iterator(); - while (iterator.hasNext()) { - MethodVisitor visitor = iterator.next(); - visitor.apply(metaData); - if (addLineEnding) { - this.blockBuilder.addEndingIfNotPresent(); - } - if (iterator.hasNext()) { - this.blockBuilder.addEmptyLine(); - } - } - return !visitors.isEmpty(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SingleTestGenerator.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SingleTestGenerator.java deleted file mode 100644 index 22b1606dd4..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SingleTestGenerator.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.nio.file.Path; -import java.util.Collection; - -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties; -import org.springframework.cloud.contract.verifier.file.ContractMetadata; - -/** - * Builds a single test. - * - * @since 1.1.0 - */ -public interface SingleTestGenerator { - - /** - * Creates contents of a single test class in which all test scenarios from the - * contract metadata should be placed. - * @param properties - properties passed to the plugin - * @param listOfFiles - list of parsed contracts with additional metadata - * @param generatedClassData - information about the generated class - * @param includedDirectoryRelativePath - relative path to the included directory - * @return contents of a single test class - */ - String buildClass(ContractVerifierConfigProperties properties, Collection listOfFiles, - String includedDirectoryRelativePath, GeneratedClassData generatedClassData); - - class GeneratedClassData { - - public final String className; - - public final String classPackage; - - public final Path testClassPath; - - public GeneratedClassData(String className, String classPackage, Path testClassPath) { - this.className = className; - this.classPackage = classPackage; - this.testClassPath = testClassPath; - } - - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockExplicitMultipartGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockExplicitMultipartGiven.java deleted file mode 100644 index ba341ed66c..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockExplicitMultipartGiven.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Map; - -import org.springframework.cloud.contract.spec.internal.NamedProperty; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.ContentUtils; -import org.springframework.cloud.contract.verifier.util.MapConverter; - -class SpockExplicitMultipartGiven implements Given, ExplicitAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private final BodyReader bodyReader; - - private final BodyParser bodyParser; - - SpockExplicitMultipartGiven(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData, - BodyParser bodyParser) { - this.blockBuilder = blockBuilder; - this.bodyReader = new BodyReader(generatedClassMetaData); - this.bodyParser = bodyParser; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - getMultipartParameters(metadata).entrySet() - .forEach(entry -> this.blockBuilder.addLine(getMultipartParameterLine(metadata, entry))); - return this; - } - - private String getMultipartParameterLine(SingleContractMetadata metadata, Map.Entry parameter) { - if (parameter.getValue() instanceof NamedProperty) { - return ".multiPart(" + getMultipartFileParameterContent(metadata, parameter.getKey(), - (NamedProperty) parameter.getValue()) + ")"; - } - return getParameterString(parameter); - } - - @SuppressWarnings("unchecked") - private Map getMultipartParameters(SingleContractMetadata metadata) { - return (Map) metadata.getContract().getRequest().getMultipart().getServerValue(); - } - - private String getMultipartFileParameterContent(SingleContractMetadata metadata, String propertyName, - NamedProperty propertyValue) { - return ContentUtils.getGroovyMultipartFileParameterContent(propertyName, propertyValue, - fileProp -> this.bodyReader.readBytesFromFileString(metadata, fileProp, CommunicationType.REQUEST)); - } - - private String getParameterString(Map.Entry parameter) { - return ".param(" + this.bodyParser.quotedShortText(parameter.getKey()) + ", " - + this.bodyParser.quotedShortText(MapConverter.getTestSideValuesForNonBody(parameter.getValue())) + ")"; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - Request request = metadata.getContract().getRequest(); - return request != null && request.getMultipart() != null && acceptType(this.generatedClassMetaData) - && this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.SPOCK; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockIgnoreImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockIgnoreImports.java deleted file mode 100644 index e1afb5d80c..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockIgnoreImports.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestFramework; - -class SpockIgnoreImports implements Imports { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - SpockIgnoreImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - this.blockBuilder.addLineWithEnding("import spock.lang.Ignore"); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.SPOCK - && this.generatedClassMetaData.listOfFiles.stream() - .anyMatch(metadata -> metadata.isIgnored() || metadata.getConvertedContractWithMetadata() - .stream().anyMatch(m -> m.isIgnored() || m.isInProgress())); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockIgnoreMethodAnnotation.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockIgnoreMethodAnnotation.java deleted file mode 100644 index 33a420833e..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockIgnoreMethodAnnotation.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class SpockIgnoreMethodAnnotation implements MethodAnnotations { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] ANNOTATIONS = { "@Ignore" }; - - SpockIgnoreMethodAnnotation(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public MethodVisitor apply(SingleContractMetadata singleContractMetadata) { - Arrays.stream(ANNOTATIONS).forEach(this.blockBuilder::addIndented); - return this; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.SPOCK - && (singleContractMetadata.getContractMetadata().isIgnored() - || singleContractMetadata.getContract().isIgnored() - || singleContractMetadata.getContract().isInProgress()); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockImports.java deleted file mode 100644 index 52f8f0a2f8..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockImports.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.config.TestFramework; - -class SpockImports implements Imports { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] IMPORTS = { "spock.lang.Specification" }; - - SpockImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - Arrays.stream(IMPORTS).forEach(s -> this.blockBuilder.addLineWithEnding("import " + s)); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.SPOCK; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockJaxRsBodyParser.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockJaxRsBodyParser.java deleted file mode 100644 index 340e88e3c3..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockJaxRsBodyParser.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.template.HandlebarsTemplateProcessor; - -interface SpockJaxRsBodyParser extends JaxRsBodyParser, GroovyBodyParser { - - SpockJaxRsBodyParser INSTANCE = HandlebarsTemplateProcessor::new; - - @Override - default String readEntity() { - return "response.readEntity(String)"; - } - - @Override - default String responseAsString() { - return "responseAsString"; - } - - @Override - default String byteArrayString() { - return "response.readEntity(byte[])"; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockJaxRsThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockJaxRsThen.java deleted file mode 100644 index 5056aebcf0..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockJaxRsThen.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class SpockJaxRsThen extends JaxRsThen { - - private final GeneratedClassMetaData metaData; - - SpockJaxRsThen(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - super(blockBuilder, generatedClassMetaData, SpockJaxRsBodyParser.INSTANCE, - GroovyComparisonBuilder.JAXRS_HTTP_INSTANCE); - this.metaData = generatedClassMetaData; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return super.accept(singleContractMetadata) - && this.metaData.configProperties.getTestFramework() == TestFramework.SPOCK; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockJaxRsWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockJaxRsWhen.java deleted file mode 100644 index 48c2304912..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockJaxRsWhen.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class SpockJaxRsWhen extends JaxRsWhen { - - private final GeneratedClassMetaData metaData; - - SpockJaxRsWhen(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - super(blockBuilder, generatedClassMetaData, SpockJaxRsBodyParser.INSTANCE); - this.metaData = generatedClassMetaData; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return super.accept(singleContractMetadata) - && this.metaData.configProperties.getTestFramework() == TestFramework.SPOCK; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMessagingBodyParser.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMessagingBodyParser.java deleted file mode 100644 index 6448138d17..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMessagingBodyParser.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.template.HandlebarsTemplateProcessor; - -interface SpockMessagingBodyParser extends MessagingBodyParser, GroovyBodyParser { - - BodyParser INSTANCE = (SpockMessagingBodyParser) HandlebarsTemplateProcessor::new; - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMessagingEmptyThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMessagingEmptyThen.java deleted file mode 100644 index f71bca69e8..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMessagingEmptyThen.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class SpockMessagingEmptyThen implements Then, BodyMethodVisitor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - SpockMessagingEmptyThen(BlockBuilder blockBuilder, GeneratedClassMetaData metaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = metaData; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - startBodyBlock(this.blockBuilder, "then:"); - this.blockBuilder.addLineWithEnding("noExceptionThrown()"); - endBodyBlock(this.blockBuilder); - return this; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return metadata.isMessaging() - && this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.SPOCK - && metadata.getContract().getOutputMessage() == null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMessagingWithBodyThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMessagingWithBodyThen.java deleted file mode 100644 index b703fe1710..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMessagingWithBodyThen.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class SpockMessagingWithBodyThen extends MessagingWithBodyThen { - - private final GeneratedClassMetaData metaData; - - SpockMessagingWithBodyThen(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - super(blockBuilder, generatedClassMetaData, GroovyComparisonBuilder.SPOCK_MESSAGING_INSTANCE); - this.metaData = generatedClassMetaData; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return super.accept(singleContractMetadata) - && this.metaData.configProperties.getTestFramework() == TestFramework.SPOCK; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMethodMetadata.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMethodMetadata.java deleted file mode 100644 index 49c031fdd3..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMethodMetadata.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class SpockMethodMetadata implements MethodMetadata { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData metaData; - - private final NameProvider nameProvider = new NameProvider(); - - SpockMethodMetadata(BlockBuilder blockBuilder, GeneratedClassMetaData metaData) { - this.blockBuilder = blockBuilder; - this.metaData = metaData; - } - - @Override - public MethodMetadata name(SingleContractMetadata metaData) { - this.blockBuilder.addAtTheEnd(this.nameProvider.methodName(metaData)); - return this; - } - - @Override - public MethodMetadata modifier() { - return this; - } - - @Override - public MethodMetadata returnType() { - this.blockBuilder.addIndented("def"); - return this; - } - - @Override - public boolean accept() { - return this.metaData.configProperties.getTestFramework() == TestFramework.SPOCK; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMockMvcMultipartGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMockMvcMultipartGiven.java deleted file mode 100644 index 68effa8986..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMockMvcMultipartGiven.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Map; - -import org.springframework.cloud.contract.spec.internal.NamedProperty; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.ContentUtils; -import org.springframework.cloud.contract.verifier.util.MapConverter; - -class SpockMockMvcMultipartGiven implements Given, MockMvcAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private final BodyReader bodyReader; - - private final BodyParser bodyParser; - - SpockMockMvcMultipartGiven(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData, - BodyParser bodyParser) { - this.blockBuilder = blockBuilder; - this.bodyReader = new BodyReader(generatedClassMetaData); - this.bodyParser = bodyParser; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - getMultipartParameters(metadata).entrySet() - .forEach(entry -> this.blockBuilder.addLine(getMultipartParameterLine(metadata, entry))); - return this; - } - - private String getMultipartParameterLine(SingleContractMetadata metadata, Map.Entry parameter) { - if (parameter.getValue() instanceof NamedProperty) { - return ".multiPart(" + getMultipartFileParameterContent(metadata, parameter.getKey(), - (NamedProperty) parameter.getValue()) + ")"; - } - return getParameterString(parameter); - } - - @SuppressWarnings("unchecked") - private Map getMultipartParameters(SingleContractMetadata metadata) { - return (Map) metadata.getContract().getRequest().getMultipart().getServerValue(); - } - - private String getMultipartFileParameterContent(SingleContractMetadata metadata, String propertyName, - NamedProperty propertyValue) { - return ContentUtils.getGroovyMultipartFileParameterContent(propertyName, propertyValue, - fileProp -> this.bodyReader.readBytesFromFileString(metadata, fileProp, CommunicationType.REQUEST)); - } - - private String getParameterString(Map.Entry parameter) { - return ".param(" + this.bodyParser.quotedShortText(parameter.getKey()) + ", " - + this.bodyParser.quotedShortText(MapConverter.getTestSideValuesForNonBody(parameter.getValue())) + ")"; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - Request request = metadata.getContract().getRequest(); - return request != null && request.getMultipart() != null && acceptType(this.generatedClassMetaData, metadata) - && this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.SPOCK; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMockMvcRequestGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMockMvcRequestGiven.java deleted file mode 100644 index cfbc3d9e67..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMockMvcRequestGiven.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class SpockMockMvcRequestGiven implements Given, MockMvcAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - SpockMockMvcRequestGiven(BlockBuilder blockBuilder, GeneratedClassMetaData metaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = metaData; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - this.blockBuilder.addIndented("def request = given()"); - return this; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return acceptType(this.generatedClassMetaData, metadata) - && this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.SPOCK; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMockMvcResponseWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMockMvcResponseWhen.java deleted file mode 100644 index 625542b8af..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMockMvcResponseWhen.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class SpockMockMvcResponseWhen implements When, MockMvcAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - SpockMockMvcResponseWhen(BlockBuilder blockBuilder, GeneratedClassMetaData metaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = metaData; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - this.blockBuilder.addIndented("def response = given().spec(request)"); - return this; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return acceptType(this.generatedClassMetaData, metadata) - && this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.SPOCK; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockOrderClassAnnotation.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockOrderClassAnnotation.java deleted file mode 100644 index e30d8a39b9..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockOrderClassAnnotation.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.config.TestFramework; - -class SpockOrderClassAnnotation implements ClassAnnotation { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] ANNOTATIONS = { "@Stepwise" }; - - SpockOrderClassAnnotation(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public ClassAnnotation call() { - Arrays.stream(ANNOTATIONS).forEach(this.blockBuilder::addLine); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.SPOCK - && this.generatedClassMetaData.listOfFiles.stream().anyMatch(meta -> meta.getOrder() != null); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockOrderImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockOrderImports.java deleted file mode 100644 index aea98b3122..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockOrderImports.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.config.TestFramework; - -class SpockOrderImports implements Imports { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] IMPORTS = { "spock.lang.Stepwise" }; - - SpockOrderImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - Arrays.stream(IMPORTS).forEach(s -> this.blockBuilder.addLineWithEnding("import " + s)); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.SPOCK - && this.generatedClassMetaData.listOfFiles.stream().anyMatch(meta -> meta.getOrder() != null); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockRestAssuredBodyParser.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockRestAssuredBodyParser.java deleted file mode 100644 index 9929a4c8ba..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockRestAssuredBodyParser.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.template.HandlebarsTemplateProcessor; - -interface SpockRestAssuredBodyParser extends RestAssuredBodyParser, GroovyBodyParser { - - BodyParser INSTANCE = (SpockRestAssuredBodyParser) HandlebarsTemplateProcessor::new; - - @Override - default String responseAsString() { - return "response.body.asString()"; - } - - @Override - default String byteArrayString() { - return "response.body.asByteArray()"; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockRestAssuredGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockRestAssuredGiven.java deleted file mode 100644 index b55da222ca..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockRestAssuredGiven.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class SpockRestAssuredGiven extends RestAssuredGiven { - - private final GeneratedClassMetaData metaData; - - SpockRestAssuredGiven(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - super(blockBuilder, generatedClassMetaData, SpockRestAssuredBodyParser.INSTANCE); - this.metaData = generatedClassMetaData; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return super.accept(singleContractMetadata) - && this.metaData.configProperties.getTestFramework() == TestFramework.SPOCK; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockRestAssuredThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockRestAssuredThen.java deleted file mode 100644 index 5a6f703e00..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockRestAssuredThen.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class SpockRestAssuredThen extends RestAssuredThen { - - private final GeneratedClassMetaData metaData; - - SpockRestAssuredThen(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - super(blockBuilder, generatedClassMetaData, SpockRestAssuredBodyParser.INSTANCE, - GroovyComparisonBuilder.SPOCK_HTTP_INSTANCE); - this.metaData = generatedClassMetaData; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return super.accept(singleContractMetadata) - && this.metaData.configProperties.getTestFramework() == TestFramework.SPOCK; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockRestAssuredWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockRestAssuredWhen.java deleted file mode 100644 index 18e4824bf6..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockRestAssuredWhen.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class SpockRestAssuredWhen extends RestAssuredWhen { - - private final GeneratedClassMetaData metaData; - - SpockRestAssuredWhen(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - super(blockBuilder, generatedClassMetaData, RestAssuredBodyParser.INSTANCE); - this.metaData = generatedClassMetaData; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return super.accept(singleContractMetadata) - && this.metaData.configProperties.getTestFramework() == TestFramework.SPOCK; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockWebTestClientMultipartGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockWebTestClientMultipartGiven.java deleted file mode 100644 index c7f754bcc2..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockWebTestClientMultipartGiven.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Map; - -import org.springframework.cloud.contract.spec.internal.NamedProperty; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.ContentUtils; -import org.springframework.cloud.contract.verifier.util.MapConverter; - -public class SpockWebTestClientMultipartGiven implements Given, WebTestClientAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private final BodyReader bodyReader; - - private final BodyParser bodyParser; - - SpockWebTestClientMultipartGiven(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData, - BodyParser bodyParser) { - this.blockBuilder = blockBuilder; - this.bodyReader = new BodyReader(generatedClassMetaData); - this.bodyParser = bodyParser; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - getMultipartParameters(metadata).entrySet() - .forEach(entry -> this.blockBuilder.addLine(getMultipartParameterLine(metadata, entry))); - return this; - } - - private String getMultipartParameterLine(SingleContractMetadata metadata, Map.Entry parameter) { - if (parameter.getValue() instanceof NamedProperty) { - return ".multiPart(" + getMultipartFileParameterContent(metadata, parameter.getKey(), - (NamedProperty) parameter.getValue()) + ")"; - } - return getParameterString(parameter); - } - - @SuppressWarnings("unchecked") - private Map getMultipartParameters(SingleContractMetadata metadata) { - return (Map) metadata.getContract().getRequest().getMultipart().getServerValue(); - } - - private String getMultipartFileParameterContent(SingleContractMetadata metadata, String propertyName, - NamedProperty propertyValue) { - return ContentUtils.getGroovyMultipartFileParameterContent(propertyName, propertyValue, - fileProp -> this.bodyReader.readBytesFromFileString(metadata, fileProp, CommunicationType.REQUEST)); - } - - private String getParameterString(Map.Entry parameter) { - return ".param(" + this.bodyParser.quotedShortText(parameter.getKey()) + ", " - + this.bodyParser.quotedShortText(MapConverter.getTestSideValuesForNonBody(parameter.getValue())) + ")"; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - Request request = metadata.getContract().getRequest(); - return request != null && request.getMultipart() != null && acceptType(this.generatedClassMetaData) - && this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.SPOCK; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SuppressWarningsClassAnnotation.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SuppressWarningsClassAnnotation.java deleted file mode 100644 index 74f54ba657..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SuppressWarningsClassAnnotation.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -class SuppressWarningsClassAnnotation implements ClassAnnotation { - - private final BlockBuilder blockBuilder; - - private static final String[] ANNOTATIONS = { "@SuppressWarnings(\"rawtypes\")" }; - - SuppressWarningsClassAnnotation(BlockBuilder blockBuilder) { - this.blockBuilder = blockBuilder; - } - - @Override - public ClassAnnotation call() { - Arrays.stream(ANNOTATIONS).forEach(this.blockBuilder::addLine); - return this; - } - - @Override - public boolean accept() { - return true; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/TemplateUpdatingMethodPostProcessor.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/TemplateUpdatingMethodPostProcessor.java deleted file mode 100644 index fc6bb398d8..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/TemplateUpdatingMethodPostProcessor.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.template.HandlebarsTemplateProcessor; -import org.springframework.cloud.contract.verifier.template.TemplateProcessor; - -class TemplateUpdatingMethodPostProcessor implements MethodPostProcessor { - - private final BlockBuilder blockBuilder; - - private final TemplateProcessor templateProcessor; - - TemplateUpdatingMethodPostProcessor(BlockBuilder blockBuilder) { - this.blockBuilder = blockBuilder; - this.templateProcessor = new HandlebarsTemplateProcessor(); - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - Request request = metadata.getContract().getRequest(); - String newBody = this.templateProcessor.transform(request, this.blockBuilder.toString()); - this.blockBuilder.updateContents(newBody); - return this; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return this.templateProcessor.containsTemplateEntry(this.blockBuilder.toString()); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/TestNGImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/TestNGImports.java deleted file mode 100644 index 36ad16cdfd..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/TestNGImports.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.config.TestFramework; - -class TestNGImports implements Imports { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] IMPORTS = { "org.testng.annotations.Test" }; - - TestNGImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - Arrays.stream(IMPORTS).forEach(s -> this.blockBuilder.addLineWithEnding("import " + s)); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.TESTNG; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/TestNGMethodAnnotation.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/TestNGMethodAnnotation.java deleted file mode 100644 index 8356519ab3..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/TestNGMethodAnnotation.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class TestNGMethodAnnotation implements MethodAnnotations { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - TestNGMethodAnnotation(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public MethodVisitor apply(SingleContractMetadata singleContractMetadata) { - final String annotation = (singleContractMetadata.isIgnored() || singleContractMetadata.isInProgress()) - ? "@Test(enabled = false)" : "@Test"; - this.blockBuilder.addIndented(annotation); - return this; - } - - @Override - public boolean accept(SingleContractMetadata singleContractMetadata) { - return this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.TESTNG; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/TestSideRequestTemplateModel.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/TestSideRequestTemplateModel.java deleted file mode 100644 index b8423cb3cf..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/TestSideRequestTemplateModel.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; - -import groovy.json.JsonOutput; -import groovy.lang.GString; -import groovy.transform.CompileStatic; -import org.apache.commons.text.StringEscapeUtils; - -import org.springframework.cloud.contract.spec.internal.FromFileProperty; -import org.springframework.cloud.contract.spec.internal.Header; -import org.springframework.cloud.contract.spec.internal.QueryParameter; -import org.springframework.cloud.contract.spec.internal.QueryParameters; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.spec.internal.Url; -import org.springframework.cloud.contract.verifier.util.ContentUtils; -import org.springframework.cloud.contract.verifier.util.MapConverter; - -/** - * Representation of the request side to be used for response templating in the generated - * tests. - * - * @author Marcin Grzejszczak - * @since 1.1.0 - */ -public class TestSideRequestTemplateModel { - - /** - * Request URL - */ - private final String url; - - /** - * Map containing query parameters - */ - private final Map> query; - - /** - * List of path entries - */ - private final Path path; - - /** - * Map containing request headers - */ - private final Map> headers; - - /** - * Request body as it would be sent to the controller - */ - private final String body; - - /** - * Escaped request body that can be put into test - */ - private final String escapedBody; - - private TestSideRequestTemplateModel(String url, Map> query, Path path, - Map> headers, String body, String escapedBody) { - this.url = url; - this.query = query; - this.path = path; - this.headers = headers; - this.body = body; - this.escapedBody = escapedBody; - } - - public String getUrl() { - return this.url; - } - - public Map> getQuery() { - return this.query; - } - - public Path getPath() { - return this.path; - } - - public Map> getHeaders() { - return this.headers; - } - - public String getBody() { - return this.body; - } - - public String getEscapedBody() { - return this.escapedBody; - } - - public static TestSideRequestTemplateModel from(final Request request) { - Url urlPath = request.getUrl() != null ? request.getUrl() : request.getUrlPath(); - String url = MapConverter.getTestSideValues(urlPath).toString(); - Path paths = new Path(buildPathsFromUrl(url)); - QueryParameters queryParameters = urlPath.getQueryParameters(); - Map> query = query(queryParameters); - boolean queryParamsPresent = query == null || query.isEmpty(); - String fullUrl = fullUrl(url, query, queryParamsPresent); - boolean headersEntriesPresent = request.getHeaders() != null && !request.getHeaders().getEntries().isEmpty(); - Map> headers = headers(request, headersEntriesPresent); - String escapedBody = trimmedAndEscapedBody(request.getBody()); - String body = getBodyAsRawJson(request.getBody()); - return new TestSideRequestTemplateModel(fullUrl, query, paths, headers, body, escapedBody); - } - - private static Map> headers(Request request, boolean headersEntriesPresent) { - if (!headersEntriesPresent) { - return new HashMap<>(); - } - return new HashMap<>(request.getHeaders().getEntries().stream() - .collect(Collectors.groupingBy(Header::getName, - Collectors.mapping((Function) o -> MapConverter.getTestSideValues(o).toString(), - Collectors.toList())))); - } - - private static String fullUrl(String url, Map> query, boolean queryParamsPresent) { - if (queryParamsPresent) { - return url; - } - String joinedParams = query.entrySet().stream().map( - entry -> entry.getValue().stream().map(s -> entry.getKey() + "=" + s).collect(Collectors.joining("&"))) - .collect(Collectors.joining("&")); - return url + "?" + joinedParams; - } - - private static Map> query(QueryParameters queryParameters) { - if (queryParameters == null) { - return new HashMap<>(); - } - return new HashMap<>(queryParameters.getParameters().stream().collect(Collectors.groupingBy( - QueryParameter::getName, Collectors.mapping(MapConverter::getTestSideValues, Collectors.toList())))); - } - - private static List buildPathsFromUrl(String url) { - String fakeUrl = "https://foo.bar" + (url.startsWith("/") ? url : "/" + url); - List paths; - try { - paths = new LinkedList<>(Arrays.asList(new URL(fakeUrl).getPath().split("/"))); - } - catch (MalformedURLException ex) { - throw new IllegalStateException(ex); - } - if (!paths.isEmpty()) { - paths.remove(0); - } - return paths; - } - - private static String trimmedAndEscapedBody(Object body) { - String rawBody = getBodyAsRawJson(body); - return StringEscapeUtils.escapeJava(rawBody); - } - - private static String getBodyAsRawJson(Object body) { - Object bodyValue = extractServerValueFromBody(body); - if (bodyValue instanceof GString || bodyValue instanceof String) { - return bodyValue.toString(); - } - else if (bodyValue instanceof FromFileProperty) { - return null; - } - return bodyValue != null ? new JsonOutput().toJson(bodyValue) : null; - } - - private static Object extractServerValueFromBody(Object bodyValue) { - if (bodyValue instanceof GString) { - bodyValue = ContentUtils.extractValue((GString) bodyValue, ContentUtils.GET_TEST_SIDE_FUNCTION); - } - else { - bodyValue = MapConverter.transformValues(bodyValue, ContentUtils.GET_TEST_SIDE_FUNCTION); - } - return bodyValue; - } - -} - -@CompileStatic -class Path extends ArrayList { - - Path(List list) { - this.addAll(list); - } - - @Override - public String toString() { - return "/" + String.join("/", this); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/Then.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/Then.java deleted file mode 100644 index 939be0c11c..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/Then.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -interface Then extends MethodVisitor { - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/UserImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/UserImports.java deleted file mode 100644 index 476ba9ef9a..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/UserImports.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -class UserImports implements Imports { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - UserImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - Arrays.stream(this.generatedClassMetaData.configProperties.getImports()) - .forEach(s -> this.blockBuilder.addLineWithEnding("import " + s)); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.configProperties.getImports() != null - && this.generatedClassMetaData.configProperties.getImports().length > 0; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/UserStaticImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/UserStaticImports.java deleted file mode 100644 index 964ffd2b31..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/UserStaticImports.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -class UserStaticImports implements Imports { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - UserStaticImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - Arrays.stream(this.generatedClassMetaData.configProperties.getStaticImports()) - .forEach(s -> this.blockBuilder.addLineWithEnding("import static " + s)); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.configProperties.getStaticImports() != null - && this.generatedClassMetaData.configProperties.getStaticImports().length > 0; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/Visitor.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/Visitor.java deleted file mode 100644 index 8c76d47ede..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/Visitor.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -interface Visitor extends Acceptor, OurCallable { - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/WebTestClientAcceptor.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/WebTestClientAcceptor.java deleted file mode 100644 index 7e9836c196..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/WebTestClientAcceptor.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.config.TestMode; - -interface WebTestClientAcceptor { - - default boolean acceptType(GeneratedClassMetaData generatedClassMetaData) { - return generatedClassMetaData.configProperties.getTestMode() == TestMode.WEBTESTCLIENT; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/WebTestClientRequestGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/WebTestClientRequestGiven.java deleted file mode 100644 index 5847955d61..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/WebTestClientRequestGiven.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class WebTestClientRequestGiven implements Given, WebTestClientAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - WebTestClientRequestGiven(BlockBuilder blockBuilder, GeneratedClassMetaData metaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = metaData; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - this.blockBuilder.addIndented("WebTestClientRequestSpecification request = given()"); - return this; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return acceptType(this.generatedClassMetaData); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/WebTestClientResponseWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/WebTestClientResponseWhen.java deleted file mode 100644 index f54dedbc8b..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/WebTestClientResponseWhen.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class WebTestClientResponseWhen implements When, WebTestClientAcceptor { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - WebTestClientResponseWhen(BlockBuilder blockBuilder, GeneratedClassMetaData metaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = metaData; - } - - @Override - public MethodVisitor apply(SingleContractMetadata metadata) { - this.blockBuilder.addIndented("WebTestClientResponse response = given().spec(request)"); - return this; - } - - @Override - public boolean accept(SingleContractMetadata metadata) { - return acceptType(this.generatedClassMetaData); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/WebTestClientRestAssured3StaticImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/WebTestClientRestAssured3StaticImports.java deleted file mode 100644 index 361fc40ada..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/WebTestClientRestAssured3StaticImports.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.config.TestMode; - -class WebTestClientRestAssured3StaticImports implements Imports { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] IMPORTS = { "io.restassured.module.webtestclient.RestAssuredWebTestClient.*" }; - - WebTestClientRestAssured3StaticImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - Arrays.stream(IMPORTS).forEach(s -> this.blockBuilder.addLineWithEnding("import static " + s)); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.configProperties.getTestMode() == TestMode.WEBTESTCLIENT - && this.generatedClassMetaData.isAnyHttp(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/WebTestClientRestAssuredImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/WebTestClientRestAssuredImports.java deleted file mode 100644 index 41b031f696..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/WebTestClientRestAssuredImports.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.config.TestMode; - -class WebTestClientRestAssuredImports implements Imports { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] REST_ASSURED_3_IMPORTS = { - "io.restassured.module.webtestclient.specification.WebTestClientRequestSpecification", - "io.restassured.module.webtestclient.response.WebTestClientResponse" }; - - WebTestClientRestAssuredImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - Arrays.stream(REST_ASSURED_3_IMPORTS).forEach(s -> this.blockBuilder.addLineWithEnding("import " + s)); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.configProperties.getTestMode() == TestMode.WEBTESTCLIENT - && this.generatedClassMetaData.isAnyHttp(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/When.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/When.java deleted file mode 100644 index 95c89cc512..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/When.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -interface When extends MethodVisitor { - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/XmlBodyVerificationBuilder.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/XmlBodyVerificationBuilder.java deleted file mode 100644 index 82149eca2c..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/XmlBodyVerificationBuilder.java +++ /dev/null @@ -1,84 +0,0 @@ -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; -import java.util.List; -import java.util.Optional; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.internal.BodyMatcher; -import org.springframework.cloud.contract.spec.internal.BodyMatchers; -import org.springframework.cloud.contract.spec.internal.ExecutionProperty; -import org.springframework.cloud.contract.spec.internal.MatchingType; -import org.springframework.cloud.contract.verifier.util.xml.XmlToXPathsConverter; - -/** - * @author Olga Maciaszek-Sharma - * @since 2.1.0 - */ -class XmlBodyVerificationBuilder implements BodyMethodGeneration { - - private final Contract contract; - - private final Optional lineSuffix; - - XmlBodyVerificationBuilder(Contract contract, Optional lineSuffix) { - this.contract = contract; - this.lineSuffix = lineSuffix; - } - - void addXmlResponseBodyCheck(BlockBuilder blockBuilder, Object responseBody, BodyMatchers bodyMatchers, - String responseString, boolean shouldCommentOutBDDBlocks) { - addXmlProcessingLines(blockBuilder, responseString); - Object processedBody = XmlToXPathsConverter.removeMatchingXPaths(responseBody, bodyMatchers); - List matchers = new XmlToXPathsConverter().mapToMatchers(processedBody); - if (bodyMatchers != null && bodyMatchers.hasMatchers()) { - matchers.addAll(bodyMatchers.matchers()); - } - - addBodyMatchingBlock(matchers, blockBuilder, responseBody, shouldCommentOutBDDBlocks); - } - - private void addXmlProcessingLines(final BlockBuilder blockBuilder, String responseString) { - Arrays.asList("DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance()", - "builderFactory.setNamespaceAware(true)", - "DocumentBuilder documentBuilder = builderFactory.newDocumentBuilder()", - "Document parsedXml = documentBuilder.parse(new InputSource(new StringReader(" + responseString + ")))") - .forEach(it -> { - blockBuilder.addLine(it); - addColonIfRequired(lineSuffix, blockBuilder); - }); - } - - @Override - public void methodForNullCheck(BodyMatcher bodyMatcher, BlockBuilder bb) { - String quotedAndEscapedPath = quotedAndEscaped(bodyMatcher.path()); - String method = "assertThat(nodeFromXPath(parsedXml, " + quotedAndEscapedPath + ")).isNull()"; - bb.addLine(method.replace("$", "\\$")); - addColonIfRequired(lineSuffix, bb); - } - - @Override - public void methodForEqualityCheck(BodyMatcher bodyMatcher, BlockBuilder bb, Object body) { - Object retrievedValue = quotedAndEscaped(XmlToXPathsConverter.retrieveValue(bodyMatcher, body)); - String comparisonMethod = bodyMatcher.matchingType().equals(MatchingType.EQUALITY) ? "isEqualTo" : "matches"; - String method = "assertThat(valueFromXPath(parsedXml, " + quotedAndEscaped(bodyMatcher.path()) + "))." - + comparisonMethod + "(" + retrievedValue + ")"; - bb.addLine(method.replace("$", "\\$")); - addColonIfRequired(lineSuffix, bb); - } - - @Override - public void methodForCommandExecution(BodyMatcher bodyMatcher, BlockBuilder bb, Object body) { - Object retrievedValue = quotedAndEscaped(XmlToXPathsConverter.retrieveValueFromBody(bodyMatcher.path(), body)); - ExecutionProperty property = (ExecutionProperty) bodyMatcher.value(); - bb.addLine(property.insertValue(((String) retrievedValue).replace("$", "\\$"))); - addColonIfRequired(lineSuffix, bb); - } - - @Override - public void methodForTypeCheck(BodyMatcher bodyMatcher, BlockBuilder bb, Object copiedBody) { - throw new UnsupportedOperationException( - "The `getNodeValue()` method in `org.w3c.dom.Node` always returns String."); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/XmlImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/XmlImports.java deleted file mode 100644 index 95e161cf24..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/XmlImports.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.util.Arrays; - -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -class XmlImports implements Imports { - - private final BlockBuilder blockBuilder; - - private final GeneratedClassMetaData generatedClassMetaData; - - private static final String[] IMPORTS = { "javax.xml.parsers.DocumentBuilder", - "javax.xml.parsers.DocumentBuilderFactory", "org.w3c.dom.Document", "org.xml.sax.InputSource", - "java.io.StringReader" }; - - XmlImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) { - this.blockBuilder = blockBuilder; - this.generatedClassMetaData = generatedClassMetaData; - } - - @Override - public Imports call() { - Arrays.stream(IMPORTS).forEach(s -> this.blockBuilder.addLineWithEnding("import " + s)); - return this; - } - - @Override - public boolean accept() { - return this.generatedClassMetaData.listOfFiles.stream().anyMatch(metadata -> metadata - .getConvertedContractWithMetadata().stream().anyMatch(SingleContractMetadata::isXml)); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/handlebars/HandlebarsEscapeHelper.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/handlebars/HandlebarsEscapeHelper.java deleted file mode 100644 index ccc98fa7ae..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/handlebars/HandlebarsEscapeHelper.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder.handlebars; - -import java.io.IOException; -import java.util.Map; - -import com.github.tomakehurst.wiremock.extension.responsetemplating.RequestTemplateModel; -import org.apache.commons.text.StringEscapeUtils; -import wiremock.com.github.jknack.handlebars.Helper; -import wiremock.com.github.jknack.handlebars.Options; - -import org.springframework.cloud.contract.verifier.builder.TestSideRequestTemplateModel; - -/** - * A Handlebars helper for the {@code escapejsonbody} helper function. - * - * @author Marcin Grzejszczak - * @since 1.1.0 - */ -public class HandlebarsEscapeHelper implements Helper> { - - public static final String NAME = "escapejsonbody"; - - public static final String REQUEST_MODEL_NAME = "request"; - - @Override - public Object apply(Map context, Options options) throws IOException { - Object model = context.get(REQUEST_MODEL_NAME); - if (model instanceof TestSideRequestTemplateModel) { - return StringEscapeUtils.escapeJson(returnObjectForTest(model).toString()); - } - else if (model instanceof RequestTemplateModel) { - return StringEscapeUtils.escapeJson(returnObjectForStub(model).toString()); - } - - throw new IllegalArgumentException("Unsupported model"); - } - - private Object returnObjectForStub(Object model) { - return ((RequestTemplateModel) model).getBody(); - } - - private Object returnObjectForTest(Object model) { - return ((TestSideRequestTemplateModel) model).getEscapedBody(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/handlebars/HandlebarsJsonPathHelper.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/handlebars/HandlebarsJsonPathHelper.java deleted file mode 100644 index 331fd7fbdf..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/handlebars/HandlebarsJsonPathHelper.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder.handlebars; - -import java.io.IOException; -import java.util.Map; - -import com.github.tomakehurst.wiremock.extension.responsetemplating.RequestTemplateModel; -import com.github.tomakehurst.wiremock.extension.responsetemplating.helpers.WireMockHelpers; -import com.jayway.jsonpath.DocumentContext; -import com.jayway.jsonpath.JsonPath; -import wiremock.com.github.jknack.handlebars.Helper; -import wiremock.com.github.jknack.handlebars.Options; - -import org.springframework.cloud.contract.verifier.builder.TestSideRequestTemplateModel; - -/** - * A Handlebars helper for the {@code jsonpath} helper function. - * - * @author Marcin Grzejszczak - * @since 1.1.0 - */ -public class HandlebarsJsonPathHelper implements Helper { - - public static final String NAME = "jsonpath"; - - public static final String REQUEST_MODEL_NAME = "request"; - - @Override - public Object apply(Object context, Options options) throws IOException { - if (context instanceof Map) { - // legacy - Map oldContext = (Map) context; - String jsonPath = options.param(0); - Object model = oldContext.get(REQUEST_MODEL_NAME); - if (model instanceof TestSideRequestTemplateModel) { - return returnObjectForTest((TestSideRequestTemplateModel) model, jsonPath); - } - else if (model instanceof RequestTemplateModel) { - return returnObjectForStub(model, jsonPath); - } - throw new IllegalArgumentException("Unsupported model"); - } - else if (context instanceof String) { - Object value = WireMockHelpers.jsonPath.apply(context, options); - if (testSideModel(options)) { - return processTestResponseValue(value); - } - return value; - } - throw new IllegalArgumentException("Unsupported context"); - } - - private boolean testSideModel(Options options) { - Object model = options.context.model(); - if (!(model instanceof Map)) { - return false; - } - - Map map = (Map) model; - return map.values().stream().anyMatch(o -> o instanceof TestSideRequestTemplateModel); - } - - private Object returnObjectForStub(Object model, String jsonPath) { - DocumentContext documentContext = JsonPath.parse(((RequestTemplateModel) model).getBody()); - return documentContext.read(jsonPath); - } - - private Object returnObjectForTest(TestSideRequestTemplateModel model, String jsonPath) { - String body = removeSurroundingQuotes(model.getEscapedBody()).replace("\\\"", "\""); - DocumentContext documentContext = JsonPath.parse(body); - Object value = documentContext.read(jsonPath); - return processTestResponseValue(value); - } - - private Object processTestResponseValue(Object value) { - if (value instanceof Long) { - return (long) value + "L"; - } - return value; - } - - private String removeSurroundingQuotes(String body) { - if (body.startsWith("\"") && body.endsWith("\"")) { - return body.substring(1, body.length() - 1); - } - return body; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/ContractVerifierConfigProperties.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/ContractVerifierConfigProperties.java deleted file mode 100644 index 2965ddf41f..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/ContractVerifierConfigProperties.java +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.config; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Represents Contract Verifier configuration properties. - * - * @author Jakub Kubrynski, codearte.io - * @since 1.0.0 - */ -public class ContractVerifierConfigProperties { - - private static final Log log = LogFactory.getLog(ContractVerifierConfigProperties.class); - - /** - * For which unit test library tests should be generated. - */ - private TestFramework testFramework = TestFramework.JUNIT5; - - /** - * Which mechanism should be used to invoke REST calls during. tests - */ - private TestMode testMode = TestMode.MOCKMVC; - - /** - * Base package for generated tests. - */ - private String basePackageForTests; - - /** - * Class which all generated tests should extend. - */ - private String baseClassForTests; - - /** - * Suffix for generated test classes, like Spec or Test. - */ - private String nameSuffixForTests; - - /** - * Rule class that should be added to generated tests. - */ - private String ruleClassForTests; - - /** - * Patterns that should not be taken into account for processing. - */ - private List excludedFiles = new ArrayList<>(); - - /** - * Patterns that should be taken into account for processing. - */ - private List includedFiles = new ArrayList(); - - /** - * Patterns for which generated tests should be @Ignored. - */ - private List ignoredFiles = new ArrayList(); - - /** - * Imports that should be added to generated tests. - */ - private String[] imports = new String[0]; - - /** - * Static imports that should be added to generated tests. - */ - private String[] staticImports = new String[0]; - - /** - * Directory containing contracts. - */ - private File contractsDslDir; - - /** - * Test source directory where tests generated. - */ - private File generatedTestSourcesDir; - - /** - * Test resource directory where additional resources for tests will be set. - */ - private File generatedTestResourcesDir; - - /** - * Dir where the generated stubs from the contracts should be placed. You can then - * mention them in your packaging task to create jar with stubs. - */ - private File stubsOutputDir; - - /** - * Suffix for the generated Stubs Jar task. - */ - private String stubsSuffix = "stubs"; - - /** - * Incubating feature. You can check the size of JSON arrays. If not turned on - * explicitly will be disabled. - */ - private Boolean assertJsonSize = false; - - /** - * A regular expression that matches contracts. Especially useful when using a single - * JAR containing all the contracts in the system. In this case you'd like to take - * into consideration only some of them. Defaults to picking all files. - */ - private String includedContracts = ".*"; - - /** - * A ant pattern to match files. Gets updated when using repo with common contracts to - * reflect the path to proper folder with contracts. - */ - private String includedRootFolderAntPattern = "**/"; - - /** - * A package that contains all the base clases for generated tests. If your contract - * resides in a location {@code src/test/resources/contracts/com/example/v1/} and you - * provide the {@code packageWithBaseClasses} value to - * {@code com.example.contracts.base} then we will search for a test source file that - * will have the package {@code com.example.contracts.base} and name - * {@code ExampleV1Base}. As you can see it will take the two last folders to and - * attach {@code Base} to its name. - */ - private String packageWithBaseClasses; - - /** - * A way to override any base class mappings. The keys are regular expressions on the - * package name of the contract and the values FQN to a base class for that given - * expression. - *

- * Example of a mapping - *

- * {@code .*.com.example.v1..*} -> {@code com.example.SomeBaseClass} - *

- * When a contract's package matches the provided regular expression then extending - * class will be the one provided in the map - in this case - * {@code com.example.SomeBaseClass} - */ - private Map baseClassMappings; - - /** - * If set to true then the {@code target} or {@code build} folders are getting - * excluded from any operations. This is used out of the box when working with common - * repo with contracts. - */ - private boolean excludeBuildFolders; - - /** - * If set to true then if any contracts that are in progress are found, will break the - * build. On the producer side you need to be explicit about the fact that you have - * contracts in progress and take into consideration that you might be causing false - * positive test execution results on the consumer side. - */ - private boolean failOnInProgress = true; - - public TestFramework getTestFramework() { - return testFramework; - } - - public void setTestFramework(TestFramework testFramework) { - this.testFramework = testFramework; - } - - public TestMode getTestMode() { - return testMode; - } - - public void setTestMode(TestMode testMode) { - this.testMode = testMode; - } - - public String getBasePackageForTests() { - return basePackageForTests; - } - - public void setBasePackageForTests(String basePackageForTests) { - this.basePackageForTests = basePackageForTests; - } - - public String getBaseClassForTests() { - return baseClassForTests; - } - - public void setBaseClassForTests(String baseClassForTests) { - this.baseClassForTests = baseClassForTests; - } - - public String getNameSuffixForTests() { - return nameSuffixForTests; - } - - public void setNameSuffixForTests(String nameSuffixForTests) { - this.nameSuffixForTests = nameSuffixForTests; - } - - public String getRuleClassForTests() { - return ruleClassForTests; - } - - public void setRuleClassForTests(String ruleClassForTests) { - this.ruleClassForTests = ruleClassForTests; - } - - public List getExcludedFiles() { - return excludedFiles; - } - - public void setExcludedFiles(List excludedFiles) { - this.excludedFiles = excludedFiles; - } - - public List getIncludedFiles() { - return includedFiles; - } - - public void setIncludedFiles(List includedFiles) { - this.includedFiles = includedFiles; - } - - public List getIgnoredFiles() { - return ignoredFiles; - } - - public void setIgnoredFiles(List ignoredFiles) { - this.ignoredFiles = ignoredFiles; - } - - public String[] getImports() { - return imports; - } - - public void setImports(String[] imports) { - this.imports = imports; - } - - public String[] getStaticImports() { - return staticImports; - } - - public void setStaticImports(String[] staticImports) { - this.staticImports = staticImports; - } - - public File getContractsDslDir() { - return contractsDslDir; - } - - public void setContractsDslDir(File contractsDslDir) { - this.contractsDslDir = contractsDslDir; - } - - public File getGeneratedTestSourcesDir() { - return generatedTestSourcesDir; - } - - public void setGeneratedTestSourcesDir(File generatedTestSourcesDir) { - this.generatedTestSourcesDir = generatedTestSourcesDir; - } - - public File getGeneratedTestResourcesDir() { - return generatedTestResourcesDir; - } - - public void setGeneratedTestResourcesDir(File generatedTestResourcesDir) { - this.generatedTestResourcesDir = generatedTestResourcesDir; - } - - public File getStubsOutputDir() { - return stubsOutputDir; - } - - public void setStubsOutputDir(File stubsOutputDir) { - this.stubsOutputDir = stubsOutputDir; - } - - public String getStubsSuffix() { - return stubsSuffix; - } - - public void setStubsSuffix(String stubsSuffix) { - this.stubsSuffix = stubsSuffix; - } - - public Boolean getAssertJsonSize() { - return assertJsonSize; - } - - public void setAssertJsonSize(Boolean assertJsonSize) { - this.assertJsonSize = assertJsonSize; - } - - public String getIncludedContracts() { - return includedContracts; - } - - public void setIncludedContracts(String includedContracts) { - this.includedContracts = includedContracts; - } - - public String getIncludedRootFolderAntPattern() { - return includedRootFolderAntPattern; - } - - public void setIncludedRootFolderAntPattern(String includedRootFolderAntPattern) { - this.includedRootFolderAntPattern = includedRootFolderAntPattern; - } - - public String getPackageWithBaseClasses() { - return packageWithBaseClasses; - } - - public void setPackageWithBaseClasses(String packageWithBaseClasses) { - this.packageWithBaseClasses = packageWithBaseClasses; - } - - public Map getBaseClassMappings() { - return baseClassMappings; - } - - public void setBaseClassMappings(Map baseClassMappings) { - this.baseClassMappings = baseClassMappings; - } - - public boolean getExcludeBuildFolders() { - return excludeBuildFolders; - } - - public boolean isExcludeBuildFolders() { - return excludeBuildFolders; - } - - public void setExcludeBuildFolders(boolean excludeBuildFolders) { - this.excludeBuildFolders = excludeBuildFolders; - } - - public boolean isFailOnInProgress() { - return this.failOnInProgress; - } - - public void setFailOnInProgress(boolean failOnInProgress) { - this.failOnInProgress = failOnInProgress; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/TestFramework.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/TestFramework.java deleted file mode 100644 index d1b9590b3e..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/TestFramework.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.config; - -import org.springframework.cloud.contract.verifier.config.framework.CustomDefinition; -import org.springframework.cloud.contract.verifier.config.framework.JUnit5Definition; -import org.springframework.cloud.contract.verifier.config.framework.JUnitDefinition; -import org.springframework.cloud.contract.verifier.config.framework.SpockDefinition; -import org.springframework.cloud.contract.verifier.config.framework.TestFrameworkDefinition; -import org.springframework.cloud.contract.verifier.config.framework.TestNGDefinition; - -/** - * Contains main building blocks for a test class for the given framework. - * - * @author Jakub Kubrynski, codearte.io - * @author Olga Maciaszek-Sharma - * - * @since 1.0.0 - */ -public enum TestFramework { - - /** - * Spock test framework. - */ - SPOCK(new SpockDefinition()), - /** - * JUnit test framework. - */ - JUNIT(new JUnitDefinition()), - /** - * JUnit5 test framework. - */ - JUNIT5(new JUnit5Definition()), - /** - * TestNG test framework. - */ - TESTNG(new TestNGDefinition()), - /** - * Custom test framework. - */ - CUSTOM(new CustomDefinition()); - - private final TestFrameworkDefinition testFrameworkDefinition; - - TestFramework(TestFrameworkDefinition testFrameworkDefinition) { - this.testFrameworkDefinition = testFrameworkDefinition; - } - - public String getClassExtension() { - return this.testFrameworkDefinition.getClassExtension(); - } - - public String getClassNameSuffix() { - return this.testFrameworkDefinition.getClassNameSuffix(); - } - - public String getIgnoreClass() { - return this.testFrameworkDefinition.getIgnoreClass(); - } - - public String getIgnoreAnnotation() { - return this.testFrameworkDefinition.getIgnoreAnnotation(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/TestMode.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/TestMode.java deleted file mode 100644 index 6cb03a421f..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/TestMode.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.config; - -import org.springframework.cloud.contract.verifier.http.HttpVerifier; - -/** - * Provides different testing modes. - * - * @author Jakub Kubrynski, codearte.io - * - * @since 1.0.0 - */ -public enum TestMode { - - /** - * Requires the user to provide an implementation of the {@link HttpVerifier}. - */ - CUSTOM, - /** - * Uses Spring's MockMvc mode. - */ - MOCKMVC, - /** - * Uses direct HTTP invocations with Rest Assured. - */ - EXPLICIT, - /** - * Uses JAX-RS client. - */ - JAXRSCLIENT, - /** - * Uses Spring's reactive WebTestClient. - */ - WEBTESTCLIENT - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/framework/CustomDefinition.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/framework/CustomDefinition.java deleted file mode 100644 index 16b814a624..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/framework/CustomDefinition.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.config.framework; - -/** - * Defines elements characteristic of Custom test framework to be used during test class - * construction. - * - * @author Olga Maciaszek-Sharma - * @since 2.1.0 - */ -public class CustomDefinition implements TestFrameworkDefinition { - - @Override - public String getClassExtension() { - return ""; - } - - @Override - public String getClassNameSuffix() { - return ""; - } - - @Override - public String getIgnoreClass() { - return ""; - } - - @Override - public String getIgnoreAnnotation() { - return "@Ignore"; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/framework/JUnit5Definition.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/framework/JUnit5Definition.java deleted file mode 100644 index 5bd068d948..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/framework/JUnit5Definition.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.config.framework; - -/** - * Defines elements characteristic of JUnit5 test framework to be used during test class - * construction. - * - * @author Olga Maciaszek-Sharma - * @since 2.1.0 - */ -public class JUnit5Definition implements TestFrameworkDefinition { - - @Override - public String getClassExtension() { - return ".java"; - } - - @Override - public String getClassNameSuffix() { - return "Test"; - } - - @Override - public String getIgnoreClass() { - return "org.junit.jupiter.api.Disabled"; - } - - @Override - public String getIgnoreAnnotation() { - return "@Disabled"; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/framework/JUnitDefinition.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/framework/JUnitDefinition.java deleted file mode 100644 index 970256bd10..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/framework/JUnitDefinition.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.config.framework; - -/** - * Defines elements characteristic of JUnit test framework to be used during test class - * construction. - * - * @author Olga Maciaszek-Sharma - * @since 2.1.0 - */ -public class JUnitDefinition implements TestFrameworkDefinition { - - @Override - public String getClassExtension() { - return ".java"; - } - - @Override - public String getClassNameSuffix() { - return "Test"; - } - - @Override - public String getIgnoreClass() { - return "org.junit.Ignore"; - } - - @Override - public String getIgnoreAnnotation() { - return "@Ignore"; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/framework/SpockDefinition.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/framework/SpockDefinition.java deleted file mode 100644 index 364e20d6ee..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/framework/SpockDefinition.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.config.framework; - -/** - * Defines elements characteristic of Spock test framework to be used during test class - * construction. - * - * @author Olga Maciaszek-Sharma - * @since 2.1.0 - */ -public class SpockDefinition implements TestFrameworkDefinition { - - @Override - public String getClassExtension() { - return ".groovy"; - } - - @Override - public String getClassNameSuffix() { - return "Spec"; - } - - @Override - public String getIgnoreClass() { - return "spock.lang.Ignore"; - } - - @Override - public String getIgnoreAnnotation() { - return "@Ignore"; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/framework/TestFrameworkDefinition.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/framework/TestFrameworkDefinition.java deleted file mode 100644 index a4244325ef..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/framework/TestFrameworkDefinition.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.config.framework; - -/** - * Defines elements characteristic of a given test framework to be used during test class - * construction. - * - * @author Olga Maciaszek-Sharma - * @since 2.1.0 - * @deprecated appropriate implementations of - * org.springframework.cloud.contract.verifier.builder.Visitor should be used - * instead. - */ -@Deprecated -public interface TestFrameworkDefinition { - - /** - * @return the file extension. E.g. for Java tests that would be {@code .java} - */ - String getClassExtension(); - - /** - * @return the test class name suffix. E.g. for JUnit tests that would be {@code Test} - */ - String getClassNameSuffix(); - - /** - * @return the qualified name of the class used to ignore or disable tests. E.g. for - * JUnit 4 tests that would be {@code org.junit.Ignore} - */ - String getIgnoreClass(); - - /** - * @return the annotation used for ignoring or disabling tests. E.g. for JUnit tests - * that would mean {@code @Ignore} - */ - String getIgnoreAnnotation(); - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/framework/TestNGDefinition.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/framework/TestNGDefinition.java deleted file mode 100644 index 1b971ac1d4..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/framework/TestNGDefinition.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.config.framework; - -/** - * Defines elements characteristic of TestNG test framework to be used during test class - * construction. - * - * @author André Hoffmann - * @since 2.2.0 - */ -public class TestNGDefinition implements TestFrameworkDefinition { - - @Override - public String getClassExtension() { - return ".java"; - } - - @Override - public String getClassNameSuffix() { - return "Test"; - } - - @Override - public String getIgnoreClass() { - throw new UnsupportedOperationException( - "There is no @Ignore annotation for TestNG. A test can be disabled directly in the @Test annotation"); - } - - @Override - public String getIgnoreAnnotation() { - throw new UnsupportedOperationException( - "There is no @Ignore annotation for TestNG. A test can be disabled directly in the @Test annotation"); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/ContractsToYaml.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/ContractsToYaml.java deleted file mode 100644 index 3b4499d40c..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/ContractsToYaml.java +++ /dev/null @@ -1,557 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.converter; - -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.internal.BodyMatchers; -import org.springframework.cloud.contract.spec.internal.Cookies; -import org.springframework.cloud.contract.spec.internal.DslProperty; -import org.springframework.cloud.contract.spec.internal.ExecutionProperty; -import org.springframework.cloud.contract.spec.internal.FromFileProperty; -import org.springframework.cloud.contract.spec.internal.Headers; -import org.springframework.cloud.contract.spec.internal.Input; -import org.springframework.cloud.contract.spec.internal.MatchingStrategy; -import org.springframework.cloud.contract.spec.internal.MatchingType; -import org.springframework.cloud.contract.spec.internal.Multipart; -import org.springframework.cloud.contract.spec.internal.NamedProperty; -import org.springframework.cloud.contract.spec.internal.NotToEscapePattern; -import org.springframework.cloud.contract.spec.internal.OutputMessage; -import org.springframework.cloud.contract.spec.internal.QueryParameter; -import org.springframework.cloud.contract.spec.internal.RegexProperty; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.spec.internal.Response; -import org.springframework.cloud.contract.spec.internal.Url; -import org.springframework.cloud.contract.verifier.util.ContentType; -import org.springframework.cloud.contract.verifier.util.JsonPaths; -import org.springframework.cloud.contract.verifier.util.JsonToJsonPathsConverter; -import org.springframework.cloud.contract.verifier.util.MapConverter; - -import static org.springframework.cloud.contract.verifier.util.ContentType.XML; -import static org.springframework.cloud.contract.verifier.util.ContentUtils.evaluateClientSideContentType; - -/** - * @author Marcin Grzejszczak - * @author Olga Maciaszek-Sharma - * @author Stessy Delcroix - */ -class ContractsToYaml { - - private static final Map, YamlContract.RegexType> PRIMITIVE_WRAPPER_TO_REGEX_TYPE = new HashMap<>(); - - private static final Map TEST_MATCHER_TYPE = new HashMap<>(); - - private static final Map STUB_MATCHER_TYPE = new HashMap<>(); - - static { - PRIMITIVE_WRAPPER_TO_REGEX_TYPE.put(Boolean.class, YamlContract.RegexType.as_boolean); - PRIMITIVE_WRAPPER_TO_REGEX_TYPE.put(Long.class, YamlContract.RegexType.as_long); - PRIMITIVE_WRAPPER_TO_REGEX_TYPE.put(Short.class, YamlContract.RegexType.as_short); - PRIMITIVE_WRAPPER_TO_REGEX_TYPE.put(Integer.class, YamlContract.RegexType.as_integer); - PRIMITIVE_WRAPPER_TO_REGEX_TYPE.put(Float.class, YamlContract.RegexType.as_float); - PRIMITIVE_WRAPPER_TO_REGEX_TYPE.put(Double.class, YamlContract.RegexType.as_double); - PRIMITIVE_WRAPPER_TO_REGEX_TYPE.put(String.class, YamlContract.RegexType.as_string); - TEST_MATCHER_TYPE.put(MatchingType.EQUALITY, YamlContract.TestMatcherType.by_equality); - TEST_MATCHER_TYPE.put(MatchingType.TYPE, YamlContract.TestMatcherType.by_type); - TEST_MATCHER_TYPE.put(MatchingType.COMMAND, YamlContract.TestMatcherType.by_command); - TEST_MATCHER_TYPE.put(MatchingType.DATE, YamlContract.TestMatcherType.by_date); - TEST_MATCHER_TYPE.put(MatchingType.TIME, YamlContract.TestMatcherType.by_time); - TEST_MATCHER_TYPE.put(MatchingType.TIMESTAMP, YamlContract.TestMatcherType.by_timestamp); - TEST_MATCHER_TYPE.put(MatchingType.REGEX, YamlContract.TestMatcherType.by_regex); - TEST_MATCHER_TYPE.put(MatchingType.NULL, YamlContract.TestMatcherType.by_null); - STUB_MATCHER_TYPE.put(MatchingType.EQUALITY, YamlContract.StubMatcherType.by_equality); - STUB_MATCHER_TYPE.put(MatchingType.DATE, YamlContract.StubMatcherType.by_date); - STUB_MATCHER_TYPE.put(MatchingType.TIME, YamlContract.StubMatcherType.by_time); - STUB_MATCHER_TYPE.put(MatchingType.TIMESTAMP, YamlContract.StubMatcherType.by_timestamp); - STUB_MATCHER_TYPE.put(MatchingType.REGEX, YamlContract.StubMatcherType.by_regex); - } - - List convertTo(Collection contracts) { - - return contracts.stream().map(contract -> { - YamlContract yamlContract = new YamlContract(); - if (contract == null) { - return yamlContract; - } - yamlContract.name = contract.getName(); - yamlContract.ignored = contract.getIgnored(); - yamlContract.inProgress = contract.getInProgress(); - yamlContract.description = contract.getDescription(); - yamlContract.label = contract.getLabel(); - yamlContract.metadata = contract.getMetadata(); - yamlContract.priority = contract.getPriority(); - request(contract, yamlContract); - response(yamlContract, contract); - input(contract, yamlContract); - output(contract, yamlContract); - return yamlContract; - }).collect(Collectors.toList()); - } - - protected void request(Contract contract, YamlContract yamlContract) { - Request request = contract.getRequest(); - if (request != null) { - ContentType requestContentType = evaluateClientSideContentType(request.getHeaders(), request.getBody()); - yamlContract.request = new YamlContract.Request(); - mapRequestMethod(yamlContract.request, request); - mapRequestUrl(yamlContract.request, request); - mapRequestUrlPath(yamlContract.request, request); - mapRequestMatchers(yamlContract.request); - Url requestUrl = Optional.ofNullable(request.getUrl()).orElse(request.getUrlPath()); - if (requestUrl.getQueryParameters() != null) { - mapRequestQueryParameters(yamlContract.request, requestUrl); - mapRequestMatchersQueryParameters(yamlContract.request, requestUrl); - } - mapRequestHeaders(yamlContract.request, request); - mapRequestCookies(yamlContract.request, request); - mapRequestBody(yamlContract.request, request); - mapRequestMultipart(yamlContract.request, request); - mapRequestMatchersBody(yamlContract.request, request); - mapRequestMatchersUrl(yamlContract.request, request); - mapRequestMatchersMultipart(yamlContract.request, request); - - // TODO: Cookie matchers - including absent - if (XML != requestContentType) { - setInputBodyMatchers(request.getBody(), yamlContract.request.matchers.body); - } - setInputHeadersMatchers(request.getHeaders(), yamlContract.request.matchers.headers); - } - } - - private void mapRequestMatchersMultipart(YamlContract.Request yamlContractRequest, Request request) { - Multipart multipart = request.getMultipart(); - if (multipart != null) { - yamlContractRequest.matchers.multipart = new YamlContract.MultipartStubMatcher(); - Map map = (Map) MapConverter.getStubSideValues(multipart); - map.forEach((key, value) -> { - if (value instanceof NamedProperty) { - Object fileName = Optional.ofNullable(((NamedProperty) value).getName()) - .map(DslProperty::getClientValue).orElse(null); - Object fileContent = Optional.ofNullable(((NamedProperty) value).getValue()) - .map(DslProperty::getClientValue).orElse(null); - Object contentType = Optional.ofNullable(((NamedProperty) value).getContentType()) - .map(DslProperty::getClientValue).orElse(null); - if (fileName instanceof RegexProperty || fileContent instanceof RegexProperty - || contentType instanceof RegexProperty) { - YamlContract.MultipartNamedStubMatcher multipartNamedStubMatcher = new YamlContract.MultipartNamedStubMatcher(); - multipartNamedStubMatcher.paramName = key; - multipartNamedStubMatcher.fileName = valueMatcher(fileName); - multipartNamedStubMatcher.fileContent = valueMatcher(fileContent); - multipartNamedStubMatcher.contentType = valueMatcher(contentType); - yamlContractRequest.matchers.multipart.named.add(multipartNamedStubMatcher); - } - } - else if (value instanceof RegexProperty || value instanceof Pattern) { - RegexProperty property = new RegexProperty(value); - YamlContract.KeyValueMatcher keyValueMatcher = new YamlContract.KeyValueMatcher(); - keyValueMatcher.key = key; - keyValueMatcher.regex = property.pattern(); - keyValueMatcher.regexType = regexType(property.clazz()); - yamlContractRequest.matchers.multipart.params.add(keyValueMatcher); - } - }); - } - } - - private void mapRequestMatchersUrl(YamlContract.Request yamlContractRequest, Request request) { - Object url = Optional.ofNullable(request.getUrl()).map(Url::getClientValue) - .orElse(Optional.ofNullable(request.getUrlPath()).map(Url::getClientValue).orElse(null)); - YamlContract.KeyValueMatcher keyValueMatcher = new YamlContract.KeyValueMatcher(); - if (url instanceof RegexProperty) { - keyValueMatcher.regex = ((RegexProperty) url).pattern(); - yamlContractRequest.matchers.url = keyValueMatcher; - } - else if (url instanceof Pattern) { - keyValueMatcher.regex = ((Pattern) url).pattern(); - yamlContractRequest.matchers.url = keyValueMatcher; - } - else if (url instanceof ExecutionProperty) { - keyValueMatcher.command = url.toString(); - yamlContractRequest.matchers.url = keyValueMatcher; - } - else { - yamlContractRequest.matchers.url = null; - } - } - - private void mapRequestMatchersBody(YamlContract.Request yamlContractRequest, Request request) { - Optional.ofNullable(request.getBodyMatchers()).map(BodyMatchers::matchers) - .ifPresent(bodyMatchers -> bodyMatchers.forEach(bodyMatcher -> { - YamlContract.BodyStubMatcher bodyStubMatcher = new YamlContract.BodyStubMatcher(); - bodyStubMatcher.path = bodyMatcher.path(); - bodyStubMatcher.type = stubMatcherType(bodyMatcher.matchingType()); - bodyStubMatcher.value = Optional.ofNullable(bodyMatcher.value()).map(Object::toString).orElse(null); - bodyStubMatcher.minOccurrence = bodyMatcher.minTypeOccurrence(); - bodyStubMatcher.maxOccurrence = bodyMatcher.maxTypeOccurrence(); - yamlContractRequest.matchers.body.add(bodyStubMatcher); - })); - } - - private void mapRequestMultipart(YamlContract.Request yamlContractRequest, Request request) { - Multipart multipart = request.getMultipart(); - if (multipart != null) { - yamlContractRequest.multipart = new YamlContract.Multipart(); - Map map = (Map) MapConverter.getTestSideValues(multipart); - map.forEach((key, value) -> { - if (value instanceof NamedProperty) { - Object fileName = Optional.ofNullable(((NamedProperty) value).getName()) - .map(DslProperty::getServerValue).orElse(null); - Object contentType = Optional.ofNullable(((NamedProperty) value).getContentType()) - .map(DslProperty::getServerValue).orElse(null); - Object fileContent = Optional.ofNullable(((NamedProperty) value).getValue()) - .map(DslProperty::getServerValue).orElse(null); - YamlContract.Named named = new YamlContract.Named(); - named.paramName = key; - named.fileName = fileName instanceof String ? Optional.ofNullable(((NamedProperty) value).getName()) - .map(DslProperty::getServerValue).map(Object::toString).orElse(null) : null; - named.fileContent = (String) Optional.ofNullable(fileContent).filter(f -> f instanceof String) - .orElse(null); - named.fileContentAsBytes = fileContent instanceof FromFileProperty - ? new String(((FromFileProperty) fileContent).asBytes()) : null; - named.fileContentFromFileAsBytes = resolveFileNameAsBytes(fileContent); - named.contentType = (String) Optional.ofNullable(contentType).filter(f -> f instanceof String) - .orElse(null); - named.fileNameCommand = fileName instanceof ExecutionProperty ? fileName.toString() : null; - named.fileContentCommand = fileContent instanceof ExecutionProperty ? fileContent.toString() : null; - named.contentTypeCommand = contentType instanceof ExecutionProperty ? contentType.toString() : null; - yamlContractRequest.multipart.named.add(named); - } - else { - yamlContractRequest.multipart.params.put(key, value != null ? value.toString() : null); - } - }); - } - } - - private void mapRequestBody(YamlContract.Request yamlContractRequest, Request request) { - Object body = Optional.ofNullable(request.getBody()).map(DslProperty::getServerValue).orElse(null); - if (body instanceof FromFileProperty) { - FromFileProperty fromFileProperty = (FromFileProperty) body; - if (fromFileProperty.isByte()) { - yamlContractRequest.bodyFromFileAsBytes = fromFileProperty.fileName(); - } - if (fromFileProperty.isString()) { - yamlContractRequest.bodyFromFile = fromFileProperty.fileName(); - } - } - else { - yamlContractRequest.body = MapConverter.getTestSideValues(request.getBody()); - } - } - - private void mapRequestCookies(YamlContract.Request yamlContractRequest, Request request) { - yamlContractRequest.cookies = Optional.ofNullable(request.getCookies()).map(Cookies::asTestSideMap) - .orElse(null); - } - - private void mapRequestHeaders(YamlContract.Request yamlContractRequest, Request request) { - yamlContractRequest.headers = request.getHeaders() != null ? request.getHeaders().asMap((headerName, prop) -> { - Object testSideValue = MapConverter.getTestSideValues(prop); - if (testSideValue instanceof ExecutionProperty) { - return MapConverter.getStubSideValuesForNonBody(prop).toString(); - } - return testSideValue.toString(); - }) : null; - } - - private void mapRequestMatchersQueryParameters(YamlContract.Request yamlContractRequest, Url requestUrl) { - yamlContractRequest.matchers.queryParameters - .addAll(requestUrl.getQueryParameters().getParameters().stream().map(parameter -> { - Object stubSide = parameter.getClientValue(); - if (stubSide instanceof RegexProperty || stubSide instanceof Pattern) { - YamlContract.QueryParameterMatcher queryParameterMatcher = new YamlContract.QueryParameterMatcher(); - queryParameterMatcher.key = parameter.getName(); - queryParameterMatcher.type = YamlContract.MatchingType.matching; - queryParameterMatcher.value = new RegexProperty(stubSide).pattern(); - return queryParameterMatcher; - } - else if (stubSide instanceof MatchingStrategy) { - YamlContract.QueryParameterMatcher queryParameterMatcher = new YamlContract.QueryParameterMatcher(); - queryParameterMatcher.key = parameter.getName(); - queryParameterMatcher.type = YamlContract.MatchingType - .from(((MatchingStrategy) stubSide).getType().getName()); - queryParameterMatcher.value = MapConverter.getStubSideValuesForNonBody(stubSide); - return queryParameterMatcher; - } - else { - return null; - } - }).filter(Objects::nonNull).collect(Collectors.toList())); - } - - private void mapRequestQueryParameters(YamlContract.Request yamlContractRequest, Url requestUrl) { - yamlContractRequest.queryParameters = requestUrl.getQueryParameters().getParameters().stream() - .collect(Collectors.toMap(QueryParameter::getName, MapConverter::getTestSideValuesForNonBody)); - } - - private void mapRequestMatchers(YamlContract.Request yamlContractRequest) { - yamlContractRequest.matchers = new YamlContract.StubMatchers(); - } - - private void mapRequestUrlPath(YamlContract.Request yamlContractRequest, Request request) { - yamlContractRequest.urlPath = Optional.ofNullable(request.getUrlPath()).map(m -> m.getServerValue().toString()) - .orElse(null); - } - - private void mapRequestUrl(YamlContract.Request yamlContractRequest, Request request) { - yamlContractRequest.url = Optional.ofNullable(request.getUrl()).map(m -> m.getServerValue().toString()) - .orElse(null); - } - - private void mapRequestMethod(YamlContract.Request yamlContractRequest, Request request) { - yamlContractRequest.method = Optional.ofNullable(request.getMethod()).map(m -> m.getServerValue().toString()) - .orElse(null); - } - - protected void output(Contract contract, YamlContract yamlContract) { - OutputMessage outputMessage = contract.getOutputMessage(); - if (outputMessage != null) { - Optional optionalResponse = Optional.ofNullable(contract.getResponse()); - ContentType contentType = evaluateClientSideContentType( - optionalResponse.map(Response::getHeaders).orElse(null), - optionalResponse.map(Response::getBody).orElse(null)); - yamlContract.outputMessage = new YamlContract.OutputMessage(); - yamlContract.outputMessage.sentTo = MapConverter.getStubSideValues(outputMessage.getSentTo()).toString(); - yamlContract.outputMessage.headers = Optional.ofNullable(outputMessage.getHeaders()) - .map(Headers::asStubSideMap).orElse(null); - yamlContract.outputMessage.body = MapConverter.getStubSideValues(outputMessage.getBody()); - Optional.ofNullable(outputMessage.getBodyMatchers()).map(BodyMatchers::matchers) - .ifPresent(bodyMatchers -> bodyMatchers.forEach(bodyMatcher -> { - YamlContract.BodyTestMatcher bodyTestMatcher = new YamlContract.BodyTestMatcher(); - bodyTestMatcher.path = bodyMatcher.path(); - bodyTestMatcher.type = testMatcherType(bodyMatcher.matchingType()); - bodyTestMatcher.value = Optional.ofNullable(bodyMatcher.value()).map(Object::toString) - .orElse(null); - bodyTestMatcher.minOccurrence = bodyMatcher.minTypeOccurrence(); - bodyTestMatcher.maxOccurrence = bodyMatcher.maxTypeOccurrence(); - yamlContract.outputMessage.matchers.body.add(bodyTestMatcher); - - })); - if (XML != contentType) { - setOutputBodyMatchers(outputMessage.getBody(), yamlContract.outputMessage.matchers.body); - } - setOutputHeadersMatchers(outputMessage.getHeaders(), yamlContract.outputMessage.matchers.headers); - } - } - - protected void input(Contract contract, YamlContract yamlContract) { - Input input = contract.getInput(); - if (input != null) { - yamlContract.input = new YamlContract.Input(); - yamlContract.input.assertThat = Optional.ofNullable(input.getAssertThat()) - .map(assertThat -> MapConverter - .getTestSideValues(assertThat.toString(), MapConverter.JSON_PARSING_FUNCTION).toString()) - .orElse(null); - yamlContract.input.triggeredBy = Optional.ofNullable(input.getTriggeredBy()) - .map(triggeredBy -> MapConverter - .getTestSideValues(triggeredBy.toString(), MapConverter.JSON_PARSING_FUNCTION).toString()) - .orElse(null); - } - } - - protected String resolveFileNameAsBytes(Object value) { - if (!(value instanceof FromFileProperty)) { - return null; - } - FromFileProperty property = (FromFileProperty) value; - return property.fileName(); - } - - protected YamlContract.ValueMatcher valueMatcher(Object o) { - return Optional.ofNullable(o).filter(object -> object instanceof RegexProperty) - .map(object -> (RegexProperty) object).map(regexProperty -> { - YamlContract.ValueMatcher valueMatcher = new YamlContract.ValueMatcher(); - valueMatcher.regex = regexProperty.pattern(); - return valueMatcher; - }).orElse(null); - } - - protected void setInputBodyMatchers(DslProperty body, List bodyMatchers) { - Object testSideValues = MapConverter.getTestSideValues(body); - JsonPaths paths = new JsonToJsonPathsConverter().transformToJsonPathWithStubsSideValues(body); - paths.stream().filter((path) -> path.valueBeforeChecking() instanceof Pattern).forEach((path) -> { - Object element = JsonToJsonPathsConverter.readElement(testSideValues, path.keyBeforeChecking()); - YamlContract.BodyStubMatcher bodyStubMatcher = new YamlContract.BodyStubMatcher(); - bodyStubMatcher.path = path.keyBeforeChecking(); - bodyStubMatcher.type = YamlContract.StubMatcherType.by_regex; - bodyStubMatcher.value = ((Pattern) path.valueBeforeChecking()).pattern(); - bodyStubMatcher.regexType = regexType(element); - bodyMatchers.add(bodyStubMatcher); - }); - } - - protected YamlContract.RegexType regexType(Object from) { - return regexType(from.getClass()); - } - - protected YamlContract.RegexType regexType(Class clazz) { - return PRIMITIVE_WRAPPER_TO_REGEX_TYPE.getOrDefault(clazz, PRIMITIVE_WRAPPER_TO_REGEX_TYPE.get(String.class)); - } - - protected void response(YamlContract yamlContract, Contract contract) { - if (contract.getResponse() != null) { - Response contractResponse = contract.getResponse(); - ContentType contentType = evaluateClientSideContentType(contractResponse.getHeaders(), - contractResponse.getBody()); - YamlContract.Response response = new YamlContract.Response(); - yamlContract.response = response; - mapResponseAsync(contractResponse, response); - mapResponseFixedDelayMilliseconds(contractResponse, response); - mapResponseStatus(contractResponse, response); - mapResponseHeaders(contractResponse, response); - mapResponseCookies(contractResponse, response); - mapResponseBody(contractResponse, response); - mapResponseBodyMatchers(contractResponse, response); - if (XML != contentType) { - setOutputBodyMatchers(contractResponse.getBody(), yamlContract.response.matchers.body); - } - setOutputHeadersMatchers(contractResponse.getHeaders(), yamlContract.response.matchers.headers); - } - } - - private void mapResponseBodyMatchers(Response contractResponse, YamlContract.Response response) { - Optional.ofNullable(contractResponse.getBodyMatchers()).map(BodyMatchers::matchers) - .ifPresent(bodyMatchers -> bodyMatchers.forEach((bodyMatcher) -> { - YamlContract.BodyTestMatcher bodyTestMatcher = new YamlContract.BodyTestMatcher(); - bodyTestMatcher.path = bodyMatcher.path(); - bodyTestMatcher.type = testMatcherType(bodyMatcher.matchingType()); - bodyTestMatcher.value = Optional.ofNullable(bodyMatcher.value()).map(Object::toString).orElse(null); - bodyTestMatcher.minOccurrence = bodyMatcher.minTypeOccurrence(); - bodyTestMatcher.maxOccurrence = bodyMatcher.maxTypeOccurrence(); - response.matchers.body.add(bodyTestMatcher); - })); - } - - private void mapResponseBody(Response contractResponse, YamlContract.Response response) { - Object body = Optional.ofNullable(contractResponse.getBody()).map(DslProperty::getClientValue).orElse(null); - if (body instanceof FromFileProperty) { - if (((FromFileProperty) body).isByte()) { - response.bodyFromFileAsBytes = ((FromFileProperty) body).fileName(); - } - if (((FromFileProperty) body).isString()) { - response.bodyFromFile = ((FromFileProperty) body).fileName(); - } - } - else { - response.body = MapConverter.getStubSideValues(contractResponse.getBody()); - } - } - - private void mapResponseCookies(Response contractResponse, YamlContract.Response response) { - response.cookies = Optional.ofNullable(contractResponse.getCookies()).map(Cookies::asStubSideMap).orElse(null); - } - - private void mapResponseHeaders(Response contractResponse, YamlContract.Response response) { - response.headers = Optional.ofNullable(contractResponse.getHeaders()) - .map(headers -> headers.asMap((headerName, dslProperty) -> MapConverter.getStubSideValues(dslProperty))) - .orElse(null); - } - - private void mapResponseStatus(Response contractResponse, YamlContract.Response response) { - response.status = Optional.ofNullable(contractResponse.getStatus()).map(DslProperty::getClientValue) - .map(clientValue -> (Integer) clientValue).orElse(null); - } - - private void mapResponseFixedDelayMilliseconds(Response contractResponse, YamlContract.Response response) { - response.fixedDelayMilliseconds = (Integer) Optional.ofNullable(contractResponse.getDelay()) - .map(DslProperty::getClientValue).orElse(null); - } - - private void mapResponseAsync(Response contractResponse, YamlContract.Response response) { - response.async = contractResponse.getAsync(); - } - - protected void setOutputBodyMatchers(DslProperty body, List bodyMatchers) { - Object testSideValues = MapConverter.getTestSideValues(body); - JsonPaths paths = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(body); - paths.stream().filter(m -> m.valueBeforeChecking() instanceof Pattern).forEach((m) -> { - Object element = JsonToJsonPathsConverter.readElement(testSideValues, m.keyBeforeChecking()); - YamlContract.BodyTestMatcher bodyTestMatcher = new YamlContract.BodyTestMatcher(); - bodyTestMatcher.path = m.keyBeforeChecking(); - bodyTestMatcher.type = YamlContract.TestMatcherType.by_regex; - bodyTestMatcher.value = ((Pattern) m.valueBeforeChecking()).pattern(); - bodyTestMatcher.regexType = regexType(element); - bodyMatchers.add(bodyTestMatcher); - }); - Optional.ofNullable(body).filter(b -> b.getServerValue() instanceof Pattern).ifPresent((b) -> { - YamlContract.BodyTestMatcher bodyTestMatcher = new YamlContract.BodyTestMatcher(); - bodyTestMatcher.type = YamlContract.TestMatcherType.by_regex; - bodyTestMatcher.value = ((Pattern) b.getServerValue()).pattern(); - bodyMatchers.add(bodyTestMatcher); - }); - } - - protected void setInputHeadersMatchers(Headers headers, List headerMatchers) { - Optional.ofNullable(headers).map(Headers::asStubSideMap) - .ifPresent(stubSideMap -> stubSideMap.forEach((key, value) -> { - if (value instanceof RegexProperty || value instanceof Pattern) { - RegexProperty property = new RegexProperty(value); - YamlContract.KeyValueMatcher keyValueMatcher = new YamlContract.KeyValueMatcher(); - keyValueMatcher.key = key; - keyValueMatcher.regex = property.pattern(); - keyValueMatcher.regexType = regexType(property.clazz()); - headerMatchers.add(keyValueMatcher); - } - })); - } - - protected void setOutputHeadersMatchers(Headers headers, List headerMatchers) { - Optional.ofNullable(headers).map(Headers::asTestSideMap) - .ifPresent(testSideMap -> testSideMap.forEach((key, value) -> { - if (value instanceof RegexProperty || value instanceof Pattern) { - RegexProperty property = new RegexProperty(value); - YamlContract.TestHeaderMatcher testHeaderMatcher = new YamlContract.TestHeaderMatcher(); - testHeaderMatcher.key = key; - testHeaderMatcher.regex = property.pattern(); - testHeaderMatcher.regexType = regexType(property.clazz()); - headerMatchers.add(testHeaderMatcher); - } - else if (value instanceof ExecutionProperty) { - YamlContract.TestHeaderMatcher testHeaderMatcher = new YamlContract.TestHeaderMatcher(); - testHeaderMatcher.key = key; - testHeaderMatcher.command = ((ExecutionProperty) value).getExecutionCommand(); - headerMatchers.add(testHeaderMatcher); - } - else if (value instanceof NotToEscapePattern) { - YamlContract.TestHeaderMatcher testHeaderMatcher = new YamlContract.TestHeaderMatcher(); - testHeaderMatcher.key = key; - testHeaderMatcher.regex = (((NotToEscapePattern) value).getServerValue()).pattern(); - headerMatchers.add(testHeaderMatcher); - } - })); - } - - protected YamlContract.TestMatcherType testMatcherType(MatchingType matchingType) { - return TEST_MATCHER_TYPE.getOrDefault(matchingType, null); - } - - protected YamlContract.StubMatcherType stubMatcherType(MatchingType matchingType) { - if (matchingType == MatchingType.COMMAND || matchingType == MatchingType.TYPE) { - return null; - } - return STUB_MATCHER_TYPE.getOrDefault(matchingType, null); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/ToYamlConverter.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/ToYamlConverter.java deleted file mode 100644 index 501d57173a..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/ToYamlConverter.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.converter; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.ContractConverter; -import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter; -import org.springframework.core.io.support.SpringFactoriesLoader; - -/** - * Converts contracts to YAML for the given folder. - * - * @author Marcin Grzejszczak - * @since 2.1.0 - */ -public final class ToYamlConverter { - - private static final Logger log = LoggerFactory.getLogger(ToYamlConverter.class); - - private ToYamlConverter() { - throw new IllegalStateException("Can't instantiate a utility class"); - } - - private static final YamlContractConverter yamlContractConverter = new YamlContractConverter(); - - private static final List CONTRACT_CONVERTERS = converters(); - - protected static void doReplaceContractWithYaml(ContractConverter converter, File file) { - if (log.isDebugEnabled()) { - log.debug("Will replace contract [{}] with a YAML version", file.getName()); - } - // base dir: target/copied_contracts/contracts/ - // target/copied_contracts/contracts/foo/baz/bar.groovy - Collection collection = converter.convertFrom(file); - if (log.isDebugEnabled()) { - log.debug("Converted file [{}] to collection of [{}] contracts", file, collection.size()); - } - List yamls = yamlContractConverter.convertTo(collection); - if (log.isDebugEnabled()) { - log.debug("Converted collection of [{}] contracts to [{}] YAML contracts", collection.size(), yamls.size()); - } - // rm target/copied_contracts/contracts/foo/baz/bar.groovy - file.delete(); - // [contracts/foo/baz/bar.groovy] -> [contracts/foo/baz/bar.yml] - Map stored = yamlContractConverter.store(yamls); - if (log.isDebugEnabled()) { - log.debug("Dumped YAMLs to following file names {}", stored.keySet()); - } - stored.forEach((key, value) -> { - File ymlContractVersion = new File(file.getParentFile(), key); - // store the YMLs instead of groovy files - try { - Files.write(ymlContractVersion.toPath(), value); - } - catch (IOException e) { - throw new RuntimeException(e); - } - if (log.isDebugEnabled()) { - log.debug("Written file [{}] with YAML contract definition", ymlContractVersion); - } - }); - } - - /** - * If a contract ends with e.g. [.groovy] we will move it to the [original] folder, - * convert the [.groovy] version to [.yml] and store it instead of the Groovy file. - * From that we will continue processing as if from the very beginning there was only - * a [.yml] file - * @param baseDir base directory for contracts - */ - public static void replaceContractWithYaml(File baseDir) { - try { - Files.walk(baseDir.toPath()).map(Path::toFile) - .forEach(file -> CONTRACT_CONVERTERS.stream().filter(converter -> converter.isAccepted(file)) - .findFirst().ifPresent(converter -> doReplaceContractWithYaml(converter, file))); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - - private static List converters() { - List converters = SpringFactoriesLoader.loadFactories(ContractConverter.class, null); - converters.add(YamlContractConverter.INSTANCE); - converters.add(ContractVerifierDslConverter.INSTANCE); - return converters; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/ToYamlConverterApplication.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/ToYamlConverterApplication.java deleted file mode 100644 index c9755dc6af..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/ToYamlConverterApplication.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.converter; - -import java.io.File; - -public final class ToYamlConverterApplication { - - private ToYamlConverterApplication() { - } - - public static void main(String[] args) { - if (args.length != 1) { - throw new RuntimeException("Invalid number of arguments"); - } - - File copiedContractsFolder = new File(args[0]); - - ToYamlConverter.replaceContractWithYaml(copiedContractsFolder); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/YamlContract.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/YamlContract.java deleted file mode 100644 index 2887575051..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/YamlContract.java +++ /dev/null @@ -1,809 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.converter; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -import org.springframework.cloud.contract.spec.Contract; - -/** - * YAML representation of a {@link Contract}. - * - * @author Marcin Grzejszczak - * @author Tim Ysewyn - * @since 1.2.1 - */ -public class YamlContract { - - public Request request; - - public Response response; - - public Input input; - - public OutputMessage outputMessage; - - public String description; - - public String label; - - public String name; - - public Integer priority; - - public boolean ignored; - - public boolean inProgress; - - public Map metadata = new HashMap<>(); - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - YamlContract that = (YamlContract) o; - return ignored == that.ignored && inProgress == that.inProgress && Objects.equals(this.request, that.request) - && Objects.equals(this.response, that.response) && Objects.equals(this.input, that.input) - && Objects.equals(this.outputMessage, that.outputMessage) - && Objects.equals(this.description, that.description) && Objects.equals(this.label, that.label) - && Objects.equals(this.name, that.name) && Objects.equals(this.priority, that.priority) - && this.metadata.equals(that.metadata); - } - - @Override - public int hashCode() { - return Objects.hash(request, response, input, outputMessage, description, label, name, priority, ignored, - inProgress, metadata); - } - - public static class Request { - - public String method; - - public String url; - - public String urlPath; - - public Map queryParameters = new LinkedHashMap(); - - public Map headers = new LinkedHashMap(); - - public Map cookies = new LinkedHashMap(); - - public Object body; - - public String bodyFromFile; - - public String bodyFromFileAsBytes; - - public StubMatchers matchers = new StubMatchers(); - - public Multipart multipart; - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Request request = (Request) o; - return Objects.equals(method, request.method) && Objects.equals(url, request.url) - && Objects.equals(urlPath, request.urlPath) - && Objects.equals(queryParameters, request.queryParameters) - && Objects.equals(headers, request.headers) && Objects.equals(cookies, request.cookies) - && Objects.equals(body, request.body) && Objects.equals(bodyFromFile, request.bodyFromFile) - && Objects.equals(bodyFromFileAsBytes, request.bodyFromFileAsBytes) - && Objects.equals(matchers, request.matchers) && Objects.equals(multipart, request.multipart); - } - - @Override - public int hashCode() { - return Objects.hash(method, url, urlPath, queryParameters, headers, cookies, body, bodyFromFile, - bodyFromFileAsBytes, matchers, multipart); - } - - @Override - public String toString() { - return "Request{" + "method='" + method + '\'' + ", url='" + url + '\'' + ", urlPath='" + urlPath + '\'' - + ", queryParameters=" + queryParameters + ", headers=" + headers + ", cookies=" + cookies - + ", body=" + body + ", bodyFromFile='" + bodyFromFile + '\'' + ", bodyFromFileAsBytes='" - + bodyFromFileAsBytes + '\'' + ", matchers=" + matchers + ", multipart=" + multipart + '}'; - } - - } - - public static class Multipart { - - public Map params = new LinkedHashMap(); - - public List named = new ArrayList(); - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Multipart multipart = (Multipart) o; - return Objects.equals(params, multipart.params) && Objects.equals(named, multipart.named); - } - - @Override - public int hashCode() { - return Objects.hash(params, named); - } - - @Override - public String toString() { - return "Multipart{" + "params=" + params + ", named=" + named + '}'; - } - - } - - public static class Named { - - public String paramName; - - public String fileName; - - public String fileContent; - - public String fileContentAsBytes; - - public String fileContentFromFileAsBytes; - - public String contentType; - - public String fileNameCommand; - - public String fileContentCommand; - - public String contentTypeCommand; - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Named named = (Named) o; - return Objects.equals(paramName, named.paramName) && Objects.equals(fileName, named.fileName) - && Objects.equals(fileContent, named.fileContent) - && Objects.equals(fileContentAsBytes, named.fileContentAsBytes) - && Objects.equals(fileContentFromFileAsBytes, named.fileContentFromFileAsBytes) - && Objects.equals(contentType, named.contentType) - && Objects.equals(fileNameCommand, named.fileNameCommand) - && Objects.equals(fileContentCommand, named.fileContentCommand) - && Objects.equals(contentTypeCommand, named.contentTypeCommand); - } - - @Override - public int hashCode() { - return Objects.hash(paramName, fileName, fileContent, fileContentAsBytes, fileContentFromFileAsBytes, - contentType, fileNameCommand, fileContentCommand, contentTypeCommand); - } - - @Override - public String toString() { - return "Named{" + "paramName='" + paramName + '\'' + ", fileName='" + fileName + '\'' + ", fileContent='" - + fileContent + '\'' + ", fileContentAsBytes='" + fileContentAsBytes + '\'' - + ", fileContentFromFileAsBytes='" + fileContentFromFileAsBytes + '\'' + ", contentType='" - + contentType + '\'' + ", fileNameCommand='" + fileNameCommand + '\'' + ", fileContentCommand='" - + fileContentCommand + '\'' + ", contentTypeCommand='" + contentTypeCommand + '\'' + '}'; - } - - } - - public static class StubMatchers { - - public KeyValueMatcher url; - - public List body = new ArrayList(); - - public List headers = new ArrayList(); - - public List queryParameters = new ArrayList(); - - public List cookies = new ArrayList(); - - public MultipartStubMatcher multipart; - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - StubMatchers that = (StubMatchers) o; - return Objects.equals(url, that.url) && Objects.equals(body, that.body) - && Objects.equals(headers, that.headers) && Objects.equals(queryParameters, that.queryParameters) - && Objects.equals(cookies, that.cookies) && Objects.equals(multipart, that.multipart); - } - - @Override - public int hashCode() { - return Objects.hash(url, body, headers, queryParameters, cookies, multipart); - } - - @Override - public String toString() { - return "StubMatchers{" + "url=" + url + ", body=" + body + ", headers=" + headers + ", queryParameters=" - + queryParameters + ", cookies=" + cookies + ", multipart=" + multipart + '}'; - } - - } - - public enum MatchingType { - - equal_to, containing, matching, not_matching, equal_to_json, equal_to_xml, absent, binary_equal_to; - - static MatchingType from(String string) { - return Arrays.stream(values()).filter(matchingType -> matchingType.name().replace("_", "") - .equalsIgnoreCase(string.toLowerCase().replace("_", ""))).findFirst().orElse(null); - } - - } - - public static class BodyStubMatcher { - - public String path; - - public StubMatcherType type; - - public String value; - - public PredefinedRegex predefined; - - public Integer minOccurrence; - - public Integer maxOccurrence; - - public RegexType regexType; - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - BodyStubMatcher that = (BodyStubMatcher) o; - return Objects.equals(path, that.path) && type == that.type && Objects.equals(value, that.value) - && predefined == that.predefined && Objects.equals(minOccurrence, that.minOccurrence) - && Objects.equals(maxOccurrence, that.maxOccurrence) && regexType == that.regexType; - } - - @Override - public int hashCode() { - return Objects.hash(path, type, value, predefined, minOccurrence, maxOccurrence, regexType); - } - - @Override - public String toString() { - return "BodyStubMatcher{" + "path='" + path + '\'' + ", type=" + type + ", value='" + value + '\'' - + ", predefined=" + predefined + ", minOccurrence=" + minOccurrence + ", maxOccurrence=" - + maxOccurrence + ", regexType=" + regexType + '}'; - } - - } - - public enum RegexType { - - as_integer, as_double, as_float, as_long, as_short, as_boolean, as_string; - - } - - public static class MultipartStubMatcher { - - public List params = new ArrayList(); - - public List named = new ArrayList(); - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - MultipartStubMatcher that = (MultipartStubMatcher) o; - return Objects.equals(params, that.params) && Objects.equals(named, that.named); - } - - @Override - public int hashCode() { - return Objects.hash(params, named); - } - - @Override - public String toString() { - return "MultipartStubMatcher{" + "params=" + params + ", named=" + named + '}'; - } - - } - - public static class MultipartNamedStubMatcher { - - public String paramName; - - public ValueMatcher fileName; - - public ValueMatcher fileContent; - - public ValueMatcher contentType; - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - MultipartNamedStubMatcher that = (MultipartNamedStubMatcher) o; - return Objects.equals(paramName, that.paramName) && Objects.equals(fileName, that.fileName) - && Objects.equals(fileContent, that.fileContent) && Objects.equals(contentType, that.contentType); - } - - @Override - public int hashCode() { - return Objects.hash(paramName, fileName, fileContent, contentType); - } - - @Override - public String toString() { - return "MultipartNamedStubMatcher{" + "paramName='" + paramName + '\'' + ", fileName=" + fileName - + ", fileContent=" + fileContent + ", contentType=" + contentType + '}'; - } - - } - - public static class ValueMatcher { - - public String regex; - - public PredefinedRegex predefined; - - public ValueMatcher() { - } - - public ValueMatcher(String regex) { - this.regex = regex; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ValueMatcher that = (ValueMatcher) o; - return Objects.equals(regex, that.regex) && predefined == that.predefined; - } - - @Override - public int hashCode() { - return Objects.hash(regex, predefined); - } - - @Override - public String toString() { - return "ValueMatcher{" + "regex='" + regex + '\'' + ", predefined=" + predefined + '}'; - } - - } - - public static class BodyTestMatcher { - - public String path; - - public TestMatcherType type; - - public String value; - - public Integer minOccurrence; - - public Integer maxOccurrence; - - public PredefinedRegex predefined; - - public RegexType regexType; - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - BodyTestMatcher that = (BodyTestMatcher) o; - return Objects.equals(path, that.path) && type == that.type && Objects.equals(value, that.value) - && Objects.equals(minOccurrence, that.minOccurrence) - && Objects.equals(maxOccurrence, that.maxOccurrence) && predefined == that.predefined - && regexType == that.regexType; - } - - @Override - public int hashCode() { - return Objects.hash(path, type, value, minOccurrence, maxOccurrence, predefined, regexType); - } - - @Override - public String toString() { - return "BodyTestMatcher{" + "path='" + path + '\'' + ", type=" + type + ", value='" + value + '\'' - + ", minOccurrence=" + minOccurrence + ", maxOccurrence=" + maxOccurrence + ", predefined=" - + predefined + ", regexType=" + regexType + '}'; - } - - } - - public static class KeyValueMatcher { - - public String key; - - public String regex; - - public PredefinedRegex predefined; - - public String command; - - public RegexType regexType; - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - KeyValueMatcher that = (KeyValueMatcher) o; - return Objects.equals(key, that.key) && Objects.equals(regex, that.regex) && predefined == that.predefined - && Objects.equals(command, that.command) && regexType == that.regexType; - } - - @Override - public int hashCode() { - return Objects.hash(key, regex, predefined, command, regexType); - } - - @Override - public String toString() { - return "KeyValueMatcher{" + "key='" + key + '\'' + ", regex='" + regex + '\'' + ", predefined=" + predefined - + ", command='" + command + '\'' + ", regexType=" + regexType + '}'; - } - - } - - public static class HeadersMatcher extends KeyValueMatcher { - - } - - public static class QueryParameterMatcher { - - public String key; - - public MatchingType type; - - public Object value; - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - QueryParameterMatcher that = (QueryParameterMatcher) o; - return Objects.equals(key, that.key) && type == that.type && Objects.equals(value, that.value); - } - - @Override - public int hashCode() { - return Objects.hash(key, type, value); - } - - @Override - public String toString() { - return "QueryParameterMatcher{" + "key='" + key + '\'' + ", type=" + type + ", value=" + value + '}'; - } - - } - - public static class TestHeaderMatcher { - - public String key; - - public String regex; - - public String command; - - public PredefinedRegex predefined; - - public RegexType regexType; - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - TestHeaderMatcher that = (TestHeaderMatcher) o; - return Objects.equals(key, that.key) && Objects.equals(regex, that.regex) - && Objects.equals(command, that.command) && predefined == that.predefined - && regexType == that.regexType; - } - - @Override - public int hashCode() { - return Objects.hash(key, regex, command, predefined, regexType); - } - - @Override - public String toString() { - return "TestHeaderMatcher{" + "key='" + key + '\'' + ", regex='" + regex + '\'' + ", command='" + command - + '\'' + ", predefined=" + predefined + ", regexType=" + regexType + '}'; - } - - } - - public static class TestCookieMatcher { - - public String key; - - public String regex; - - public String command; - - public PredefinedRegex predefined; - - public RegexType regexType; - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - TestCookieMatcher that = (TestCookieMatcher) o; - return Objects.equals(key, that.key) && Objects.equals(regex, that.regex) - && Objects.equals(command, that.command) && predefined == that.predefined - && regexType == that.regexType; - } - - @Override - public int hashCode() { - return Objects.hash(key, regex, command, predefined, regexType); - } - - @Override - public String toString() { - return "TestCookieMatcher{" + "key='" + key + '\'' + ", regex='" + regex + '\'' + ", command='" + command - + '\'' + ", predefined=" + predefined + ", regexType=" + regexType + '}'; - } - - } - - public enum PredefinedRegex { - - only_alpha_unicode, number, any_double, any_boolean, ip_address, hostname, email, url, uuid, iso_date, - iso_date_time, iso_time, iso_8601_with_offset, non_empty, non_blank; - - } - - public enum StubMatcherType { - - by_date, by_time, by_timestamp, by_regex, by_equality, by_type, by_null; - - } - - public enum TestMatcherType { - - by_date, by_time, by_timestamp, by_regex, by_equality, by_type, by_command, by_null; - - } - - public static class Response { - - public int status; - - public Map headers = new LinkedHashMap(); - - public Map cookies = new LinkedHashMap(); - - public Object body; - - public String bodyFromFile; - - public String bodyFromFileAsBytes; - - public TestMatchers matchers = new TestMatchers(); - - public Boolean async; - - public Integer fixedDelayMilliseconds; - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Response response = (Response) o; - return status == response.status && Objects.equals(headers, response.headers) - && Objects.equals(cookies, response.cookies) && Objects.equals(body, response.body) - && Objects.equals(bodyFromFile, response.bodyFromFile) - && Objects.equals(bodyFromFileAsBytes, response.bodyFromFileAsBytes) - && Objects.equals(matchers, response.matchers) && Objects.equals(async, response.async) - && Objects.equals(fixedDelayMilliseconds, response.fixedDelayMilliseconds); - } - - @Override - public int hashCode() { - return Objects.hash(status, headers, cookies, body, bodyFromFile, bodyFromFileAsBytes, matchers, async, - fixedDelayMilliseconds); - } - - @Override - public String toString() { - return "Response{" + "status=" + status + ", headers=" + headers + ", cookies=" + cookies + ", body=" + body - + ", bodyFromFile='" + bodyFromFile + '\'' + ", bodyFromFileAsBytes='" + bodyFromFileAsBytes + '\'' - + ", matchers=" + matchers + ", async=" + async + ", fixedDelayMilliseconds=" - + fixedDelayMilliseconds + '}'; - } - - } - - public static class TestMatchers { - - public List body = new ArrayList(); - - public List headers = new ArrayList(); - - public List cookies = new ArrayList(); - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - TestMatchers that = (TestMatchers) o; - return Objects.equals(body, that.body) && Objects.equals(headers, that.headers) - && Objects.equals(cookies, that.cookies); - } - - @Override - public int hashCode() { - return Objects.hash(body, headers, cookies); - } - - @Override - public String toString() { - return "TestMatchers{" + "body=" + body + ", headers=" + headers + ", cookies=" + cookies + '}'; - } - - } - - public static class Input { - - public String triggeredBy; - - public String assertThat; - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Input input = (Input) o; - return Objects.equals(triggeredBy, input.triggeredBy) && Objects.equals(assertThat, input.assertThat); - } - - @Override - public int hashCode() { - return Objects.hash(triggeredBy, assertThat); - } - - @Override - public String toString() { - return "Input{" + "triggeredBy='" + triggeredBy + '\'' + ", assertThat='" + assertThat + '\'' + '}'; - } - - } - - public static class OutputMessage { - - public String sentTo; - - public Map headers = new LinkedHashMap(); - - public Object body; - - public String bodyFromFile; - - public String bodyFromFileAsBytes; - - public String assertThat; - - public TestMatchers matchers = new TestMatchers(); - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - OutputMessage that = (OutputMessage) o; - return Objects.equals(sentTo, that.sentTo) && Objects.equals(headers, that.headers) - && Objects.equals(body, that.body) && Objects.equals(bodyFromFile, that.bodyFromFile) - && Objects.equals(bodyFromFileAsBytes, that.bodyFromFileAsBytes) - && Objects.equals(assertThat, that.assertThat) && Objects.equals(matchers, that.matchers); - } - - @Override - public int hashCode() { - return Objects.hash(sentTo, headers, body, bodyFromFile, bodyFromFileAsBytes, assertThat, matchers); - } - - @Override - public String toString() { - return "OutputMessage{" + "sentTo='" + sentTo + '\'' + ", headers=" + headers + ", body=" + body - + ", bodyFromFile='" + bodyFromFile + '\'' + ", bodyFromFileAsBytes='" + bodyFromFileAsBytes + '\'' - + ", assertThat='" + assertThat + '\'' + ", matchers=" + matchers + '}'; - } - - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.java deleted file mode 100644 index 9b7dee667a..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.converter; - -import java.io.File; -import java.io.IOException; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.dataformat.yaml.YAMLMapper; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.ContractConverter; - -import static java.util.Collections.singletonList; -import static java.util.stream.Collectors.toMap; - -/** - * Simple converter from and to a {@link YamlContract} to a collection of - * {@link Contract}. - * - * @author Marcin Grzejszczak - * @author Tim Ysewyn - * @since 1.2.1 - */ -public class YamlContractConverter implements ContractConverter> { - - private static final Logger log = LoggerFactory.getLogger(YamlContractConverter.class); - - public static final YamlContractConverter INSTANCE = new YamlContractConverter(); - - private final YAMLMapper mapper = new YAMLMapper(); - - private final YamlToContracts yamlToContracts = new YamlToContracts(); - - private final ContractsToYaml contractsToYaml = new ContractsToYaml(); - - @Override - public boolean isAccepted(File file) { - String name = file.getName(); - boolean acceptFile = name.endsWith(".yml") || name.endsWith(".yaml"); - if (acceptFile) { - try { - this.yamlToContracts.convertFrom(file); - } - catch (Exception e) { - log.warn("Error Processing yaml file. Skipping Contract Generation ", e); - acceptFile = false; - } - } - return acceptFile; - } - - @Override - public Collection convertFrom(File file) { - return this.yamlToContracts.convertFrom(file); - } - - @Override - public List convertTo(Collection contracts) { - return this.contractsToYaml.convertTo(contracts); - } - - @Override - public Map store(List contracts) { - return contracts.stream().collect(toMap(this::name, this::getBytes)); - } - - @Override - public List read(byte[] bytes) { - try { - return singletonList(this.mapper.readValue(bytes, YamlContract.class)); - } - catch (Exception e) { - try { - return this.mapper.readerForListOf(YamlContract.class).readValue(bytes); - } - catch (IOException ioException) { - throw new RuntimeException(ioException); - } - } - } - - protected String name(YamlContract contract) { - return StringUtils.defaultIfEmpty(contract.name, String.valueOf(Math.abs((contract.hashCode())))) + ".yml"; - } - - protected byte[] getBytes(YamlContract yamlContract) { - try { - return this.mapper.writeValueAsString(yamlContract).getBytes(); - } - catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/YamlToContracts.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/YamlToContracts.java deleted file mode 100644 index 65e1ce3c33..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/YamlToContracts.java +++ /dev/null @@ -1,872 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.converter; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.dataformat.yaml.YAMLMapper; -import org.apache.commons.collections.MapUtils; -import org.yaml.snakeyaml.Yaml; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.internal.DslProperty; -import org.springframework.cloud.contract.spec.internal.ExecutionProperty; -import org.springframework.cloud.contract.spec.internal.Header; -import org.springframework.cloud.contract.spec.internal.Headers; -import org.springframework.cloud.contract.spec.internal.Input; -import org.springframework.cloud.contract.spec.internal.MatchingTypeValue; -import org.springframework.cloud.contract.spec.internal.NamedProperty; -import org.springframework.cloud.contract.spec.internal.OutputMessage; -import org.springframework.cloud.contract.spec.internal.RegexPatterns; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.spec.internal.Response; -import org.springframework.cloud.contract.spec.internal.Url; -import org.springframework.cloud.contract.verifier.util.ContentType; -import org.springframework.cloud.contract.verifier.util.NamesUtil; -import org.springframework.util.StringUtils; - -import static java.util.stream.Collectors.toSet; -import static org.springframework.cloud.contract.verifier.util.ContentType.XML; -import static org.springframework.cloud.contract.verifier.util.ContentUtils.evaluateClientSideContentType; - -/** - * @author Marcin Grzejszczak - * @author Olga Maciaszek-Sharma - * @author Tim Ysewyn - * @author Stessy Delcroix - */ -class YamlToContracts { - - Collection convertFrom(File contractFile) { - ClassLoader classLoader = YamlContractConverter.class.getClassLoader(); - YAMLMapper mapper = new YAMLMapper(); - try { - Iterable iterables = new Yaml().loadAll(Files.newInputStream(contractFile.toPath())); - Collection contracts = new ArrayList<>(); - int counter = 0; - for (Object document : iterables) { - List processedYaml = processYaml(counter, document, mapper, classLoader, contractFile); - contracts.addAll(processedYaml); - counter = counter + 1; - } - return contracts; - } - catch (FileNotFoundException e) { - throw new IllegalStateException(e); - } - catch (IllegalStateException ise) { - throw ise; - } - catch (Exception e1) { - throw new IllegalStateException("Exception occurred while processing the file [" + contractFile + "]", e1); - } - finally { - Thread.currentThread().setContextClassLoader(classLoader); - } - } - - protected List processYaml(int counter, Object document, ObjectMapper mapper, ClassLoader classLoader, - File contractFile) { - List yamlContracts = convert(mapper, document); - Thread.currentThread().setContextClassLoader(updatedClassLoader(contractFile.getParentFile(), classLoader)); - List contracts = new ArrayList<>(); - for (YamlContract yamlContract : yamlContracts) { - Contract contract = Contract.make((dslContract) -> { - mapDescription(yamlContract, dslContract); - mapLabel(yamlContract, dslContract); - mapName(counter, contractFile, yamlContracts, yamlContract, dslContract); - mapPriority(yamlContract, dslContract); - mapIgnored(yamlContract, dslContract); - mapInProgress(yamlContract, dslContract); - mapMetadata(yamlContract, dslContract); - mapRequest(yamlContract, dslContract); - mapResponse(yamlContract, dslContract); - mapInput(yamlContract, dslContract); - mapOutput(yamlContract, dslContract); - }); - contracts.add(contract); - } - return contracts; - } - - private void mapMetadata(YamlContract yamlContract, Contract dslContract) { - if (yamlContract.metadata != null) { - dslContract.metadata(yamlContract.metadata); - } - } - - private void mapInProgress(YamlContract yamlContract, Contract dslContract) { - if (yamlContract.inProgress) { - dslContract.inProgress(); - } - } - - private void mapIgnored(YamlContract yamlContract, Contract dslContract) { - if (yamlContract.ignored) { - dslContract.ignored(); - } - } - - private void mapPriority(YamlContract yamlContract, Contract dslContract) { - if (yamlContract.priority != null) { - dslContract.priority(yamlContract.priority); - } - } - - private void mapName(int counter, File contractFile, List yamlContracts, YamlContract yamlContract, - Contract dslContract) { - dslContract.name(StringUtils.hasText(yamlContract.name) ? yamlContract.name - : NamesUtil.defaultContractName(contractFile, yamlContracts, counter)); - } - - private void mapLabel(YamlContract yamlContract, Contract dslContract) { - if (yamlContract.label != null) { - dslContract.label(yamlContract.label); - } - } - - private void mapDescription(YamlContract yamlContract, Contract dslContract) { - if (yamlContract.description != null) { - dslContract.description(yamlContract.description); - } - } - - private void mapRequest(YamlContract yamlContract, Contract dslContract) { - YamlContract.Request yamlContractRequest = yamlContract.request; - if (yamlContractRequest != null) { - dslContract.request((dslContractRequest) -> { - mapRequestMethod(yamlContractRequest, dslContractRequest); - mapRequestUrl(yamlContract, dslContractRequest); - mapRequestUrlPath(yamlContract, dslContractRequest); - mapRequestHeaders(yamlContractRequest, dslContractRequest); - mapRequestCookies(yamlContractRequest, dslContractRequest); - mapRequestBody(yamlContractRequest, dslContractRequest); - mapRequestMultiPart(yamlContractRequest, dslContractRequest); - mapRequestBodyMatchers(yamlContractRequest, dslContractRequest); - }); - } - } - - private void mapRequestMethod(YamlContract.Request yamlContractRequest, Request dslContractRequest) { - if (yamlContractRequest.method != null) { - dslContractRequest.method(yamlContractRequest.method); - } - } - - private void mapRequestUrl(YamlContract yamlContract, Request dslContractRequest) { - String yamlContractRequestUrl = yamlContract.request.url; - if (yamlContractRequestUrl != null) { - YamlContract.KeyValueMatcher yamlContractRequestMatchersUrl = Optional - .ofNullable(yamlContract.request.matchers).map(matchers -> matchers.url).orElse(null); - dslContractRequest.url(urlValue(yamlContractRequestUrl, yamlContractRequestMatchersUrl), - url -> handleQueryParameters(yamlContract, url)); - } - } - - private void mapRequestUrlPath(YamlContract yamlContract, Request dslContractRequest) { - String yamlContractRequestUrlPath = yamlContract.request.urlPath; - if (yamlContractRequestUrlPath != null) { - YamlContract.KeyValueMatcher yamlContractRequestMatchersUrl = Optional - .ofNullable(yamlContract.request.matchers).map(matchers -> matchers.url).orElse(null); - dslContractRequest.urlPath(urlValue(yamlContractRequestUrlPath, yamlContractRequestMatchersUrl), - urlPath -> handleQueryParameters(yamlContract, urlPath)); - } - } - - private void handleQueryParameters(YamlContract yamlContract, Url url) { - if (yamlContract.request.queryParameters != null) { - url.queryParameters((queryParameters -> yamlContract.request.queryParameters.forEach((key, value) -> { - if (value instanceof List) { - ((List) value) - .forEach(v -> queryParameters.parameter(key, queryParamValue(yamlContract, key, v))); - } - else { - queryParameters.parameter(key, queryParamValue(yamlContract, key, value)); - } - }))); - } - } - - private void mapRequestHeaders(YamlContract.Request yamlContractRequest, Request dslContractRequest) { - Map yamlContractRequestHeaders = yamlContractRequest.headers; - if (MapUtils.isNotEmpty(yamlContractRequestHeaders)) { - dslContractRequest.headers((headers) -> yamlContractRequestHeaders.forEach((key, value) -> { - List matchers = yamlContractRequest.matchers.headers.stream() - .filter((header) -> header.key.equals(key)).collect(Collectors.toList()); - matchers.forEach(matcher -> { - if (value instanceof List) { - ((List) value) - .forEach(v -> headers.header(key, clientValue(v, matcher, key).getClientValue())); - } - else { - headers.header(key, new DslProperty<>(clientValue(value, matcher, key).getClientValue(), - serverValue(value, matcher))); - } - }); - if (matchers.isEmpty()) { - headers.header(key, value); - } - })); - } - } - - private void mapRequestCookies(YamlContract.Request yamlContractRequest, Request dslContractRequest) { - Map yamlContractRequestCookies = yamlContractRequest.cookies; - if (MapUtils.isNotEmpty(yamlContractRequestCookies)) { - dslContractRequest.cookies((cookies) -> yamlContractRequestCookies.forEach((key, value) -> { - YamlContract.KeyValueMatcher matcher = yamlContractRequest.matchers.cookies.stream() - .filter(cookie -> cookie.key.equals(key)).findFirst().orElse(null); - cookies.cookie(key, clientValue(value, matcher, key)); - })); - } - } - - private void mapRequestBody(YamlContract.Request yamlContractRequest, Request dslContractRequest) { - if (yamlContractRequest.body != null) { - dslContractRequest.body(yamlContractRequest.body); - } - if (yamlContractRequest.bodyFromFile != null) { - dslContractRequest.body(file(yamlContractRequest.bodyFromFile)); - } - if (yamlContractRequest.bodyFromFileAsBytes != null) { - dslContractRequest.body(dslContractRequest.fileAsBytes(yamlContractRequest.bodyFromFileAsBytes)); - } - } - - private void mapRequestMultiPart(YamlContract.Request yamlContractRequest, Request dslContractRequest) { - if (yamlContractRequest.multipart != null) { - Map multipartMap = new HashMap<>(); - yamlContractRequest.multipart.params.forEach((paramKey, paramValue) -> { - YamlContract.KeyValueMatcher matcher = yamlContractRequest.matchers.multipart.params.stream() - .filter((param) -> param.key.equals(paramKey)).findFirst().orElse(null); - Object value = paramValue; - if (matcher != null) { - value = matcher.regex != null ? Pattern.compile(matcher.regex) - : predefinedToPattern(matcher.predefined); - } - multipartMap.put(paramKey, new DslProperty<>(value, paramValue)); - }); - yamlContractRequest.multipart.named.forEach(namedParam -> { - YamlContract.MultipartNamedStubMatcher matcher = yamlContractRequest.matchers.multipart.named.stream() - .filter((stubMatcher) -> stubMatcher.paramName.equals(namedParam.paramName)).findFirst() - .orElse(null); - Object fileNameValue = namedParam.fileName; - Object fileContentValue = namedParam.fileContent; - String fileContentAsBytes = namedParam.fileContentAsBytes; - String fileContentFromFileAsBytes = namedParam.fileContentFromFileAsBytes; - String contentTypeCommand = namedParam.contentTypeCommand; - String fileContentCommand = namedParam.fileContentCommand; - String fileNameCommand = namedParam.fileNameCommand; - Object contentTypeValue = namedParam.contentType; - if (matcher != null && matcher.fileName != null) { - fileNameValue = matcher.fileName.regex != null ? Pattern.compile(matcher.fileName.regex) - : predefinedToPattern(matcher.fileName.predefined); - } - if (matcher != null && matcher.fileContent != null) { - fileContentValue = matcher.fileContent.regex != null ? Pattern.compile(matcher.fileContent.regex) - : predefinedToPattern(matcher.fileContent.predefined); - } - if (matcher != null && matcher.contentType != null) { - contentTypeValue = matcher.contentType.regex != null ? Pattern.compile(matcher.contentType.regex) - : predefinedToPattern(matcher.contentType.predefined); - } - multipartMap.put(namedParam.paramName, new NamedProperty( - new DslProperty<>(fileNameValue, - fileNameCommand != null ? new ExecutionProperty(fileNameCommand) : namedParam.fileName), - new DslProperty<>(fileContentValue, - namedParam.fileContent != null ? namedParam.fileContent - : fileContentFromFileAsBytes != null - ? dslContractRequest.fileAsBytes(namedParam.fileContentFromFileAsBytes) - : fileContentAsBytes != null ? fileContentAsBytes.getBytes() - : new ExecutionProperty(fileContentCommand)), - new DslProperty<>(contentTypeValue, contentTypeCommand != null - ? new ExecutionProperty(contentTypeCommand) : namedParam.contentType))); - }); - dslContractRequest.multipart(multipartMap); - } - - } - - private void mapRequestBodyMatchers(YamlContract.Request yamlContractRequest, Request dslContractRequest) { - dslContractRequest.bodyMatchers((bodyMatchers) -> Optional.ofNullable(yamlContractRequest.matchers) - .map(stubMatchers -> stubMatchers.body).ifPresent(stubMatchers -> stubMatchers.forEach(stubMatcher -> { - ContentType contentType = evaluateClientSideContentType( - yamlHeadersToContractHeaders( - Optional.ofNullable(yamlContractRequest.headers).orElse(new HashMap<>())), - Optional.ofNullable(yamlContractRequest.body).orElse(null)); - MatchingTypeValue value = null; - switch (stubMatcher.type) { - case by_date: - value = bodyMatchers.byDate(); - break; - case by_time: - value = bodyMatchers.byTime(); - break; - case by_timestamp: - value = bodyMatchers.byTimestamp(); - break; - case by_regex: - String regex = stubMatcher.value; - if (stubMatcher.predefined != null) { - regex = predefinedToPattern(stubMatcher.predefined).pattern(); - } - value = bodyMatchers.byRegex(regex); - break; - case by_equality: - value = bodyMatchers.byEquality(); - break; - case by_type: - value = bodyMatchers.byType(matchingTypeValueHolder -> { - if (stubMatcher.minOccurrence != null) { - matchingTypeValueHolder.minOccurrence(stubMatcher.minOccurrence); - } - if (stubMatcher.maxOccurrence != null) { - matchingTypeValueHolder.maxOccurrence(stubMatcher.maxOccurrence); - } - }); - break; - case by_null: - // do nothing - break; - default: - throw new UnsupportedOperationException("The type [" + stubMatcher.type + "] is" - + " unsupported.Hint:If you 're using remember to pass "); - } - if (value != null) { - if (XML == contentType) { - bodyMatchers.xPath(stubMatcher.path, value); - } - else { - bodyMatchers.jsonPath(stubMatcher.path, value); - } - } - }))); - } - - private void mapResponse(YamlContract yamlContract, Contract dslContract) { - YamlContract.Response yamlContractResponse = yamlContract.response; - if (yamlContractResponse != null) { - dslContract.response(dslContractResponse -> { - mapResponseStatus(yamlContractResponse, dslContractResponse); - mapResponseHeaders(yamlContractResponse, dslContractResponse); - mapResponseCookies(yamlContractResponse, dslContractResponse); - mapResponseBody(yamlContractResponse, dslContractResponse); - mapResponseAsync(yamlContractResponse, dslContractResponse); - mapResponseFixedDelayMilliseconds(yamlContractResponse, dslContractResponse); - mapResponseBodyMatchers(yamlContractResponse, dslContractResponse); - }); - } - - } - - private void mapResponseStatus(YamlContract.Response yamlContractResponse, Response dslContractResponse) { - dslContractResponse.status(yamlContractResponse.status); - } - - private void mapResponseHeaders(YamlContract.Response yamlContractResponse, Response dslContractResponse) { - dslContractResponse.headers(headers -> Optional.ofNullable(yamlContractResponse.headers) - .ifPresent(yamlContractResponseHeaders -> yamlContractResponseHeaders.forEach((key, value) -> { - YamlContract.TestHeaderMatcher matcher = yamlContractResponse.matchers.headers.stream() - .filter(h -> h.key.equals(key)).findFirst().orElse(null); - - if (value instanceof List) { - ((List) value).forEach(v -> { - Object serverValue = serverValue(v, matcher, key); - headers.header(key, new DslProperty<>(v, serverValue)); - }); - } - else { - Object serverValue = serverValue(value, matcher, key); - headers.header(key, new DslProperty<>(value, serverValue)); - } - }))); - } - - private void mapResponseCookies(YamlContract.Response yamlContractResponse, Response dslContractResponse) { - if (yamlContractResponse.cookies != null) { - dslContractResponse.cookies(cookies -> yamlContractResponse.cookies.forEach((key, value) -> { - YamlContract.TestCookieMatcher matcher = yamlContractResponse.matchers.cookies.stream() - .filter(testCookieMatcher -> testCookieMatcher.key.equals(key)).findFirst().orElse(null); - DslProperty cookieValue = serverCookieValue(value, matcher, key); - cookies.cookie(key, cookieValue); - })); - } - } - - private void mapResponseBody(YamlContract.Response yamlContractResponse, Response dslContractResponse) { - if (yamlContractResponse.body != null) { - YamlContract.BodyTestMatcher bodyTestMatcher = Optional.ofNullable(yamlContractResponse.matchers) - .map(testMatchers -> testMatchers.body) - .flatMap( - bodyTestMatchers -> bodyTestMatchers.stream() - .filter(m -> m.path == null && (m.type == YamlContract.TestMatcherType.by_regex - || m.type == YamlContract.TestMatcherType.by_command)) - .findFirst()) - .orElse(null); - if (bodyTestMatcher != null) { - dslContractResponse.body(new DslProperty<>(yamlContractResponse.body, - bodyTestMatcher.type == YamlContract.TestMatcherType.by_regex - ? Pattern.compile(bodyTestMatcher.value) - : new ExecutionProperty(bodyTestMatcher.value))); - } - else { - dslContractResponse.body(yamlContractResponse.body); - } - } - if (yamlContractResponse.bodyFromFile != null) { - dslContractResponse.body(file(yamlContractResponse.bodyFromFile)); - } - if (yamlContractResponse.bodyFromFileAsBytes != null) { - dslContractResponse.body(dslContractResponse.fileAsBytes(yamlContractResponse.bodyFromFileAsBytes)); - } - } - - private void mapResponseAsync(YamlContract.Response yamlContractResponse, Response dslContractResponse) { - if (yamlContractResponse.async != null && yamlContractResponse.async) { - dslContractResponse.async(); - } - } - - private void mapResponseFixedDelayMilliseconds(YamlContract.Response yamlContractResponse, - Response dslContractResponse) { - if (yamlContractResponse.fixedDelayMilliseconds != null) { - dslContractResponse.async(); - dslContractResponse.fixedDelayMilliseconds(yamlContractResponse.fixedDelayMilliseconds); - } - } - - private void mapResponseBodyMatchers(YamlContract.Response yamlContractResponse, Response dslContractResponse) { - dslContractResponse.bodyMatchers(bodyMatchers -> Optional.ofNullable(yamlContractResponse.matchers) - .map(yamlContractResponseTestMatchers -> yamlContractResponseTestMatchers.body) - .ifPresent(yamlContractBodyTestMatchers -> yamlContractBodyTestMatchers - .forEach(yamlContractBodyTestMatcher -> { - ContentType contentType = evaluateClientSideContentType( - yamlHeadersToContractHeaders(yamlContractResponse.headers), - yamlContractResponse.body); - MatchingTypeValue value; - switch (yamlContractBodyTestMatcher.type) { - case by_date: - value = bodyMatchers.byDate(); - break; - case by_time: - value = bodyMatchers.byTime(); - break; - case by_timestamp: - value = bodyMatchers.byTimestamp(); - break; - case by_regex: - String regex = yamlContractBodyTestMatcher.value; - if (yamlContractBodyTestMatcher.predefined != null) { - regex = predefinedToPattern(yamlContractBodyTestMatcher.predefined).pattern(); - } - value = bodyMatchers.byRegex(regex); - break; - case by_equality: - value = bodyMatchers.byEquality(); - break; - case by_type: - value = bodyMatchers.byType(v -> { - if (yamlContractBodyTestMatcher.minOccurrence != null) { - v.minOccurrence(yamlContractBodyTestMatcher.minOccurrence); - } - if (yamlContractBodyTestMatcher.maxOccurrence != null) { - v.maxOccurrence(yamlContractBodyTestMatcher.maxOccurrence); - } - }); - break; - case by_command: - value = bodyMatchers.byCommand(yamlContractBodyTestMatcher.value); - break; - case by_null: - value = bodyMatchers.byNull(); - break; - default: - throw new UnsupportedOperationException("The type [" - + yamlContractBodyTestMatcher.type + "] is unsupported. " - + "Hint: If you're using remember to pass < type:by_regex > "); - } - if (yamlContractBodyTestMatcher.path != null) { - if (XML == contentType) { - bodyMatchers.xPath(yamlContractBodyTestMatcher.path, value); - } - else { - bodyMatchers.jsonPath(yamlContractBodyTestMatcher.path, value); - } - } - }))); - } - - private void mapOutput(YamlContract yamlContract, Contract dslContract) { - YamlContract.OutputMessage yamlContractOutputMessage = yamlContract.outputMessage; - if (yamlContract.outputMessage != null) { - dslContract.outputMessage((dslContractOutputMessage) -> { - mapOutputAssertThat(yamlContractOutputMessage, dslContractOutputMessage); - mapOutputSentTo(yamlContractOutputMessage, dslContractOutputMessage); - mapOutputMessageHeaders(yamlContractOutputMessage, dslContractOutputMessage); - mapOutputBody(yamlContractOutputMessage, dslContractOutputMessage); - mapOutputBodyMatchers(yamlContractOutputMessage, dslContractOutputMessage); - }); - } - } - - private void mapOutputBodyMatchers(YamlContract.OutputMessage yamlContractOutputMessage, - OutputMessage dslContractOutputMessage) { - if (yamlContractOutputMessage.matchers != null) { - dslContractOutputMessage.bodyMatchers( - dslContractOutputMessageBodyMatchers -> Optional.ofNullable(yamlContractOutputMessage.matchers.body) - .ifPresent(yamlContractBodyTestMatchers -> yamlContractBodyTestMatchers - .forEach(yamlContractBodyTestMatcher -> { - ContentType contentType = evaluateClientSideContentType( - yamlHeadersToContractHeaders(yamlContractOutputMessage.headers), - yamlContractOutputMessage.body); - MatchingTypeValue value; - switch (yamlContractBodyTestMatcher.type) { - case by_date: - value = dslContractOutputMessageBodyMatchers.byDate(); - break; - case by_time: - value = dslContractOutputMessageBodyMatchers.byTime(); - break; - case by_timestamp: - value = dslContractOutputMessageBodyMatchers.byTimestamp(); - break; - case by_regex: - String regex = yamlContractBodyTestMatcher.value; - if (yamlContractBodyTestMatcher.predefined != null) { - regex = predefinedToPattern(yamlContractBodyTestMatcher.predefined) - .pattern(); - } - value = dslContractOutputMessageBodyMatchers.byRegex(regex); - break; - case by_equality: - value = dslContractOutputMessageBodyMatchers.byEquality(); - break; - case by_type: - value = dslContractOutputMessageBodyMatchers.byType(v -> { - if (yamlContractBodyTestMatcher.minOccurrence != null) { - v.minOccurrence(yamlContractBodyTestMatcher.minOccurrence); - } - if (yamlContractBodyTestMatcher.maxOccurrence != null) { - v.maxOccurrence(yamlContractBodyTestMatcher.maxOccurrence); - } - }); - break; - case by_command: - value = dslContractOutputMessageBodyMatchers - .byCommand(yamlContractBodyTestMatcher.value); - break; - case by_null: - value = dslContractOutputMessageBodyMatchers.byNull(); - break; - default: - throw new UnsupportedOperationException("The type " + "[" - + yamlContractBodyTestMatcher.type - + "] is unsupported. Hint: If " - + "you're using remember to pass < type:by_regex > "); - } - if (XML == contentType) { - dslContractOutputMessageBodyMatchers.xPath(yamlContractBodyTestMatcher.path, - value); - } - else { - dslContractOutputMessageBodyMatchers - .jsonPath(yamlContractBodyTestMatcher.path, value); - } - }))); - } - } - - private void mapOutputMessageHeaders(YamlContract.OutputMessage yamlContractOutputMessage, - OutputMessage dslContractOutputMessage) { - dslContractOutputMessage.headers(dslContractOutputMessageHeaders -> Optional - .ofNullable(yamlContractOutputMessage).map(yamlContractOutput -> yamlContractOutput.headers).ifPresent( - yamlContractOutputMessageHeaders -> yamlContractOutputMessageHeaders.forEach((key, value) -> { - YamlContract.TestHeaderMatcher matcher = Optional - .ofNullable(yamlContractOutputMessage.matchers) - .map(yamlContractOutputMatchers -> yamlContractOutputMatchers.headers) - .flatMap(yamlContractOutputMatchersHeaders -> yamlContractOutputMatchersHeaders - .stream() - .filter(yamlContractOutputMatchersHeader -> yamlContractOutputMatchersHeader.key - .equals(key)) - .findFirst()) - .orElse(null); - Object serverValue = serverValue(value, matcher, key); - dslContractOutputMessageHeaders.header(key, new DslProperty<>(value, serverValue)); - }))); - } - - private void mapOutputBody(YamlContract.OutputMessage yamlContractOutputMessage, - OutputMessage dslContractOutputMessage) { - if (yamlContractOutputMessage.body != null) { - dslContractOutputMessage.body(yamlContractOutputMessage.body); - } - if (yamlContractOutputMessage.bodyFromFile != null) { - dslContractOutputMessage.body(file(yamlContractOutputMessage.bodyFromFile)); - } - if (yamlContractOutputMessage.bodyFromFileAsBytes != null) { - dslContractOutputMessage - .body(dslContractOutputMessage.fileAsBytes(yamlContractOutputMessage.bodyFromFileAsBytes)); - } - } - - private void mapOutputSentTo(YamlContract.OutputMessage yamlContractOutputMessage, - OutputMessage dslContractOutputMessage) { - if (yamlContractOutputMessage.sentTo != null) { - dslContractOutputMessage.sentTo(yamlContractOutputMessage.sentTo); - } - } - - private void mapOutputAssertThat(YamlContract.OutputMessage yamlContractOutputMessage, - OutputMessage dslContractOutputMessage) { - if (yamlContractOutputMessage.assertThat != null) { - dslContractOutputMessage.assertThat(yamlContractOutputMessage.assertThat); - } - } - - private void mapInput(YamlContract yamlContract, Contract dslContract) { - YamlContract.Input yamlContractInput = yamlContract.input; - if (yamlContractInput != null) { - dslContract.input(dslContractInput -> { - mapInputAssertThat(yamlContractInput, dslContractInput); - mapInputTriggeredBy(yamlContractInput, dslContractInput); - }); - } - - } - - private void mapInputAssertThat(YamlContract.Input yamlContractInput, Input dslContractInput) { - if (yamlContractInput.assertThat != null) { - dslContractInput.assertThat(yamlContractInput.assertThat); - } - } - - private void mapInputTriggeredBy(YamlContract.Input yamlContractInput, Input dslContractInput) { - if (yamlContractInput.triggeredBy != null) { - dslContractInput.triggeredBy(yamlContractInput.triggeredBy); - } - } - - private Headers yamlHeadersToContractHeaders(Map headers) { - Set
convertedHeaders = headers != null - ? headers.keySet().stream().map(header -> Header.build(header, headers.get(header))).collect(toSet()) - : new HashSet<>(); - Headers contractHeaders = new Headers(); - contractHeaders.headers(convertedHeaders); - return contractHeaders; - } - - protected DslProperty urlValue(String url, YamlContract.KeyValueMatcher urlMatcher) { - if (urlMatcher != null) { - if (urlMatcher.command != null) { - return new DslProperty(url, new ExecutionProperty(urlMatcher.command)); - } - return new DslProperty<>(urlMatcher.regex != null ? Pattern.compile(urlMatcher.regex) - : urlMatcher.predefined != null ? predefinedToPattern(urlMatcher.predefined) : url, url); - } - return new DslProperty<>(url); - } - - protected List convert(ObjectMapper mapper, Object o) { - try { - return Arrays.asList(mapper.convertValue(o, YamlContract[].class)); - } - catch (IllegalArgumentException e) { - return Collections.singletonList(mapper.convertValue(o, YamlContract.class)); - } - } - - protected Object serverValue(Object value, YamlContract.TestHeaderMatcher matcher, String key) { - Object serverValue = value; - if (matcher != null && matcher.regex != null) { - serverValue = Pattern.compile(matcher.regex); - Pattern pattern = (Pattern) serverValue; - assertPatternMatched(pattern, value, key); - } - else if (matcher != null && matcher.predefined != null) { - Pattern pattern = predefinedToPattern(matcher.predefined); - serverValue = pattern; - assertPatternMatched(pattern, value, key); - } - else if (matcher != null && matcher.command != null) { - serverValue = new ExecutionProperty(matcher.command); - } - return serverValue; - } - - protected DslProperty serverCookieValue(Object value, YamlContract.TestCookieMatcher matcher, String key) { - Object serverValue = value; - if (matcher != null && matcher.regex != null) { - serverValue = Pattern.compile(matcher.regex); - Pattern pattern = (Pattern) serverValue; - assertPatternMatched(pattern, value, key); - } - else if (matcher != null && matcher.predefined != null) { - Pattern pattern = predefinedToPattern(matcher.predefined); - serverValue = pattern; - assertPatternMatched(pattern, value, key); - } - else if (matcher != null && matcher.command != null) { - return new DslProperty<>(new ExecutionProperty(matcher.command), value); - } - return new DslProperty<>(value, serverValue); - } - - protected DslProperty clientValue(Object value, YamlContract.KeyValueMatcher matcher, String key) { - Object clientValue = value instanceof DslProperty ? ((DslProperty) value).getClientValue() : value; - if (matcher != null && matcher.regex != null) { - clientValue = Pattern.compile(matcher.regex); - Pattern pattern = (Pattern) clientValue; - assertPatternMatched(pattern, value, key); - } - else if (matcher != null && matcher.predefined != null) { - Pattern pattern = predefinedToPattern(matcher.predefined); - clientValue = pattern; - assertPatternMatched(pattern, value, key); - } - else if (matcher != null && matcher.command != null) { - return new DslProperty<>(value, new ExecutionProperty(matcher.command)); - } - return new DslProperty<>(clientValue, value); - } - - protected Object queryParamValue(YamlContract yamlContract, String key, Object value) { - Request request = new Request(); - YamlContract.QueryParameterMatcher matcher = yamlContract.request.matchers.queryParameters.stream() - .filter(queryParameter -> queryParameter.key.equals(key)).findFirst().orElse(null); - if (matcher == null) { - return value; - } - switch (matcher.type) { - case equal_to: - return new DslProperty<>(request.equalTo(matcher.value), value); - case containing: - return new DslProperty<>(request.containing(matcher.value), value); - case matching: - return new DslProperty<>(request.matching(matcher.value), value); - case not_matching: - return new DslProperty<>(request.notMatching(matcher.value), value); - case equal_to_json: - return new DslProperty<>(request.equalToJson(matcher.value), value); - case equal_to_xml: - return new DslProperty<>(request.equalToXml(matcher.value), value); - case absent: - return new DslProperty(request.absent(), null); - default: - throw new UnsupportedOperationException("The provided matching type [" + matcher - + "] is unsupported. Use on of " + Arrays.toString(YamlContract.MatchingType.values())); - } - } - - protected Object serverValue(Object value, YamlContract.KeyValueMatcher matcher) { - if (matcher != null && matcher.command != null) { - return new ExecutionProperty(matcher.command); - } - return value instanceof DslProperty ? ((DslProperty) value).getServerValue() : value; - } - - private void assertPatternMatched(Pattern pattern, Object value, String key) { - boolean matches = pattern.matcher(value.toString()).matches(); - if (!matches) { - throw new IllegalStateException("Broken headers! A header with " + "key [" + key + "] with value [" + value - + "] is not matched by regex [" + pattern.pattern() + "]"); - } - } - - protected Pattern predefinedToPattern(YamlContract.PredefinedRegex predefinedRegex) { - switch (predefinedRegex) { - case only_alpha_unicode: - return RegexPatterns.onlyAlphaUnicode().getPattern(); - case number: - return RegexPatterns.number().getPattern(); - case any_double: - return RegexPatterns.aDouble().getPattern(); - case any_boolean: - return RegexPatterns.anyBoolean().getPattern(); - case ip_address: - return RegexPatterns.ipAddress().getPattern(); - case hostname: - return RegexPatterns.hostname().getPattern(); - case email: - return RegexPatterns.email().getPattern(); - case url: - return RegexPatterns.url().getPattern(); - case uuid: - return RegexPatterns.uuid().getPattern(); - case iso_date: - return RegexPatterns.isoDate().getPattern(); - case iso_date_time: - return RegexPatterns.isoDateTime().getPattern(); - case iso_time: - return RegexPatterns.isoTime().getPattern(); - case iso_8601_with_offset: - return RegexPatterns.iso8601WithOffset().getPattern(); - case non_empty: - return RegexPatterns.nonEmpty().getPattern(); - case non_blank: - return RegexPatterns.nonBlank().getPattern(); - default: - throw new UnsupportedOperationException("The predefined regex [" + predefinedRegex - + "] is unsupported. Use one of " + Arrays.toString(YamlContract.PredefinedRegex.values())); - } - } - - protected String file(String relativePath) { - URL resource = Thread.currentThread().getContextClassLoader().getResource(relativePath); - if (resource == null) { - throw new IllegalStateException("File [" + relativePath + "] is not present"); - } - try { - return String.join("\n", Files.readAllLines(Paths.get(resource.toURI()))); - } - catch (URISyntaxException | IOException e) { - throw new IllegalStateException("File [" + relativePath + "] syntax is incorrect"); - } - } - - protected static ClassLoader updatedClassLoader(File rootFolder, ClassLoader classLoader) { - try { - ClassLoader urlCl = URLClassLoader.newInstance(new URL[] { rootFolder.toURI().toURL() }, classLoader); - Thread.currentThread().setContextClassLoader(urlCl); - return urlCl; - } - catch (MalformedURLException e) { - throw new IllegalStateException("Root folder [" + rootFolder + "] URL is incorrect"); - } - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/ContractVerifierMetadata.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/ContractVerifierMetadata.java deleted file mode 100644 index a94fd46bfd..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/ContractVerifierMetadata.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.dsl; - -import java.util.Map; - -import org.springframework.cloud.contract.verifier.util.MetadataUtil; -import org.springframework.cloud.contract.verifier.util.SpringCloudContractMetadata; -import org.springframework.lang.NonNull; - -/** - * Metadata representation of the Contract Verifier. - * - * @author Marcin Grzejszczak - * @since 3.0.0 - */ -public class ContractVerifierMetadata implements SpringCloudContractMetadata { - - /** - * Metadata entry in the contract. - */ - public static final String METADATA_KEY = "verifier"; - - public ContractVerifierMetadata(String tool) { - this.tool = tool; - } - - public ContractVerifierMetadata() { - } - - private String tool; - - public String getTool() { - return this.tool; - } - - public void setTool(String tool) { - this.tool = tool; - } - - @NonNull - public static ContractVerifierMetadata fromMetadata(Map metadata) { - return MetadataUtil.fromMetadata(metadata, METADATA_KEY, new ContractVerifierMetadata()); - } - - @Override - public String key() { - return METADATA_KEY; - } - - @Override - public String description() { - return "Metadata entries used by the framework"; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/BaseWireMockStubStrategy.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/BaseWireMockStubStrategy.java deleted file mode 100644 index cb2c551a66..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/BaseWireMockStubStrategy.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.dsl.wiremock; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.jayway.jsonpath.DocumentContext; -import com.jayway.jsonpath.JsonPath; -import groovy.lang.GString; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.ContractTemplate; -import org.springframework.cloud.contract.spec.internal.DslProperty; -import org.springframework.cloud.contract.spec.internal.FromFileProperty; -import org.springframework.cloud.contract.spec.internal.Headers; -import org.springframework.cloud.contract.verifier.template.HandlebarsTemplateProcessor; -import org.springframework.cloud.contract.verifier.template.TemplateProcessor; -import org.springframework.cloud.contract.verifier.util.ContentType; -import org.springframework.cloud.contract.verifier.util.ContentUtils; -import org.springframework.cloud.contract.verifier.util.MapConverter; - -import static org.springframework.cloud.contract.verifier.util.ContentType.UNKNOWN; -import static org.springframework.cloud.contract.verifier.util.ContentUtils.extractValue; -import static org.springframework.cloud.contract.verifier.util.ContentUtils.getClientContentType; -import static org.springframework.cloud.contract.verifier.util.MapConverter.transformValues; - -/** - * Common abstraction over WireMock Request / Response conversion implementations. - * - * @since 1.0.0 - */ -abstract class BaseWireMockStubStrategy { - - private static final String WRAPPER = "UNQUOTE_ME"; - - protected final TemplateProcessor processor; - - protected final ContractTemplate template; - - protected final Contract contract; - - protected BaseWireMockStubStrategy(Contract contract) { - this.processor = templateProcessor(); - this.template = contractTemplate(); - this.contract = contract; - } - - private TemplateProcessor templateProcessor() { - return new HandlebarsTemplateProcessor(); - } - - private ContractTemplate contractTemplate() { - return new HandlebarsTemplateProcessor(); - } - - /** - * @return the stub side values from the object - */ - protected Object getStubSideValue(Object object) { - return MapConverter.getStubSideValues(object); - } - - /** - * For the given {@link ContentType} returns the String version of the body. - */ - String parseBody(Object value, ContentType contentType) { - return parseBody(value.toString(), contentType); - } - - /** - * Return body as String from file. - */ - String parseBody(FromFileProperty value, ContentType contentType) { - return value.asString(); - } - - /** - * For the given {@link ContentType} returns the Boolean version of the body. - */ - Boolean parseBody(Boolean value, ContentType contentType) { - return value; - } - - /** - * For the given {@link ContentType} returns the Number version of the body. - */ - Number parseBody(Number value, ContentType contentType) { - return value; - } - - /** - * For the given {@link ContentType} returns the String version of the body. - */ - String parseBody(Map map, ContentType contentType) { - Object transformedMap = MapConverter.getStubSideValues(map); - transformedMap = transformMapIfRequestPresent(transformedMap); - String json = toJson(transformedMap); - // the space is important cause at the end of the json body you also have a } - // you can't have 4 } next to each other - String unquotedJson = json.replace('"' + WRAPPER, "").replace(WRAPPER + '"', " "); - String unescapedJson = unquotedJson.replace("\\/", "/"); - return parseBody(unescapedJson, contentType); - } - - private Object transformMapIfRequestPresent(Object transformedMap) { - Object requestBody = contract.getRequest().getBody(); - if (requestBody == null) { - return transformedMap; - } - String testSideBody = toJson(MapConverter.getTestSideValues(requestBody)); - DocumentContext context = JsonPath.parse(testSideBody); - return processEntriesForTemplating(transformedMap, context); - } - - private Object processEntriesForTemplating(Object transformedMap, DocumentContext context) { - return transformValues(transformedMap, (val) -> { - if (val instanceof String && processor.containsJsonPathTemplateEntry((String) val)) { - String jsonPath = processor.jsonPathFromTemplateEntry((String) val); - if (jsonPath == null) { - return val; - } - Object value = context.read(jsonPath); - if (value instanceof String) { - return val; - } - return WRAPPER + val + WRAPPER; - } - else if (val instanceof String && processor.containsTemplateEntry((String) val) - && template.escapedBody().equals(val)) { - return template.escapedBody(); - } - return val; - }); - } - - /** - * For the given {@link ContentType} returns the String version of the body. - */ - String parseBody(List list, ContentType contentType) { - final List result = new ArrayList<>(); - list.forEach(l -> { - if (l instanceof Map) { - result.add(MapConverter.getStubSideValues(l)); - } - else if (l instanceof List) { - result.add(parseBody((List) l, contentType)); - } - else if (l instanceof Boolean) { - result.add(parseBody((Boolean) l, contentType)); - } - else if (l instanceof Number) { - result.add(parseBody((Number) l, contentType)); - } - else if (l == null) { - result.add(null); - } - else { - result.add(parseBody(l, contentType)); - } - }); - return parseBody(toJson(result), contentType); - } - - /** - * For the given {@link ContentType} returns the String version of the body. - */ - String parseBody(GString value, ContentType contentType) { - Object processedValue = extractValue(value, contentType, - (o) -> o instanceof DslProperty ? ((DslProperty) o).getClientValue() : o); - if (processedValue instanceof GString) { - return parseBody(processedValue.toString(), contentType); - } - return parseBody(processedValue, contentType); - } - - /** - * For the given {@link ContentType} returns the String version of the body. - */ - String parseBody(String value, ContentType contentType) { - return value; - } - - private static String toJson(Object value) { - try { - if (value instanceof Map) { - Object convertedMap = MapConverter.transformValues(value, - (v) -> v instanceof GString ? ((GString) v).toString() : v); - String jsonOutput = new ObjectMapper().writeValueAsString(convertedMap); - return jsonOutput.replaceAll("\\\\\\\\\\\\", "\\\\"); - } - return new ObjectMapper().writeValueAsString(value); - } - catch (JsonProcessingException e) { - throw new IllegalArgumentException("The current object [" + value + "] could not be serialized"); - } - } - - /** - * Attempts to guess the {@link ContentType} from body and headers. Returns - * {@link ContentType#UNKNOWN} if it fails to guess. - */ - protected ContentType tryToGetContentType(Object body, Headers headers) { - ContentType contentType = ContentUtils.recognizeContentTypeFromHeader(headers); - if (UNKNOWN == contentType) { - if (body == null) { - return UNKNOWN; - } - return getClientContentType(body); - } - return contentType; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/DefaultResponseTransformer.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/DefaultResponseTransformer.java deleted file mode 100644 index aa2b81a6d6..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/DefaultResponseTransformer.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.dsl.wiremock; - -import java.util.HashMap; -import java.util.Map; - -import com.github.tomakehurst.wiremock.extension.responsetemplating.ResponseTemplateTransformer; -import wiremock.com.github.jknack.handlebars.Helper; - -import org.springframework.cloud.contract.verifier.builder.handlebars.HandlebarsEscapeHelper; -import org.springframework.cloud.contract.verifier.builder.handlebars.HandlebarsJsonPathHelper; - -/** - * . Default implementation of {@link ResponseTemplateTransformer} that contains default - * set of handlebars helpers - * - * @author Marcin Grzejszczak - * @since 1.2.0 - */ -public class DefaultResponseTransformer extends ResponseTemplateTransformer { - - public DefaultResponseTransformer() { - super(false, defaultHelpers()); - } - - public DefaultResponseTransformer(boolean global) { - super(global); - } - - public DefaultResponseTransformer(boolean global, String helperName, Helper helper) { - super(global, helperName, helper); - } - - public DefaultResponseTransformer(boolean global, Map> helpers) { - super(global, helpers); - } - - private static Map> defaultHelpers() { - Map> helpers = new HashMap<>(); - helpers.put(HandlebarsJsonPathHelper.NAME, new HandlebarsJsonPathHelper()); - helpers.put(HandlebarsEscapeHelper.NAME, new HandlebarsEscapeHelper()); - return helpers; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/SpringCloudContractRequestMatcher.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/SpringCloudContractRequestMatcher.java deleted file mode 100644 index 1242a2b927..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/SpringCloudContractRequestMatcher.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.dsl.wiremock; - -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.tomakehurst.wiremock.extension.Parameters; -import com.github.tomakehurst.wiremock.http.Request; -import com.github.tomakehurst.wiremock.matching.MatchResult; -import com.github.tomakehurst.wiremock.matching.RequestMatcherExtension; -import net.javacrumbs.jsonunit.assertj.JsonAssertions; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.assertj.core.api.Assertions; - -import org.springframework.cloud.contract.verifier.converter.YamlContract; -import org.springframework.cloud.contract.verifier.converter.YamlContractConverter; - -/** - * Provides custom matching for WireMock's stub requests. - * - * @author Marcin Grzejszczak - * @since 3.0.0 - */ -public class SpringCloudContractRequestMatcher extends RequestMatcherExtension { - - private static final List SUPPORTED_TOOLS = Arrays.asList(GraphQlMatcher.NAME); - - /** - * Name of the transformer inside the stub. - */ - public static final String NAME = "spring-cloud-contract"; - - private static final Log log = LogFactory.getLog(SpringCloudContractRequestMatcher.class); - - @Override - public MatchResult match(Request request, Parameters parameters) { - if (!parameters.containsKey("contract") || !parameters.containsKey("tool")) { - return MatchResult.noMatch(); - } - String tool = parameters.getString("tool"); - if (!SUPPORTED_TOOLS.contains(tool)) { - if (log.isWarnEnabled()) { - log.warn("The tool [" + tool + "] is not supported"); - } - return MatchResult.noMatch(); - } - String string = parameters.getString("contract"); - List contracts; - try { - contracts = YamlContractConverter.INSTANCE.read(string.getBytes()); - } - catch (Exception e) { - if (log.isWarnEnabled()) { - log.warn("An exception occurred while trying to parse the contract", e); - } - return MatchResult.noMatch(); - } - return new RequestMatcherFactory(matchers()).pick(tool).match(contracts, request, parameters); - } - - List matchers() { - return Arrays.asList(new GraphQlMatcher()); - } - - @Override - public String getName() { - return NAME; - } - -} - -class RequestMatcherFactory { - - private final List matchers; - - RequestMatcherFactory(List matchers) { - this.matchers = matchers; - } - - RequestMatcher pick(String tool) { - return this.matchers.stream().filter(m -> m.isApplicable(tool)).findFirst() - .orElse(new NotMatchingRequestMatcher()); - } - -} - -interface RequestMatcher { - - MatchResult match(List contracts, Request request, Parameters parameters); - - default boolean assertThat(Runnable runnable) { - try { - runnable.run(); - return true; - } - catch (Exception | AssertionError er) { - return false; - } - } - - default boolean isApplicable(String tool) { - return false; - } - -} - -class NotMatchingRequestMatcher implements RequestMatcher { - - @Override - public MatchResult match(List contracts, Request request, Parameters parameters) { - return MatchResult.noMatch(); - } - - @Override - public boolean isApplicable(String tool) { - return true; - } - -} - -class GraphQlMatcher implements RequestMatcher { - - static final String NAME = "graphql"; - - private static final Log log = LogFactory.getLog(GraphQlMatcher.class); - - private final ObjectMapper objectMapper = new ObjectMapper(); - - @Override - public MatchResult match(List contracts, Request request, Parameters parameters) { - YamlContract contract = contracts.get(0); - // TODO: What if the body is in files? - Map body = (Map) contract.request.body; - try { - Map jsonBodyFromContract = body; - Map jsonBodyFromRequest = this.objectMapper.readerForMapOf(Object.class).readValue(request.getBody()); - String query = (String) jsonBodyFromContract.get("query"); - String queryFromRequest = (String) jsonBodyFromRequest.get("query"); - Map variables = (Map) jsonBodyFromContract.get("variables"); - Map variablesFromRequest = (Map) jsonBodyFromRequest.get("variables"); - String operationName = (String) jsonBodyFromContract.get("operationName"); - String operationNameFromRequest = (String) jsonBodyFromRequest.get("operationName"); - boolean queryMatches = assertThat( - () -> Assertions.assertThat(query).isEqualToIgnoringWhitespace(queryFromRequest)); - boolean variablesMatch = assertThat( - () -> JsonAssertions.assertThatJson(variables).isEqualTo(variablesFromRequest)); - boolean operationMatches = StringUtils.equals(operationName, operationNameFromRequest); - return MatchResult.of(queryMatches && variablesMatch && operationMatches); - } - catch (Exception e) { - if (log.isWarnEnabled()) { - log.warn("An exception occurred while trying to parse the graphql entries", e); - } - return MatchResult.noMatch(); - } - } - - @Override - public boolean isApplicable(String tool) { - return NAME.equals(tool); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockExtensions.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockExtensions.java deleted file mode 100644 index d76c4e19bc..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockExtensions.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.dsl.wiremock; - -import java.util.List; - -import com.github.tomakehurst.wiremock.extension.Extension; - -/** - * Contract that describes a list of {@link Extension} extensions that should be applied - * to the response. - * - * @author Marcin Grzejszczak - * @since 1.2.0 - */ -public interface WireMockExtensions { - - List extensions(); - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockRequestStubStrategy.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockRequestStubStrategy.java deleted file mode 100644 index a8f3f9ea5a..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockRequestStubStrategy.java +++ /dev/null @@ -1,554 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.dsl.wiremock; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.tomakehurst.wiremock.client.WireMock; -import com.github.tomakehurst.wiremock.extension.Parameters; -import com.github.tomakehurst.wiremock.http.RequestMethod; -import com.github.tomakehurst.wiremock.matching.ContentPattern; -import com.github.tomakehurst.wiremock.matching.RequestPattern; -import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder; -import com.github.tomakehurst.wiremock.matching.StringValuePattern; -import com.github.tomakehurst.wiremock.matching.UrlPattern; -import groovy.lang.GString; -import org.apache.commons.text.StringEscapeUtils; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.internal.Body; -import org.springframework.cloud.contract.spec.internal.BodyMatcher; -import org.springframework.cloud.contract.spec.internal.BodyMatchers; -import org.springframework.cloud.contract.spec.internal.ClientDslProperty; -import org.springframework.cloud.contract.spec.internal.DslProperty; -import org.springframework.cloud.contract.spec.internal.FromFileProperty; -import org.springframework.cloud.contract.spec.internal.MatchingStrategy; -import org.springframework.cloud.contract.spec.internal.MatchingType; -import org.springframework.cloud.contract.spec.internal.NamedProperty; -import org.springframework.cloud.contract.spec.internal.OptionalProperty; -import org.springframework.cloud.contract.spec.internal.PathBodyMatcher; -import org.springframework.cloud.contract.spec.internal.QueryParameters; -import org.springframework.cloud.contract.spec.internal.RegexPatterns; -import org.springframework.cloud.contract.spec.internal.RegexProperty; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.spec.internal.Url; -import org.springframework.cloud.contract.verifier.converter.YamlContract; -import org.springframework.cloud.contract.verifier.converter.YamlContractConverter; -import org.springframework.cloud.contract.verifier.dsl.ContractVerifierMetadata; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.ContentType; -import org.springframework.cloud.contract.verifier.util.ContentUtils; -import org.springframework.cloud.contract.verifier.util.JsonPaths; -import org.springframework.cloud.contract.verifier.util.JsonToJsonPathsConverter; -import org.springframework.cloud.contract.verifier.util.MapConverter; -import org.springframework.cloud.contract.verifier.util.MethodBufferingJsonVerifiable; -import org.springframework.cloud.contract.verifier.util.xml.XmlToXPathsConverter; -import org.springframework.util.CollectionUtils; -import org.springframework.util.StringUtils; - -import static org.springframework.cloud.contract.spec.internal.MatchingStrategy.Type.BINARY_EQUAL_TO; -import static org.springframework.cloud.contract.spec.internal.MatchingType.EQUALITY; -import static org.springframework.cloud.contract.verifier.util.ContentType.FORM; -import static org.springframework.cloud.contract.verifier.util.ContentType.JSON; -import static org.springframework.cloud.contract.verifier.util.ContentUtils.getEqualsTypeFromContentType; -import static org.springframework.cloud.contract.verifier.util.RegexpBuilders.buildGStringRegexpForStubSide; -import static org.springframework.cloud.contract.verifier.util.RegexpBuilders.buildJSONRegexpMatch; -import static org.springframework.cloud.contract.verifier.util.xml.XmlToXPathsConverter.retrieveValue; - -/** - * Converts a {@link Request} into {@link RequestPattern}. - * - * @author Marcin Grzejszczak - * @author Tim Ysewyn - * @author Olga Maciaszek-Sharma - * @since 1.0.0 - */ -class WireMockRequestStubStrategy extends BaseWireMockStubStrategy { - - private final Request request; - - private final ContentType contentType; - - WireMockRequestStubStrategy(Contract groovyDsl, SingleContractMetadata singleContractMetadata) { - super(groovyDsl); - this.request = groovyDsl.getRequest(); - this.contentType = contentType(singleContractMetadata); - } - - protected ContentType contentType(SingleContractMetadata singleContractMetadata) { - return singleContractMetadata.getEvaluatedInputStubContentType(); - } - - RequestPattern buildClientRequestContent() { - if (request == null) { - return null; - } - RequestPatternBuilder requestPatternBuilder = appendMethodAndUrl(); - appendCookies(requestPatternBuilder); - appendHeaders(requestPatternBuilder); - appendQueryParameters(requestPatternBuilder); - appendBody(requestPatternBuilder); - appendMultipart(requestPatternBuilder); - return requestPatternBuilder.build(); - } - - private void appendBody(RequestPatternBuilder requestPatternBuilder) { - if (contract.getMetadata().containsKey(ContractVerifierMetadata.METADATA_KEY)) { - ContractVerifierMetadata metadata = ContractVerifierMetadata.fromMetadata(contract.getMetadata()); - appendSpringCloudContractMatcher(metadata, requestPatternBuilder); - if (!StringUtils.hasLength(metadata.getTool())) { - doAppendBody(requestPatternBuilder); - } - } - else { - doAppendBody(requestPatternBuilder); - } - } - - private void appendSpringCloudContractMatcher(ContractVerifierMetadata metadata, - RequestPatternBuilder requestPatternBuilder) { - Parameters parameters = Parameters.one("tool", metadata.getTool() != null ? metadata.getTool() : "unknown"); - YamlContractConverter converter = new YamlContractConverter(); - List contracts = converter.convertTo(Collections.singleton(contract)); - Map store = converter.store(contracts); - parameters.put("contract", new String(store.entrySet().iterator().next().getValue())); - requestPatternBuilder.andMatching(SpringCloudContractRequestMatcher.NAME, parameters); - } - - private RequestPatternBuilder appendMethodAndUrl() { - if (request.getMethod() == null) { - return null; - } - RequestMethod requestMethod = RequestMethod.fromString( - Optional.ofNullable(request.getMethod().getClientValue()).map(c -> c.toString()).orElse(null)); - UrlPattern urlPattern = urlPattern(); - return RequestPatternBuilder.newRequestPattern(requestMethod, urlPattern); - } - - private void doAppendBody(RequestPatternBuilder requestPattern) { - if (request.getBody() == null) { - return; - } - boolean bodyHasMatchingStrategy = request.getBody().getClientValue() instanceof MatchingStrategy; - MatchingStrategy matchingStrategy = getMatchingStrategyFromBody(request.getBody()); - if (contentType == ContentType.JSON) { - Object clientSideBody = MapConverter.transformToClientValues(request.getBody()); - Object originalBody = Optional.ofNullable(matchingStrategy).map(DslProperty::getClientValue).orElse(null); - if (bodyHasMatchingStrategy) { - requestPattern.withRequestBody(convertToValuePattern(matchingStrategy)); - } - else if (clientSideBody instanceof Pattern || clientSideBody instanceof RegexProperty) { - requestPattern.withRequestBody( - convertToValuePattern(appendBodyRegexpMatchPattern(request.getBody(), contentType))); - } - else { - Object body = JsonToJsonPathsConverter.removeMatchingJsonPaths(originalBody, request.getBodyMatchers()); - JsonPaths values = JsonToJsonPathsConverter - .transformToJsonPathWithStubsSideValuesAndNoArraySizeCheck(body); - if ((values.isEmpty() && request.getBodyMatchers() != null && !request.getBodyMatchers().hasMatchers()) - || onlySizeAssertionsArePresent(values)) { - try { - requestPattern.withRequestBody(WireMock.equalToJson( - new ObjectMapper().writeValueAsString( - getMatchingStrategy(request.getBody().getClientValue()).getClientValue()), - false, false)); - } - catch (JsonProcessingException e) { - throw new IllegalArgumentException("The MatchingStrategy could not be serialized", e); - } - } - else { - values.stream().filter(v -> !v.assertsSize()).forEach(it -> requestPattern - .withRequestBody(WireMock.matchingJsonPath(it.jsonPath().replace("\\\\", "\\")))); - } - } - Optional.ofNullable(request.getBodyMatchers()).map(BodyMatchers::matchers) - .ifPresent(bodyMatchers -> bodyMatchers.forEach(bodyMatcher -> { - String newPath = JsonToJsonPathsConverter.convertJsonPathAndRegexToAJsonPath(bodyMatcher, - originalBody); - requestPattern.withRequestBody(WireMock.matchingJsonPath(newPath.replace("\\\\", "\\"))); - })); - } - else if (contentType == ContentType.XML) { - Object originalBody = Optional.ofNullable(matchingStrategy).map(DslProperty::getClientValue).orElse(null); - if (bodyHasMatchingStrategy) { - requestPattern.withRequestBody(convertToValuePattern(matchingStrategy)); - } - else { - Object body = XmlToXPathsConverter.removeMatchingXPaths(originalBody, request.getBodyMatchers()); - List byEqualityMatchersFromXml = XmlToXPathsConverter.mapToMatchers(body); - byEqualityMatchersFromXml.forEach( - bodyMatcher -> addWireMockStubMatchingSection(bodyMatcher, requestPattern, originalBody)); - } - Optional.ofNullable(request.getBodyMatchers()).map(BodyMatchers::matchers) - .ifPresent(bodyMatchers -> bodyMatchers.forEach( - bodyMatcher -> addWireMockStubMatchingSection(bodyMatcher, requestPattern, originalBody))); - } - else if (containsPattern(request.getBody())) { - requestPattern.withRequestBody(convertToValuePattern(appendBodyRegexpMatchPattern(request.getBody()))); - } - else { - requestBodyGuessedFromMatchingStrategy(requestPattern); - } - } - - private Object generateConcreteValue(Object originalBody) { - if (originalBody instanceof Pattern || originalBody instanceof RegexProperty) { - return new RegexProperty(originalBody).generate(); - } - return originalBody; - } - - private RequestPatternBuilder requestBodyGuessedFromMatchingStrategy(RequestPatternBuilder requestPattern) { - return requestPattern - .withRequestBody(convertToValuePattern(getMatchingStrategy(request.getBody().getClientValue()))); - } - - private static void addWireMockStubMatchingSection(BodyMatcher matcher, RequestPatternBuilder requestPattern, - Object body) { - Set matchingTypesUnsupportedForRequest = new HashSet<>( - Arrays.asList(MatchingType.NULL, MatchingType.COMMAND, MatchingType.TYPE)); - if (!(matcher instanceof PathBodyMatcher)) { - throw new IllegalArgumentException("Only jsonPath and XPath matchers can be processed."); - } - String retrievedValue = Optional.ofNullable(matcher.value()).map(Object::toString).orElseGet(() -> { - if (matchingTypesUnsupportedForRequest.contains(matcher.matchingType())) { - throw new IllegalArgumentException("Null, Command and Type matchers are not supported in requests."); - } - if (EQUALITY == matcher.matchingType()) { - return retrieveValue(matcher, body); - } - else { - return ""; - } - }); - PathBodyMatcher pathMatcher = (PathBodyMatcher) matcher; - requestPattern.withRequestBody( - WireMock.matchingXPath(pathMatcher.path(), XPathBodyMatcherToWireMockValuePatternConverter - .mapToPattern(pathMatcher.matchingType(), String.valueOf(retrievedValue)))); - } - - private boolean onlySizeAssertionsArePresent(JsonPaths values) { - return !CollectionUtils.isEmpty(values) - && (request.getBodyMatchers() == null || !request.getBodyMatchers().hasMatchers()) - && this.every(values.iterator(), MethodBufferingJsonVerifiable::assertsSize); - } - - private boolean every(Iterator self, Function function) { - while (self.hasNext()) { - if (!function.apply(self.next())) { - return false; - } - } - return true; - } - - private void appendMultipart(RequestPatternBuilder requestPattern) { - if (request.getMultipart() == null) { - return; - } - if (request.getMultipart().getClientValue() instanceof Map) { - List multipartPattern = ((Map) request.getMultipart() - .getClientValue()) - .entrySet().stream().map( - it -> it.getValue() instanceof NamedProperty - ? WireMock.matching(RegexPatterns.multipartFile(it.getKey(), - ((NamedProperty) it.getValue()).getName().getClientValue(), - ((NamedProperty) it.getValue()).getValue().getClientValue(), - Optional.ofNullable( - ((NamedProperty) it.getValue()).getContentType()) - .map(DslProperty::getClientValue).orElse(null))) - : WireMock.matching(RegexPatterns.multipartParam(it.getKey(), - MapConverter.getStubSideValuesForNonBody(it.getValue())))) - .collect(Collectors.toList()); - multipartPattern.forEach(requestPattern::withRequestBody); - - } - - } - - private void appendHeaders(RequestPatternBuilder requestPattern) { - if (request.getHeaders() != null) { - request.getHeaders().getEntries().forEach(header -> requestPattern.withHeader(header.getName(), - (StringValuePattern) convertToValuePattern(header.getClientValue()))); - } - } - - private void appendCookies(RequestPatternBuilder requestPattern) { - if (request.getCookies() == null) { - return; - } - request.getCookies().getEntries().forEach(cookie -> requestPattern.withCookie(cookie.getKey(), - (StringValuePattern) convertToValuePattern(cookie.getClientValue()))); - } - - private UrlPattern urlPattern() { - Object urlPath = urlPathOrUrlIfQueryPresent(); - if (urlPath != null) { - if (urlPath instanceof Pattern || urlPath instanceof RegexProperty) { - return WireMock.urlPathMatching((String) getStubSideValue(new RegexProperty(urlPath).pattern())); - } - else { - return WireMock.urlPathEqualTo((String) getStubSideValue(urlPath.toString())); - } - } - if (request.getUrl() == null) { - throw new IllegalStateException("URL is required!"); - } - Object url = getUrlIfGstring(request.getUrl().getClientValue()); - if (url instanceof Pattern || url instanceof RegexProperty) { - return WireMock.urlMatching(new RegexProperty(url).pattern()); - } - return WireMock.urlEqualTo(url.toString()); - } - - private Object urlPathOrUrlIfQueryPresent() { - Object urlPath = Optional.ofNullable(request).map(Request::getUrlPath).map(DslProperty::getClientValue) - .orElse(null); - Object queryParamsFromUrl = Optional.ofNullable(request).map(Request::getUrl).map(Url::getQueryParameters) - .map(QueryParameters::getParameters).orElse(null); - if (urlPath != null) { - return urlPath; - } - if (queryParamsFromUrl != null) { - return Optional.ofNullable(request).map(Request::getUrl).map(Url::getClientValue).orElse(null); - } - return null; - } - - private Object getUrlIfGstring(Object clientSide) { - if (clientSide instanceof GString) { - if (Arrays.stream(((GString) clientSide).getValues()).anyMatch(it -> { - Object value = getStubSideValue(it); - return value instanceof Pattern || value instanceof RegexProperty; - })) { - String string = getStubSideValue(clientSide).toString(); - return new RegexProperty(Pattern.compile(string)); - } - else { - return getStubSideValue(clientSide).toString(); - } - } - return clientSide; - } - - private void appendQueryParameters(RequestPatternBuilder requestPattern) { - QueryParameters queryParameters = Optional.ofNullable(request).map(Request::getUrlPath) - .map(Url::getQueryParameters).orElseGet(() -> Optional.ofNullable(request).map(Request::getUrl) - .map(Url::getQueryParameters).orElse(null)); - - Optional.ofNullable(queryParameters).map(QueryParameters::getParameters).ifPresent( - parameters -> parameters.forEach(parameter -> requestPattern.withQueryParam(parameter.getName(), - (StringValuePattern) convertToValuePattern(parameter.getClientValue())))); - } - - protected ContentPattern convertToValuePattern(Object object) { - if (object instanceof ClientDslProperty) { - object = ((ClientDslProperty) object).getClientValue(); - } - - if (object instanceof Pattern || object instanceof RegexProperty) { - return WireMock.matching(new RegexProperty(object).pattern()); - } - else if (object instanceof OptionalProperty) { - return WireMock.matching(((OptionalProperty) object).optionalPattern()); - } - else if (object instanceof MatchingStrategy) { - MatchingStrategy value = (MatchingStrategy) object; - switch (value.getType()) { - case NOT_MATCHING: - return WireMock.notMatching(value.getClientValue().toString()); - case ABSENT: - return WireMock.absent(); - case EQUAL_TO: - return WireMock.equalTo(clientBody(value.getClientValue(), contentType).toString()); - case CONTAINS: - return WireMock.containing(clientBody(value.getClientValue(), contentType).toString()); - case MATCHING: - return WireMock.matching(clientBody(value.getClientValue(), contentType).toString()); - case EQUAL_TO_JSON: - return WireMock.equalToJson(clientBody(value.getClientValue(), contentType).toString()); - case EQUAL_TO_XML: - return WireMock.equalToXml(clientBody(value.getClientValue(), contentType).toString()); - case BINARY_EQUAL_TO: - return WireMock.binaryEqualTo((byte[]) clientBody(value.getClientValue(), contentType)); - default: - throw new UnsupportedOperationException("Unknown matching strategy " + value.getType()); - } - } - else { - return WireMock.equalTo(clientBody(object, contentType).toString()); - } - } - - protected Object clientBody(Object bodyValue, ContentType contentType) { - if (FORM == contentType) { - if (bodyValue instanceof Map) { - // [a:3, b:4] == "a=3&b=4" - return ((Map) bodyValue).entrySet().stream() - .map(e -> StringEscapeUtils.unescapeEcmaScript(e.getKey().toString() + "=" + e.getValue())) - .collect(Collectors.joining("&")); - } - else if (bodyValue instanceof List) { - // ["a=3", "b=4"] == "a=3&b=4" - return ((List) bodyValue).stream().map(it -> StringEscapeUtils.unescapeEcmaScript(it.toString())) - .collect(Collectors.joining("&")); - } - } - else if (bodyValue instanceof FromFileProperty) { - return ((FromFileProperty) bodyValue).isByte() ? ((FromFileProperty) bodyValue).asBytes() - : ((FromFileProperty) bodyValue).asString(); - } - else if (JSON == contentType) { - return parseBody(bodyValue, contentType); - } - return bodyValue; - } - - private MatchingStrategy getMatchingStrategyFromBody(Body body) { - if (body == null) { - return null; - } - return getMatchingStrategy(body.getClientValue()); - } - - private MatchingStrategy getMatchingStrategy(Object bodyValue) { - if (bodyValue instanceof GString) { - return this.getMatchingStrategy((GString) bodyValue); - } - else if (bodyValue instanceof MatchingStrategy) { - return this.getMatchingStrategy((MatchingStrategy) bodyValue); - } - else if (bodyValue instanceof FromFileProperty) { - return this.getMatchingStrategy((FromFileProperty) bodyValue); - } - else { - return tryToFindMachingStrategy(bodyValue); - } - } - - private MatchingStrategy getMatchingStrategy(FromFileProperty bodyValue) { - return new MatchingStrategy(bodyValue, BINARY_EQUAL_TO); - } - - private MatchingStrategy getMatchingStrategy(MatchingStrategy matchingStrategy) { - return getMatchingStrategyIncludingContentType(matchingStrategy); - } - - private MatchingStrategy getMatchingStrategy(GString gString) { - if (gString == null) { - return new MatchingStrategy("", MatchingStrategy.Type.EQUAL_TO); - } - Object extractedValue = ContentUtils.extractValue(gString, - it -> it instanceof DslProperty ? ((DslProperty) it).getClientValue() : getStringFromGString(it)); - - Object value = getStringFromGString(extractedValue); - return getMatchingStrategy(value); - } - - private Object getStringFromGString(Object object) { - return object instanceof GString ? object.toString() : object; - } - - private MatchingStrategy tryToFindMachingStrategy(Object bodyValue) { - return new MatchingStrategy(MapConverter.transformToClientValues(bodyValue), - getEqualsTypeFromContentType(contentType)); - } - - private MatchingStrategy getMatchingStrategyIncludingContentType(MatchingStrategy matchingStrategy) { - MatchingStrategy.Type type = matchingStrategy.getType(); - Object value = matchingStrategy.getClientValue(); - ContentType contentType = ContentUtils.recognizeContentTypeFromMatchingStrategy(type); - if (contentType == ContentType.UNKNOWN && type == MatchingStrategy.Type.EQUAL_TO) { - contentType = ContentUtils.recognizeContentTypeFromContent(value); - type = getEqualsTypeFromContentType(contentType); - } - MatchingStrategy newMatchingStrategy; - if (value instanceof Map) { - newMatchingStrategy = new MatchingStrategy(parseBody((Map) value, contentType), type); - } - else if (value instanceof List) { - newMatchingStrategy = new MatchingStrategy(parseBody((List) value, contentType), type); - } - else if (value instanceof GString) { - newMatchingStrategy = new MatchingStrategy(parseBody((GString) value, contentType), type); - } - else { - newMatchingStrategy = new MatchingStrategy(parseBody(value, contentType), type); - } - return newMatchingStrategy; - } - - private MatchingStrategy appendBodyRegexpMatchPattern(Object value, ContentType contentType) { - Object clientValue = MapConverter.transformToClientValues(value); - switch (contentType) { - case JSON: - return new MatchingStrategy(buildJSONRegexpMatch(clientValue), MatchingStrategy.Type.MATCHING); - case UNKNOWN: - return new MatchingStrategy(buildGStringRegexpForStubSide(clientValue), MatchingStrategy.Type.MATCHING); - default: - throw new IllegalStateException(contentType.name() + " pattern matching is not implemented yet"); - } - } - - private MatchingStrategy appendBodyRegexpMatchPattern(Object value) { - return appendBodyRegexpMatchPattern(value, ContentType.UNKNOWN); - } - - private boolean containsPattern(Object o) { - if (o instanceof GString) { - return containsPattern(((GString) o).getValues()); - } - else if (o instanceof Map) { - return containsPattern(((Map) o).entrySet()); - } - else if (o instanceof Collection) { - List result = (List) ((Collection) o).stream().map(this::containsPattern) - .collect(Collectors.toList()); - return result.stream().reduce(false, (a, b) -> a || b); - } - else if (o instanceof Object[]) { - return containsPattern(Arrays.asList((Object[]) o)); - } - else if (o instanceof Map.Entry) { - return containsPattern(((Map.Entry) o).getValue()); - } - else if (o instanceof RegexProperty) { - return true; - } - else if (o instanceof DslProperty) { - return containsPattern(((DslProperty) o).getClientValue()); - } - else { - return o instanceof Pattern; - } - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockResponseStubStrategy.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockResponseStubStrategy.java deleted file mode 100755 index 2d803f769b..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockResponseStubStrategy.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.dsl.wiremock; - -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - -import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.extension.Extension; -import com.github.tomakehurst.wiremock.http.HttpHeader; -import com.github.tomakehurst.wiremock.http.HttpHeaders; -import com.github.tomakehurst.wiremock.http.ResponseDefinition; -import groovy.lang.GString; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.internal.FromFileProperty; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.spec.internal.Response; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; -import org.springframework.cloud.contract.verifier.util.ContentType; -import org.springframework.cloud.contract.verifier.util.MapConverter; -import org.springframework.core.io.support.SpringFactoriesLoader; - -import static java.util.stream.Collectors.collectingAndThen; -import static java.util.stream.Collectors.toList; - -/** - * Converts a {@link Request} into {@link ResponseDefinition}. - * - * @author Marcin Grzejszczak - * @author Olga Maciaszek-Sharma - * @since 1.0.0 - */ -class WireMockResponseStubStrategy extends BaseWireMockStubStrategy { - - private final Response response; - - private final ContentType contentType; - - private final SingleContractMetadata contractMetadata; - - WireMockResponseStubStrategy(Contract groovyDsl, SingleContractMetadata singleContractMetadata) { - super(groovyDsl); - this.response = groovyDsl.getResponse(); - this.contentType = contentType(singleContractMetadata); - this.contractMetadata = singleContractMetadata; - } - - protected ContentType contentType(SingleContractMetadata singleContractMetadata) { - return singleContractMetadata.getEvaluatedOutputStubContentType(); - } - - ResponseDefinition buildClientResponseContent() { - if (response == null) { - return null; - } - ResponseDefinitionBuilder builder = new ResponseDefinitionBuilder() - .withStatus((Integer) MapConverter.getStubSideValues(response.getStatus())); - appendHeaders(builder); - appendBody(builder); - appendResponseDelayTime(builder); - builder.withTransformers(responseTransformerNames()); - return builder.build(); - } - - private String[] responseTransformerNames() { - List wireMockExtensions = SpringFactoriesLoader.loadFactories(WireMockExtensions.class, - null); - if (!wireMockExtensions.isEmpty()) { - return wireMockExtensions.stream().map(WireMockExtensions::extensions).flatMap(Collection::stream) - .map(Extension::getName).toArray(String[]::new); - } - return new String[] { new DefaultResponseTransformer().getName(), SpringCloudContractRequestMatcher.NAME }; - } - - private void appendHeaders(ResponseDefinitionBuilder builder) { - if (response.getHeaders() != null) { - HttpHeaders headers = response.getHeaders().getEntries().stream().map( - it -> new HttpHeader(it.getName(), MapConverter.getStubSideValues(it.getClientValue()).toString())) - .collect(collectingAndThen(toList(), HttpHeaders::new)); - builder.withHeaders(headers); - } - } - - private void appendBody(ResponseDefinitionBuilder builder) { - if (response.getBody() != null) { - Object body = MapConverter.getStubSideValues(response.getBody(), parsingClosureForContentType()); - if (body instanceof byte[]) { - builder.withBody((byte[]) body); - } - else if (body instanceof FromFileProperty && ((FromFileProperty) body).isByte()) { - builder.withBody(((FromFileProperty) body).asBytes()); - } - else if (body instanceof Map) { - builder.withBody(parseBody((Map) body, contentType)); - } - else if (body instanceof List) { - builder.withBody(parseBody((List) body, contentType)); - } - else if (body instanceof GString) { - builder.withBody(parseBody((GString) body, contentType)); - } - else { - builder.withBody(parseBody(body, contentType)); - } - } - } - - Function parsingClosureForContentType() { - return contractMetadata.getDefinedOutputStubContentType().contains("/stream") ? MapConverter.IDENTITY - : MapConverter.JSON_PARSING_FUNCTION; - } - - private void appendResponseDelayTime(ResponseDefinitionBuilder builder) { - // TODO: Add a missing test for this - if (response.getDelay() != null) { - builder.withFixedDelay((Integer) response.getDelay().getClientValue()); - } - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockStubMapping.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockStubMapping.java deleted file mode 100644 index 6caa63a9a4..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockStubMapping.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.dsl.wiremock; - -import com.github.tomakehurst.wiremock.stubbing.StubMapping; - -/** - * @author Marcin Grzejszczak - */ -public final class WireMockStubMapping { - - private WireMockStubMapping() { - throw new IllegalStateException("Can't instantiate a utility class"); - } - - public static StubMapping buildFrom(String mappingDefinition) { - return StubMapping.buildFrom(mappingDefinition); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockStubStrategy.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockStubStrategy.java deleted file mode 100644 index 075945412e..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockStubStrategy.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.dsl.wiremock; - -import com.github.tomakehurst.wiremock.http.ResponseDefinition; -import com.github.tomakehurst.wiremock.matching.RequestPattern; -import com.github.tomakehurst.wiremock.stubbing.StubMapping; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.verifier.file.ContractMetadata; -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata; - -/** - * Converts a {@link ContractMetadata} into a WireMock {@link StubMapping}. - * - * @since 1.0.0 - */ -public class WireMockStubStrategy { - - private static final String STEP_START = "Started"; - - private static final String STEP_PREFIX = "Step"; - - private final WireMockRequestStubStrategy wireMockRequestStubStrategy; - - private final WireMockResponseStubStrategy wireMockResponseStubStrategy; - - private final Integer priority; - - private final ContractMetadata contract; - - private final String rootName; - - private final Contract groovyDsl; - - public WireMockStubStrategy(String rootName, ContractMetadata contract, Contract groovyDsl) { - this.rootName = rootName; - this.contract = contract; - SingleContractMetadata singleContractMetadata = contract.forContract(groovyDsl); - this.wireMockRequestStubStrategy = new WireMockRequestStubStrategy(groovyDsl, singleContractMetadata); - this.wireMockResponseStubStrategy = new WireMockResponseStubStrategy(groovyDsl, singleContractMetadata); - this.priority = groovyDsl.getPriority(); - this.groovyDsl = groovyDsl; - } - - /** - * Converts {@link ContractMetadata} to {@link StubMapping}. - */ - public StubMapping toWireMockClientStub() { - StubMapping stubMapping = new StubMapping(); - RequestPattern request = wireMockRequestStubStrategy.buildClientRequestContent(); - ResponseDefinition response = wireMockResponseStubStrategy.buildClientResponseContent(); - if (priority != null) { - stubMapping.setPriority(priority); - } - stubMapping.setRequest(request); - stubMapping.setResponse(response); - if (request == null || response == null) { - return null; - } - if (groovyDsl.getIgnored() || contract.getIgnored()) { - return null; - } - if (contract.getOrder() != null) { - stubMapping.setScenarioName("Scenario_" + rootName); - stubMapping.setRequiredScenarioState( - contract.getOrder() == 0 ? STEP_START : STEP_PREFIX + contract.getOrder()); - if (contract.getOrder() < contract.getGroupSize() - 1) { - stubMapping.setNewScenarioState(STEP_PREFIX + (contract.getOrder() + 1)); - } - } - return stubMapping; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/XPathBodyMatcherToWireMockValuePatternConverter.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/XPathBodyMatcherToWireMockValuePatternConverter.java deleted file mode 100644 index 1d164c236c..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/dsl/wiremock/XPathBodyMatcherToWireMockValuePatternConverter.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.dsl.wiremock; - -import com.github.tomakehurst.wiremock.client.WireMock; -import com.github.tomakehurst.wiremock.matching.StringValuePattern; - -import org.springframework.cloud.contract.spec.internal.MatchingType; - -/** - * @author Olga Maciaszek-Sharma - * @since 2.1.0 - */ -final class XPathBodyMatcherToWireMockValuePatternConverter { - - private XPathBodyMatcherToWireMockValuePatternConverter() { - throw new IllegalStateException("Can't instantiate an utility class"); - } - - public static StringValuePattern mapToPattern(MatchingType type, String value) { - if (type == MatchingType.EQUALITY) { - return WireMock.equalTo(value); - } - return WireMock.matching(value); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/file/ContractFileScanner.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/file/ContractFileScanner.java deleted file mode 100644 index d73a377b95..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/file/ContractFileScanner.java +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.file; - -import java.io.File; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.nio.file.Path; -import java.nio.file.PathMatcher; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Set; -import java.util.regex.Pattern; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.ContractConverter; -import org.springframework.cloud.contract.verifier.converter.YamlContractConverter; -import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter; -import org.springframework.core.io.support.SpringFactoriesLoader; -import org.springframework.util.CollectionUtils; -import org.springframework.util.MultiValueMap; -import org.springframework.util.StringUtils; - -/** - * Scans the provided file path for the DSLs. There's a possibility to provide inclusion - * and exclusion filters. - * - * @author Jakub Kubrynski, codearte.io - * @author Stessy Delcroix - * @since 1.0.0 - */ -public class ContractFileScanner { - - private static final Logger LOG = LoggerFactory.getLogger(ContractFileScanner.class); - - private static final String OS_NAME = System.getProperty("os.name"); - - private static final String OS_NAME_WINDOWS_PREFIX = "Windows"; - - protected static final boolean IS_OS_WINDOWS = getOSMatchesName(OS_NAME_WINDOWS_PREFIX); - - private static final String MATCH_PREFIX = "glob:"; - - private static final Pattern SCENARIO_STEP_FILENAME_PATTERN = Pattern.compile("[0-9]+_.*"); - - private final File baseDir; - - private final Set excludeMatchers; - - private final Set ignoreMatchers; - - private final Set includeMatchers; - - private final String includeMatcher; - - public ContractFileScanner(File baseDir, Set excluded, Set ignored, Set included, - String includeMatcher) { - this.baseDir = baseDir; - this.excludeMatchers = processPatterns(excluded != null ? excluded : Collections.emptySet()); - this.ignoreMatchers = processPatterns(ignored != null ? ignored : Collections.emptySet()); - this.includeMatchers = processPatterns(included != null ? included : Collections.emptySet()); - this.includeMatcher = includeMatcher != null ? includeMatcher : ""; - } - - private Set processPatterns(Set patterns) { - FileSystem fileSystem = FileSystems.getDefault(); - Set pathMatchers = new HashSet<>(); - for (String pattern : patterns) { - String syntaxAndPattern = MATCH_PREFIX + "**" + File.separator + pattern; - // FIXME: This looks strange, need to be checked on windows - if (IS_OS_WINDOWS) { - syntaxAndPattern = syntaxAndPattern.replace("\\", "\\\\"); - } - pathMatchers.add(fileSystem.getPathMatcher(syntaxAndPattern)); - } - return pathMatchers; - } - - public MultiValueMap findContractsRecursively() { - MultiValueMap result = CollectionUtils.toMultiValueMap(new LinkedHashMap<>()); - appendRecursively(baseDir, result); - return result; - } - - /** - * We iterate over found contracts, filter out those that should be excluded and try - * to convert via pluggable Contract Converters any possible contracts. - */ - private void appendRecursively(File baseDir, MultiValueMap result) { - List converters = convertersWithYml(); - if (LOG.isTraceEnabled()) { - LOG.trace("Found the following contract converters " + converters); - } - File[] files = baseDir.listFiles(); - if (files == null) { - return; - } - Arrays.sort(files); - for (int i = 0; i < files.length; i++) { - File file = files[i]; - boolean excluded = matchesPattern(file, excludeMatchers); - if (!excluded) { - boolean contractFile = isContractFile(file); - boolean included = !StringUtils.hasText(includeMatcher) - || file.getAbsolutePath().matches(includeMatcher); - included = !CollectionUtils.isEmpty(includeMatchers) ? matchesPattern(file, includeMatchers) : included; - if (contractFile && included) { - addContractToTestGeneration(result, files, file, i, - ContractVerifierDslConverter.convertAsCollection(baseDir, file)); - } - if (!contractFile && included) { - addContractToTestGeneration(converters, result, files, file, i); - } - else { - appendRecursively(file, result); - if (LOG.isDebugEnabled()) { - LOG.debug("File [" + file + "] is ignored. Is a contract file? [" + contractFile - + "]. Should be included by pattern? [" + included + "]"); - } - } - } - else { - if (LOG.isDebugEnabled()) { - LOG.debug("File [" + file + "] is ignored. Should be excluded? [" + excluded + "]"); - } - } - } - } - - protected List convertersWithYml() { - List converters = converters(); - converters.add(ContractVerifierDslConverter.INSTANCE); - converters.add(YamlContractConverter.INSTANCE); - return converters; - } - - protected List converters() { - return SpringFactoriesLoader.loadFactories(ContractConverter.class, null); - } - - private void addContractToTestGeneration(List converters, - MultiValueMap result, File[] files, File file, int index) { - boolean converted = false; - if (!file.isDirectory()) { - for (ContractConverter converter : converters) { - Collection contracts = tryConvert(converter, file); - if (contracts != null) { - addContractToTestGeneration(result, files, file, index, contracts); - converted = true; - break; - } - } - } - if (!converted) { - appendRecursively(file, result); - if (LOG.isDebugEnabled()) { - LOG.debug( - "File [" + file + "] wasn't ignored but no converter was applicable. The file is a directory [" - + file.isDirectory() + "]"); - } - } - } - - private Collection tryConvert(ContractConverter converter, File file) { - boolean accepted = converter.isAccepted(file); - if (!accepted) { - return null; - } - try { - return converter.convertFrom(file); - } - catch (Exception e) { - throw new IllegalStateException("Failed to convert file [" + file + "]", e); - } - } - - private void addContractToTestGeneration(MultiValueMap result, File[] files, File file, - int index, Collection convertedContract) { - Path path = file.toPath(); - Integer order = null; - if (hasScenarioFilenamePattern(path)) { - order = index; - } - Path parent = file.getParentFile().toPath(); - ContractMetadata metadata = new ContractMetadata(path, matchesPattern(file, ignoreMatchers), files.length, - order, convertedContract); - if (LOG.isDebugEnabled()) { - LOG.debug("Creating a contract entry for path [" + path + "] and metadata [" + metadata + "]"); - } - result.add(parent, metadata); - } - - private boolean hasScenarioFilenamePattern(Path path) { - return SCENARIO_STEP_FILENAME_PATTERN.matcher(path.getFileName().toString()).matches(); - } - - private boolean matchesPattern(File file, Set matchers) { - for (PathMatcher matcher : matchers) { - if (matcher.matches(file.toPath())) { - return true; - } - } - return false; - } - - private boolean isContractFile(File file) { - return file.isFile() && ContractVerifierDslConverter.INSTANCE.isAccepted(file); - } - - /** - * Decides if the operating system matches. - * @param osNamePrefix the prefix for the os name - * @return true if matches, or false if not or can't determine - */ - private static boolean getOSMatchesName(final String osNamePrefix) { - return isOSNameMatch(OS_NAME, osNamePrefix); - } - - /** - * Decides if the operating system matches. - *

- * This method is package private instead of private to support unit test invocation. - *

- * @param osName the actual OS name - * @param osNamePrefix the prefix for the expected OS name - * @return true if matches, or false if not or can't determine - */ - private static boolean isOSNameMatch(final String osName, final String osNamePrefix) { - if (osName == null) { - return false; - } - return osName.startsWith(osNamePrefix); - } - - public static Builder builder() { - return new Builder(); - } - - public static class Builder { - - private File baseDir; - - private Set excluded; - - private Set ignored; - - private Set included = Collections.emptySet(); - - private String includeMatcher = ""; - - public Builder baseDir(File baseDir) { - this.baseDir = baseDir; - return this; - } - - public Builder excluded(Set excluded) { - this.excluded = excluded; - return this; - } - - public Builder ignored(Set ignored) { - this.ignored = ignored; - return this; - } - - public Builder included(Set included) { - this.included = included; - return this; - } - - public Builder includeMatcher(String includeMatcher) { - this.includeMatcher = includeMatcher; - return this; - } - - public ContractFileScanner build() { - return new ContractFileScanner(this.baseDir, this.excluded, this.ignored, this.included, - this.includeMatcher); - } - - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/file/ContractMetadata.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/file/ContractMetadata.java deleted file mode 100644 index 81df9e6040..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/file/ContractMetadata.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.file; - -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Objects; - -import org.springframework.cloud.contract.spec.Contract; - -import static java.util.Collections.singletonList; -import static java.util.stream.Collectors.toList; - -/** - * Contains metadata for a particular file with a DSL. - * - * @author Jakub Kubrynski, codearte.io - * @since 1.0.0 - */ -public class ContractMetadata { - - /** - * Path to the file. - */ - private final Path path; - - /** - * Should the contract be ignored. - */ - private final boolean ignored; - - /** - * How many files are there in the folder. - */ - private final int groupSize; - - /** - * If scenario related will contain an order of execution. - */ - private final Integer order; - - /** - * The list of contracts for the given file. - */ - private final List convertedContract = new ArrayList<>(); - - /** - * Converted contracts with meta data information. - */ - private final Collection convertedContractWithMetadata = new ArrayList<>(); - - public ContractMetadata(Path path, boolean ignored, int groupSize, Integer order, Contract convertedContract) { - this(path, ignored, groupSize, order, singletonList(convertedContract)); - } - - public ContractMetadata(Path path, boolean ignored, int groupSize, Integer order, - Collection convertedContract) { - this.groupSize = groupSize; - this.path = path; - this.ignored = ignored; - this.order = order; - this.convertedContract.addAll(convertedContract); - this.convertedContractWithMetadata.addAll(this.convertedContract.stream().filter(Objects::nonNull) - .map(it -> new SingleContractMetadata(it, this)).collect(toList())); - } - - public SingleContractMetadata forContract(Contract contract) { - return this.convertedContractWithMetadata.stream().filter(it -> it.getContract().equals(contract)).findFirst() - .orElse(null); - } - - public boolean anyInProgress() { - return this.convertedContract.stream().anyMatch(Contract::getInProgress); - } - - public Path getPath() { - return path; - } - - public boolean getIgnored() { - return ignored; - } - - public boolean isIgnored() { - return ignored; - } - - public int getGroupSize() { - return groupSize; - } - - public Integer getOrder() { - return order; - } - - public List getConvertedContract() { - return convertedContract; - } - - public Collection getConvertedContractWithMetadata() { - return convertedContractWithMetadata; - } - - @Override - public String toString() { - return "ContractMetadata{" + "path=" + path + ", ignored=" + ignored + ", groupSize=" + groupSize + ", order=" - + order + '}'; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/file/SingleContractMetadata.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/file/SingleContractMetadata.java deleted file mode 100644 index 4845c17da6..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/file/SingleContractMetadata.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.file; - -import java.io.File; -import java.nio.file.Path; -import java.util.Collection; -import java.util.List; -import java.util.Optional; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.internal.DslProperty; -import org.springframework.cloud.contract.spec.internal.Header; -import org.springframework.cloud.contract.spec.internal.Headers; -import org.springframework.cloud.contract.spec.internal.OutputMessage; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.spec.internal.Response; -import org.springframework.cloud.contract.verifier.util.ContentType; -import org.springframework.util.Assert; - -import static org.springframework.cloud.contract.verifier.util.ContentType.DEFINED; -import static org.springframework.cloud.contract.verifier.util.ContentType.JSON; -import static org.springframework.cloud.contract.verifier.util.ContentType.UNKNOWN; -import static org.springframework.cloud.contract.verifier.util.ContentType.XML; -import static org.springframework.cloud.contract.verifier.util.ContentUtils.evaluateClientSideContentType; -import static org.springframework.cloud.contract.verifier.util.ContentUtils.evaluateServerSideContentType; -import static org.springframework.cloud.contract.verifier.util.NamesUtil.afterLast; -import static org.springframework.cloud.contract.verifier.util.NamesUtil.camelCase; -import static org.springframework.cloud.contract.verifier.util.NamesUtil.convertIllegalMethodNameChars; -import static org.springframework.cloud.contract.verifier.util.NamesUtil.convertIllegalPackageChars; -import static org.springframework.cloud.contract.verifier.util.NamesUtil.isEmpty; -import static org.springframework.cloud.contract.verifier.util.NamesUtil.toLastDot; - -public class SingleContractMetadata { - - private static final Logger log = LoggerFactory.getLogger(SingleContractMetadata.class); - - private final ContractMetadata contractMetadata; - - private final Path stubsPath; - - private final Contract contract; - - private final List allContracts; - - private final String definedInputStubContentType; - - private final ContentType inputStubContentType; - - private final ContentType evaluatedInputStubContentType; - - private final String definedOutputStubContentType; - - private final ContentType outputStubContentType; - - private final ContentType evaluatedOutputStubContentType; - - private final String definedInputTestContentType; - - private final ContentType inputTestContentType; - - private final ContentType evaluatedInputTestContentType; - - private final String definedOutputTestContentType; - - private final ContentType outputTestContentType; - - private final ContentType evaluatedOutputTestContentType; - - private String methodName; - - private final boolean http; - - public SingleContractMetadata(Contract currentContract, ContractMetadata contractMetadata) { - Assert.notNull(currentContract, "Contract must not be null"); - this.allContracts = contractMetadata.getConvertedContract(); - this.contract = currentContract; - this.contractMetadata = contractMetadata; - Headers inputHeaders = inputHeaders(currentContract); - DslProperty inputBody = inputBody(currentContract); - Headers outputHeaders = outputHeaders(currentContract); - DslProperty outputBody = outputBody(currentContract); - Header inputContentType = contentTypeHeader(inputHeaders); - Header outputContentType = contentTypeHeader(outputHeaders); - this.definedInputTestContentType = Optional.ofNullable(inputContentType).map(DslProperty::getServerValue) - .map(Object::toString).orElse(""); - this.evaluatedInputTestContentType = tryToEvaluateTestContentType(inputHeaders, inputBody); - this.inputTestContentType = inputBody != null ? this.evaluatedInputTestContentType : UNKNOWN; - this.definedOutputTestContentType = Optional.ofNullable(outputContentType).map(DslProperty::getServerValue) - .map(Object::toString).orElse(""); - this.evaluatedOutputTestContentType = tryToEvaluateTestContentType(outputHeaders, outputBody); - this.outputTestContentType = outputBody != null ? this.evaluatedOutputTestContentType : UNKNOWN; - this.definedInputStubContentType = Optional.ofNullable(inputContentType).map(DslProperty::getClientValue) - .map(Object::toString).orElse(""); - this.evaluatedInputStubContentType = tryToEvaluateStubContentType(inputHeaders, inputBody); - this.inputStubContentType = inputBody != null ? this.evaluatedInputStubContentType : UNKNOWN; - this.definedOutputStubContentType = Optional.ofNullable(outputContentType).map(DslProperty::getClientValue) - .map(Object::toString).orElse(""); - this.evaluatedOutputStubContentType = tryToEvaluateStubContentType(outputHeaders, outputBody); - this.outputStubContentType = outputBody != null ? this.evaluatedOutputStubContentType : UNKNOWN; - this.http = currentContract.getRequest() != null; - this.stubsPath = contractMetadata.getPath(); - } - - private Header contentTypeHeader(Headers headers) { - return headers == null ? null : headers.getEntries().stream() - .filter(it -> "Content-Type".equalsIgnoreCase(it.getName())).findFirst().orElse(null); - } - - private ContentType tryToEvaluateStubContentType(Headers mainHeaders, DslProperty body) { - Object clientValue = Optional.ofNullable(body).map(DslProperty::getClientValue).orElse(null); - ContentType contentType = evaluateClientSideContentType(mainHeaders, clientValue); - if (contentType == DEFINED || contentType == UNKNOWN) { - // try to retrieve from the other side (e.g. stub side was a regex, but test - // side is concrete) - Object serverValue = Optional.ofNullable(body).map(DslProperty::getServerValue).orElse(null); - return evaluateServerSideContentType(mainHeaders, serverValue); - } - return contentType; - } - - private ContentType tryToEvaluateTestContentType(Headers mainHeaders, DslProperty body) { - Object serverValue = Optional.ofNullable(body).map(DslProperty::getServerValue).orElse(null); - ContentType contentType = evaluateClientSideContentType(mainHeaders, serverValue); - if (contentType == DEFINED || contentType == UNKNOWN) { - // try to retrieve from the other side (e.g. stub side was a regex, but test - // side is concrete) - Object clientValue = Optional.ofNullable(body).map(DslProperty::getClientValue).orElse(null); - return evaluateServerSideContentType(mainHeaders, clientValue); - } - return contentType; - } - - public boolean isJson() { - return this.inputTestContentType.equals(JSON) || this.outputTestContentType.equals(JSON) - || this.inputStubContentType.equals(JSON) || this.outputStubContentType.equals(JSON); - } - - public boolean evaluatesToJson() { - return isJson() || this.evaluatedInputTestContentType.equals(JSON) - || this.evaluatedOutputTestContentType.equals(JSON) || this.evaluatedInputStubContentType.equals(JSON) - || this.evaluatedOutputStubContentType.equals(JSON); - } - - public boolean isIgnored() { - return this.contract.getIgnored() || this.contractMetadata.getIgnored(); - } - - public boolean isXml() { - return this.inputTestContentType.equals(XML) || this.outputTestContentType.equals(XML) - || this.inputStubContentType.equals(XML) || this.outputStubContentType.equals(XML); - } - - public boolean isHttp() { - return this.http; - } - - public boolean isInProgress() { - return this.contract.isInProgress(); - } - - public boolean isMessaging() { - return !isHttp(); - } - - private DslProperty inputBody(Contract contract) { - return Optional.ofNullable(contract.getRequest()).map(Request::getBody).map(DslProperty.class::cast) - .orElse(null); - } - - private Headers inputHeaders(Contract contract) { - return Optional.ofNullable(contract.getRequest()).map(Request::getHeaders).orElse(null); - } - - private DslProperty outputBody(Contract contract) { - return Optional.ofNullable(contract.getResponse()).map(Response::getBody).map(DslProperty.class::cast) - .orElseGet(() -> Optional.ofNullable(contract.getOutputMessage()).map(OutputMessage::getBody) - .orElse(null)); - } - - private Headers outputHeaders(Contract contract) { - return Optional.ofNullable(contract.getResponse()).map(Response::getHeaders).orElseGet( - () -> Optional.ofNullable(contract.getOutputMessage()).map(OutputMessage::getHeaders).orElse(null)); - } - - public String methodName() { - if (this.methodName == null) { - this.methodName = calculateMethodName(); - } - return this.methodName; - } - - private String calculateMethodName() { - if (!isEmpty(contract.getName())) { - String name = camelCase(convertIllegalPackageChars(contract.getName())); - log.trace("Overriding the default test name with [{}]", name); - return name; - } - if (allContracts.size() > 1) { - int index = allContracts.indexOf(getContract()); - String name = String.format("%s_%d", camelCasedMethodFromFileName(stubsPath), index); - log.trace("Scenario found. The method name will be [{}]", name); - return name; - } - String name = camelCasedMethodFromFileName(stubsPath); - log.trace("The method name will be [{}]", name); - return name; - } - - private static String camelCasedMethodFromFileName(Path stubsPath) { - return camelCase(convertIllegalMethodNameChars(toLastDot(afterLast(stubsPath.toString(), File.separator)))); - } - - public ContractMetadata getContractMetadata() { - return contractMetadata; - } - - public Contract getContract() { - return contract; - } - - public Collection getAllContracts() { - return allContracts; - } - - public String getDefinedInputStubContentType() { - return definedInputStubContentType; - } - - public ContentType getInputStubContentType() { - return inputStubContentType; - } - - public ContentType getEvaluatedInputStubContentType() { - return evaluatedInputStubContentType; - } - - public String getDefinedOutputStubContentType() { - return definedOutputStubContentType; - } - - public ContentType getEvaluatedOutputStubContentType() { - return evaluatedOutputStubContentType; - } - - public String getDefinedInputTestContentType() { - return definedInputTestContentType; - } - - public ContentType getInputTestContentType() { - return inputTestContentType; - } - - public String getDefinedOutputTestContentType() { - return definedOutputTestContentType; - } - - public ContentType getOutputTestContentType() { - return outputTestContentType; - } - - public ContentType getEvaluatedOutputTestContentType() { - return evaluatedOutputTestContentType; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/Body.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/Body.java deleted file mode 100644 index f4c6a3fde1..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/Body.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.http; - -import java.nio.charset.Charset; - -/** - * Abstraction over an HTTP body. - * - * Warning! This API is experimental and can change in time. - * - * @author Marcin Grzejszczak - * @since 3.0.0 - */ -public class Body { - - final Object body; - - Body(Object body) { - this.body = body; - } - - /** - * @return body as byte array - */ - public byte[] asByteArray() { - if (body instanceof byte[]) { - return (byte[]) this.body; - } - return body.toString().getBytes(); - } - - /** - * @return body as string - */ - public String asString() { - return asString(Charset.defaultCharset()); - } - - /** - * @param charset to encode the body - * @return body as string - */ - public String asString(Charset charset) { - if (body instanceof String) { - return (String) body; - } - else if (body instanceof byte[]) { - return new String((byte[]) body, charset); - } - return body.toString(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/ContractVerifierHttpMetaData.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/ContractVerifierHttpMetaData.java deleted file mode 100644 index 1d245557a0..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/ContractVerifierHttpMetaData.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.http; - -import java.util.Arrays; -import java.util.Map; - -import org.springframework.cloud.contract.verifier.util.MetadataUtil; -import org.springframework.cloud.contract.verifier.util.SpringCloudContractMetadata; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; - -/** - * Metadata representation of the Contract Verifier's HTTP communication. - * - * Warning! This API is experimental and can change in time. - * - * @author Marcin Grzejszczak - * @since 3.0.0 - */ -public class ContractVerifierHttpMetaData implements SpringCloudContractMetadata { - - /** - * Metadata entry in the contract. - */ - public static final String METADATA_KEY = "verifierHttp"; - - /** - * Scheme used for HTTP communication. - */ - private Scheme scheme = Scheme.HTTP; - - /** - * Protocol used for HTTP communication. - */ - private Protocol protocol = Protocol.HTTP_1_1; - - @NonNull - public static ContractVerifierHttpMetaData fromMetadata(Map metadata) { - return MetadataUtil.fromMetadata(metadata, METADATA_KEY, new ContractVerifierHttpMetaData()); - } - - @Override - public String key() { - return METADATA_KEY; - } - - @Override - public String description() { - return "Metadata entries used by the framework"; - } - - public Scheme getScheme() { - return scheme; - } - - public void setScheme(Scheme scheme) { - this.scheme = scheme; - } - - public void setScheme(String scheme) { - this.scheme = Scheme.fromString(scheme); - } - - public Protocol getProtocol() { - return this.protocol; - } - - public void setProtocol(Protocol protocol) { - this.protocol = protocol; - } - - public void setProtocol(String protocol) { - this.protocol = Protocol.fromString(protocol); - } - - /** - * HTTP communication scheme. - */ - public enum Scheme { - - /** - * HTTP scheme. - */ - HTTP, - - /** - * HTTPS scheme. - */ - HTTPS; - - /** - * Builds an enum from string. - */ - @Nullable - public static Scheme fromString(String scheme) { - return Arrays.stream(values()).filter(p -> p.name().equalsIgnoreCase(scheme)).findFirst().orElse(null); - } - - } - - /** - * Taken from OKHttp's Protocol {@link okhttp3.Protocol}. - */ - public enum Protocol { - - /** - * An obsolete plaintext framing that does not use persistent sockets by default. - */ - HTTP_1_0("http/1.0"), - - /** - * A plaintext framing that includes persistent connections. - * - * This version of OkHttp implements [RFC 7230][rfc_7230], and tracks revisions to - * that spec. - * - * [rfc_7230]: https://tools.ietf.org/html/rfc7230 - */ - HTTP_1_1("http/1.1"), - - /** - * The IETF's binary-framed protocol that includes header compression, - * multiplexing multiple requests on the same socket, and server-push. HTTP/1.1 - * semantics are layered on HTTP/2. - * - * HTTP/2 requires deployments of HTTP/2 that use TLS 1.2 support - * [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256], present in Java 8+ and - * Android 5+. Servers that enforce this may send an exception message including - * the string `INADEQUATE_SECURITY`. - */ - HTTP_2("h2"), - - /** - * Cleartext HTTP/2 with no "upgrade" round trip. This option requires the client - * to have prior knowledge that the server supports cleartext HTTP/2. - * - * See also [Starting HTTP/2 with Prior Knowledge][rfc_7540_34]. - * - * [rfc_7540_34]: https://tools.ietf.org/html/rfc7540.section-3.4 - */ - H2_PRIOR_KNOWLEDGE("h2_prior_knowledge"), - - /** - * QUIC (Quick UDP Internet Connection) is a new multiplexed and secure transport - * atop UDP, designed from the ground up and optimized for HTTP/2 semantics. - * HTTP/1.1 semantics are layered on HTTP/2. - * - * QUIC is not natively supported by OkHttp, but provided to allow a theoretical - * interceptor that provides support. - */ - QUIC("quic"); - - private final String protocol; - - Protocol(String protocol) { - this.protocol = protocol; - } - - @Override - public String toString() { - return this.protocol; - } - - /** - * Builds an enum from string. - */ - @Nullable - public static Protocol fromString(String protocol) { - return Arrays.stream(values()).filter(p -> p.protocol.equalsIgnoreCase(protocol)).findFirst().orElse(null); - } - - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/HttpVerifier.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/HttpVerifier.java deleted file mode 100644 index 391f5bb8d5..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/HttpVerifier.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.http; - -/** - * Abstraction over sending and receiving of http messages. - * - * Warning! This API is experimental and can change in time. - * - * @author Marcin Grzejszczak - * @since 3.0.0 - */ -public interface HttpVerifier { - - /** - * Sends a request and blocks for the response. - * @param request - HTTP request - * @return HTTP response - */ - Response exchange(Request request); - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/OkHttpHttpVerifier.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/OkHttpHttpVerifier.java deleted file mode 100644 index bea1c0ca64..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/OkHttpHttpVerifier.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.http; - -import java.io.IOException; -import java.util.AbstractMap; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import okhttp3.Headers; -import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.Protocol; -import okhttp3.RequestBody; - -/** - * {@link HttpVerifier} implementation that uses {@link OkHttpClient}. Has an inbuilt - * support for GRPC. - * - * Warning! This API is experimental and can change in time. - * - * @author Marcin Grzejszczak - * @since 3.0.0 - */ -public class OkHttpHttpVerifier implements HttpVerifier { - - private final String hostAndPort; - - /** - * @param hostAndPort - don't pass the scheme, it will be resolved from - * {@link Request#scheme()}. E.g. pass {@code localhost:1234}. - */ - public OkHttpHttpVerifier(String hostAndPort) { - this.hostAndPort = hostAndPort; - } - - @Override - public Response exchange(Request request) { - String requestContentType = request.contentType(); - OkHttpClient client = new OkHttpClient.Builder().protocols(toProtocol(request.protocol().toString())).build(); - Map headers = stringTyped(request.headers()); - if (!request.cookies().isEmpty()) { - headers.put("Set-Cookie", request.cookies().entrySet().stream() - .map(e -> e.getKey() + "=" + e.getValue().toString()).collect(Collectors.joining(";"))); - } - okhttp3.Request req = new okhttp3.Request.Builder().url(url(request)) - .method(request.method().name(), requestBody(request, requestContentType)).headers(Headers.of(headers)) - .build(); - try (okhttp3.Response res = client.newCall(req).execute()) { - return response(res); - } - catch (IOException e) { - throw new IllegalStateException(e); - } - } - - private String url(Request request) { - String url = request.scheme().name().toLowerCase() + ":" + this.hostAndPort - + (request.path().startsWith("/") ? request.path() : "/" + request.path()); - if (!request.queryParams().isEmpty()) { - return url + "?" + request.queryParams().stream().map(e -> e.getKey() + "=" + e.getValue()) - .collect(Collectors.joining("&")); - } - return url; - } - - private List toProtocol(String string) { - try { - Protocol protocol = Protocol.get(string); - switch (protocol) { - case HTTP_1_0: - case HTTP_2: - case QUIC: - return Arrays.asList(protocol, Protocol.HTTP_1_1); - case HTTP_1_1: - return Collections.singletonList(Protocol.HTTP_1_1); - case H2_PRIOR_KNOWLEDGE: - return Collections.singletonList(Protocol.H2_PRIOR_KNOWLEDGE); - } - return Collections.emptyList(); - } - catch (IOException e) { - throw new IllegalStateException(e); - } - } - - private Response response(okhttp3.Response res) throws IOException { - byte[] responseBody = responseBody(res); - return Response.builder().body(responseBody).statusCode(res.code()).headers(withSingleHeader(res)).cookies( - res.headers().values("Set-Cookie").stream().flatMap(s -> Arrays.stream(s.split(";"))).map(s -> { - String[] singleCookie = s.split("="); - return new AbstractMap.SimpleEntry<>(singleCookie[0], - singleCookie.length > 1 ? singleCookie[1] : ""); - }).collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue, - (a, b) -> a, HashMap::new))) - .build(); - } - - private RequestBody requestBody(Request request, String requestContentType) { - if (request.body() == null) { - return null; - } - byte[] bodyArray = request.body().asByteArray(); - return RequestBody.create(MediaType.parse(requestContentType), bodyArray); - } - - private byte[] responseBody(okhttp3.Response res) throws IOException { - return res.body() != null ? res.body().bytes() : null; - } - - private Map withSingleHeader(okhttp3.Response res) { - return res.headers().toMultimap().entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0), (a, b) -> a, HashMap::new)); - } - - private Map stringTyped(Map headers) { - return headers.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().toString())); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/Request.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/Request.java deleted file mode 100644 index b193869e05..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/Request.java +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.http; - -import java.util.AbstractMap; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import org.springframework.cloud.contract.spec.internal.HttpMethods; - -/** - * Abstraction over a HTTP request. - * - * Warning! This API is experimental and can change in time. - * - * @author Marcin Grzejszczak - * @since 3.0.0 - */ -public class Request { - - private final ContractVerifierHttpMetaData.Protocol protocol; - - private final ContractVerifierHttpMetaData.Scheme scheme; - - private final HttpMethods.HttpMethod method; - - private final String path; - - private final List> queryParameters; - - private final Body body; - - private final Map headers; - - private final Map cookies; - - Request(ContractVerifierHttpMetaData.Protocol protocol, ContractVerifierHttpMetaData.Scheme scheme, - HttpMethods.HttpMethod method, String path, List> queryParameters, - Body body, Map headers, Map cookies) { - this.protocol = protocol; - this.scheme = scheme; - this.method = method; - this.path = path; - this.queryParameters = queryParameters == null ? new LinkedList<>() : queryParameters; - this.body = body; - this.headers = headers == null ? new HashMap<>() : headers; - this.cookies = cookies == null ? new HashMap<>() : cookies; - } - - /** - * @return content type from headers - */ - public String contentType() { - Object value = this.headers.entrySet().stream().filter(e -> e.getKey().toLowerCase().equals("content-type")) - .findFirst().orElse(new AbstractMap.SimpleEntry<>("", null)).getValue(); - if (value == null) { - return null; - } - return value.toString(); - } - - /** - * @return {@link ContractVerifierHttpMetaData.Protocol} - */ - public ContractVerifierHttpMetaData.Protocol protocol() { - return this.protocol; - } - - /** - * @return {@link ContractVerifierHttpMetaData.Scheme} - */ - public ContractVerifierHttpMetaData.Scheme scheme() { - return this.scheme; - } - - /** - * @return HTTP method - */ - public HttpMethods.HttpMethod method() { - return this.method; - } - - /** - * @return HTTP path - */ - public String path() { - return this.path; - } - - /** - * @return request body - */ - public Body body() { - return this.body; - } - - /** - * @return request headers - */ - public Map headers() { - return this.headers; - } - - /** - * @return request cookies - */ - public Map cookies() { - return this.cookies; - } - - /** - * @return query parameters - */ - public List> queryParams() { - return this.queryParameters; - } - - /** - * Factory method to pick the HTTP method. - * @return method builder - */ - public static Request.MethodBuilder given() { - return new Request.MethodBuilder(); - } - - /** - * @param request from which a builder will be built - * @return a builder with request data filled in - */ - public static Request.Builder from(Request request) { - return new MethodBuilder().method(request.method.getMethodName(), request.path).scheme(request.scheme) - .protocol(request.protocol).queryParams(request.queryParameters).headers(request.headers) - .cookies(request.cookies).body(request.body); - } - - /** - * Builder over HTTP methods. - */ - public static class MethodBuilder { - - /** - * Factory method for a generic HTTP method. - * @param method to call - * @param path to call - * @return builder - */ - public Request.Builder method(String method, String path) { - return new Request.Builder(HttpMethods.HttpMethod.valueOf(method.toUpperCase()), path); - } - - /** - * Factory method for DELETE HTTP method. - * @param path to call - * @return builder - */ - public Request.Builder delete(String path) { - return new Request.Builder(HttpMethods.HttpMethod.DELETE, path); - } - - /** - * Factory method for GET HTTP method. - * @param path to call - * @return builder - */ - public Request.Builder get(String path) { - return new Request.Builder(HttpMethods.HttpMethod.GET, path); - } - - /** - * Factory method for HEAD HTTP method. - * @param path to call - * @return builder - */ - public Request.Builder head(String path) { - return new Request.Builder(HttpMethods.HttpMethod.HEAD, path); - } - - /** - * Factory method for OPTIONS HTTP method. - * @param path to call - * @return builder - */ - public Request.Builder options(String path) { - return new Request.Builder(HttpMethods.HttpMethod.OPTIONS, path); - } - - /** - * Factory method for PATCH HTTP method. - * @param path to call - * @return builder - */ - public Request.Builder patch(String path) { - return new Request.Builder(HttpMethods.HttpMethod.PATCH, path); - } - - /** - * Factory method for POST HTTP method. - * @param path to call - * @return builder - */ - public Request.Builder post(String path) { - return new Request.Builder(HttpMethods.HttpMethod.POST, path); - } - - /** - * Factory method for PUT HTTP method. - * @param path to call - * @return builder - */ - public Request.Builder put(String path) { - return new Request.Builder(HttpMethods.HttpMethod.PUT, path); - } - - /** - * Factory method for TRACE HTTP method. - * @param path to call - * @return builder - */ - public Request.Builder trace(String path) { - return new Request.Builder(HttpMethods.HttpMethod.TRACE, path); - } - - } - - /** - * Builder for a {@link Request}. - */ - public static class Builder { - - HttpMethods.HttpMethod method; - - String path; - - List> queryParameters = new LinkedList<>(); - - ContractVerifierHttpMetaData.Protocol protocol = ContractVerifierHttpMetaData.Protocol.HTTP_1_1; - - ContractVerifierHttpMetaData.Scheme scheme = ContractVerifierHttpMetaData.Scheme.HTTP; - - Body body; - - Map headers = new HashMap<>(); - - Map cookies = new HashMap<>(); - - Builder(HttpMethods.HttpMethod method, String path) { - this.method = method; - this.path = path; - } - - /** - * @param method HTTP method - * @return builder - */ - public Request.Builder method(HttpMethods.HttpMethod method) { - this.method = method; - return this; - } - - /** - * @param path HTTP path - * @return builder - */ - public Request.Builder path(String path) { - this.path = path; - return this; - } - - /** - * @param scheme text representation of a scheme - * @return builder - */ - public Request.Builder scheme(String scheme) { - this.scheme = ContractVerifierHttpMetaData.Scheme.fromString(scheme); - return this; - } - - /** - * @param protocol text representation of a protocol - * @return builder - */ - public Request.Builder protocol(String protocol) { - this.protocol = ContractVerifierHttpMetaData.Protocol.fromString(protocol); - return this; - } - - /** - * @param scheme representation of a scheme - * @return builder - */ - public Request.Builder scheme(ContractVerifierHttpMetaData.Scheme scheme) { - this.scheme = scheme; - return this; - } - - /** - * @param protocol representation of a protocol - * @return builder - */ - public Request.Builder protocol(ContractVerifierHttpMetaData.Protocol protocol) { - this.protocol = protocol; - return this; - } - - /** - * @param body HTTP body - * @return builder - */ - public Request.Builder body(Object body) { - this.body = new Body(body); - return this; - } - - /** - * @param name - query parameter name - * @param value - query parameter value - * @return builder - */ - public Request.Builder queryParam(String name, String value) { - this.queryParameters.add(new AbstractMap.SimpleEntry<>(name, value)); - return this; - } - - /** - * @param queryParameters - list of query parameters - * @return builder - */ - public Request.Builder queryParams(List> queryParameters) { - this.queryParameters = queryParameters; - return this; - } - - /** - * @param headers HTTP headers - * @return builder - */ - public Request.Builder headers(Map headers) { - this.headers = headers; - return this; - } - - /** - * @param key HTTP header key - * @param value HTTP header value - * @return builder - */ - public Request.Builder header(String key, Object value) { - this.headers.put(key, value); - return this; - } - - /** - * @param key cookie key - * @param value cookie value - * @return builder - */ - public Request.Builder cookie(String key, Object value) { - this.cookies.put(key, value); - return this; - } - - /** - * @param cookies HTTP cookies - * @return builder - */ - public Request.Builder cookies(Map cookies) { - this.cookies = cookies; - return this; - } - - /** - * @return built {@link Request} - */ - public Request build() { - return new Request(this.protocol, this.scheme, this.method, this.path, this.queryParameters, this.body, - this.headers, this.cookies); - } - - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/Response.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/Response.java deleted file mode 100644 index 923ee853f7..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/Response.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.http; - -import java.util.HashMap; -import java.util.Map; - -/** - * Abstraction over a HTTP response. - * - * Warning! This API is experimental and can change in time. - * - * @author Marcin Grzejszczak - * @since 3.0.0 - */ -public class Response { - - private final int statusCode; - - private final Body body; - - private final Map headers; - - private final Map cookies; - - Response(int statusCode, Body body, Map headers, Map cookies) { - this.statusCode = statusCode; - this.body = body; - this.headers = headers; - this.cookies = cookies; - } - - /** - * @return numerical representation of a status code - */ - public int statusCode() { - return this.statusCode; - } - - /** - * @param key header key - * @return header value or null if not present - */ - public String header(String key) { - return this.headers.entrySet().stream().filter(e -> e.getKey().equalsIgnoreCase(key)).findFirst() - .map(e -> e.getValue().toString()).orElse(null); - } - - /** - * @param key cookie key - * @return header value or null if not present - */ - public String cookie(String key) { - return this.cookies.entrySet().stream().filter(e -> e.getKey().equalsIgnoreCase(key)).findFirst() - .map(e -> e.getValue().toString()).orElse(null); - } - - /** - * @return response body - */ - public Body getBody() { - return this.body; - } - - /** - * @return builder - */ - public static Response.Builder builder() { - return new Response.Builder(); - } - - /** - * @return headers - */ - public Map headers() { - return this.headers; - } - - /** - * @return cookies - */ - public Map cookies() { - return this.cookies; - } - - /** - * @param response template of a response - * @return builder filled with response data - */ - public static Builder from(Response response) { - return new Builder().headers(response.headers).statusCode(response.statusCode).cookies(response.cookies) - .body(response.body); - } - - /** - * Response builder. - */ - public static class Builder { - - int statusCode; - - Body body; - - Map headers = new HashMap<>(); - - Map cookies = new HashMap<>(); - - /** - * @param status as int - * @return builder - */ - public Response.Builder statusCode(int status) { - this.statusCode = status; - return this; - } - - /** - * @param body - response body - * @return builder - */ - public Response.Builder body(Object body) { - this.body = new Body(body); - return this; - } - - /** - * @param headers - response headers - * @return builder - */ - public Response.Builder headers(Map headers) { - this.headers = headers; - return this; - } - - /** - * @param key header key - * @param value header value - * @return builder - */ - public Response.Builder header(String key, Object value) { - this.headers.put(key, value); - return this; - } - - /** - * @param key cookie key - * @param value cookie value - * @return builder - */ - public Response.Builder cookie(String key, Object value) { - this.cookies.put(key, value); - return this; - } - - /** - * @param cookies - response cookies - * @return builder - */ - public Response.Builder cookies(Map cookies) { - this.cookies = cookies; - return this; - } - - /** - * @return response - */ - public Response build() { - return new Response(this.statusCode, this.body, this.headers, this.cookies); - } - - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/MessageVerifierReceiver.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/MessageVerifierReceiver.java deleted file mode 100644 index b6c8af02cd..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/MessageVerifierReceiver.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging; - -import java.util.concurrent.TimeUnit; - -import javax.annotation.Nullable; - -import org.springframework.cloud.contract.verifier.converter.YamlContract; - -/** - * Core interface that allows you to receive messages. - * - * Destination is relevant to the underlying implementation. Might be a channel, queue, - * topic etc. - * - * @param message type - * @author Marcin Grzejszczak - * @since 2.2.0 - */ -public interface MessageVerifierReceiver { - - /** - * Receives the message from the given destination. You can provide the timeout for - * receiving that message. - * @param destination destination from which the message will be received - * @param timeout timeout to wait for the message - * @param timeUnit param to define the unit of timeout - * @return received message - */ - default M receive(String destination, long timeout, TimeUnit timeUnit) { - return receive(destination, timeout, timeUnit, null); - } - - /** - * Receives the message from the given destination. A default timeout will be applied. - * @param destination destination from which the message will be received - * @return received message - */ - default M receive(String destination) { - return receive(destination, null); - } - - /** - * Receives the message from the given destination. You can provide the timeout for - * receiving that message. - * @param destination destination from which the message will be received - * @param timeout timeout to wait for the message - * @param timeUnit param to define the unit of timeout - * @param contract contract related to this method - * @return received message - */ - M receive(String destination, long timeout, TimeUnit timeUnit, @Nullable YamlContract contract); - - /** - * Receives the message from the given destination. A default timeout will be applied. - * @param destination destination from which the message will be received - * @param contract contract related to this method - * @return received message - */ - M receive(String destination, YamlContract contract); - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/MessageVerifierSender.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/MessageVerifierSender.java deleted file mode 100644 index b93dccf4c6..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/MessageVerifierSender.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging; - -import java.util.Map; - -import javax.annotation.Nullable; - -import org.springframework.cloud.contract.verifier.converter.YamlContract; - -/** - * Core interface that allows you to send messages. - * - * Destination is relevant to the underlying implementation. Might be a channel, queue, - * topic etc. - * - * @param message type - * @author Marcin Grzejszczak - * @since 2.2.0 - */ -public interface MessageVerifierSender { - - /** - * Sends the message to the given destination. - * @param message to send - * @param destination destination to which the message will be sent - */ - default void send(M message, String destination) { - send(message, destination, null); - } - - /** - * Sends the given payload with headers, to the given destination. - * @param payload type - * @param payload payload to send - * @param headers headers to send - * @param destination destination to which the message will be sent - */ - default void send(T payload, Map headers, String destination) { - send(payload, headers, destination, null); - } - - /** - * Sends the message to the given destination. - * @param message to send - * @param destination destination to which the message will be sent - * @param contract contract related to this method - */ - void send(M message, String destination, @Nullable YamlContract contract); - - /** - * Sends the given payload with headers, to the given destination. - * @param payload type - * @param payload payload to send - * @param headers headers to send - * @param destination destination to which the message will be sent - * @param contract contract related to this method - */ - void send(T payload, Map headers, String destination, @Nullable YamlContract contract); - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/amqp/AmqpMetadata.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/amqp/AmqpMetadata.java deleted file mode 100644 index 101b7a0142..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/amqp/AmqpMetadata.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.amqp; - -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import org.springframework.amqp.core.MessageProperties; -import org.springframework.cloud.contract.verifier.util.MetadataUtil; -import org.springframework.cloud.contract.verifier.util.SpringCloudContractMetadata; - -/** - * Represents metadata for AMQP based communication. - * - * @author Marcin Grzejszczak - * @since 3.0.0 - */ -public class AmqpMetadata implements SpringCloudContractMetadata { - - /** - * Key under which this metadata entry can be found in contract's metadata. - */ - public static final String METADATA_KEY = "amqp"; - - /** - * Metadata for the input message. - */ - private MessageAmqpMetadata input = new MessageAmqpMetadata(); - - /** - * Metadata for the output message. - */ - private MessageAmqpMetadata outputMessage = new MessageAmqpMetadata(); - - public MessageAmqpMetadata getInput() { - return this.input; - } - - public void setInput(MessageAmqpMetadata input) { - this.input = input; - } - - public MessageAmqpMetadata getOutputMessage() { - return this.outputMessage; - } - - public void setOutputMessage(MessageAmqpMetadata outputMessage) { - this.outputMessage = outputMessage; - } - - public static AmqpMetadata fromMetadata(Map metadata) { - return MetadataUtil.fromMetadata(metadata, AmqpMetadata.METADATA_KEY, new AmqpMetadata()); - } - - @Override - public String key() { - return METADATA_KEY; - } - - @Override - public String description() { - return "Metadata for AMQP based communication"; - } - - @Override - public List additionalClassesToLookAt() { - return Collections.singletonList(MessageProperties.class); - } - - /** - * AMQP message metadata. - */ - public static class MessageAmqpMetadata { - - /** - * Spring AMQP message properties. - */ - private MessageProperties messageProperties; - - /** - * Properties related to connecting to a real broker. - */ - private ConnectToBroker connectToBroker = new ConnectToBroker(); - - public MessageProperties getMessageProperties() { - return this.messageProperties; - } - - public void setMessageProperties(MessageProperties messageProperties) { - this.messageProperties = messageProperties; - } - - public ConnectToBroker getConnectToBroker() { - return this.connectToBroker; - } - - public void setConnectToBroker(ConnectToBroker connectToBroker) { - this.connectToBroker = connectToBroker; - } - - } - - /** - * Options related to connecting to the real broker. - */ - public static class ConnectToBroker { - - /** - * If set, will append any options to the existing ones that define connection to - * the broker. - */ - private String additionalOptions; - - /** - * If set, will declare a queue with given name and bind it to the provided - * exchange from the contract. - */ - private String declareQueueWithName; - - public String getAdditionalOptions() { - return this.additionalOptions; - } - - public void setAdditionalOptions(String additionalOptions) { - this.additionalOptions = additionalOptions; - } - - public String getDeclareQueueWithName() { - return declareQueueWithName; - } - - public void setDeclareQueueWithName(String declareQueueWithName) { - this.declareQueueWithName = declareQueueWithName; - } - - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/boot/AutoConfigureMessageVerifier.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/boot/AutoConfigureMessageVerifier.java deleted file mode 100644 index 6900501d4c..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/boot/AutoConfigureMessageVerifier.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.boot; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.boot.autoconfigure.ImportAutoConfiguration; - -/** - * @author Dave Syer - * - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@ImportAutoConfiguration -public @interface AutoConfigureMessageVerifier { - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/camel/CamelStubMessages.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/camel/CamelStubMessages.java deleted file mode 100644 index 5bfced70d7..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/camel/CamelStubMessages.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.camel; - -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import org.apache.camel.CamelContext; -import org.apache.camel.ConsumerTemplate; -import org.apache.camel.Exchange; -import org.apache.camel.Message; -import org.apache.camel.ProducerTemplate; -import org.apache.camel.support.DefaultExchange; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.cloud.contract.verifier.converter.YamlContract; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessageMetadata; -import org.springframework.util.StringUtils; - -/** - * @author Marcin Grzejszczak - */ -public class CamelStubMessages implements MessageVerifierSender, MessageVerifierReceiver { - - private static final Logger log = LoggerFactory.getLogger(CamelStubMessages.class); - - private final CamelContext context; - - private final ProducerTemplate producerTemplate; - - private final ConsumerTemplate consumerTemplate; - - private final ContractVerifierCamelMessageBuilder builder; - - public CamelStubMessages(CamelContext context, ProducerTemplate producerTemplate, - ConsumerTemplate consumerTemplate) { - this.context = context; - this.producerTemplate = producerTemplate; - this.consumerTemplate = consumerTemplate; - this.builder = new ContractVerifierCamelMessageBuilder(context); - } - - @Override - public void send(Message message, String destination, YamlContract contract) { - try { - Exchange exchange = new DefaultExchange(this.context); - exchange.setIn(message); - StandaloneMetadata standaloneMetadata = StandaloneMetadata - .fromMetadata(contract != null ? contract.metadata : null); - ContractVerifierMessageMetadata verifierMessageMetadata = ContractVerifierMessageMetadata - .fromMetadata(contract != null ? contract.metadata : null); - String finalDestination = finalDestination(destination, - additionalOptions(verifierMessageMetadata, standaloneMetadata), verifierMessageMetadata); - log.info("Will send a message to URI [" + finalDestination + "]"); - this.producerTemplate.send(finalDestination, exchange); - } - catch (Exception e) { - log.error("Exception occurred while trying to send a message [" + message + "] " - + "to a channel with name [" + destination + "]", e); - throw e; - } - } - - private String additionalOptions(ContractVerifierMessageMetadata verifierMessageMetadata, - StandaloneMetadata metadata) { - return verifierMessageMetadata.getMessageType() == ContractVerifierMessageMetadata.MessageType.INPUT - ? metadata.getInput().getAdditionalOptions() : metadata.getOutputMessage().getAdditionalOptions(); - } - - public String finalDestination(String destination, String additionalOpts, - ContractVerifierMessageMetadata verifierMessageMetadata) { - String finalDestination = destination; - if (verifierMessageMetadata.getMessageType() == ContractVerifierMessageMetadata.MessageType.SETUP) { - return finalDestination; - } - if (StringUtils.hasText(additionalOpts)) { - finalDestination = finalDestination + "?" + additionalOpts; - } - return finalDestination; - } - - @Override - public void send(T payload, Map headers, String destination, YamlContract contract) { - send(this.builder.create(payload, headers), destination, contract); - } - - @Override - public Message receive(String destination, long timeout, TimeUnit timeUnit, YamlContract contract) { - try { - StandaloneMetadata standaloneMetadata = StandaloneMetadata - .fromMetadata(contract != null ? contract.metadata : null); - ContractVerifierMessageMetadata verifierMessageMetadata = ContractVerifierMessageMetadata - .fromMetadata(contract != null ? contract.metadata : null); - String finalDestination = finalDestination(destination, - additionalOptions(verifierMessageMetadata, standaloneMetadata), verifierMessageMetadata); - log.info("Will receive a message from URI [" + finalDestination + "]"); - Exchange exchange = this.consumerTemplate.receive(finalDestination, timeUnit.toMillis(timeout)); - return exchange != null ? exchange.getIn() : null; - } - catch (Exception e) { - log.error("Exception occurred while trying to read a message from " + " a channel with name [" + destination - + "]", e); - throw new IllegalStateException(e); - } - } - - @Override - public Message receive(String destination, YamlContract contract) { - return receive(destination, 5, TimeUnit.SECONDS, contract); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/camel/ContractVerifierCamelConfiguration.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/camel/ContractVerifierCamelConfiguration.java deleted file mode 100644 index 52f1d629cc..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/camel/ContractVerifierCamelConfiguration.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.camel; - -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import org.apache.camel.CamelContext; -import org.apache.camel.ConsumerTemplate; -import org.apache.camel.Message; -import org.apache.camel.ProducerTemplate; -import org.apache.camel.spring.boot.CamelAutoConfiguration; -import org.jetbrains.annotations.Nullable; - -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cloud.contract.verifier.converter.YamlContract; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging; -import org.springframework.cloud.contract.verifier.messaging.jms.ContractVerifierJmsConfiguration; -import org.springframework.cloud.contract.verifier.messaging.noop.NoOpContractVerifierAutoConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; - -/** - * @author Marcin Grzejszczak - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnClass(Message.class) -@Import(CamelAutoConfiguration.class) -@ConditionalOnProperty(name = "stubrunner.camel.enabled", havingValue = "true", matchIfMissing = true) -@AutoConfigureBefore({ NoOpContractVerifierAutoConfiguration.class, ContractVerifierJmsConfiguration.class }) -public class ContractVerifierCamelConfiguration { - - @Bean - @ConditionalOnMissingBean(MessageVerifierSender.class) - MessageVerifierSender camelContractVerifierMessageSender(CamelContext camelContext, - ProducerTemplate producerTemplate, ConsumerTemplate consumerTemplate) { - CamelStubMessages camelStubMessages = new CamelStubMessages(camelContext, producerTemplate, consumerTemplate); - return new MessageVerifierSender<>() { - @Override - public void send(Message message, String destination, @Nullable YamlContract contract) { - camelStubMessages.send(message, destination, contract); - } - - @Override - public void send(T payload, Map headers, String destination, - @Nullable YamlContract contract) { - camelStubMessages.send(payload, headers, destination, contract); - } - }; - } - - @Bean - @ConditionalOnMissingBean(MessageVerifierReceiver.class) - MessageVerifierReceiver camelContractVerifierMessageReceiver(CamelContext camelContext, - ProducerTemplate producerTemplate, ConsumerTemplate consumerTemplate) { - CamelStubMessages camelStubMessages = new CamelStubMessages(camelContext, producerTemplate, consumerTemplate); - return new MessageVerifierReceiver<>() { - @Override - public Message receive(String destination, long timeout, TimeUnit timeUnit, - @Nullable YamlContract contract) { - return camelStubMessages.receive(destination, timeout, timeUnit, contract); - } - - @Override - public Message receive(String destination, YamlContract contract) { - return camelStubMessages.receive(destination, contract); - } - }; - } - - @Bean - @ConditionalOnMissingBean(ContractVerifierMessaging.class) - public ContractVerifierMessaging camelContractVerifierMessaging(MessageVerifierSender sender, - MessageVerifierReceiver receiver) { - return new ContractVerifierCamelHelper(sender, receiver); - } - -} - -class ContractVerifierCamelHelper extends ContractVerifierMessaging { - - ContractVerifierCamelHelper(MessageVerifierSender sender, MessageVerifierReceiver receiver) { - super(sender, receiver); - } - - @Override - protected ContractVerifierMessage convert(Message receive) { - if (receive == null) { - return null; - } - return new ContractVerifierMessage(receive.getBody(), receive.getHeaders()); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/camel/ContractVerifierCamelMessageBuilder.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/camel/ContractVerifierCamelMessageBuilder.java deleted file mode 100644 index bc3b50942c..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/camel/ContractVerifierCamelMessageBuilder.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.camel; - -import java.util.Map; - -import org.apache.camel.CamelContext; -import org.apache.camel.Message; -import org.apache.camel.support.DefaultMessage; - -/** - * @author Marcin Grzejszczak - */ -class ContractVerifierCamelMessageBuilder { - - private final CamelContext context; - - ContractVerifierCamelMessageBuilder(CamelContext context) { - this.context = context; - } - - public Message create(T payload, Map headers) { - DefaultMessage message = new DefaultMessage(this.context); - message.setBody(payload); - if (headers != null) { - message.setHeaders(headers); - } - return message; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/camel/StandaloneMetadata.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/camel/StandaloneMetadata.java deleted file mode 100644 index 9196de809e..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/camel/StandaloneMetadata.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.camel; - -import java.util.Map; - -import org.springframework.cloud.contract.verifier.util.MetadataUtil; -import org.springframework.cloud.contract.verifier.util.SpringCloudContractMetadata; - -/** - * Represents metadata for standalone communication. - * - * @author Marcin Grzejszczak - * @since 3.0.0 - */ -public class StandaloneMetadata implements SpringCloudContractMetadata { - - /** - * Key under which this metadata entry can be found in contract's metadata. - */ - public static final String METADATA_KEY = "standalone"; - - /** - * Metadata for the setup message. - */ - private SetupMetadata setup = new SetupMetadata(); - - /** - * Metadata for the input message. - */ - private MessageMetadata input = new MessageMetadata(); - - /** - * Metadata for the output message. - */ - private MessageMetadata outputMessage = new MessageMetadata(); - - public SetupMetadata getSetup() { - return this.setup; - } - - public void setSetup(SetupMetadata setup) { - this.setup = setup; - } - - public MessageMetadata getInput() { - return this.input; - } - - public void setInput(MessageMetadata input) { - this.input = input; - } - - public MessageMetadata getOutputMessage() { - return this.outputMessage; - } - - public void setOutputMessage(MessageMetadata outputMessage) { - this.outputMessage = outputMessage; - } - - public static StandaloneMetadata fromMetadata(Map metadata) { - return MetadataUtil.fromMetadata(metadata, StandaloneMetadata.METADATA_KEY, new StandaloneMetadata()); - } - - @Override - public String key() { - return METADATA_KEY; - } - - @Override - public String description() { - return "Metadata for standalone communication - with running middleware"; - } - - /** - * Message metadata. - */ - public static class MessageMetadata { - - /** - * If set, will append any options to the existing ones that define connection to - * the broker. - */ - private String additionalOptions; - - public String getAdditionalOptions() { - return this.additionalOptions; - } - - public void setAdditionalOptions(String additionalOptions) { - this.additionalOptions = additionalOptions; - } - - } - - /** - * Setup metadata. - */ - public static class SetupMetadata { - - /** - * If set, will be set as the full URI. - */ - private String options; - - public String getOptions() { - return this.options; - } - - public void setOptions(String options) { - this.options = options; - } - - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/integration/ContractVerifierIntegrationConfiguration.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/integration/ContractVerifierIntegrationConfiguration.java deleted file mode 100644 index 88bd077f02..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/integration/ContractVerifierIntegrationConfiguration.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.integration; - -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import org.jetbrains.annotations.Nullable; - -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.cloud.contract.verifier.converter.YamlContract; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging; -import org.springframework.cloud.contract.verifier.messaging.noop.NoOpContractVerifierAutoConfiguration; -import org.springframework.cloud.contract.verifier.messaging.stream.ContractVerifierStreamAutoConfiguration; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.messaging.Message; - -/** - * @author Marcin Grzejszczak - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnClass(Message.class) -@AutoConfigureBefore(NoOpContractVerifierAutoConfiguration.class) -@AutoConfigureAfter(ContractVerifierStreamAutoConfiguration.class) -public class ContractVerifierIntegrationConfiguration { - - @Bean - @ConditionalOnMissingBean(MessageVerifierSender.class) - public MessageVerifierSender> integrationContractVerifierMessageSender( - ApplicationContext applicationContext) { - SpringIntegrationStubMessages springIntegrationStubMessages = new SpringIntegrationStubMessages( - applicationContext); - return new MessageVerifierSender<>() { - @Override - public void send(Message message, String destination, @Nullable YamlContract contract) { - springIntegrationStubMessages.send(message, destination, contract); - } - - @Override - public void send(T payload, Map headers, String destination, - @Nullable YamlContract contract) { - springIntegrationStubMessages.send(payload, headers, destination, contract); - } - }; - } - - @Bean - @ConditionalOnMissingBean(MessageVerifierReceiver.class) - public MessageVerifierReceiver> integrationContractVerifierMessageReceiver( - ApplicationContext applicationContext) { - SpringIntegrationStubMessages springIntegrationStubMessages = new SpringIntegrationStubMessages( - applicationContext); - return new MessageVerifierReceiver<>() { - @Override - public Message receive(String destination, long timeout, TimeUnit timeUnit, - @Nullable YamlContract contract) { - return springIntegrationStubMessages.receive(destination, timeout, timeUnit, contract); - } - - @Override - public Message receive(String destination, YamlContract contract) { - return springIntegrationStubMessages.receive(destination, contract); - } - }; - } - - @Bean - @ConditionalOnMissingBean(ContractVerifierMessaging.class) - public ContractVerifierMessaging> integrationContractVerifierMessaging( - MessageVerifierSender> sender, MessageVerifierReceiver> receiver) { - return new ContractVerifierHelper(sender, receiver); - } - -} - -class ContractVerifierHelper extends ContractVerifierMessaging> { - - ContractVerifierHelper(MessageVerifierSender> sender, MessageVerifierReceiver> receiver) { - super(sender, receiver); - } - - @Override - protected ContractVerifierMessage convert(Message receive) { - return new ContractVerifierMessage(receive.getPayload(), receive.getHeaders()); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/integration/ContractVerifierIntegrationMessageBuilder.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/integration/ContractVerifierIntegrationMessageBuilder.java deleted file mode 100644 index a10b8cbbc5..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/integration/ContractVerifierIntegrationMessageBuilder.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.integration; - -import java.util.Map; - -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageHeaders; -import org.springframework.messaging.support.MessageBuilder; - -/** - * @author Marcin Grzejszczak - */ -class ContractVerifierIntegrationMessageBuilder { - - public Message create(T payload, Map headers) { - return MessageBuilder.createMessage(payload, new MessageHeaders(headers)); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/integration/SpringIntegrationStubMessages.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/integration/SpringIntegrationStubMessages.java deleted file mode 100644 index 927a10fe15..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/integration/SpringIntegrationStubMessages.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.integration; - -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.verifier.converter.YamlContract; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender; -import org.springframework.context.ApplicationContext; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.PollableChannel; - -/** - * @author Marcin Grzejszczak - */ -public class SpringIntegrationStubMessages - implements MessageVerifierSender>, MessageVerifierReceiver> { - - private static final Log log = LogFactory.getLog(SpringIntegrationStubMessages.class); - - private final ApplicationContext context; - - private final ContractVerifierIntegrationMessageBuilder builder = new ContractVerifierIntegrationMessageBuilder(); - - public SpringIntegrationStubMessages(ApplicationContext context) { - this.context = context; - } - - @Override - public void send(T payload, Map headers, String destination, YamlContract contract) { - send(this.builder.create(payload, headers), destination, contract); - } - - @Override - public void send(Message message, String destination, YamlContract contract) { - try { - MessageChannel messageChannel = this.context.getBean(destination, MessageChannel.class); - messageChannel.send(message); - } - catch (Exception e) { - log.error("Exception occurred while trying to send a message [" + message + "] " - + "to a channel with name [" + destination + "]", e); - throw e; - } - } - - @Override - public Message receive(String destination, long timeout, TimeUnit timeUnit, YamlContract contract) { - try { - PollableChannel messageChannel = this.context.getBean(destination, PollableChannel.class); - return messageChannel.receive(timeUnit.toMillis(timeout)); - } - catch (Exception e) { - log.error("Exception occurred while trying to read a message from " + " a channel with name [" + destination - + "]", e); - throw new IllegalStateException(e); - } - } - - @Override - public Message receive(String destination, YamlContract contract) { - return receive(destination, 5, TimeUnit.SECONDS, contract); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierMessage.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierMessage.java deleted file mode 100644 index d2e6572e72..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierMessage.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.internal; - -import java.util.LinkedHashMap; -import java.util.Map; - -/** - * Yet another message abstraction. Provides generated tests with a layer that is - * independent of the message provider. - * - * @author Dave Syer - * - */ -public class ContractVerifierMessage { - - private Object payload; - - private Map headers = new LinkedHashMap<>(); - - public ContractVerifierMessage() { - } - - public ContractVerifierMessage(Object payload, Map headers) { - this.payload = payload; - if (headers != null) { - this.headers.putAll(headers); - } - } - - public Object getPayload() { - return this.payload; - } - - public void setPayload(Object payload) { - this.payload = payload; - } - - public byte[] getPayloadAsByteArray() { - if (this.payload instanceof byte[]) { - return (byte[]) this.payload; - } - throw new IllegalStateException("Payload [" + this.payload.getClass() + "]" + "is not instance of byte[]"); - } - - public Map getHeaders() { - return this.headers; - } - - public void setHeaders(Map headers) { - this.headers = headers; - } - - public Object getHeader(String name) { - return this.headers.get(name); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierMessageMetadata.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierMessageMetadata.java deleted file mode 100644 index cd728b5754..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierMessageMetadata.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.internal; - -import java.util.Map; - -import org.springframework.cloud.contract.verifier.util.MetadataUtil; -import org.springframework.cloud.contract.verifier.util.SpringCloudContractMetadata; - -/** - * Metadata representation of the Contract Verifier messaging. - * - * @author Marcin Grzejszczak - * @since 3.0.0 - */ -public class ContractVerifierMessageMetadata implements SpringCloudContractMetadata { - - /** - * Metadata entry in the contract. - */ - public static final String METADATA_KEY = "verifierMessage"; - - private MessageType messageType; - - public ContractVerifierMessageMetadata(MessageType messageType) { - this.messageType = messageType; - } - - public ContractVerifierMessageMetadata() { - } - - public MessageType getMessageType() { - return this.messageType; - } - - public void setMessageType(MessageType messageType) { - this.messageType = messageType; - } - - public static ContractVerifierMessageMetadata fromMetadata(Map metadata) { - return MetadataUtil.fromMetadata(metadata, METADATA_KEY, new ContractVerifierMessageMetadata()); - } - - @Override - public String key() { - return METADATA_KEY; - } - - @Override - public String description() { - return "Internal metadata entries used by the framework, related to messaging"; - } - - /** - * Type of a message. - */ - public enum MessageType { - - /** - * Setup message. - */ - SETUP, - - /** - * Input message. - */ - INPUT, - - /** - * Output message. - */ - OUTPUT - - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierMessaging.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierMessaging.java deleted file mode 100644 index 886b1a3eda..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierMessaging.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.internal; - -import java.util.Map; - -import javax.annotation.Nullable; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.verifier.converter.YamlContract; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender; - -/** - * Wrapper around messaging. Abstracts all message related operations like sending, - * converting and receiving. Delegates the actual work to an implementation of a - * {@link MessageVerifierSender} and {@link MessageVerifierReceiver}. - * - * @param message type - * @author Dave Syer - */ -public class ContractVerifierMessaging { - - private static final Log log = LogFactory.getLog(ContractVerifierMessaging.class); - - private final MessageVerifierSender sender; - - private final MessageVerifierReceiver receiver; - - public ContractVerifierMessaging(MessageVerifierSender sender, MessageVerifierReceiver receiver) { - this.sender = sender; - this.receiver = receiver; - if (sender != null) { - log.info("The message verifier sender implementation is of type [" + sender.getClass() + "]"); - } - if (receiver != null) { - log.info("The message verifier receiver implementation is of type [" + receiver.getClass() + "]"); - } - } - - public void send(ContractVerifierMessage message, String destination, @Nullable YamlContract contract) { - if (contract != null) { - setMessageType(contract, ContractVerifierMessageMetadata.MessageType.INPUT); - } - this.sender.send(message.getPayload(), message.getHeaders(), destination, contract); - } - - public void send(ContractVerifierMessage message, String destination) { - send(message, destination, null); - } - - public ContractVerifierMessage receive(String destination, @Nullable YamlContract contract) { - if (contract != null) { - setMessageType(contract, ContractVerifierMessageMetadata.MessageType.OUTPUT); - } - return convert(this.receiver.receive(destination, contract)); - } - - private void setMessageType(YamlContract contract, ContractVerifierMessageMetadata.MessageType output) { - contract.metadata.put(ContractVerifierMessageMetadata.METADATA_KEY, - new ContractVerifierMessageMetadata(output)); - } - - public ContractVerifierMessage receive(String destination) { - return receive(destination, null); - } - - public ContractVerifierMessage create(T payload, Map headers) { - return new ContractVerifierMessage(payload, headers); - } - - protected ContractVerifierMessage convert(M receive) { - return new ContractVerifierMessage(receive, null); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierObjectMapper.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierObjectMapper.java deleted file mode 100644 index 2a966beed7..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierObjectMapper.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.internal; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; - -/** - * Wrapper over {@link ObjectMapper} that won't try to parse String but will directly - * return it. - * - * @author Marcin Grzejszczak - */ -public class ContractVerifierObjectMapper { - - private final ObjectMapper objectMapper; - - public ContractVerifierObjectMapper(ObjectMapper objectMapper) { - this.objectMapper = objectMapper; - } - - public ContractVerifierObjectMapper() { - this.objectMapper = new ObjectMapper(); - } - - public String writeValueAsString(Object payload) throws JsonProcessingException { - if (payload instanceof String) { - return payload.toString(); - } - else if (payload instanceof byte[]) { - return new String((byte[]) payload); - } - return this.objectMapper.writeValueAsString(payload); - } - - public byte[] writeValueAsBytes(Object payload) throws JsonProcessingException { - if (payload instanceof String) { - return payload.toString().getBytes(); - } - else if (payload instanceof byte[]) { - return (byte[]) payload; - } - return this.objectMapper.writeValueAsBytes(payload); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/jms/ContractVerifierJmsConfiguration.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/jms/ContractVerifierJmsConfiguration.java deleted file mode 100644 index feb9b65f3b..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/jms/ContractVerifierJmsConfiguration.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.jms; - -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import jakarta.jms.JMSException; -import jakarta.jms.Message; -import jakarta.jms.ObjectMessage; -import jakarta.jms.StreamMessage; -import jakarta.jms.TextMessage; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.jetbrains.annotations.Nullable; - -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cloud.contract.verifier.converter.YamlContract; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender; -import org.springframework.cloud.contract.verifier.messaging.integration.ContractVerifierIntegrationConfiguration; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging; -import org.springframework.cloud.contract.verifier.messaging.noop.NoOpContractVerifierAutoConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.jms.core.JmsTemplate; - -/** - * @author Marcin Grzejszczak - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnClass(JmsTemplate.class) -@ConditionalOnProperty(name = "stubrunner.jms.enabled", havingValue = "true", matchIfMissing = true) -@AutoConfigureBefore({ ContractVerifierIntegrationConfiguration.class, NoOpContractVerifierAutoConfiguration.class }) -public class ContractVerifierJmsConfiguration { - - @Bean - @ConditionalOnMissingBean(MessageVerifierSender.class) - MessageVerifierSender contractVerifierJmsMessageSender(ObjectProvider jmsTemplateProvider) { - JmsTemplate jmsTemplate = jmsTemplateProvider.getIfAvailable(JmsTemplate::new); - JmsStubMessages jmsStubMessages = new JmsStubMessages(jmsTemplate); - return new MessageVerifierSender<>() { - @Override - public void send(Message message, String destination, @Nullable YamlContract contract) { - jmsStubMessages.send(message, destination, contract); - } - - @Override - public void send(T payload, Map headers, String destination, - @Nullable YamlContract contract) { - jmsStubMessages.send(payload, headers, destination, contract); - } - }; - } - - @Bean - @ConditionalOnMissingBean(MessageVerifierReceiver.class) - MessageVerifierReceiver contractVerifierJmsMessageReceiver( - ObjectProvider jmsTemplateProvider) { - JmsTemplate jmsTemplate = jmsTemplateProvider.getIfAvailable(JmsTemplate::new); - JmsStubMessages jmsStubMessages = new JmsStubMessages(jmsTemplate); - return new MessageVerifierReceiver<>() { - @Override - public Message receive(String destination, long timeout, TimeUnit timeUnit, - @Nullable YamlContract contract) { - return jmsStubMessages.receive(destination, timeout, timeUnit, contract); - } - - @Override - public Message receive(String destination, YamlContract contract) { - return jmsStubMessages.receive(destination, contract); - } - }; - } - - @Bean - @ConditionalOnMissingBean(ContractVerifierMessaging.class) - ContractVerifierMessaging contractVerifierJmsMessaging(MessageVerifierSender sender, - MessageVerifierReceiver receiver) { - return new ContractVerifierJmsHelper(sender, receiver); - } - -} - -class ContractVerifierJmsHelper extends ContractVerifierMessaging { - - private static final Log log = LogFactory.getLog(ContractVerifierJmsHelper.class); - - ContractVerifierJmsHelper(MessageVerifierSender sender, MessageVerifierReceiver receiver) { - super(sender, receiver); - } - - @Override - protected ContractVerifierMessage convert(Message message) { - try { - Map headers = headers(message); - return new ContractVerifierMessage(getPayload(message), headers); - } - catch (JMSException ex) { - log.warn("An exception occurred while trying to convert the JMS message", ex); - throw new IllegalStateException(ex); - } - } - - private Map headers(Message message) throws JMSException { - Map headers = new HashMap<>(); - if (message == null) { - return headers; - } - Enumeration enumeration = message.getPropertyNames(); - while (enumeration.hasMoreElements()) { - Object element = enumeration.nextElement(); - String asString = element.toString(); - Object property = message.getObjectProperty(asString); - headers.put(asString, property); - } - return headers; - } - - private Object getPayload(Message message) throws JMSException { - if (message == null) { - return null; - } - else if (message instanceof TextMessage) { - return ((TextMessage) message).getText(); - } - else if (message instanceof StreamMessage) { - return ((StreamMessage) message).readObject(); - } - else if (message instanceof ObjectMessage) { - return ((ObjectMessage) message).getObject(); - } - return message.getBody(Object.class); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/jms/JmsStubMessages.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/jms/JmsStubMessages.java deleted file mode 100644 index fe5eca5aea..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/jms/JmsStubMessages.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.jms; - -import java.io.Serializable; -import java.util.Collections; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import jakarta.jms.BytesMessage; -import jakarta.jms.JMSException; -import jakarta.jms.Message; -import jakarta.jms.Session; - -import org.springframework.cloud.contract.verifier.converter.YamlContract; -import org.springframework.jms.core.JmsTemplate; -import org.springframework.jms.core.MessagePostProcessor; - -class JmsStubMessages implements org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender, - org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver { - - private final JmsTemplate jmsTemplate; - - JmsStubMessages(JmsTemplate jmsTemplate) { - this.jmsTemplate = jmsTemplate; - } - - @Override - public void send(Message message, String destination, YamlContract contract) { - jmsTemplate.convertAndSend(destination, message, new ReplyToProcessor()); - } - - @Override - public Message receive(String destination, long timeout, TimeUnit timeUnit, YamlContract contract) { - jmsTemplate.setReceiveTimeout(timeUnit.toMillis(timeout)); - return jmsTemplate.receive(destination); - } - - @Override - public Message receive(String destination, YamlContract contract) { - return receive(destination, 5, TimeUnit.SECONDS, contract); - } - - @Override - public void send(Object payload, Map headers, String destination, YamlContract contract) { - jmsTemplate.send(destination, session -> { - Message message = createMessage(session, payload); - setHeaders(message, headers == null ? Collections.emptyMap() : headers); - return message; - }); - } - - private Message createMessage(Session session, Object payload) throws JMSException { - if (payload instanceof String) { - return session.createTextMessage((String) payload); - } - else if (payload instanceof byte[]) { - BytesMessage bytesMessage = session.createBytesMessage(); - bytesMessage.writeBytes((byte[]) payload); - return bytesMessage; - } - else if (payload instanceof Serializable) { - return session.createObjectMessage((Serializable) payload); - } - return session.createMessage(); - } - - private void setHeaders(Message message, Map headers) { - for (Map.Entry entry : headers.entrySet()) { - String key = entry.getKey(); - Object value = entry.getValue(); - try { - if (value instanceof String) { - message.setStringProperty(key, (String) value); - } - else if (value instanceof Boolean) { - message.setBooleanProperty(key, (Boolean) value); - } - else { - message.setObjectProperty(key, value); - } - } - catch (JMSException ex) { - throw new IllegalStateException(ex); - } - } - } - -} - -class ReplyToProcessor implements MessagePostProcessor { - - @Override - public Message postProcessMessage(Message message) throws JMSException { - message.setStringProperty("requiresReply", "no"); - return message; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/kafka/KafkaMetadata.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/kafka/KafkaMetadata.java deleted file mode 100644 index 912a20540f..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/kafka/KafkaMetadata.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.kafka; - -import java.util.Map; - -import org.springframework.cloud.contract.verifier.util.MetadataUtil; -import org.springframework.cloud.contract.verifier.util.SpringCloudContractMetadata; - -/** - * Represents metadata for Kafka based communication. - * - * @author Marcin Grzejszczak - * @since 3.0.0 - */ -public class KafkaMetadata implements SpringCloudContractMetadata { - - /** - * Key under which this metadata entry can be found in contract's metadata. - */ - public static final String METADATA_KEY = "kafka"; - - /** - * Metadata for the input message. - */ - private MessageKafkaMetadata input = new MessageKafkaMetadata(); - - /** - * Metadata for the output message. - */ - private MessageKafkaMetadata outputMessage = new MessageKafkaMetadata(); - - public MessageKafkaMetadata getInput() { - return this.input; - } - - public void setInput(MessageKafkaMetadata input) { - this.input = input; - } - - public MessageKafkaMetadata getOutputMessage() { - return this.outputMessage; - } - - public void setOutputMessage(MessageKafkaMetadata outputMessage) { - this.outputMessage = outputMessage; - } - - public static KafkaMetadata fromMetadata(Map metadata) { - return MetadataUtil.fromMetadata(metadata, KafkaMetadata.METADATA_KEY, new KafkaMetadata()); - } - - @Override - public String key() { - return METADATA_KEY; - } - - @Override - public String description() { - return "Metadata for Kafka based communication"; - } - - /** - * Kafka message metadata. - */ - public static class MessageKafkaMetadata { - - /** - * Properties related to connecting to a real broker. - */ - private ConnectToBroker connectToBroker = new ConnectToBroker(); - - public ConnectToBroker getConnectToBroker() { - return this.connectToBroker; - } - - public void setConnectToBroker(ConnectToBroker connectToBroker) { - this.connectToBroker = connectToBroker; - } - - } - - /** - * Options related to connecting to the real broker. - */ - public static class ConnectToBroker { - - /** - * If set, will append any options to the existing ones that define connection to - * the broker. - */ - private String additionalOptions; - - public String getAdditionalOptions() { - return this.additionalOptions; - } - - public void setAdditionalOptions(String additionalOptions) { - this.additionalOptions = additionalOptions; - } - - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/noop/NoOpContractVerifierAutoConfiguration.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/noop/NoOpContractVerifierAutoConfiguration.java deleted file mode 100644 index 66547f79d7..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/noop/NoOpContractVerifierAutoConfiguration.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.noop; - -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.jetbrains.annotations.Nullable; - -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.boot.autoconfigure.AutoConfigureOrder; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.cloud.contract.verifier.converter.YamlContract; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.Ordered; - -/** - * Verifier auto configuration containing default beans for messaging. - * - * @author Marcin Grzejszczak - */ -@Configuration(proxyBeanMethods = false) -@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE) -public class NoOpContractVerifierAutoConfiguration { - - @Bean - @ConditionalOnMissingBean(MessageVerifierSender.class) - public MessageVerifierSender noOpContractVerifierMessageSender() { - NoOpStubMessages noOpStubMessages = new NoOpStubMessages<>(); - return new MessageVerifierSender<>() { - - @Override - public void send(Object message, String destination, @Nullable YamlContract contract) { - noOpStubMessages.send(message, destination, contract); - } - - @Override - public void send(T payload, Map headers, String destination, - @Nullable YamlContract contract) { - noOpStubMessages.send(payload, headers, destination, contract); - } - }; - } - - @Bean - @ConditionalOnMissingBean(MessageVerifierReceiver.class) - public MessageVerifierReceiver noOpContractVerifierMessageReceiver() { - NoOpStubMessages noOpStubMessages = new NoOpStubMessages<>(); - return new MessageVerifierReceiver<>() { - - @Override - public Object receive(String destination, long timeout, TimeUnit timeUnit, - @Nullable YamlContract contract) { - return noOpStubMessages.receive(destination, timeout, timeUnit, contract); - } - - @Override - public Object receive(String destination, YamlContract contract) { - return noOpStubMessages.receive(destination, contract); - } - }; - } - - @Bean - @ConditionalOnMissingBean(ContractVerifierMessaging.class) - public ContractVerifierMessaging contractVerifierMessaging() { - return new ContractVerifierMessaging<>(new NoOpStubMessages<>(), new NoOpStubMessages<>()); - } - - @Bean - @ConditionalOnMissingBean - public ContractVerifierObjectMapper contractVerifierObjectMapper(ObjectProvider objectMapper) { - ObjectMapper mapper = objectMapper.getIfAvailable(); - if (mapper != null) { - return new ContractVerifierObjectMapper(mapper); - } - return new ContractVerifierObjectMapper(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/noop/NoOpStubMessages.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/noop/NoOpStubMessages.java deleted file mode 100644 index ae3fe87b17..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/noop/NoOpStubMessages.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.noop; - -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import org.springframework.cloud.contract.verifier.converter.YamlContract; - -/** - * @author Marcin Grzejszczak - */ -public class NoOpStubMessages - implements org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender, - org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver { - - @Override - public void send(U message, String destination, YamlContract contract) { - } - - @Override - public void send(T payload, Map headers, String destination, YamlContract contract) { - } - - @Override - public U receive(String destination, long timeout, TimeUnit timeUnit, YamlContract contract) { - return null; - } - - @Override - public U receive(String destination, YamlContract contract) { - return null; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/ContractVerifierStreamAutoConfiguration.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/ContractVerifierStreamAutoConfiguration.java deleted file mode 100644 index 301436442a..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/ContractVerifierStreamAutoConfiguration.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.stream; - -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import org.jetbrains.annotations.Nullable; - -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cloud.contract.verifier.converter.YamlContract; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging; -import org.springframework.cloud.contract.verifier.messaging.noop.NoOpContractVerifierAutoConfiguration; -import org.springframework.cloud.stream.binder.Binder; -import org.springframework.cloud.stream.binder.test.InputDestination; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.messaging.Message; -import org.springframework.util.Assert; - -/** - * @author Marcin Grzejszczak - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnClass(Binder.class) -@ConditionalOnProperty(name = "stubrunner.stream.enabled", havingValue = "true", matchIfMissing = true) -@AutoConfigureBefore(NoOpContractVerifierAutoConfiguration.class) -public class ContractVerifierStreamAutoConfiguration { - - @Bean - @ConditionalOnMissingBean(ContractVerifierMessaging.class) - public ContractVerifierMessaging streamContractVerifierMessaging(MessageVerifierSender> sender, - MessageVerifierReceiver> receiver) { - return new ContractVerifierHelper(sender, receiver); - } - - @Configuration(proxyBeanMethods = false) - @ConditionalOnClass(InputDestination.class) - static class InputDestinationConfiguration { - - @Bean - @ConditionalOnMissingBean(MessageVerifierSender.class) - MessageVerifierSender> streamContractVerifierMessageSenderExchangeWithDestinations( - ApplicationContext context) { - StreamStubMessages stubMessages = new StreamStubMessages(new StreamInputDestinationMessageSender(context), - new StreamOutputDestinationMessageReceiver(context)); - return new MessageVerifierSender<>() { - @Override - public void send(Message message, String destination, @Nullable YamlContract contract) { - stubMessages.send(message, destination, contract); - } - - @Override - public void send(T payload, Map headers, String destination, - @Nullable YamlContract contract) { - stubMessages.send(payload, headers, destination, contract); - } - }; - } - - @Bean - @ConditionalOnMissingBean(MessageVerifierReceiver.class) - MessageVerifierReceiver> streamContractVerifierMessageReceiverExchangeWithDestinations( - ApplicationContext context) { - StreamStubMessages stubMessages = new StreamStubMessages(new StreamInputDestinationMessageSender(context), - new StreamOutputDestinationMessageReceiver(context)); - return new MessageVerifierReceiver<>() { - @Override - public Message receive(String destination, long timeout, TimeUnit timeUnit, - @Nullable YamlContract contract) { - return stubMessages.receive(destination, timeout, timeUnit, contract); - } - - @Override - public Message receive(String destination, YamlContract contract) { - return stubMessages.receive(destination, contract); - } - }; - } - - } - -} - -class ContractVerifierHelper extends ContractVerifierMessaging> { - - ContractVerifierHelper(MessageVerifierSender> sender, MessageVerifierReceiver> receiver) { - super(sender, receiver); - } - - @Override - protected ContractVerifierMessage convert(Message receive) { - Assert.notNull(receive, "Message must not be null!"); - return new ContractVerifierMessage(receive.getPayload(), receive.getHeaders()); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/ContractVerifierStreamMessageBuilder.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/ContractVerifierStreamMessageBuilder.java deleted file mode 100644 index 1cf0597ac2..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/ContractVerifierStreamMessageBuilder.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.stream; - -import java.util.Map; - -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageHeaders; -import org.springframework.messaging.support.MessageBuilder; - -/** - * @author Marcin Grzejszczak - */ -class ContractVerifierStreamMessageBuilder { - - public Message create(T payload, Map headers) { - Object payloadToSend = payload; - if (payload instanceof String) { - payloadToSend = ((String) payload).getBytes(); - } - return MessageBuilder.createMessage(payloadToSend, new MessageHeaders(headers)); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/DefaultChannels.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/DefaultChannels.java deleted file mode 100644 index e6c5c27dbe..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/DefaultChannels.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.stream; - -enum DefaultChannels { - - INPUT, OUTPUT - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/DestinationResolver.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/DestinationResolver.java deleted file mode 100644 index ebd489f809..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/DestinationResolver.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.stream; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.stream.config.BindingProperties; -import org.springframework.cloud.stream.config.BindingServiceProperties; -import org.springframework.context.ApplicationContext; -import org.springframework.util.StringUtils; - -class DestinationResolver { - - private static final Log log = LogFactory.getLog(DestinationResolver.class); - - private final ApplicationContext context; - - DestinationResolver(ApplicationContext context) { - this.context = context; - } - - String resolvedDestination(String destination, DefaultChannels defaultChannel) { - try { - BindingServiceProperties channelBindingServiceProperties = this.context - .getBean(BindingServiceProperties.class); - Map channels = new HashMap<>(); - for (Map.Entry entry : channelBindingServiceProperties.getBindings() - .entrySet()) { - if (destination.equals(entry.getValue().getDestination())) { - if (log.isDebugEnabled()) { - log.debug("Found a channel named [" + entry.getKey() + "] with destination [" + destination - + "]"); - } - channels.put(entry.getKey(), destination); - } - } - if (channels.size() == 1) { - return channels.keySet().iterator().next(); - } - else if (channels.size() > 0) { - if (log.isDebugEnabled()) { - log.debug("Found following channels [" + channels + "] for destination [" + destination + "]. " - + "Will pick the one that matches the default channel name or the first one if none is matching"); - } - String defaultChannelName = channels.get(defaultChannel.name().toLowerCase()); - String matchingChannelName = StringUtils.hasText(defaultChannelName) - ? defaultChannel.name().toLowerCase() : channels.keySet().iterator().next(); - if (log.isDebugEnabled()) { - log.debug("Picked channel name is [" + matchingChannelName + "]"); - } - return matchingChannelName; - } - } - catch (Exception e) { - log.error("Exception took place while trying to resolve the destination. Will assume the name [" - + destination + "]", e); - } - if (log.isDebugEnabled()) { - log.debug("No destination named [" + destination - + "] was found. Assuming that the destination equals the channel name"); - } - return destination; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/StreamInputDestinationMessageSender.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/StreamInputDestinationMessageSender.java deleted file mode 100644 index ef7c2d5400..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/StreamInputDestinationMessageSender.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.stream; - -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.verifier.converter.YamlContract; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender; -import org.springframework.cloud.stream.binder.test.InputDestination; -import org.springframework.context.ApplicationContext; -import org.springframework.messaging.Message; - -/** - * @author Marcin Grzejszczak - */ -class StreamInputDestinationMessageSender implements MessageVerifierSender> { - - private static final Log log = LogFactory.getLog(StreamInputDestinationMessageSender.class); - - private final ApplicationContext context; - - private final ContractVerifierStreamMessageBuilder builder = new ContractVerifierStreamMessageBuilder(); - - StreamInputDestinationMessageSender(ApplicationContext context) { - this.context = context; - } - - @Override - public void send(T payload, Map headers, String destination, YamlContract contract) { - send(this.builder.create(payload, headers), destination, contract); - } - - @Override - public void send(Message message, String destination, YamlContract contract) { - try { - InputDestination inputDestination = this.context.getBean(InputDestination.class); - inputDestination.send(message, destination); - } - catch (Exception e) { - log.error("Exception occurred while trying to send a message [" + message + "] " - + "to a destination with name [" + destination + "]", e); - throw e; - } - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/StreamOutputDestinationMessageReceiver.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/StreamOutputDestinationMessageReceiver.java deleted file mode 100644 index f0b54cc5e7..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/StreamOutputDestinationMessageReceiver.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.stream; - -import java.util.concurrent.TimeUnit; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.verifier.converter.YamlContract; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver; -import org.springframework.cloud.stream.binder.test.OutputDestination; -import org.springframework.context.ApplicationContext; -import org.springframework.messaging.Message; - -class StreamOutputDestinationMessageReceiver implements MessageVerifierReceiver> { - - private static final Log log = LogFactory.getLog(StreamOutputDestinationMessageReceiver.class); - - private final ApplicationContext context; - - StreamOutputDestinationMessageReceiver(ApplicationContext context) { - this.context = context; - } - - @Override - public Message receive(String destination, long timeout, TimeUnit timeUnit, YamlContract contract) { - try { - OutputDestination outputDestination = this.context.getBean(OutputDestination.class); - return outputDestination.receive(timeUnit.toMillis(timeout), destination); - } - catch (Exception e) { - log.error("Exception occurred while trying to read a message from " + " a channel with name [" + destination - + "]", e); - throw new IllegalStateException(e); - } - } - - @Override - public Message receive(String destination, YamlContract contract) { - return receive(destination, 5, TimeUnit.SECONDS, contract); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/StreamStubMessageSender.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/StreamStubMessageSender.java deleted file mode 100644 index f98d198b35..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/StreamStubMessageSender.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.stream; - -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.verifier.converter.YamlContract; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender; -import org.springframework.context.ApplicationContext; -import org.springframework.integration.support.channel.BeanFactoryChannelResolver; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageChannel; - -/** - * @author Marcin Grzejszczak - */ -class StreamStubMessageSender implements MessageVerifierSender> { - - private static final Log log = LogFactory.getLog(StreamStubMessageSender.class); - - private final ApplicationContext context; - - private final ContractVerifierStreamMessageBuilder builder = new ContractVerifierStreamMessageBuilder(); - - private BeanFactoryChannelResolver resolver; - - StreamStubMessageSender(ApplicationContext context) { - this.context = context; - } - - @Override - public void send(T payload, Map headers, String destination, YamlContract contract) { - send(this.builder.create(payload, headers), destination, contract); - } - - @Override - public void send(Message message, String destination, YamlContract contract) { - try { - MessageChannel messageChannel = resolver().resolveDestination(destination); - messageChannel.send(message); - } - catch (Exception e) { - log.error("Exception occurred while trying to send a message [" + message + "] " - + "to a channel with name [" + destination + "]", e); - throw e; - } - } - - private BeanFactoryChannelResolver resolver() { - if (this.resolver == null) { - this.resolver = context.getBean(BeanFactoryChannelResolver.class); - } - return this.resolver; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/StreamStubMessages.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/StreamStubMessages.java deleted file mode 100644 index 978c5293ac..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/stream/StreamStubMessages.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.stream; - -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import org.springframework.cloud.contract.verifier.converter.YamlContract; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender; -import org.springframework.messaging.Message; - -/** - * @author Marcin Grzejszczak - */ -public class StreamStubMessages implements MessageVerifierSender>, MessageVerifierReceiver> { - - private final MessageVerifierSender> sender; - - private final MessageVerifierReceiver> receiver; - - public StreamStubMessages(MessageVerifierSender> sender, MessageVerifierReceiver> receiver) { - this.sender = sender; - this.receiver = receiver; - } - - @Override - public void send(T payload, Map headers, String destination, YamlContract contract) { - this.sender.send(payload, headers, destination, contract); - } - - @Override - public void send(Message message, String destination, YamlContract contract) { - this.sender.send(message, destination, contract); - } - - @Override - public Message receive(String destination, long timeout, TimeUnit timeUnit, YamlContract contract) { - return this.receiver.receive(destination, timeout, timeUnit, contract); - } - - @Override - public Message receive(String destination, YamlContract contract) { - return this.receiver.receive(destination, contract); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/util/ContractVerifierMessagingUtil.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/util/ContractVerifierMessagingUtil.java deleted file mode 100644 index de40279566..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/util/ContractVerifierMessagingUtil.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.util; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -/** - * Helper class that allows to build headers in a nice way. - * - * @author Marcin Grzejszczak - */ -public final class ContractVerifierMessagingUtil { - - private ContractVerifierMessagingUtil() { - throw new IllegalStateException("Can't instantiate a utility class"); - } - - /** - * @return a builder for headers - */ - public static ContractVerifierHeaders headers() { - return new ContractVerifierHeaders(); - } - - /** - * A map with a fluent interface. Thanks to this, the generated tests look much nicer. - */ - public static class ContractVerifierHeaders implements Map { - - private final Map delegate = new HashMap<>(); - - public ContractVerifierHeaders header(String key, Object value) { - put(key, value); - return this; - } - - @Override - public int size() { - return this.delegate.size(); - } - - @Override - public boolean isEmpty() { - return this.delegate.isEmpty(); - } - - @Override - public boolean containsKey(Object key) { - return this.delegate.containsKey(key); - } - - @Override - public boolean containsValue(Object value) { - return this.delegate.containsValue(value); - } - - @Override - public Object get(Object key) { - return this.delegate.get(key); - } - - @Override - public Object put(String key, Object value) { - return this.delegate.put(key, value); - } - - @Override - public Object remove(Object key) { - return this.delegate.remove(key); - } - - @Override - public void putAll(Map m) { - this.delegate.putAll(m); - } - - @Override - public void clear() { - this.delegate.clear(); - } - - @Override - public Set keySet() { - return this.delegate.keySet(); - } - - @Override - public Collection values() { - return this.delegate.values(); - } - - @Override - public Set> entrySet() { - return this.delegate.entrySet(); - } - - @Override - public boolean equals(Object o) { - return this.delegate.equals(o); - } - - @Override - public int hashCode() { - return this.delegate.hashCode(); - } - - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/template/HandlebarsTemplateProcessor.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/template/HandlebarsTemplateProcessor.java deleted file mode 100644 index 30b315db74..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/template/HandlebarsTemplateProcessor.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.template; - -import java.io.IOException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import com.github.tomakehurst.wiremock.extension.responsetemplating.helpers.WireMockHelpers; -import wiremock.com.github.jknack.handlebars.Handlebars; -import wiremock.com.github.jknack.handlebars.Template; - -import org.springframework.cloud.contract.spec.ContractTemplate; -import org.springframework.cloud.contract.spec.internal.CompositeContractTemplate; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.verifier.builder.TestSideRequestTemplateModel; -import org.springframework.cloud.contract.verifier.builder.handlebars.HandlebarsJsonPathHelper; - -/** - * Default Handlebars template processor. - * - * @author Marcin Grzejszczak - * @since 1.1.0 - */ -public class HandlebarsTemplateProcessor implements TemplateProcessor, ContractTemplate { - - private static final Pattern ESCAPED_LEGACY_JSON_PATH_PATTERN = Pattern - .compile("^.*\\{\\{\\{jsonpath this '(.*)'}}}.*$"); - - private static final Pattern ESCAPED_JSON_PATH_PATTERN = Pattern - .compile("^.*\\{\\{\\{jsonPath request.body '(.*)'}}}.*$"); - - private static final Pattern LEGACY_JSON_PATH_PATTERN = Pattern.compile("^.*\\{\\{jsonpath this '(.*)'}}.*$"); - - private static final Pattern JSON_PATH_PATTERN = Pattern.compile("^.*\\{\\{jsonPath request.body '(.*)'}}.*$"); - - private static final List PATTERNS = Arrays.asList(ESCAPED_LEGACY_JSON_PATH_PATTERN, - ESCAPED_JSON_PATH_PATTERN, LEGACY_JSON_PATH_PATTERN, JSON_PATH_PATTERN); - - private static final String LEGACY_JSON_PATH_TEMPLATE_NAME = HandlebarsJsonPathHelper.NAME; - - private static final String JSON_PATH_TEMPLATE_NAME = WireMockHelpers.jsonPath.name(); - - private final ContractTemplate contractTemplate = new CompositeContractTemplate(); - - @Override - public String transform(Request request, String testContents) { - TestSideRequestTemplateModel templateModel = TestSideRequestTemplateModel.from(request); - Map model = new HashMap<>(); - model.put(HandlebarsJsonPathHelper.REQUEST_MODEL_NAME, templateModel); - Template bodyTemplate = uncheckedCompileTemplate(testContents); - return templatedResponseBody(model, bodyTemplate); - } - - @Override - public boolean containsTemplateEntry(String line) { - return (line.contains(contractTemplate.openingTemplate()) && line.contains(contractTemplate.closingTemplate())) - || (line.contains(contractTemplate.escapedOpeningTemplate()) - && line.contains(contractTemplate.escapedClosingTemplate())); - } - - @Override - public boolean containsJsonPathTemplateEntry(String line) { - return line.contains(openingTemplate() + LEGACY_JSON_PATH_TEMPLATE_NAME) - || line.contains(openingTemplate() + JSON_PATH_TEMPLATE_NAME) - || line.contains(escapedOpeningTemplate() + LEGACY_JSON_PATH_TEMPLATE_NAME) - || line.contains(escapedOpeningTemplate() + JSON_PATH_TEMPLATE_NAME); - } - - @Override - public String jsonPathFromTemplateEntry(String line) { - if (!containsJsonPathTemplateEntry(line)) { - return ""; - } - for (Pattern pattern : PATTERNS) { - Matcher matcher = pattern.matcher(line); - if (matcher.matches()) { - return matcher.group(1); - } - } - return ""; - } - - private String templatedResponseBody(Map model, Template bodyTemplate) { - return uncheckedApplyTemplate(bodyTemplate, model); - } - - private String uncheckedApplyTemplate(Template template, Object context) { - try { - return template.apply(context); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - - private Template uncheckedCompileTemplate(String content) { - try { - final Handlebars handlebars = new Handlebars(); - handlebars.registerHelper(HandlebarsJsonPathHelper.NAME, new HandlebarsJsonPathHelper()); - handlebars.registerHelper(WireMockHelpers.jsonPath.name(), new HandlebarsJsonPathHelper()); - Arrays.stream(WireMockHelpers.values()).filter(helper -> !helper.equals(WireMockHelpers.jsonPath)) - .forEach(helper -> handlebars.registerHelper(helper.name(), helper)); - return handlebars.compileInline(content); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - - @Override - public boolean startsWithTemplate(String text) { - return contractTemplate.startsWithTemplate(text); - } - - @Override - public boolean startsWithEscapedTemplate(String text) { - return contractTemplate.startsWithEscapedTemplate(text); - } - - @Override - public String openingTemplate() { - return contractTemplate.openingTemplate(); - } - - @Override - public String closingTemplate() { - return contractTemplate.closingTemplate(); - } - - @Override - public String escapedOpeningTemplate() { - return contractTemplate.escapedOpeningTemplate(); - } - - @Override - public String escapedClosingTemplate() { - return contractTemplate.escapedClosingTemplate(); - } - - @Override - public String url() { - return contractTemplate.url(); - } - - @Override - public String query(String key) { - return contractTemplate.query(key); - } - - @Override - public String query(String key, int index) { - return contractTemplate.query(key, index); - } - - @Override - public String path() { - return contractTemplate.path(); - } - - @Override - public String path(int index) { - return contractTemplate.path(index); - } - - @Override - public String header(String key) { - return contractTemplate.header(key); - } - - @Override - public String header(String key, int index) { - return contractTemplate.header(key, index); - } - - @Override - public String cookie(String key) { - return contractTemplate.cookie(key); - } - - @Override - public String body() { - return contractTemplate.body(); - } - - @Override - public String body(String jsonPath) { - return contractTemplate.body(jsonPath); - } - - @Override - public String escapedUrl() { - return contractTemplate.escapedUrl(); - } - - @Override - public String escapedQuery(String key) { - return contractTemplate.escapedQuery(key); - } - - @Override - public String escapedQuery(String key, int index) { - return contractTemplate.escapedQuery(key, index); - } - - @Override - public String escapedPath() { - return contractTemplate.escapedPath(); - } - - @Override - public String escapedPath(int index) { - return contractTemplate.escapedPath(index); - } - - @Override - public String escapedHeader(String key) { - return contractTemplate.escapedHeader(key); - } - - @Override - public String escapedHeader(String key, int index) { - return contractTemplate.escapedHeader(key, index); - } - - @Override - public String escapedCookie(String key) { - return contractTemplate.escapedCookie(key); - } - - @Override - public String escapedBody() { - return contractTemplate.escapedBody(); - } - - @Override - public String escapedBody(String jsonPath) { - return contractTemplate.escapedBody(jsonPath); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/template/TemplateProcessor.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/template/TemplateProcessor.java deleted file mode 100644 index 0112e1790f..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/template/TemplateProcessor.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.template; - -import org.springframework.cloud.contract.spec.internal.Request; - -/** - * Contract for conversion of templated responses. - * - * If no implementation is provided then Handlebars will be picked as a default - * implementation. - * - * @author Marcin Grzejszczak - * @since 1.1.0 - */ -public interface TemplateProcessor { - - /** - * For the given {@link Request} and the test contents should perform a transformation - * and return the converted test. - */ - String transform(Request request, String testContents); - - /** - * @return {@code true} if the current line contains template related entry. E.g. for - * Handlebars if a line contains {{{...}}} then it's considered to contain template - * related entry - */ - boolean containsTemplateEntry(String line); - - /** - * @return {@code true} if the current line contains template related entry for json - * path processing. E.g. for Handlebars if a line contains {{{jsonpath ...}}} or - * {{{jsonPath ...}}} then it's considered to contain template related entry for json - * path processing - */ - boolean containsJsonPathTemplateEntry(String line); - - /** - * @return the json path entry from the current line that contains template related - * entry for json path processing. E.g. for Handlebars if a line contains {{{jsonpath - * this '$.a.b.c'}}} or {{{jsonPath request.body ...}}} then the te method would - * return {@code $.a.b.c}. Returns empty string if there's no matching json path entry - */ - String jsonPathFromTemplateEntry(String line); - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/AssertionUtil.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/AssertionUtil.java deleted file mode 100644 index 64d5f014d8..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/AssertionUtil.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util; - -import org.json.JSONException; -import org.skyscreamer.jsonassert.JSONAssert; - -public final class AssertionUtil { - - private static boolean NON_STRICT = false; - - private AssertionUtil() { - throw new IllegalStateException("You shouldn't instantiate the utility class"); - } - - public static void assertThatJsonsAreEqual(String expected, String actual) { - try { - JSONAssert.assertEquals(expected, actual, NON_STRICT); - } - catch (JSONException ex) { - throw new IllegalStateException(ex); - } - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/CloneUtils.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/CloneUtils.java deleted file mode 100644 index 83c39cb411..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/CloneUtils.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util; - -import org.springframework.util.SerializationUtils; - -/** - * Creates a clone. - * - * @author Marcin Grzejszczak - * @since 2.2.0 - */ -public final class CloneUtils { - - private CloneUtils() { - throw new IllegalStateException("Can't instantiate an utility class"); - } - - /** - * Clones an object if it's serializable. - * @param object to clone - * @return a clone of the object - */ - public static Object clone(Object object) { - byte[] serializedObject = SerializationUtils.serialize(object); - return SerializationUtils.deserialize(serializedObject); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ContentType.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ContentType.java deleted file mode 100644 index 3004aac542..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ContentType.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util; - -/** - * Represents content type. Used to pick the way bodies are parsed. - * - * @since 1.0.0 - */ -public enum ContentType { - - /** - * application/json. - */ - JSON("application/json"), - /** - * application/xml. - */ - XML("application/xml"), - /** - * text/plain. - */ - TEXT("text/plain"), - /** - * application/x-www-form-urlencoded. - */ - FORM("application/x-www-form-urlencoded"), - /** - * The content-type was defined and we don't want to override it. - */ - DEFINED(""), - /** - * application/octet-stream. - */ - UNKNOWN("application/octet-stream"); - - private final String mimeType; - - ContentType(String mimeType) { - this.mimeType = mimeType; - } - - public final String getMimeType() { - return mimeType; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ContractScanner.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ContractScanner.java deleted file mode 100644 index d321fab7ce..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ContractScanner.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Collection; -import java.util.Collections; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.ContractConverter; -import org.springframework.cloud.contract.verifier.converter.YamlContractConverter; -import org.springframework.core.io.support.SpringFactoriesLoader; - -/** - * Scans through the given directory and converts all files for contract definitions. - * - * @author Marcin Grzejszczak - * @author Anatolii Zhmaiev - * @since 2.1.0 - */ -public final class ContractScanner { - - private static final Log log = LogFactory.getLog(ContractScanner.class); - - private ContractScanner() { - throw new IllegalStateException("Can't instantiate an utility class"); - } - - /** - * Traverses through the directories, applies converters to files that match them and - * converts the files to {@link Contract}. No additional file filtering takes place. - * @param rootDirectory - directory to traverse through - * @return collection of converted contracts - */ - public static Collection collectContractDescriptors(File rootDirectory) { - return collectContractDescriptors(rootDirectory, (file) -> true); - } - - /** - * Traverses through the directories, applies converters to files that match them and - * converts the files to {@link Contract}. Filters out files not matching a predicate. - * @param rootDirectory - directory to traverse through - * @param predicate - test applied against a file - * @return collection of converted contracts - */ - public static Collection collectContractDescriptors(File rootDirectory, Predicate predicate) { - try { - return Files.walk(rootDirectory.toPath()).map(Path::toFile).filter(file -> !file.isDirectory()) - .filter(predicate).map(ContractScanner::doCollectContractDescriptors).flatMap(Collection::stream) - .collect(Collectors.toList()); - } - catch (IOException e) { - log.warn("Exception occurred while trying to parse file", e); - return Collections.emptyList(); - } - } - - private static Collection doCollectContractDescriptors(File file) { - if (isContractDescriptor(file)) { - return ContractVerifierDslConverter.convertAsCollection(file.getParentFile(), file); - } - ContractConverter converter = contractConverter(file); - if (converter != null && converter.isAccepted(file)) { - return converter.convertFrom(file); - } - if (YamlContractConverter.INSTANCE.isAccepted(file)) { - return YamlContractConverter.INSTANCE.convertFrom(file); - } - return Collections.emptyList(); - } - - private static ContractConverter contractConverter(File file) { - return SpringFactoriesLoader.loadFactories(ContractConverter.class, null).stream() - .filter(converter -> converter.isAccepted(file)).findFirst().orElse(null); - } - - private static boolean isContractDescriptor(File file) { - return ContractVerifierDslConverter.INSTANCE.isAccepted(file); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ContractVerifierDslConverter.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ContractVerifierDslConverter.java deleted file mode 100644 index 856f03b931..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ContractVerifierDslConverter.java +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Supplier; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import javax.tools.DiagnosticCollector; -import javax.tools.JavaCompiler; -import javax.tools.StandardJavaFileManager; -import javax.tools.StandardLocation; -import javax.tools.ToolProvider; - -import groovy.lang.GroovyShell; -import org.codehaus.groovy.control.CompilerConfiguration; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.ContractConverter; -import org.springframework.util.ClassUtils; -import org.springframework.util.ObjectUtils; -import org.springframework.util.StringUtils; - -/** - * Converts a String or a Groovy or Java file into a {@link Contract}. - * - * @author Marcin Grzejszczak - * @author Olga Maciaszek-Sharma - * @author Stessy Delcroix - * @since 1.0.0 - */ -public class ContractVerifierDslConverter implements ContractConverter> { - - private static final Logger LOG = LoggerFactory.getLogger(ContractVerifierDslConverter.class); - - /** - * {@link ContractVerifierDslConverter} instance. - */ - public static final ContractVerifierDslConverter INSTANCE = new ContractVerifierDslConverter(); - - private static final Pattern PACKAGE_PATTERN = Pattern.compile(".*package (.+?);.+?", Pattern.DOTALL); - - private static final Pattern CLASS_PATTERN = Pattern.compile(".+?class (.+?)( |\\{).+?", Pattern.DOTALL); - - private static final JavaCompiler COMPILER = ToolProvider.getSystemJavaCompiler(); - - public static Collection convertAsCollection(File rootFolder, String dsl) { - ClassLoader classLoader = ContractVerifierDslConverter.class.getClassLoader(); - try { - ClassLoader urlCl = updatedClassLoader(rootFolder, classLoader); - Object object = groovyShell(urlCl, rootFolder).evaluate(dsl); - return listOfContracts(object); - } - catch (DslParseException e) { - throw e; - } - catch (Exception e) { - LOG.error("Exception occurred while trying to evaluate the contract", e); - throw new DslParseException(e); - } - finally { - Thread.currentThread().setContextClassLoader(classLoader); - } - } - - public static Collection convertAsCollection(File dsl) { - return convertAsCollection(dsl.getParentFile(), dsl); - } - - public static Collection convertAsCollection(File rootFolder, File dsl) { - ClassLoader classLoader = ContractVerifierDslConverter.class.getClassLoader(); - try { - ClassLoader urlCl = updatedClassLoader(rootFolder, classLoader); - Object object = toObject(urlCl, rootFolder, dsl); - return listOfContracts(dsl, object); - } - catch (DslParseException e) { - throw e; - } - catch (Exception e) { - LOG.error("Exception occurred while trying to evaluate the contract at path [" + dsl.getPath() + "]", e); - throw new DslParseException(e); - } - finally { - Thread.currentThread().setContextClassLoader(classLoader); - } - } - - private static ClassLoader updatedClassLoader(File rootFolder, ClassLoader classLoader) { - ClassLoader urlCl; - try { - urlCl = URLClassLoader.newInstance( - Collections.singletonList(rootFolder.toURI().toURL()).toArray(new URL[0]), classLoader); - } - catch (MalformedURLException e) { - LOG.error("Exception occurred while trying to construct the URL from the root folder at path [" - + rootFolder.getPath() + "]", e); - throw new DslParseException(e); - } - updateTheThreadClassLoader(urlCl); - return urlCl; - } - - private static void updateTheThreadClassLoader(ClassLoader urlCl) { - Thread.currentThread().setContextClassLoader(urlCl); - } - - private static Object toObject(ClassLoader cl, File rootFolder, File dsl) throws IOException { - if (isJava(dsl)) { - try { - return parseJavaFile(rootFolder, dsl); - } - catch (Exception ex) { - if (LOG.isWarnEnabled()) { - LOG.warn("Exception occurred while trying to parse the file [" + dsl - + "] as a contract. Will not parse it.", ex); - } - return null; - } - } - return groovyShell(cl, rootFolder).evaluate(dsl); - } - - private static Object parseJavaFile(File rootFolder, File dsl) throws IllegalAccessException, - InvocationTargetException, InstantiationException, IOException, NoSuchMethodException { - Constructor constructor = classConstructor(rootFolder, dsl); - Object newInstance = constructor.newInstance(); - if (!(newInstance instanceof Supplier)) { - if (LOG.isDebugEnabled()) { - LOG.debug("The class [" + dsl + "] is not instance of Supplier. Will not parse it as a contract"); - } - return null; - } - Supplier supplier = (Supplier) newInstance; - return supplier.get(); - } - - private static Constructor classConstructor(File rootFolder, File dsl) - throws IllegalAccessException, IOException, NoSuchMethodException { - try (StandardJavaFileManager fileManager = COMPILER.getStandardFileManager(null, null, null)) { - try (Stream lines = Files.lines(Paths.get(dsl.getAbsolutePath()))) { - String classText = lines.collect(Collectors.joining("\n")); - String fqn = fqn(classText); - Path directory = Files.createTempDirectory(fqn); - fileManager.setLocation(StandardLocation.CLASS_OUTPUT, List.of(directory.toFile())); - // set compiler's classpath to be same as the runtime's - Set classpathLocations = new HashSet<>(); - classpathLocations.add(rootFolder); - appendUrlsFromAllClassLoaders(classpathLocations); - String classPath = System.getProperty("java.class.path", ""); - if (StringUtils.hasText(classPath)) { - classpathLocations.addAll(Arrays.stream(classPath.split(":")).map(File::new).toList()); - } - fileManager.setLocation(StandardLocation.CLASS_PATH, classpathLocations); - // Compile the file - DiagnosticCollector diagnostics = new DiagnosticCollector<>(); - JavaCompiler.CompilationTask task = COMPILER.getTask(null, fileManager, diagnostics, null, null, - fileManager.getJavaFileObjectsFromFiles(List.of(dsl))); - boolean success = task.call(); - if (!success) { - throw new IllegalStateException("Exceptions occurred while trying to compile the file \n" - + diagnostics.getDiagnostics().stream() - .map(d -> "Error " + d.getMessage(Locale.getDefault()) + " on line " - + d.getLineNumber() + " in " + d.getSource()) - .collect(Collectors.joining("\n"))); - } - try { - // Add the folder with compiled classes to the class loader - URLClassLoader urlClassLoader = new URLClassLoader("contract-classloader", - new URL[] { new URL("file://" + directory.toAbsolutePath() + "/") }, - Thread.currentThread().getContextClassLoader()); - Class clazz = ClassUtils.forName(fqn, urlClassLoader); - Constructor constructor = clazz.getDeclaredConstructor(); - constructor.setAccessible(true); - return constructor; - } - catch (ClassNotFoundException e) { - throw new IllegalStateException("Class with name [" + fqn + "] not found"); - } - } - } - } - - private static void appendUrlsFromAllClassLoaders(Set files) { - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - if (classLoader != null) { - appendUrlsFromClasspath(files, classLoader); - while (classLoader.getParent() != null) { - classLoader = classLoader.getParent(); - appendUrlsFromClasspath(files, classLoader); - } - } - } - - private static void appendUrlsFromClasspath(Set files, ClassLoader classLoader) { - if (classLoader instanceof URLClassLoader urlClassLoader) { - URL[] urLs = urlClassLoader.getURLs(); - if (urLs.length > 0) { - Arrays.stream(urLs).forEach(url -> files.add(new File(url.getFile()))); - } - } - } - - private static boolean isJava(File dsl) { - return dsl.getName().endsWith(".java"); - } - - private static String fqn(String classText) throws IllegalAccessException { - Matcher packageMatcher = PACKAGE_PATTERN.matcher(classText); - String fqn = ""; - if (packageMatcher.matches()) { - fqn = packageMatcher.group(1) + "."; - } - Matcher classMatcher = CLASS_PATTERN.matcher(classText); - if (!classMatcher.matches()) { - throw new IllegalAccessException("Can't parse the class name"); - } - return fqn + classMatcher.group(1); - } - - private static GroovyShell groovyShell(ClassLoader cl, File rootFolder) { - CompilerConfiguration compilerConfiguration = new CompilerConfiguration(); - compilerConfiguration.setSourceEncoding("UTF-8"); - compilerConfiguration.setClasspathList(Collections.singletonList(rootFolder.getAbsolutePath())); - return new GroovyShell(cl, compilerConfiguration); - } - - private static Collection listOfContracts(Object object) { - if (object instanceof Collection) { - return (Collection) object; - } - else if (!(object instanceof Contract)) { - throw new DslParseException("Contract is not returning a Contract or list of Contracts"); - } - return Collections.singletonList((Contract) object); - } - - private static Collection listOfContracts(File file, Object object) { - if (object == null) { - return Collections.emptyList(); - } - else if (isACollectionOfContracts(object)) { - return withName(file, (Collection) object); - } - else if (!(object instanceof Contract)) { - throw new DslParseException("Contract is not returning a Contract or list of Contracts"); - } - return withName(file, Collections.singletonList((Contract) object)); - } - - private static boolean isACollectionOfContracts(Object object) { - return object instanceof Collection && ((Collection) object).stream().allMatch(it -> it instanceof Contract); - } - - private static Collection withName(File file, Collection contracts) { - AtomicInteger counter = new AtomicInteger(0); - return contracts.stream().peek(it -> { - if (contractNameEmpty(it)) { - it.name(NamesUtil.defaultContractName(file, contracts, counter.get())); - } - counter.getAndIncrement(); - }).collect(Collectors.toList()); - } - - private static boolean contractNameEmpty(Contract it) { - return it != null && ObjectUtils.isEmpty(it.getName()); - } - - @Override - public boolean isAccepted(File file) { - return file.getName().endsWith(".groovy") || file.getName().endsWith(".gvy") - || file.getName().endsWith(".java"); - } - - @Override - public Collection convertFrom(File file) { - return convertAsCollection(file); - } - - @Override - public Collection convertTo(Collection contract) { - return contract; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ContractVerifierUtil.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ContractVerifierUtil.java deleted file mode 100644 index 94a9a0b646..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ContractVerifierUtil.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -import org.springframework.cloud.contract.verifier.converter.YamlContract; -import org.springframework.cloud.contract.verifier.converter.YamlContractConverter; -import org.springframework.cloud.contract.verifier.util.xml.DOMNamespaceContext; - -/** - * Helper class for the generated tests. - * - * @author Marcin Grzejszczak - * @author Olga Maciaszek-Sharma - * @since 2.1.0 - */ -public final class ContractVerifierUtil { - - /** - * Prefix for the generated test names. - */ - // TODO: Find a better place for this. - public static final String TEST_METHOD_PREFIX = "validate_"; - - private static final Log LOG = LogFactory.getLog(ContractVerifierUtil.class); - - private ContractVerifierUtil() { - throw new IllegalStateException("Can't instantiate utility class"); - } - - /** - * Helper method to convert a file to bytes. - * @param testClass - test class relative to which the file is stored - * @param relativePath - relative path to the file - * @return bytes of the file - * @since 2.1.0 - */ - public static byte[] fileToBytes(Object testClass, String relativePath) { - try { - URL url = testClass.getClass().getResource(relativePath); - if (url == null) { - throw new FileNotFoundException(relativePath); - } - return Files.readAllBytes(Paths.get(url.toURI())); - } - catch (IOException | URISyntaxException ex) { - throw new IllegalStateException(ex); - } - } - - /** - * Helper method to retrieve XML node value with provided xPath. - * @param parsedXml - a {@link Document} object with parsed XML content - * @param path - the xPath expression to retrieve the value with - * @return {@link String} value of the XML node - * @since 2.1.0 - */ - public static String valueFromXPath(Document parsedXml, String path) { - XPath xPath = XPathFactory.newInstance().newXPath(); - Element documentElement = parsedXml.getDocumentElement(); - xPath.setNamespaceContext(new DOMNamespaceContext(documentElement)); - try { - return xPath.evaluate(path, documentElement); - } - catch (XPathExpressionException exception) { - LOG.error("Incorrect xpath provided: " + path, exception); - throw new IllegalArgumentException(); - } - } - - /** - * Helper method to retrieve XML {@link Node} with provided xPath. - * @param parsedXml - a {@link Document} object with parsed XML content - * @param path - the xPath expression to retrieve the value with - * @return XML {@link Node} object - * @since 2.1.0 - */ - public static Node nodeFromXPath(Document parsedXml, String path) { - XPath xPath = XPathFactory.newInstance().newXPath(); - Element documentElement = parsedXml.getDocumentElement(); - xPath.setNamespaceContext(new DOMNamespaceContext(documentElement)); - try { - return (Node) xPath.evaluate(path, documentElement, XPathConstants.NODE); - } - catch (XPathExpressionException exception) { - LOG.error("Incorrect xpath provided: " + path, exception); - throw new IllegalArgumentException(); - } - } - - /** - * Helper method to convert a file to bytes. - * @param testClass - test class relative to which the file is stored - * @param relativePath - relative path to the file - * @return bytes of the file - * @since 3.0.0 - */ - public static YamlContract contract(Object testClass, String relativePath) { - String path = fromRelativePath(relativePath); - byte[] bytes = fileToBytes(testClass, path); - List read = new YamlContractConverter().read(bytes); - return read.isEmpty() ? null : read.get(0); - } - - static String fromRelativePath(String relativePath) { - String path = relativePath; - if (path.startsWith(TEST_METHOD_PREFIX)) { - path = path.substring(TEST_METHOD_PREFIX.length()); - } - if (path.endsWith("()")) { - path = path.replace("()", ""); - } - if (!path.endsWith(".yml")) { - path = path + ".yml"; - } - return path; - } - - /** - * @return a builder for map - */ - public static ContractVerifierMap map() { - return new ContractVerifierMap(); - } - - /** - * A map with a fluent interface. - */ - public static class ContractVerifierMap implements Map { - - private final Map delegate = new HashMap<>(); - - public ContractVerifierMap entry(String key, Object value) { - put(key, value); - return this; - } - - @Override - public int size() { - return this.delegate.size(); - } - - @Override - public boolean isEmpty() { - return this.delegate.isEmpty(); - } - - @Override - public boolean containsKey(Object key) { - return this.delegate.containsKey(key); - } - - @Override - public boolean containsValue(Object value) { - return this.delegate.containsValue(value); - } - - @Override - public Object get(Object key) { - return this.delegate.get(key); - } - - @Override - public Object put(Object key, Object value) { - return this.delegate.put(key, value); - } - - @Override - public Object remove(Object key) { - return this.delegate.remove(key); - } - - @Override - public void putAll(Map m) { - this.delegate.putAll(m); - } - - @Override - public void clear() { - this.delegate.clear(); - } - - @Override - public Set keySet() { - return this.delegate.keySet(); - } - - @Override - public Collection values() { - return this.delegate.values(); - } - - @Override - public Set> entrySet() { - return this.delegate.entrySet(); - } - - @Override - public boolean equals(Object o) { - return this.delegate.equals(o); - } - - @Override - public int hashCode() { - return this.delegate.hashCode(); - } - - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/DelegatingJsonVerifiable.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/DelegatingJsonVerifiable.java deleted file mode 100644 index 63ac51ac40..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/DelegatingJsonVerifiable.java +++ /dev/null @@ -1,410 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util; - -import java.util.LinkedList; -import java.util.regex.Pattern; - -import com.toomuchcoding.jsonassert.JsonVerifiable; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.commons.text.StringEscapeUtils; - -/** - * Implementation of the {@link MethodBufferingJsonVerifiable} that contains a list of - * String method commands that need to be executed to assert JSONs. - * - * @author Marcin Grzejszczak - * @since 1.0.0 - */ -class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable { - - private static final Log log = LogFactory.getLog(DelegatingJsonVerifiable.class); - - private static final Pattern FIELD_PATTERN = Pattern.compile("\\.field\\((\")?(.)+(\")?\\)"); - - private static final Pattern ARRAY_PATTERN = Pattern.compile("\\.array\\((\")?(.)+(\")?\\)"); - - final JsonVerifiable delegate; - - final LinkedList methodsBuffer; - - final Object valueToCheck; - - DelegatingJsonVerifiable(JsonVerifiable delegate, LinkedList methodsBuffer, Object valueToCheck) { - this.delegate = delegate; - this.methodsBuffer = new LinkedList<>(methodsBuffer); - this.valueToCheck = valueToCheck; - } - - DelegatingJsonVerifiable(JsonVerifiable delegate, LinkedList methodsBuffer) { - this.delegate = delegate; - this.methodsBuffer = new LinkedList<>(methodsBuffer); - this.valueToCheck = null; - } - - DelegatingJsonVerifiable(JsonVerifiable delegate) { - this.delegate = delegate; - this.methodsBuffer = new LinkedList<>(); - this.valueToCheck = null; - } - - private static String stringWithEscapedQuotes(Object object) { - String stringValue = object.toString(); - return stringValue.replaceAll("\"", "\\\\\""); - } - - private static String wrapValueWithQuotes(Object value) { - return value instanceof String ? "\"" + stringWithEscapedQuotes(value) + "\"" : value.toString(); - } - - private void appendMethodWithValue(String methodName, Object value) { - this.methodsBuffer.offer("." + methodName + "(" + value + ")"); - } - - private void appendMethodWithQuotedValue(String methodName, Object value) { - appendMethodWithValue(methodName, wrapValueWithQuotes(value)); - } - - @Override - public MethodBufferingJsonVerifiable contains(Object value) { - DelegatingJsonVerifiable verifiable = new FinishedDelegatingJsonVerifiable(this.delegate.jsonPath(), - this.delegate.contains(value), this.methodsBuffer); - verifiable.appendMethodWithQuotedValue("contains", value); - if (isAssertingAValueInArray()) { - verifiable.methodsBuffer.offer(".value()"); - } - return verifiable; - } - - @Override - public MethodBufferingJsonVerifiable field(Object value) { - Object valueToPut = value instanceof ShouldTraverse ? ((ShouldTraverse) value).value : value; - Object wrappedValue = wrapInBrackets(valueToPut); - DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(this.delegate.field(wrappedValue), - this.methodsBuffer, value); - if (this.delegate.isIteratingOverArray() && !(value instanceof ShouldTraverse)) { - verifiable.appendMethodWithQuotedValue("contains", wrappedValue); - } - else { - verifiable.appendMethodWithQuotedValue("field", wrappedValue); - } - return verifiable; - } - - @Override - public MethodBufferingJsonVerifiable field(String... strings) { - MethodBufferingJsonVerifiable verifiable = null; - for (String string : strings) { - verifiable = verifiable == null ? field(string) : verifiable.field(string); - } - return verifiable; - } - - @Override - public MethodBufferingJsonVerifiable array(Object value) { - Object valueToPut = wrapInBrackets(value); - DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(this.delegate.array(valueToPut), - this.methodsBuffer, value); - verifiable.appendMethodWithQuotedValue("array", valueToPut); - return verifiable; - } - - @Override - public MethodBufferingJsonVerifiable arrayField(Object value) { - Object valueToPut = wrapInBrackets(value); - DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(this.delegate.field(valueToPut).arrayField(), - this.methodsBuffer, value); - verifiable.appendMethodWithQuotedValue("array", valueToPut); - return verifiable; - } - - @Override - public MethodBufferingJsonVerifiable arrayField() { - DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(this.delegate.arrayField(), - this.methodsBuffer); - verifiable.methodsBuffer.offer(".arrayField()"); - return verifiable; - } - - @Override - public MethodBufferingJsonVerifiable array() { - DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(this.delegate.array(), this.methodsBuffer); - verifiable.methodsBuffer.offer(".array()"); - return verifiable; - } - - @Override - public JsonVerifiable elementWithIndex(int i) { - DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(this.delegate.elementWithIndex(i), - this.methodsBuffer); - this.methodsBuffer.offer(".elementWithIndex(" + i + ")"); - return verifiable; - } - - @Override - public MethodBufferingJsonVerifiable iterationPassingArray() { - return new DelegatingJsonVerifiable(this.delegate, this.methodsBuffer); - } - - @Override - public MethodBufferingJsonVerifiable isEqualTo(String value) { - DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(this.delegate.jsonPath(), - this.delegate.isEqualTo(value), this.methodsBuffer, value); - if (this.delegate.isAssertingAValueInArray() && readyToCheck.methodsBuffer.peekLast().equals(".arrayField()")) { - readyToCheck.appendMethodWithQuotedValue("isEqualTo", escapedHackedJavaText(value)); - readyToCheck.methodsBuffer.offer(".value()"); - } - else if (this.delegate.isAssertingAValueInArray() && !readyToCheck.methodsBuffer.peekLast().contains("array")) { - readyToCheck.methodsBuffer.offer(".value()"); - } - else { - readyToCheck.appendMethodWithQuotedValue("isEqualTo", escapedHackedJavaText(value)); - } - return readyToCheck; - } - - @Override - public MethodBufferingJsonVerifiable isEqualTo(Object value) { - if (value == null) { - return isNull(); - } - return isEqualTo(value.toString()); - } - - @Override - public MethodBufferingJsonVerifiable isEqualTo(Number value) { - DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(this.delegate.jsonPath(), - this.delegate.isEqualTo(value), this.methodsBuffer, value); - // related to #271 - the problem is with asserting arrays of maps vs arrays of - // primitives - String last = readyToCheck.methodsBuffer.peekLast(); - boolean containsAMatcher = containsAnyMatcher(last); - if (this.delegate.isAssertingAValueInArray() && containsAMatcher) { - readyToCheck.methodsBuffer.offer(".value()"); - } - else { - readyToCheck.appendMethodWithValue("isEqualTo", - value instanceof Long ? String.valueOf(value).concat("L") : String.valueOf(value)); - } - return readyToCheck; - } - - private boolean containsAnyMatcher(String string) { - return string.contains("isEqualTo") || string.contains("matches") || string.contains("isNull"); - } - - @Override - public MethodBufferingJsonVerifiable isNull() { - DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(this.delegate.jsonPath(), - this.delegate.isNull(), this.methodsBuffer); - readyToCheck.methodsBuffer.offer(".isNull()"); - return readyToCheck; - } - - @Override - public MethodBufferingJsonVerifiable isEmpty() { - DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(this.delegate.jsonPath(), - this.delegate.isEmpty(), this.methodsBuffer); - readyToCheck.methodsBuffer.offer(".isEmpty()"); - return readyToCheck; - } - - @Override - public MethodBufferingJsonVerifiable isInstanceOf(Class clazz) throws IllegalStateException { - DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(this.delegate.jsonPath(), - this.delegate.isInstanceOf(clazz), this.methodsBuffer); - readyToCheck.methodsBuffer.offer(".isInstanceOf(" + clazz.getName() + ")"); - return readyToCheck; - } - - @Override - public MethodBufferingJsonVerifiable matches(String value) { - DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(this.delegate.jsonPath(), - this.delegate.matches(value), this.methodsBuffer, compilePattern(value)); - if (this.delegate.isAssertingAValueInArray()) { - readyToCheck.appendMethodWithQuotedValue("matches", escapedHackedJavaText(value)); - readyToCheck.methodsBuffer.offer(".value()"); - } - else { - readyToCheck.appendMethodWithQuotedValue("matches", escapedHackedJavaText(value)); - } - return readyToCheck; - } - - private Object compilePattern(String value) { - try { - return Pattern.compile(value); - } - catch (Exception e) { - log.warn("Exception occurred while trying to compile the pattern [" + value - + "]. Will return the value explicitly. Hopefully, you know what you're doing..."); - return value; - } - } - - /** - * We need to escape the pattern in order for the produced text to be compilable. The - * problem is that sometimes we get quotes that already escaped. If we escape them we - * get code that doesn't compile. That's why we're doing this hack to unescape an - * double escaped text. Related to - * https://github.com/spring-cloud/spring-cloud-contract/issues/169 - * @param value text to escape - * @return escaped text with lower number of escaped backslashes - */ - private String escapedHackedJavaText(String value) { - return StringEscapeUtils.escapeJava(value).replace("\\\"", "\""); - } - - @Override - public MethodBufferingJsonVerifiable isEqualTo(Boolean value) { - DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(this.delegate.jsonPath(), - this.delegate.isEqualTo(value), this.methodsBuffer, value); - if (this.delegate.isAssertingAValueInArray()) { - readyToCheck.methodsBuffer.offer(".value()"); - } - else { - readyToCheck.appendMethodWithValue("isEqualTo", String.valueOf(value)); - } - return readyToCheck; - } - - @Override - public MethodBufferingJsonVerifiable value() { - return new FinishedDelegatingJsonVerifiable(this.delegate, this.methodsBuffer); - } - - @Override - public String keyBeforeChecking() { - return this.delegate.jsonPath(); - } - - @Override - public Object valueBeforeChecking() { - return this.valueToCheck; - } - - @Override - public boolean assertsSize() { - for (String s : this.methodsBuffer) { - if (s.contains(".hasSize(") || s.contains(".isEmpty()")) { - return true; - } - } - return false; - } - - @Override - public boolean assertsConcreteValue() { - for (String s : this.methodsBuffer) { - if (FIELD_PATTERN.matcher(s).matches() || ARRAY_PATTERN.matcher(s).matches()) { - return true; - } - } - return false; - } - - @Override - public JsonVerifiable withoutThrowingException() { - return this.delegate.withoutThrowingException(); - } - - @Override - public String jsonPath() { - return this.delegate.jsonPath(); - } - - @Override - public void matchesJsonPath(String s) { - this.delegate.matchesJsonPath(s); - } - - @Override - public JsonVerifiable hasSize(int size) { - FinishedDelegatingJsonVerifiable verifiable = new FinishedDelegatingJsonVerifiable(this.delegate.jsonPath(), - this.delegate.hasSize(size), this.methodsBuffer); - verifiable.methodsBuffer.offer(".hasSize(" + size + ")"); - return verifiable; - } - - @Override - public boolean isIteratingOverNamelessArray() { - return this.delegate.isIteratingOverNamelessArray(); - } - - @Override - public boolean isIteratingOverArray() { - return this.delegate.isIteratingOverArray(); - } - - @Override - public boolean isAssertingAValueInArray() { - return this.delegate.isAssertingAValueInArray(); - } - - // Related to https://github.com/spring-cloud/spring-cloud-contract/issues/269 - private Object wrapInBrackets(Object name) { - if (name instanceof Number) { - return name; - } - return "['" + name.toString() + "']"; - } - - @Override - public String method() { - return createMethodString(); - } - - private String createMethodString() { - LinkedList queue = new LinkedList<>(this.methodsBuffer); - StringBuilder stringBuffer = new StringBuilder(); - while (!queue.isEmpty()) { - stringBuffer.append(queue.remove()); - } - return stringBuffer.toString(); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - DelegatingJsonVerifiable that = (DelegatingJsonVerifiable) o; - return this.methodsBuffer.toString().equals(that.methodsBuffer.toString()); - } - - @Override - public int hashCode() { - int result = this.methodsBuffer.toString().hashCode(); - return 31 * result; - } - - @Override - public String toString() { - return "DelegatingJsonVerifiable{" + "delegate=\n" + this.delegate + ", methodsBuffer=" + this.methodsBuffer - + '}'; - } - - @Override - public T read(Class aClass) { - return this.delegate.read(aClass); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/DslParseException.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/DslParseException.java deleted file mode 100644 index 7bd68b2c18..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/DslParseException.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util; - -/** - * Exception occurring when we're trying to parse the DSL. - * - * @author Marcin Grzejszczak - * @since 1.1.0 - */ -public class DslParseException extends RuntimeException { - - public DslParseException(String message) { - super(message); - } - - public DslParseException(Throwable cause) { - super(cause); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/FinishedDelegatingJsonVerifiable.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/FinishedDelegatingJsonVerifiable.java deleted file mode 100644 index 43287365bf..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/FinishedDelegatingJsonVerifiable.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util; - -import java.util.LinkedList; - -import com.toomuchcoding.jsonassert.JsonVerifiable; - -/** - * Helper class that represents a finished assertion of a JSON. Contains a list of all - * necessary method calls to assert the JSON. - * - * @author Marcin Grzejszczak - * @since 1.0.0 - */ -class FinishedDelegatingJsonVerifiable extends DelegatingJsonVerifiable { - - final String keyBeforeChecking; - - FinishedDelegatingJsonVerifiable(String keyBeforeChecking, JsonVerifiable delegate, - LinkedList methodsBuffer) { - super(delegate, methodsBuffer); - this.keyBeforeChecking = keyBeforeChecking; - } - - FinishedDelegatingJsonVerifiable(String keyBeforeChecking, JsonVerifiable delegate, - LinkedList methodsBuffer, Object value) { - super(delegate, methodsBuffer, value); - this.keyBeforeChecking = keyBeforeChecking; - } - - FinishedDelegatingJsonVerifiable(JsonVerifiable delegate, LinkedList methodsBuffer) { - super(delegate, methodsBuffer); - this.keyBeforeChecking = delegate.jsonPath(); - } - - @Override - public String keyBeforeChecking() { - return this.keyBeforeChecking; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/JsonPaths.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/JsonPaths.java deleted file mode 100644 index d230bff85b..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/JsonPaths.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util; - -import java.util.LinkedHashSet; - -/** - * Represents a set of Strings - set of method calls to assert a JSON. - * - * @since 1.0.0 - */ -public class JsonPaths extends LinkedHashSet { - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/MapConverter.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/MapConverter.java deleted file mode 100644 index 147f7e1c0e..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/MapConverter.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util; - -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import groovy.json.JsonSlurper; -import groovy.lang.Closure; -import groovy.lang.GString; - -import org.springframework.cloud.contract.spec.internal.DslProperty; -import org.springframework.cloud.contract.spec.internal.FromFileProperty; -import org.springframework.cloud.contract.verifier.template.HandlebarsTemplateProcessor; -import org.springframework.cloud.contract.verifier.template.TemplateProcessor; - -/** - * Converts an object into either client or server side representation. Iterates over the - * structure of an object (depending on whether it's an iterable or a primitive type - * etc.), converts the {@link DslProperty} into their client / server representation and - * returns the result - * - * @author Marcin Grzejszczak - * @author Stessy Delcroix - * @author Ravil Galeyev - * @since 1.1.0 - */ -public class MapConverter { - - private static final boolean STUB_SIDE = true; - - private static final boolean TEST_SIDE = false; - - /** - * Generic {@link Function} used to deserialize a json file. - */ - public static final Function JSON_PARSING_FUNCTION = (value) -> { - try { - return new ObjectMapper().readValue(value, Object.class); - } - catch (JsonProcessingException e) { - throw new IllegalArgumentException("The current json [" + value + "] could not be deserialized"); - } - }; - - /** - * Generic {@link Closure} used to deserialize a json file. - */ - public static final Closure JSON_PARSING_CLOSURE = new Closure(null) { - public Object doCall(Object it) { - return new JsonSlurper().parseText((String) it); - } - }; - - /** - * Function used to return its input argument. {@link Function#identity()} cannot be - * used as the return type is Function<T,T>, whilst this function return type is - * Function<T,R> - */ - public static final Function IDENTITY = (value) -> value; - - private final TemplateProcessor templateProcessor; - - MapConverter() { - this.templateProcessor = processor(); - } - - private TemplateProcessor processor() { - return new HandlebarsTemplateProcessor(); - } - - /** - * @return the object with client side values of - * {@link org.springframework.cloud.contract.spec.internal.DslProperty} - */ - public static Object transformToClientValues(Object value) { - return transformValues(value, (v) -> v instanceof DslProperty ? ((DslProperty) v).getClientValue() : v); - } - - public static Object transformValues(Object value, Function function) { - return transformValues(value, function, JSON_PARSING_FUNCTION); - } - - /** - * Iterates over the structure of the object and executes the function on each element - * of that structure. - * @return the transformed structure - */ - public static Object transformValues(Object value, Function function, - Function parsingFunction) { - if (value instanceof String) { - try { - Object parsed = parsingFunction.apply((String) value); - if (parsed instanceof Map) { - return convert((Map) parsed, function, parsingFunction); - } - else if (parsed instanceof List) { - return transformValues(parsed, function, parsingFunction); - } - } - catch (Exception ignore) { - } - return extractValue(value, function); - } - else if (value instanceof Map) { - return convert((Map) value, function, parsingFunction); - } - else if (value instanceof Collection) { - return ((Collection) value).stream().map((v) -> transformValues(v, function, parsingFunction)) - .collect(Collectors.toList()); - } - return transformValue(function, value, parsingFunction); - } - - /** - * Transforms a value with the given function. Needs to be protected, otherwise method - * access exception will occur at runtime. - */ - protected static Object transformValue(Function function, Object value, - Function parsingFunction) { - return extractValue(value, (val) -> { - Object newValue = function.apply(val); - if (newValue instanceof Map || newValue instanceof List || newValue instanceof String && val != null) { - return transformValues(newValue, function, parsingFunction); - } - return newValue; - }); - } - - private static Object extractValue(Object value, Function function) { - try { - return function.apply(value); - } - catch (Exception ignore) { - return value; - } - } - - private static Map convert(Map map, Function function, - Function parsingFunction) { - Map convertedMap = new LinkedHashMap<>(); - for (Map.Entry entry : map.entrySet()) { - convertedMap.put(entry.getKey(), transformValues(entry.getValue(), function, parsingFunction)); - } - return convertedMap; - } - - public static Object getClientOrServerSideValues(Object json, boolean clientSide) { - return getClientOrServerSideValues(json, clientSide, JSON_PARSING_FUNCTION); - } - - /** - * If {@code clientSide} is {@code true} returns the client side value for the - * provided object. - */ - public static Object getClientOrServerSideValues(Object json, boolean clientSide, - Function parsingFunction) { - return transformValues(json, val -> { - if (val instanceof DslProperty) { - DslProperty dslProperty = ((DslProperty) val); - return clientSide - ? getClientOrServerSideValues(dslProperty.getClientValue(), clientSide, parsingFunction) - : getClientOrServerSideValues(dslProperty.getServerValue(), clientSide, parsingFunction); - } - else if (val instanceof GString) { - ContentType type = new MapConverter().templateProcessor.containsJsonPathTemplateEntry( - ContentUtils.extractValueForGString((GString) val, ContentUtils.GET_TEST_SIDE).toString()) - ? ContentType.TEXT : null; - return ContentUtils.extractValue((GString) val, type, (v) -> { - if (v instanceof DslProperty) { - return clientSide - ? getClientOrServerSideValues(((DslProperty) v).getClientValue(), clientSide, - parsingFunction) - : getClientOrServerSideValues(((DslProperty) v).getServerValue(), clientSide, - parsingFunction); - } - return v; - }); - } - else if (val instanceof FromFileProperty) { - return ((FromFileProperty) val).isByte() ? ((FromFileProperty) val).asBytes() - : ((FromFileProperty) val).asString(); - } - return val; - }, parsingFunction); - } - - public static Object getStubSideValues(Object json) { - return getClientOrServerSideValues(json, STUB_SIDE, JSON_PARSING_FUNCTION); - } - - public static Object getStubSideValues(Object json, Function parsingClosure) { - return getClientOrServerSideValues(json, STUB_SIDE, parsingClosure); - } - - public static Object getTestSideValues(Object json) { - return getTestSideValues(json, JSON_PARSING_FUNCTION); - } - - public static Object getTestSideValues(Object json, Function parsingClosure) { - return getClientOrServerSideValues(json, TEST_SIDE, parsingClosure); - } - - public static Object getTestSideValuesForText(Object json) { - return getClientOrServerSideValues(json, TEST_SIDE, IDENTITY); - } - - public static Object getStubSideValuesForNonBody(Object object) { - return getClientOrServerSideValues(object, STUB_SIDE, IDENTITY); - } - - public static Object getTestSideValuesForNonBody(Object object) { - return getClientOrServerSideValues(object, TEST_SIDE, IDENTITY); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/MetadataUtil.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/MetadataUtil.java deleted file mode 100644 index 3ab96a6fbc..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/MetadataUtil.java +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util; - -import java.io.Serializable; -import java.lang.reflect.Field; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Properties; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; - -import com.fasterxml.jackson.annotation.JsonFilter; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.exc.InvalidDefinitionException; -import com.fasterxml.jackson.databind.ser.FilterProvider; -import com.fasterxml.jackson.databind.ser.PropertyWriter; -import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; -import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; - -import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; -import org.springframework.boot.context.properties.bind.Binder; -import org.springframework.boot.context.properties.source.MapConfigurationPropertySource; -import org.springframework.core.io.ByteArrayResource; -import org.springframework.util.ReflectionUtils; - -/** - * Helper class that allows to work with metadata. - * - * @author Marcin Grzejszczak - * @since 3.0.0 - */ -public final class MetadataUtil { - - private static final ObjectMapper MAPPER = new VerifierObjectMapper(); - - private MetadataUtil() { - throw new IllegalStateException("Can't instantiate a utility class"); - } - - /** - * Fills an object with entries from metadata for a given key. - * @param metadata - metadata from the contract - * @param key - key under which metadata can be found - * @param objectToMerge - object to be filled with entries from the metadata - * @param - type of the object to merge - * @return merged object with metadata or object without metadata entries if metadata - * key wasn't present - */ - public static T fromMetadata(Map metadata, String key, T objectToMerge) { - if (metadata == null || !metadata.containsKey(key)) { - return objectToMerge; - } - return merge(objectToMerge, metadata.get(key)); - } - - /** - * Patches the object to merge. - * @param objectToMerge - object to be filled with entries from the metadata - * @param patch - object that is a patch for an object to merge - * @param - type of the object to merge - * @return merged object with metadata or object without metadata entries if metadata - * key wasn't present - */ - public static T merge(T objectToMerge, Object patch) { - if (patch == null) { - return objectToMerge; - } - byte[] bytes = new byte[0]; - try { - bytes = MAPPER.writer().writeValueAsBytes(patch); - return MAPPER.readerForUpdating(objectToMerge).readValue(bytes); - } - catch (Exception e) { - if (e.getClass().toString().contains("InaccessibleObjectException") - || (e instanceof InvalidDefinitionException - && e.getMessage().contains("InaccessibleObjectException"))) { - // JDK 16 workaround - ObjectMapper seems not be JDK16 compatible - // with the setup present in Spring Cloud Contract. So we will not - // allow patching but we will just copy values from the patch to - // to the object to merge - try { - YamlPropertiesFactoryBean yamlProcessor = new YamlPropertiesFactoryBean(); - yamlProcessor.setResources(new ByteArrayResource(bytes)); - Properties properties = yamlProcessor.getObject(); - T props = (T) new Binder( - new MapConfigurationPropertySource(properties.entrySet().stream() - .collect(Collectors.toMap(entry -> entry.getKey().toString(), - entry -> entry.getValue().toString())))).bind("", objectToMerge.getClass()) - .get(); - BeanUtils.copyProperties(props, objectToMerge); - return objectToMerge; - } - catch (Exception ex) { - throw new IllegalStateException(ex); - } - } - throw new IllegalStateException(e); - } - } - - public static MetadataMap map() { - return new MetadataMap(); - } - - public static class MetadataMap implements Map { - - private final Map delegate = new HashMap<>(); - - public MetadataMap entry(String key, Object value) { - put(key, value); - return this; - } - - @Override - public int size() { - return this.delegate.size(); - } - - @Override - public boolean isEmpty() { - return this.delegate.isEmpty(); - } - - @Override - public boolean containsKey(Object key) { - return this.delegate.containsKey(key); - } - - @Override - public boolean containsValue(Object value) { - return this.delegate.containsValue(value); - } - - @Override - public Object get(Object key) { - return this.delegate.get(key); - } - - @Override - public Object put(String key, Object value) { - return this.delegate.put(key, value); - } - - @Override - public Object remove(Object key) { - return this.delegate.remove(key); - } - - @Override - public void putAll(Map m) { - this.delegate.putAll(m); - } - - @Override - public void clear() { - this.delegate.clear(); - } - - @Override - public Set keySet() { - return this.delegate.keySet(); - } - - @Override - public Collection values() { - return this.delegate.values(); - } - - @Override - public Set> entrySet() { - return this.delegate.entrySet(); - } - - @Override - public boolean equals(Object o) { - return this.delegate.equals(o); - } - - @Override - public int hashCode() { - return this.delegate.hashCode(); - } - - } - -} - -class VerifierObjectMapper extends ObjectMapper { - - VerifierObjectMapper() { - setDefaultPropertyInclusion(JsonInclude.Include.NON_NULL) - .setDefaultPropertyInclusion(JsonInclude.Include.NON_DEFAULT) - .setDefaultPropertyInclusion(JsonInclude.Include.NON_EMPTY) - .setDefaultPropertyInclusion(JsonInclude.Include.NON_ABSENT); - configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - FilterProvider filters = new SimpleFilterProvider().addFilter("non default properties", new MyFilter()); - addMixIn(Object.class, PropertyFilterMixIn.class); - setFilterProvider(filters); - } - -} - -@JsonFilter("non default properties") -class PropertyFilterMixIn { - -} - -class MyFilter extends SimpleBeanPropertyFilter implements Serializable { - - private static final Map CACHE = new ConcurrentHashMap<>(); - - @Override - public void serializeAsField(Object pojo, JsonGenerator jgen, SerializerProvider provider, PropertyWriter writer) - throws Exception { - if (pojo instanceof Map || pojo instanceof Collection) { - writer.serializeAsField(pojo, jgen, provider); - return; - } - Object defaultInstance = defaultInstance(pojo); - if (defaultInstance instanceof CantInstantiateThisClass - || !valueSameAsDefault(pojo, defaultInstance, writer.getName())) { - writer.serializeAsField(pojo, jgen, provider); - } - } - - Object defaultInstance(Object pojo) { - return CACHE.computeIfAbsent(pojo.getClass(), this::defaultInstance); - } - - private Object defaultInstance(Class aClass) { - try { - return aClass.getDeclaredConstructor().newInstance(); - } - catch (Exception e) { - return new CantInstantiateThisClass(); - } - } - - boolean valueSameAsDefault(Object pojo, Object defaultInstance, String fieldName) { - Field field = ReflectionUtils.findField(pojo.getClass(), fieldName); - if (field == null) { - return false; - } - ReflectionUtils.makeAccessible(field); - try { - return Objects.equals(field.get(pojo), field.get(defaultInstance)); - } - catch (IllegalAccessException e) { - throw new IllegalStateException(e); - } - } - -} - -class CantInstantiateThisClass { - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/MethodBuffering.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/MethodBuffering.java deleted file mode 100644 index eb8c6311d6..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/MethodBuffering.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util; - -/** - * Contract for classes that buffer method executions. - * - * @author Marcin Grzejszczak - * @since 1.0.0 - */ -public interface MethodBuffering { - - String method(); - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/MethodBufferingJsonVerifiable.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/MethodBufferingJsonVerifiable.java deleted file mode 100644 index a05fdf37aa..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/MethodBufferingJsonVerifiable.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util; - -import com.toomuchcoding.jsonassert.JsonVerifiable; - -/** - * A wrapper over {@link JsonVerifiable} that allows to store the method name in order to - * print it out in the generated test. - * - * @author Marcin Grzejszczak - * @since 1.0.0 - */ -public interface MethodBufferingJsonVerifiable extends JsonVerifiable, MethodBuffering { - - @Override - MethodBufferingJsonVerifiable contains(Object value); - - @Override - MethodBufferingJsonVerifiable field(Object value); - - @Override - MethodBufferingJsonVerifiable array(Object value); - - MethodBufferingJsonVerifiable arrayField(Object value); - - @Override - MethodBufferingJsonVerifiable arrayField(); - - @Override - MethodBufferingJsonVerifiable array(); - - MethodBufferingJsonVerifiable iterationPassingArray(); - - @Override - MethodBufferingJsonVerifiable isEqualTo(String value); - - @Override - MethodBufferingJsonVerifiable isEqualTo(Object value); - - @Override - MethodBufferingJsonVerifiable isEqualTo(Number value); - - @Override - MethodBufferingJsonVerifiable isNull(); - - @Override - MethodBufferingJsonVerifiable isEmpty(); - - @Override - MethodBufferingJsonVerifiable matches(String value); - - @Override - MethodBufferingJsonVerifiable isInstanceOf(Class clazz); - - @Override - MethodBufferingJsonVerifiable isEqualTo(Boolean value); - - @Override - MethodBufferingJsonVerifiable value(); - - String keyBeforeChecking(); - - Object valueBeforeChecking(); - - boolean assertsSize(); - - boolean assertsConcreteValue(); - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/NamesUtil.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/NamesUtil.java deleted file mode 100644 index beda224d4d..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/NamesUtil.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util; - -import java.io.File; -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayDeque; -import java.util.Collection; -import java.util.Deque; - -/** - * A utility class that helps to convert names. - * - * @author Jakub Kubrynski, codearte.io - * @since 1.0.0 - */ -public final class NamesUtil { - - private NamesUtil() { - throw new IllegalStateException("Can't instantiate a utility class"); - } - - /** - * Returns the first element before the last separator presence. - * @return empty string if separator is not found. - */ - public static String beforeLast(String string, String separator) { - if (string != null && string.indexOf(separator) > -1) { - return string.substring(0, string.lastIndexOf(separator)); - } - return ""; - } - - /** - * Returns the first element after the last separator presence. - * @return the provided string if separator is not found. - */ - public static String afterLast(String string, String separator) { - if (hasSeparator(string, separator)) { - return string.substring(string.lastIndexOf(separator) + 1); - } - return string; - } - - /** - * Returns {@code true} if has a separatot in the string. - */ - public static boolean hasSeparator(String string, String separator) { - return string.indexOf(separator) > -1; - } - - /** - * Returns the first element after the last dot presence. - * @return the provided string if separator is not found. - */ - public static String afterLastDot(String string) { - return afterLast(string, "."); - } - - /** - * @return {@code true} if has a dot - */ - public static boolean hasDot(String string) { - return hasSeparator(string, "."); - } - - /** - * @param file - file with contracts - * @param contracts - collection of contracts - * @param counter - given contract index - * @return the default contract name, resolved from file name, taking * into - * consideration also the index of contract (for multiple contracts * stored in a - * single file). - */ - public static String defaultContractName(File file, Collection contracts, int counter) { - int lastIndexOfDot = file.getName().lastIndexOf("."); - String tillExtension = file.getName().substring(0, lastIndexOfDot); - return tillExtension + (counter > 0 || contracts.size() > 1 ? "_" + counter : ""); - } - - /** - * Converts a string into a camel case format. - */ - public static String camelCase(String className) { - if (isEmpty(className)) { - return className; - } - String firstChar = className.substring(0, 1).toLowerCase(); - return firstChar + className.substring(1); - } - - /** - * Capitalizes the provided string. - */ - public static String capitalize(String className) { - if (isEmpty(className)) { - return className; - } - String firstChar = className.substring(0, 1).toUpperCase(); - return firstChar + className.substring(1); - } - - public static boolean isEmpty(String string) { - return string == null || string.length() == 0; - } - - /** - * Returns the whole string to the last present dot. - * @return input string if there is no dot - */ - public static String toLastDot(String string) { - if (string.indexOf(".") > -1) { - return string.substring(0, string.lastIndexOf(".")); - } - return string; - } - - /** - * Converts the Java package notation to a path format. - */ - public static String packageToDirectory(String packageName) { - return packageName.replace('.', File.separatorChar); - } - - /** - * Converts the path format to a Java package notation. - */ - public static String directoryToPackage(String directory) { - return directory.replace('.', '_').replace(File.separatorChar, '.').replaceAll("\\.([0-9])", "._$1") - .replaceAll("^([0-9].*)", "_$1"); - } - - /** - * Traverses the directories and converts renames illegal folder names to package - * names. - * @param rootDir - folder from which to start traversing - */ - public static void recrusiveDirectoryToPackage(File rootDir) { - try { - if (!rootDir.exists()) { - return; - } - InvalidFolderRenamer renamer = new InvalidFolderRenamer(); - Files.walkFileTree(rootDir.toPath(), renamer); - renamer.rename(); - } - catch (IOException ex) { - throw new IllegalStateException(ex); - } - } - - /** - * Converts illegal package characters to underscores. - */ - public static String convertIllegalPackageChars(String packageName) { - return packageName.replaceAll("[_\\- .+]", "_"); - } - - /** - * Converts illegal characters in method names to underscores. - */ - public static String convertIllegalMethodNameChars(String methodName) { - String result = methodName.replaceAll("^[^a-zA-Z_$0-9]", "_"); - return result.replaceAll("[^a-zA-Z_$0-9]", "_"); - } - - private static class InvalidFolderRenamer extends SimpleFileVisitor { - - private final Deque filesToRename = new ArrayDeque(); - - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { - String name = dir.toFile().getName(); - String convertedName = directoryToPackage(name); - if (!name.equals(convertedName)) { - this.filesToRename.addFirst(new FileAndNewName(dir.toFile(), convertedName)); - } - - return FileVisitResult.CONTINUE; - } - - public void rename() { - this.filesToRename.forEach(fileAndNewName -> { - fileAndNewName.file.renameTo(new File(fileAndNewName.file.getParentFile(), fileAndNewName.newName)); - }); - } - - } - - private static final class FileAndNewName { - - private FileAndNewName(File file, String newName) { - this.file = file; - this.newName = newName; - } - - private final File file; - - private final String newName; - - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/RegexpBuilders.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/RegexpBuilders.java deleted file mode 100644 index e4190d1148..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/RegexpBuilders.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util; - -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import groovy.lang.GString; -import org.codehaus.groovy.runtime.GStringImpl; - -import org.springframework.cloud.contract.spec.internal.DslProperty; -import org.springframework.cloud.contract.spec.util.RegexpUtils; - -import static org.apache.commons.text.StringEscapeUtils.escapeJson; -import static org.springframework.cloud.contract.verifier.util.ContentType.JSON; -import static org.springframework.cloud.contract.verifier.util.ContentUtils.extractValue; - -/** - * Useful utility methods to work with regular expressions. - * - * @since 1.0.0 - */ -public final class RegexpBuilders { - - private final static String WS = "/\\s*/"; - - private static final Function, Object> CLIENT_VALUE_EXTRACTOR = DslProperty::getClientValue; - - private RegexpBuilders() { - } - - /** - * Converts the {@link Object} passed values into their stub side String - * representations. - */ - public static String buildGStringRegexpForStubSide(Object o) { - if (o instanceof DslProperty) { - return buildGStringRegexpForStubSide((DslProperty) o); - } - else if (o instanceof Pattern) { - return buildGStringRegexpForStubSide((Pattern) o); - } - else if (o instanceof GString) { - return buildGStringRegexpForStubSide((GString) o); - } - return escapeSpecialRegexChars(o.toString()); - } - - /** - * Converts the {@link GString} passed values into their stub side String - * representations. - */ - static String buildGStringRegexpForStubSide(GString gString) { - return new GStringImpl( - Stream.of(gString.getValues()).map(RegexpBuilders::buildGStringRegexpForStubSide).map(s -> (Object) s) - .toArray(), - Stream.of(gString.getStrings()).map(RegexpBuilders::escapeSpecialRegexChars).toArray(String[]::new)) - .toString(); - } - - /** - * Converts the {@link Pattern} passed values into their stub side String - * representations. - */ - static String buildGStringRegexpForStubSide(Pattern pattern) { - return pattern.pattern(); - } - - /** - * Converts the {@link org.springframework.cloud.contract.spec.internal.DslProperty} - * passed values into their stub side String representations. - */ - static String buildGStringRegexpForStubSide(DslProperty dslProperty) { - return buildGStringRegexpForStubSide(dslProperty.getClientValue()); - } - - /** - * Converts the {@link GString} passed values into their test side String - * representations. - */ - public static String buildGStringRegexpForTestSide(GString gString) { - return new GStringImpl( - Stream.of(gString.getValues()).map(RegexpBuilders::buildGStringRegexpForTestSide).map(s -> (Object) s) - .toArray(), - Stream.of(gString.getStrings()).map(RegexpBuilders::escapeSpecialRegexChars).toArray(String[]::new)) - .toString(); - } - - /** - * Converts the {@link Object} passed values into their test side String - * representations. - */ - public static String buildGStringRegexpForTestSide(Object o) { - return o.toString().replaceAll("\\\\", "\\\\\\\\"); - } - - public static String escapeSpecialRegexChars(String str) { - return RegexpUtils.escapeSpecialRegexChars(str); - } - - public static String buildJSONRegexpMatch(GString gString) { - return buildJSONRegexpMatch(extractValue(gString, JSON, CLIENT_VALUE_EXTRACTOR)); - } - - public static String buildJSONRegexpMatch(Map jsonMap) { - return WS + "\\{" - + jsonMap.entrySet().stream().map(RegexpBuilders::buildJSONRegexpMatch).collect(Collectors.joining(",")) - + "\\}" + WS; - } - - public static String buildJSONRegexpMatch(List jsonList) { - return WS + "\\[" + jsonList.stream().map(RegexpBuilders::buildJSONRegexpMatch).collect(Collectors.joining(",")) - + "\\]" + WS; - } - - /** - * Converts the map into String representation of regular expressions. - */ - public static String buildJSONRegexpMatch(Map.Entry entry) { - return buildJSONRegexpMatchString(escapeJson(entry.getKey())) + ":" + buildJSONRegexpMatch(entry.getValue()); - } - - /** - * Converts the object into String representation of regular expressions. - */ - public static String buildJSONRegexpMatch(Object value) { - return buildJSONRegexpMatchStringOptionalQuotes(escapeJson(value.toString())); - } - - /** - * Converts the pattern into String representation of regular expressions. - */ - public static String buildJSONRegexpMatch(Pattern pattern) { - return buildJSONRegexpMatchStringOptionalQuotes(pattern.pattern()); - } - - /** - * Converts the String into String representation of regular expressions. - */ - public static String buildJSONRegexpMatchString(String value) { - return WS + '"' + value + '"' + WS; - } - - /** - * Converts the String into an optional String representation of regular expressions. - */ - public static String buildJSONRegexpMatchStringOptionalQuotes(String value) { - return WS + "\"?" + value + "\"?" + WS; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ShouldTraverse.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ShouldTraverse.java deleted file mode 100644 index d7245d6f8c..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ShouldTraverse.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util; - -/** - * Utility class that wraps an object that should be traversed when building a list of - * methods to execute in the generated test. - * - * @author Marcin Grzejszczak - * @since 1.0.0 - */ -class ShouldTraverse { - - final Object value; - - ShouldTraverse(Object value) { - this.value = value; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/SpringCloudContractMetadata.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/SpringCloudContractMetadata.java deleted file mode 100644 index b9f1dc5ebe..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/SpringCloudContractMetadata.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util; - -import java.util.Collections; -import java.util.List; - -/** - * Interface for metadata objects parsed from the metadata in a contract. Will be used to - * scan for implementations of the interface in order to build a schema of how metadata - * can look like. - * - * @author Marcin Grzejszczak - * @since 3.0.0 - */ -public interface SpringCloudContractMetadata { - - /** - * Name of the key under which this metadata entry will be present in contract's - * metadata. - * @return key name - */ - String key(); - - /** - * Short description of the metadata. Will be used in the generated documentation. - * @return description of the metadata. - */ - String description(); - - /** - * Collection of additional classes to look at if one is interested. - * @return additional classes - */ - default List additionalClassesToLookAt() { - return Collections.emptyList(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ToFileContractsTransformer.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ToFileContractsTransformer.java deleted file mode 100644 index a89743340d..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ToFileContractsTransformer.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util; - -import java.io.File; -import java.nio.file.Files; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.ContractConverter; - -import static org.springframework.cloud.contract.verifier.util.ContractScanner.collectContractDescriptors; - -/** - * Allows conversion of Contract files to files. - * - * WARNING: This class is incubating and experimental. It might change in the future. - * - * @author Marcin Grzejszczak - * @since 2.1.0 - */ -public final class ToFileContractsTransformer { - - private static final Logger log = LoggerFactory.getLogger(ToFileContractsTransformer.class); - - /** - * Dumps contracts as files for the given {@link ContractConverter}. - * - * - argument 1 : FQN - fully qualified name of the {@link ContractConverter} - * [REQUIRED] - argument 2 : path - path where the dumped files should be stored - * [OPTIONAL - defaults to target/converted-contracts] - argument 3 : path - path were - * the contracts should be searched for [OPTIONAL - defaults to - * src/test/resources/contracts] - */ - public static void main(String[] args) { - if (args.length == 0) { - throw new IllegalStateException(exceptionMessage()); - } - log.warn("You're using an incubating feature. Note, that it can be changed / removed in the future"); - String fqn = args[0]; - String outputPath = args.length >= 2 ? args[1] : "target/converted-contracts"; - String path = args.length >= 3 ? args[2] : "src/test/resources/contracts"; - new ToFileContractsTransformer().storeContractsAsFiles(path, fqn, outputPath); - } - - private static String exceptionMessage() { - return "Please provide the FQN of the ContractConverter. E.g. [org.springframework.cloud.contract.verifier.converter.YamlContractConverter]"; - } - - /** - * @param path - path were the contracts should be searched for - * @param fqn - fully qualified name of the {@link ContractConverter} - * @param outputPath - path where the dumped files should be stored - * @return list of dumped files - */ - List storeContractsAsFiles(String path, String fqn, String outputPath) { - try { - log.info("Input path [{}]", path); - log.info("FQN of the converter [{}]", fqn); - log.info("Output path [{}]", outputPath); - Collection contracts = collectContractDescriptors(new File(path)); - log.info("Found [{}] contract definition", contracts.size()); - Class name = Class.forName(fqn); - ContractConverter contractConverter = (ContractConverter) name.getDeclaredConstructors()[0] - .newInstance(); - Collection converted = contractConverter.convertTo(contracts); - log.info("Successfully converted contracts definitions"); - Map stored = contractConverter.store(converted); - File outputFolder = new File(outputPath); - outputFolder.mkdirs(); - int i = 1; - Set> entries = stored.entrySet(); - log.info("Will convert [{}] contracts", entries.size()); - List files = new ArrayList<>(); - for (Map.Entry entry : entries) { - File outputFile = new File(outputFolder, entry.getKey()); - Files.write(outputFile.toPath(), entry.getValue()); - log.info("[{}/{}] Successfully stored [{}]", i, entries.size(), outputFile.getName()); - files.add(outputFile); - } - return files; - } - catch (Exception ex) { - throw new IllegalStateException(ex); - } - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/ArrayValueAssertion.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/ArrayValueAssertion.java deleted file mode 100644 index 9557525c17..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/ArrayValueAssertion.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util.xml; - -import java.util.Iterator; -import java.util.LinkedList; - -import org.eclipse.wst.xml.xpath2.api.Item; -import org.eclipse.wst.xml.xpath2.api.ResultSequence; - -class ArrayValueAssertion extends FieldAssertion implements XmlArrayVerifiable { - - private final boolean checkingPrimitiveType; - - ArrayValueAssertion(XmlCachedObjects cachedObjects, LinkedList xPathBuffer, - LinkedList specialCaseXPathBuffer, Object arrayName, - XmlAsserterConfiguration xmlAsserterConfiguration) { - super(cachedObjects, xPathBuffer, specialCaseXPathBuffer, arrayName, xmlAsserterConfiguration); - this.checkingPrimitiveType = true; - } - - private ArrayValueAssertion(XmlCachedObjects cachedObjects, LinkedList xPathBuffer, - LinkedList specialCaseXPathBuffer, Object arrayName, - XmlAsserterConfiguration xmlAsserterConfiguration, boolean checkingPrimitiveType) { - super(cachedObjects, xPathBuffer, specialCaseXPathBuffer, arrayName, xmlAsserterConfiguration); - this.checkingPrimitiveType = checkingPrimitiveType; - } - - private ArrayValueAssertion(XmlAsserter asserter, boolean checkingPrimitiveType) { - super(asserter); - this.checkingPrimitiveType = checkingPrimitiveType; - } - - @Override - public XmlArrayVerifiable contains(String value) { - return new ArrayValueAssertion(this.cachedObjects, this.xPathBuffer, this.specialCaseXPathBuffer, value, - this.xmlAsserterConfiguration, false); - } - - @Override - public XmlArrayVerifiable hasSize(int size) { - String xPath = "count(" + createXPathString() + ")"; - ArrayValueAssertion verifiable = new ArrayValueAssertion(this, this.checkingPrimitiveType); - verifiable.specialCaseXPathBuffer.clear(); - verifiable.specialCaseXPathBuffer.add(xPath); - String xPathString = verifiable.createSpecialCaseXPathString(); - ResultSequence sequence = verifiable.resultSequence(xPathString); - Iterator iterator = sequence.iterator(); - if (!iterator.hasNext()) { - throw new IllegalStateException("Parsed XML [" + this.cachedObjects.xmlAsString - + "] doesn't match the XPath <" + xPathString + ">"); - } - int retrievedSize = Integer.valueOf(iterator.next().getStringValue()); - if (retrievedSize != size) { - throw new IllegalStateException("Parsed XML [" + this.cachedObjects.xmlAsString + "] has size [" - + retrievedSize + "] and not [" + size + "] for XPath <" + xPathString + "> "); - } - return verifiable; - } - - @Override - public FieldAssertion node(String value) { - FieldAssertion assertion = super.node(value); - return new ArrayValueAssertion(assertion, false); - } - - @Override - public FieldAssertion nodeWithDefaultNamespace(String value, String defaultNamespace) { - FieldAssertion assertion = super.nodeWithDefaultNamespace(value, defaultNamespace); - return new ArrayValueAssertion(assertion, false); - } - - @Override - public FieldAssertion node(String... nodeNames) { - FieldAssertion assertion = super.node(nodeNames); - return new ArrayValueAssertion(assertion, false); - } - - @Override - protected void removeLastFieldElement(XmlAsserter readyToCheck) { - readyToCheck.xPathBuffer.removeLast(); - } - - @Override - public XmlVerifiable isEqualTo(String value) { - if (!this.checkingPrimitiveType) { - return super.isEqualTo(value); - } - return equalityOnAPrimitive("[text()=" + escapeText(value) + "]"); - } - - @Override - public XmlVerifiable isEqualTo(Number value) { - if (!this.checkingPrimitiveType) { - return super.isEqualTo(value); - } - return equalityOnAPrimitive("[number()=" + String.valueOf(value) + "]"); - } - - private XmlVerifiable equalityOnAPrimitive(String xPath) { - ReadyToCheckAsserter readyToCheck = new ReadyToCheckAsserter(this.cachedObjects, this.xPathBuffer, - this.fieldName, this.xmlAsserterConfiguration); - readyToCheck.xPathBuffer.removeLast(); - readyToCheck.xPathBuffer.offer(xPath); - readyToCheck.checkBufferedXPathString(); - return readyToCheck; - } - - @Override - public XmlVerifiable matches(String value) { - if (!this.checkingPrimitiveType) { - return super.matches(value); - } - return equalityOnAPrimitive("[matches(text(), " + escapeText(escapeRegex(value)) + ")]"); - } - - @Override - public XmlVerifiable isEqualTo(Boolean value) { - if (!this.checkingPrimitiveType) { - return super.isEqualTo(value); - } - return isEqualTo(String.valueOf(value)); - } - - @Override - public boolean isAssertingAValueInArray() { - return true; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/DOMNamespaceContext.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/DOMNamespaceContext.java deleted file mode 100644 index b24429bed8..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/DOMNamespaceContext.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util.xml; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import javax.xml.namespace.NamespaceContext; - -import org.w3c.dom.Attr; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; - -public class DOMNamespaceContext implements NamespaceContext { - - private final Map namespaceMap = new HashMap<>(); - - public DOMNamespaceContext(Node contextNode) { - addNamespaces(contextNode); - } - - public String getNamespaceURI(String arg0) { - return namespaceMap.get(arg0); - } - - public String getPrefix(String arg0) { - for (Map.Entry entry : namespaceMap.entrySet()) { - if (entry.getValue().equals(arg0)) { - return entry.getKey(); - } - } - return null; - } - - public Iterator getPrefixes(String arg0) { - return namespaceMap.keySet().iterator(); - } - - private void addNamespaces(Node element) { - if (element.getChildNodes() != null) { - // loops through child Element Nodes and check for namespace attributes - for (int i = 0; i < element.getChildNodes().getLength(); i++) { - if (element.getChildNodes().item(i) instanceof Element) { - addNamespaces(element.getChildNodes().item(i)); - } - } - } - if (element instanceof Element) { - Element el = (Element) element; - NamedNodeMap map = el.getAttributes(); - for (int x = 0; x < map.getLength(); x++) { - Attr attr = (Attr) map.item(x); - if ("xmlns".equals(attr.getPrefix())) { - namespaceMap.putIfAbsent(attr.getLocalName(), attr.getValue()); - } - } - } - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/FieldAssertion.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/FieldAssertion.java deleted file mode 100644 index ed89ab2f85..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/FieldAssertion.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util.xml; - -import java.util.LinkedList; - -class FieldAssertion extends XmlAsserter { - - FieldAssertion(XmlCachedObjects cachedObjects, LinkedList xPathBuffer, - LinkedList specialCaseXPathBuffer, Object value, - XmlAsserterConfiguration xmlAsserterConfiguration) { - super(cachedObjects, xPathBuffer, specialCaseXPathBuffer, value, xmlAsserterConfiguration); - } - - FieldAssertion(XmlAsserter asserter) { - super(asserter); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/IteratingOverArray.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/IteratingOverArray.java deleted file mode 100644 index 8428df8283..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/IteratingOverArray.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util.xml; - -/** - * Helper interface describing the process of current iteration. - * - * @author Marcin Grzejszczak - * @since 2.1.0 - */ -public interface IteratingOverArray { - - /** - * @return {@code true} if is in progress of iterating over an array. - */ - boolean isIteratingOverArray(); - - /** - * @return {@code true} if current element is a particular value on which concrete - * assertion will take place. - */ - boolean isAssertingAValueInArray(); - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/ReadyToCheckAsserter.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/ReadyToCheckAsserter.java deleted file mode 100644 index f8910f1bac..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/ReadyToCheckAsserter.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util.xml; - -import java.util.LinkedList; - -class ReadyToCheckAsserter extends XmlAsserter { - - ReadyToCheckAsserter(XmlCachedObjects cachedObjects, LinkedList xPathBuffer, Object fieldName, - XmlAsserterConfiguration xmlAsserterConfiguration) { - super(cachedObjects, xPathBuffer, new LinkedList(), fieldName, xmlAsserterConfiguration); - } - - @Override - protected boolean isReadyToCheck() { - return true; - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XPathBuilder.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XPathBuilder.java deleted file mode 100644 index 869cbffcee..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XPathBuilder.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util.xml; - -/** - * Builder of XPaths. - * - * @author Marcin Grzejszczak - * @since 2.1.0 - * @see XmlVerifiable - * @see XmlAssertion - */ -public final class XPathBuilder { - - private XPathBuilder() { - throw new IllegalStateException("Can't instantiate a utility class"); - } - - /** - * @return a builder of {@link XmlVerifiable} with which you can build your XPath. - * Once finished just call {@link XmlVerifiable#xPath()} to get XPath as String. - */ - public static XmlVerifiable builder() { - return XmlAssertion.assertThat("").withoutThrowingException(); - } - - /** - * Using a XPath builder for the given XML you can read its value. - * @param xml xml to assert - * @return builder of {@link XmlVerifiable} - */ - public static XmlVerifiable builder(String xml) { - return XmlAssertion.assertThat(xml).withoutThrowingException(); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlArrayVerifiable.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlArrayVerifiable.java deleted file mode 100644 index af6c35a465..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlArrayVerifiable.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util.xml; - -/** - * Contract to match an array in a parsed XML via XPath. - * - * @author Marcin Grzejszczak - * @since 2.1.0 - */ -public interface XmlArrayVerifiable extends XmlVerifiable { - - /** - * When you want to assert a node with a name in an array. - * @param nodeName name of the node - * @return this - */ - XmlArrayVerifiable contains(String nodeName); - - /** - * When you want to assert if an array is of given size. - * @param size size to assert - * @return this - */ - XmlArrayVerifiable hasSize(int size); - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlAsserter.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlAsserter.java deleted file mode 100644 index c91778e90e..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlAsserter.java +++ /dev/null @@ -1,445 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util.xml; - -import java.util.LinkedList; -import java.util.List; -import java.util.regex.Pattern; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.eclipse.wst.xml.xpath2.api.ResultSequence; -import org.eclipse.wst.xml.xpath2.api.XPath2Expression; -import org.eclipse.wst.xml.xpath2.processor.Engine; -import org.eclipse.wst.xml.xpath2.processor.internal.types.ElementType; -import org.eclipse.wst.xml.xpath2.processor.util.DynamicContextBuilder; - -import org.springframework.util.StringUtils; - -class XmlAsserter implements XmlVerifiable { - - private static final Log log = LogFactory.getLog(XmlAsserter.class); - - private final static Pattern SPECIAL_REGEX_CHARS = Pattern.compile("[{}()\\[\\].+*?^$\\\\|]"); - - final XmlCachedObjects cachedObjects; - - final LinkedList xPathBuffer; - - // for things like count(...) - final LinkedList specialCaseXPathBuffer; - - final Object fieldName; - - final XmlAsserterConfiguration xmlAsserterConfiguration; - - XmlAsserter(XmlCachedObjects cachedObjects, LinkedList xPathBuffer, - LinkedList specialCaseXPathBuffer, Object fieldName, - XmlAsserterConfiguration xmlAsserterConfiguration) { - this.cachedObjects = cachedObjects; - this.xPathBuffer = new LinkedList<>(xPathBuffer); - this.specialCaseXPathBuffer = new LinkedList<>(specialCaseXPathBuffer); - this.fieldName = fieldName; - this.xmlAsserterConfiguration = xmlAsserterConfiguration; - } - - XmlAsserter(XmlAsserter asserter) { - this.cachedObjects = asserter.cachedObjects; - this.xPathBuffer = new LinkedList<>(asserter.xPathBuffer); - this.specialCaseXPathBuffer = new LinkedList<>(asserter.specialCaseXPathBuffer); - this.fieldName = asserter.fieldName; - this.xmlAsserterConfiguration = asserter.xmlAsserterConfiguration; - } - - static String escapeText(Object object) { - String string = String.valueOf(object); - if (!string.contains("'")) { - return wrapValueWithSingleQuotes(string); - } - String[] split = string.split("'"); - LinkedList list = new LinkedList(); - list.add("concat("); - for (String splitString : split) { - list.add("'" + splitString + "'"); - list.add(","); - list.add("\"'\""); - list.add(","); - } - // will remove the last ,', entries - // removing last colon - list.removeLast(); - // removing last escaped apostrophe - list.removeLast(); - // removing last colon - list.removeLast(); - list.add(")"); - return buildStringFromList(list); - } - - static String escapeRegex(Object object) { - return String.valueOf(object); - } - - private static String escapeSpecialRegexChars(String str) { - return SPECIAL_REGEX_CHARS.matcher(str).replaceAll("\\\\$0"); - } - - private static String buildStringFromList(List list) { - StringBuilder builder = new StringBuilder(); - for (String string : list) { - builder.append(string); - } - return builder.toString(); - } - - private static String wrapValueWithSingleQuotes(Object value) { - return value instanceof String ? "'" + value + "'" : value.toString(); - } - - @Override - public FieldAssertion node(final String value) { - FieldAssertion asserter = new FieldAssertion(this.cachedObjects, this.xPathBuffer, this.specialCaseXPathBuffer, - value, this.xmlAsserterConfiguration); - asserter.xPathBuffer.offer(String.valueOf(value)); - asserter.xPathBuffer.offer("/"); - return asserter; - } - - @Override - public FieldAssertion nodeWithDefaultNamespace(final String value, String defaultNamespace) { - FieldAssertion asserter = new FieldAssertion(this.cachedObjects, this.xPathBuffer, this.specialCaseXPathBuffer, - value, this.xmlAsserterConfiguration); - String path = String.format("*[local-name()='%s'", value); - if (StringUtils.hasText(defaultNamespace)) { - path += String.format(" and namespace-uri()='%s'", defaultNamespace); - } - path += "]"; - asserter.xPathBuffer.offer(path); - asserter.xPathBuffer.offer("/"); - return asserter; - } - - @Override - public XmlVerifiable withAttribute(String attribute, String attributeValue) { - FieldAssertion asserter = new FieldAssertion(this.cachedObjects, this.xPathBuffer, this.specialCaseXPathBuffer, - this.fieldName, this.xmlAsserterConfiguration); - if (asserter.xPathBuffer.peekLast().equals("/")) { - asserter.xPathBuffer.removeLast(); - } - if (isReadyToCheck()) { - asserter.xPathBuffer.offer("/" + this.fieldName); - } - asserter.xPathBuffer.offer("[@" + String.valueOf(attribute) + "=" + escapeText(attributeValue) + "]"); - updateCurrentBuffer(asserter); - asserter.checkBufferedXPathString(); - return asserter; - } - - @Override - public XmlVerifiable withAttribute(String attribute) { - FieldAssertion asserter = new FieldAssertion(this.cachedObjects, this.xPathBuffer, this.specialCaseXPathBuffer, - this.fieldName, this.xmlAsserterConfiguration); - String path = "@" + attribute; - if (attribute.startsWith("xmlns:")) { - path = "namespace::" + attribute.substring("xmlns:".length()); - } - asserter.xPathBuffer.offer(path); - updateCurrentBuffer(asserter); - asserter.checkBufferedXPathString(); - return asserter; - } - - @Override - public XmlVerifiable text() { - FieldAssertion asserter = new FieldAssertion(this.cachedObjects, this.xPathBuffer, this.specialCaseXPathBuffer, - this.fieldName, this.xmlAsserterConfiguration); - asserter.xPathBuffer.offer("text()"); - return asserter; - } - - @Override - public XmlVerifiable index(int index) { - FieldAssertion asserter = new FieldAssertion(this.cachedObjects, this.xPathBuffer, this.specialCaseXPathBuffer, - this.fieldName, this.xmlAsserterConfiguration); - if (asserter.xPathBuffer.peekLast().equals("/")) { - asserter.xPathBuffer.removeLast(); - } - asserter.xPathBuffer.offer("[" + index + "]"); - asserter.xPathBuffer.offer("/"); - return asserter; - } - - @Override - public FieldAssertion node(String... nodeNames) { - FieldAssertion assertion = null; - for (String field : nodeNames) { - assertion = assertion == null ? node(field) : assertion.node(field); - } - return assertion; - } - - @Override - public XmlArrayVerifiable array(final String value) { - ArrayValueAssertion asserter = new ArrayValueAssertion(this.cachedObjects, this.xPathBuffer, - this.specialCaseXPathBuffer, value, this.xmlAsserterConfiguration); - asserter.xPathBuffer.offer(String.valueOf(value)); - asserter.xPathBuffer.offer("/"); - return asserter; - } - - @Override - public XmlVerifiable isEqualTo(String value) { - if (value == null) { - return isNull(); - } - ReadyToCheckAsserter readyToCheck = new ReadyToCheckAsserter(this.cachedObjects, this.xPathBuffer, - this.fieldName, this.xmlAsserterConfiguration); - removeLastFieldElement(readyToCheck); - readyToCheck.xPathBuffer.offer("[" + this.fieldName + "=" + escapeText(value) + "]"); - updateCurrentBuffer(readyToCheck); - readyToCheck.checkBufferedXPathString(); - return readyToCheck; - } - - private void updateCurrentBuffer(XmlAsserter readyToCheck) { - this.xPathBuffer.clear(); - this.xPathBuffer.addAll(readyToCheck.xPathBuffer); - } - - @Override - public XmlVerifiable isEqualTo(Object value) { - if (value == null) { - return isNull(); - } - if (value instanceof Number) { - return isEqualTo((Number) value); - } - else if (value instanceof Boolean) { - return isEqualTo((Boolean) value); - } - else if (value instanceof Pattern) { - return matches(((Pattern) value).pattern()); - } - return isEqualTo(value.toString()); - } - - @Override - public XmlVerifiable isEqualTo(Number value) { - if (value == null) { - return isNull(); - } - return xmlVerifiableFromObject(value); - } - - private XmlVerifiable xmlVerifiableFromObject(Object value) { - ReadyToCheckAsserter readyToCheck = new ReadyToCheckAsserter(this.cachedObjects, this.xPathBuffer, - this.fieldName, this.xmlAsserterConfiguration); - removeLastFieldElement(readyToCheck); - readyToCheck.xPathBuffer.offer("[" + this.fieldName + "=" + String.valueOf(value) + "]"); - // and finally '/foo/bar[baz='sth'] - updateCurrentBuffer(readyToCheck); - readyToCheck.checkBufferedXPathString(); - return readyToCheck; - } - - protected void removeLastFieldElement(XmlAsserter readyToCheck) { - // assuming /foo/bar/baz/ - // remove '/' - readyToCheck.xPathBuffer.removeLast(); - // remove field name ('baz') - readyToCheck.xPathBuffer.removeLast(); - // remove '/' - readyToCheck.xPathBuffer.removeLast(); - // and then we get '/foo/bar' - } - - @Override - public XmlVerifiable isNull() { - ReadyToCheckAsserter readyToCheck = new ReadyToCheckAsserter(this.cachedObjects, this.xPathBuffer, - this.fieldName, this.xmlAsserterConfiguration); - String xpath = createXPathString(); - readyToCheck.xPathBuffer.clear(); - readyToCheck.xPathBuffer.offer("not(boolean(" + xpath + "/text()[1]))"); - updateCurrentBuffer(readyToCheck); - readyToCheck.checkBufferedXPathString(); - return readyToCheck; - } - - @Override - public XmlVerifiable matches(String value) { - if (value == null) { - return isNull(); - } - ReadyToCheckAsserter readyToCheck = new ReadyToCheckAsserter(this.cachedObjects, this.xPathBuffer, - this.fieldName, this.xmlAsserterConfiguration); - removeLastFieldElement(readyToCheck); - readyToCheck.xPathBuffer.offer("[matches(" + this.fieldName + ", " + escapeText(escapeRegex(value)) + ")]"); - updateCurrentBuffer(readyToCheck); - readyToCheck.checkBufferedXPathString(); - return readyToCheck; - } - - @Override - public XmlVerifiable isEqualTo(Boolean value) { - if (value == null) { - return isNull(); - } - return isEqualTo(String.valueOf(value)); - } - - @Override - public XmlVerifiable withoutThrowingException() { - this.xmlAsserterConfiguration.ignoreXPathException = true; - return this; - } - - protected void check(String xPathString) { - if (this.xmlAsserterConfiguration.ignoreXPathException) { - log.trace( - "WARNING!!! Overriding verification of the XPath. Your tests may pass even though they shouldn't"); - return; - } - ResultSequence expr = resultSequence(xPathString); - boolean xpathMatched = !expr.empty(); - if (!xpathMatched) { - throw new IllegalStateException("Parsed XML [" + this.cachedObjects.xmlAsString - + "] doesn't match the XPath <" + xPathString + ">"); - } - } - - ResultSequence resultSequence(String xPathString) { - return xPathExpression(xPathString); - } - - private ResultSequence xPathExpression(String xPathString) { - try { - XPath2Expression expr = new Engine().parseExpression(xPathString, this.cachedObjects.xpathBuilder); - return expr.evaluate(new DynamicContextBuilder(this.cachedObjects.xpathBuilder), - new Object[] { this.cachedObjects.document }); - } - catch (Exception e) { - throw new XmlAsserterXpathException(xPath(), this.cachedObjects.xmlAsString, e); - } - } - - void checkBufferedXPathString() { - check(createXPathString()); - } - - String createXPathString() { - return createXPathString(this.xPathBuffer); - } - - String createSpecialCaseXPathString() { - return createXPathString(this.specialCaseXPathBuffer); - } - - String createXPathString(LinkedList buffer) { - LinkedList queue = new LinkedList(buffer); - StringBuilder stringBuffer = new StringBuilder(); - while (!queue.isEmpty()) { - String value = queue.remove(); - if (!(queue.isEmpty() && value.equals("/"))) { - stringBuffer.append(value); - } - } - return stringBuffer.toString(); - } - - @Override - public String xPath() { - if (!this.specialCaseXPathBuffer.isEmpty()) { - return createSpecialCaseXPathString(); - } - return createXPathString(); - } - - @Override - public void matchesXPath(String xPath) { - check(xPath); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - XmlAsserter that = (XmlAsserter) o; - if (!this.xPathBuffer.equals(that.xPathBuffer)) { - return false; - } - return this.fieldName != null ? this.fieldName.equals(that.fieldName) : that.fieldName == null; - - } - - @Override - public int hashCode() { - int result = this.xPathBuffer.hashCode(); - result = 31 * result + (this.fieldName != null ? this.fieldName.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "\\nAsserter{\n " + "xPathBuffer=" + String.valueOf(this.xPathBuffer) + "\n}"; - } - - @Override - public boolean isIteratingOverArray() { - return false; - } - - @Override - public boolean isAssertingAValueInArray() { - return false; - } - - @Override - public String read() { - String xpath = xPath(); - ResultSequence expr = resultSequence(xpath); - if (expr.empty()) { - throw new XmlAsserterXpathException(xPath(), this.cachedObjects.xmlAsString); - } - if (expr instanceof ElementType) { - return ((ElementType) expr).getStringValue(); - } - throw new UnsupportedOperationException("Can't return values of complex types"); - } - - protected boolean isReadyToCheck() { - return false; - } - - private static class XmlAsserterXpathException extends RuntimeException { - - XmlAsserterXpathException(String xPath, String xmlAsString) { - super("Exception occurred while trying to evaluate " + "XPath [" + xPath + "] from XML [" + xmlAsString - + "]"); - } - - XmlAsserterXpathException(String xPath, String xmlAsString, Exception e) { - super("Exception occurred while trying to evaluate " + "XPath [" + xPath + "] from XML [" + xmlAsString - + "]", e); - } - - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlAsserterConfiguration.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlAsserterConfiguration.java deleted file mode 100644 index 4d293994e7..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlAsserterConfiguration.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util.xml; - -/** - * Assertion configuration. - * - * @author Marcin Grzejszczak - * @since 2.1.0 - */ -class XmlAsserterConfiguration { - - boolean ignoreXPathException = false; - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlAssertion.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlAssertion.java deleted file mode 100644 index 29601be5e0..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlAssertion.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util.xml; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.LinkedList; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.eclipse.wst.xml.xpath2.processor.DOMLoader; -import org.eclipse.wst.xml.xpath2.processor.XercesLoader; -import org.w3c.dom.Document; - -/** - * Entry point for assertions. Use the static factory method and you're ready to go! - * - * @author Marcin Grzejszczak - * @since 2.1.0 - * @see XmlVerifiable - */ -public final class XmlAssertion { - - private static final Map CACHE = new ConcurrentHashMap<>(); - - private final XmlCachedObjects cachedObjects; - - private final LinkedList xPathBuffer = new LinkedList<>(); - - private final LinkedList specialCaseXPathBuffer = new LinkedList<>(); - - private final XmlAsserterConfiguration xmlAsserterConfiguration = new XmlAsserterConfiguration(); - - private XmlAssertion(Document parsedXml) { - this.cachedObjects = new XmlCachedObjects(parsedXml); - } - - private XmlAssertion(String xml) { - XmlCachedObjects cachedObjects = CACHE.get(xml); - if (cachedObjects == null && !empty(xml)) { - try { - InputStream inputXml = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)); - DOMLoader loader = new XercesLoader(); - Document document = loader.load(inputXml); - cachedObjects = new XmlCachedObjects(document, xml); - } - catch (Exception e) { - throw new IllegalStateException("Exception occurred while trying to parse the XML", e); - } - CACHE.put(xml, cachedObjects); - } - this.cachedObjects = cachedObjects; - } - - /** - * Starts assertions for the XML provided as {@link String}. - * @param xml xml to assert - * @return {@link XmlVerifiable} - */ - public static XmlVerifiable assertThat(String xml) { - return new XmlAssertion(xml).root(); - } - - /** - * Starts assertions for the XML provided as {@link Document}. - * @param parsedXml xml to assert - * @return {@link XmlVerifiable} - */ - public static XmlVerifiable assertThat(Document parsedXml) { - return new XmlAssertion(parsedXml).root(); - } - - /** - * Helper method so that there are no clashes with other static methods of that name. - * @param body xml to assert - * @return {@link XmlVerifiable} - * @see XmlAssertion#assertThat(String) - */ - public static XmlVerifiable assertThatXml(String body) { - return assertThat(body); - } - - /** - * Helper method so that there are no clashes with other static methods of that name. - * @param parsedXml xml to assert - * @return {@link XmlVerifiable} - * @see XmlAssertion#assertThat(Document) - */ - public static XmlVerifiable assertThatXml(Document parsedXml) { - return assertThat(parsedXml); - } - - private boolean empty(String text) { - return text == null || text.length() == 0 || text.matches("^\\s*$"); - } - - private XmlVerifiable root() { - return new FieldAssertion(this.cachedObjects, this.xPathBuffer, this.specialCaseXPathBuffer, "", - this.xmlAsserterConfiguration).node(""); - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlCachedObjects.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlCachedObjects.java deleted file mode 100644 index 7056f6a71c..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlCachedObjects.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util.xml; - -import java.io.StringWriter; - -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; - -import org.eclipse.wst.xml.xpath2.processor.util.StaticContextBuilder; -import org.w3c.dom.Document; - -/** - * Contains cached objects that are memory consuming. - * - * @author Marcin Grzejszczak - * @since 2.1.0 - */ -class XmlCachedObjects { - - final Document document; - - final StaticContextBuilder xpathBuilder; - - final String xmlAsString; - - XmlCachedObjects(Document document) { - this.document = document; - this.xpathBuilder = new StaticContextBuilder(); - this.xmlAsString = xmlAsString(); - } - - XmlCachedObjects(Document document, String xmlAsString) { - this.document = document; - this.xpathBuilder = new StaticContextBuilder(); - this.xmlAsString = xmlAsString; - } - - private String xmlAsString() { - try { - TransformerFactory tf = TransformerFactory.newInstance(); - Transformer transformer = tf.newTransformer(); - transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); - StringWriter writer = new StringWriter(); - transformer.transform(new DOMSource(this.document), new StreamResult(writer)); - return writer.getBuffer().toString().replaceAll("\n|\r", ""); - } - catch (TransformerException e) { - throw new RuntimeException("Exception occured while trying to convert XML Document to String", e); - } - } - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlReader.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlReader.java deleted file mode 100644 index ca33cd4a21..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlReader.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util.xml; - -/** - * Contract to read the value from a XML basing on it. - * - * @author Marcin Grzejszczak - * @since 2.1.0 - */ -public interface XmlReader { - - /** - * @return the value from the XML, based on the created XPath. - */ - String read(); - -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlVerifiable.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlVerifiable.java deleted file mode 100644 index ce7c89564e..0000000000 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/xml/XmlVerifiable.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util.xml; - -/** - * Contract to match a parsed XML via XPath. - * - * @author Marcin Grzejszczak - * @author Olga Maciaszek-Sharma - * @author Chris Bono - * @since 2.1.0 - */ -public interface XmlVerifiable extends IteratingOverArray, XmlReader { - - /** - * Field assertion. Adds a XPath entry for a single node. - * @param nodeName name of the node - * @return new {@code XmlVerifiable} - */ - XmlVerifiable node(String nodeName); - - /** - * Field assertion. Adds a XPath entry for a single node that uses a default - * namespace. - * @param nodeName local name of the node - * @param namespace the default namespace uri or null if one of the node ancestor - * declares the namespace - * @return new {@code XmlVerifiable} - */ - XmlVerifiable nodeWithDefaultNamespace(String nodeName, String namespace); - - /** - * Field assertion. Adds a attribute to the currently checked node. NOTE: If you want - * to both check equality and attributes you have to first check the equality and then - * attributes. E.g. having such an XML - * - *

- * - * {@code - - <some> - <nested> - <json>with &quot;val&apos;ue</json> - <anothervalue>4</anothervalue> - <withattr id="a" id2="b">foo</withattr> - <withlist> - <name>name1</name> - </withlist> - <withlist> - <name>name2</name> - </withlist> - <withlist> - 8 - </withlist> - <withlist> - <name id="10" surname="kowalski">name3</name> - </withlist> - </nested> - </some> - * } - * - *

- * - * In order to check the values of the attributes of the {@code withlist} element with - * value {@code name3} you'd have to call: - * - *

- * - * {@code assertThat(xml1).node("some").node("nested") - * .array("withlist").contains("name").isEqualTo("name3") - * .withAttribute("id", "10").withAttribute("surname", "kowalski")} - * - *

- * - * The following XPath would be created: - * {@code /some/nested/withlist[name='name3']/name[@id='10'][@surname='kowalski'] } - * @param attribute attribute name - * @param attributeValue attribute value - * @return new {@code XmlVerifiable} - */ - XmlVerifiable withAttribute(String attribute, String attributeValue); - - /** - * Adds attribute query to xPath without comparing with any provided value. - * @param attribute AttributeName - * @return new {@code XmlVerifiable} - */ - XmlVerifiable withAttribute(String attribute); - - /** - * Adds a {@code text()} call to xPath. - * @return new {@code XmlVerifiable} - */ - XmlVerifiable text(); - - /** - * Adds an index to xPath. - * @param index index of xPath - * @return new {@code XmlVerifiable} - */ - XmlVerifiable index(int index); - - /** - * Field assertions. Traverses through the list of nodes and adds a XPath entry for - * each one. - * @param nodeNames names of nodes - * @return new {@code XmlVerifiable} - */ - XmlVerifiable node(String... nodeNames); - - /** - * When you want to assert values in a array with a given name, e.g. - * - *

- * - * {@code - <list> - <element>foo</element> - <element>bar</element> - <complexElement> - <param>baz</param> - </complexElement> - </list> - * } - * - *

- * The code to check it would look like this: - *

- * - * {@code array("list").contains("element").isEqualTo("foo")} - * {@code array("list").contains("complexElement").node("param").isEqualTo("baz")} - * - *

- * The generated XPaths would be - *

- * - * {@code /list/element[text()='foo']} {@code /list/complexElement[param='baz']} - * @param value element - * @return new {@code XmlVerifiable} - */ - XmlArrayVerifiable array(String value); - - /** - * Equality comparison with String. - * @param value element - * @return new {@code XmlVerifiable} - * @throws IllegalStateException - if XPath is not matched for the parsed XML - */ - XmlVerifiable isEqualTo(String value) throws IllegalStateException; - - /** - * Equality comparison with any object. - * @param value element - * @return new {@code XmlVerifiable} - * @throws IllegalStateException - if XPath is not matched for the parsed XML - */ - XmlVerifiable isEqualTo(Object value) throws IllegalStateException; - - /** - * Equality comparison with a Number. - * @param value element - * @return new {@code XmlVerifiable} - * @throws IllegalStateException - if XPath is not matched for the parsed XML - */ - XmlVerifiable isEqualTo(Number value) throws IllegalStateException; - - /** - * Equality comparison to null. - * @return new {@code XmlVerifiable} - * @throws IllegalStateException - if XPath is not matched for the parsed XML - */ - XmlVerifiable isNull() throws IllegalStateException; - - /** - * Regex matching for strings. - * @param value element - * @return new {@code XmlVerifiable} - * @throws IllegalStateException - if XPath is not matched for the parsed XML - */ - XmlVerifiable matches(String value) throws IllegalStateException; - - /** - * Equality comparison with a Boolean. - * @param value element - * @return new {@code XmlVerifiable} - * @throws IllegalStateException - if XPath is not matched for the parsed XML - */ - XmlVerifiable isEqualTo(Boolean value) throws IllegalStateException; - - /** - * Calling this method will setup the fluent interface to ignore any XPath - * verification. - * @return new {@code XmlVerifiable} - */ - XmlVerifiable withoutThrowingException(); - - /** - * @return current XPath expression - */ - String xPath(); - - /** - * Checks if the parsed document matches given XPath. - * @param xPath xpath value - */ - void matchesXPath(String xPath); - -} diff --git a/spring-cloud-contract-verifier/src/main/resources/META-INF/spring/org.springframework.cloud.contract.verifier.messaging.boot.AutoConfigureMessageVerifier.imports b/spring-cloud-contract-verifier/src/main/resources/META-INF/spring/org.springframework.cloud.contract.verifier.messaging.boot.AutoConfigureMessageVerifier.imports deleted file mode 100644 index d095ad09bd..0000000000 --- a/spring-cloud-contract-verifier/src/main/resources/META-INF/spring/org.springframework.cloud.contract.verifier.messaging.boot.AutoConfigureMessageVerifier.imports +++ /dev/null @@ -1,5 +0,0 @@ -org.springframework.cloud.contract.verifier.messaging.stream.ContractVerifierStreamAutoConfiguration -org.springframework.cloud.contract.verifier.messaging.integration.ContractVerifierIntegrationConfiguration -org.springframework.cloud.contract.verifier.messaging.camel.ContractVerifierCamelConfiguration -org.springframework.cloud.contract.verifier.messaging.jms.ContractVerifierJmsConfiguration -org.springframework.cloud.contract.verifier.messaging.noop.NoOpContractVerifierAutoConfiguration diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/GeneratorScannerSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/GeneratorScannerSpec.groovy deleted file mode 100644 index 224564297e..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/GeneratorScannerSpec.groovy +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier - -import spock.lang.Specification - -import org.springframework.cloud.contract.verifier.builder.SingleTestGenerator -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties - -import static org.springframework.cloud.contract.verifier.config.TestFramework.SPOCK - -class GeneratorScannerSpec extends Specification { - - private SingleTestGenerator classGenerator = Mock(SingleTestGenerator) - - def "should find all json files and generate 6 classes for them"() { - given: - File resource = new File(this.getClass().getResource("/directory/with/stubs/stubsRepositoryIndicator").toURI()) - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() - properties.contractsDslDir = resource.parentFile - TestGenerator testGenerator = new TestGenerator(properties, classGenerator, Stub(FileSaver)) - when: - testGenerator.generateTestClasses("org.springframework.cloud.contract.verifier") - then: - 6 * classGenerator.buildClass(_, _, _, _) >> "qwerty" - } - - def "should create class with full package"() { - given: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties(testFramework: SPOCK) - properties.contractsDslDir = new File(this.getClass().getResource("/directory/with/stubs/package").toURI()) - TestGenerator testGenerator = new TestGenerator(properties, classGenerator, Stub(FileSaver)) - when: - testGenerator.generateTestClasses("org.springframework.cloud.contract.verifier") - then: - 1 * classGenerator.buildClass(_, _, _, { SingleTestGenerator.GeneratedClassData it -> it.className == 'exceptionsSpec' && it.classPackage == 'org.springframework.cloud.contract.verifier' }) >> "spec" - 1 * classGenerator.buildClass(_, _, _, { SingleTestGenerator.GeneratedClassData it -> it.className == 'exceptionsSpec' && it.classPackage == 'org.springframework.cloud.contract.verifier.v1' }) >> "spec1" - 1 * classGenerator.buildClass(_, _, _, { SingleTestGenerator.GeneratedClassData it -> it.className == 'exceptionsSpec' && it.classPackage == 'org.springframework.cloud.contract.verifier.v2' }) >> "spec2" - } - - def "should create class with name with hyphen"() { - given: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties(testFramework: SPOCK) - properties.contractsDslDir = new File(this.getClass().getResource("/directory/with/name-with-hyphen").toURI()) - TestGenerator testGenerator = new TestGenerator(properties, classGenerator, Stub(FileSaver)) - when: - testGenerator.generateTestClasses("org.springframework.cloud.contract.verifier") - then: - 1 * classGenerator.buildClass(_, _, _, { SingleTestGenerator.GeneratedClassData it -> it.className == 'car_rentalSpec' && it.classPackage == 'org.springframework.cloud.contract.verifier' }) >> "spec" - } - -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/MainTest.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/MainTest.groovy deleted file mode 100644 index eb9f1da408..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/MainTest.groovy +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier - -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties -import org.springframework.cloud.contract.verifier.config.TestFramework -import org.springframework.cloud.contract.verifier.config.TestMode - -class MainTest { - - static void main(String[] args) { - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties( - contractsDslDir: new File('/some/path/dsl'), - generatedTestSourcesDir: new File('/tmp/contracts'), - testFramework: TestFramework.SPOCK, testMode: TestMode.MOCKMVC, basePackageForTests: 'io.test', - staticImports: ['com.package.Test.*'], imports: ['org.package.Test'], excludedFiles: ["**/other"]) - println new TestGenerator(properties).generate() - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/TestGeneratorTests.java b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/TestGeneratorTests.java deleted file mode 100644 index 6cb3741a54..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/TestGeneratorTests.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier; - -import java.io.File; -import java.nio.file.Path; -import java.util.LinkedHashMap; - -import org.assertj.core.api.BDDAssertions; -import org.junit.Test; -import org.mockito.BDDMockito; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.verifier.builder.SingleTestGenerator; -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties; -import org.springframework.cloud.contract.verifier.file.ContractFileScanner; -import org.springframework.cloud.contract.verifier.file.ContractMetadata; -import org.springframework.util.CollectionUtils; -import org.springframework.util.MultiValueMap; - -public class TestGeneratorTests { - - @Test - public void should_throw_exception_when_in_progress_contracts_found() { - // given: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties(); - properties.setFailOnInProgress(true); - properties.setContractsDslDir(new File(".")); - SingleTestGenerator singleTestGenerator = BDDMockito.mock(SingleTestGenerator.class); - FileSaver fileSaver = BDDMockito.mock(FileSaver.class); - // and: - MultiValueMap multimap = CollectionUtils.toMultiValueMap(new LinkedHashMap<>()); - Path path = new File(".").toPath(); - multimap.add(path, new ContractMetadata(path, false, 0, null, Contract.make(it -> { - it.inProgress(); - it.request(r -> { - r.method(r.GET()); - r.url("/foo"); - }); - it.response(r -> { - r.status(r.OK()); - }); - }))); - ContractFileScanner scanner = new ContractFileScanner(null, null, null, null, null) { - @Override - public MultiValueMap findContractsRecursively() { - return multimap; - } - }; - // and: - TestGenerator testGenerator = new TestGenerator(properties, singleTestGenerator, fileSaver, scanner); - - // then: - BDDAssertions.thenThrownBy(() -> { - // when: - testGenerator.generateTestClasses("com.example"); - }).isInstanceOf(IllegalStateException.class).hasMessageContaining("In progress contracts found in"); - } - - @Test - public void should_not_throw_exception_when_in_progress_contracts_found_but_the_fail_on_in_progress_switch_is_off() { - // given: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties(); - properties.setFailOnInProgress(false); - properties.setContractsDslDir(new File(".")); - SingleTestGenerator singleTestGenerator = BDDMockito.mock(SingleTestGenerator.class); - FileSaver fileSaver = BDDMockito.mock(FileSaver.class); - // and: - MultiValueMap multimap = CollectionUtils.toMultiValueMap(new LinkedHashMap<>()); - Path path = new File(".").toPath(); - multimap.add(path, new ContractMetadata(path, false, 0, null, Contract.make(it -> { - it.inProgress(); - it.request(r -> { - r.method(r.GET()); - r.url("/foo"); - }); - it.response(r -> { - r.status(r.OK()); - }); - }))); - ContractFileScanner scanner = new ContractFileScanner(null, null, null, null, null) { - @Override - public MultiValueMap findContractsRecursively() { - return multimap; - } - }; - // and: - TestGenerator testGenerator = new TestGenerator(properties, singleTestGenerator, fileSaver, scanner) { - @Override - void processAll(MultiValueMap contracts, String basePackageName) { - } - }; - - // when: - testGenerator.generateTestClasses("com.example"); - - // then: noExceptionThrown() - } - -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/BlockBuilderTests.java b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/BlockBuilderTests.java deleted file mode 100644 index 44fef4a7f6..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/BlockBuilderTests.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import org.assertj.core.api.BDDAssertions; -import org.junit.Test; - -public class BlockBuilderTests { - - @Test - public void should_add_ending_if_no_special_char_is_at_the_end() { - BlockBuilder blockBuilder = blockBuilder(); - - blockBuilder.append("foo").addEndingIfNotPresent(); - - BDDAssertions.then(blockBuilder.toString()).isEqualTo("foo;"); - - blockBuilder = blockBuilder(); - - blockBuilder.append("foo\n").addEndingIfNotPresent(); - BDDAssertions.then(blockBuilder.toString()).isEqualTo("foo;\n"); - - blockBuilder = blockBuilder(); - - blockBuilder.append( - "DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.getPayload()))\n") - .addEndingIfNotPresent(); - BDDAssertions.then(blockBuilder.toString()).isEqualTo( - "DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.getPayload()));\n"); - } - - @Test - public void should_not_add_ending_if_no_char_is_at_the_end() { - BlockBuilder blockBuilder = blockBuilder(); - - blockBuilder.append("foo;").addEndingIfNotPresent(); - BDDAssertions.then(blockBuilder.toString()).isEqualTo("foo;"); - - blockBuilder = blockBuilder(); - - blockBuilder.append("foo {").addEndingIfNotPresent(); - BDDAssertions.then(blockBuilder.toString()).isEqualTo("foo {"); - - blockBuilder = blockBuilder(); - - blockBuilder.append("foo {\n").addEndingIfNotPresent(); - BDDAssertions.then(blockBuilder.toString()).isEqualTo("foo {\n"); - - blockBuilder = blockBuilder(); - - blockBuilder.append("foo;\n").addEndingIfNotPresent(); - BDDAssertions.then(blockBuilder.toString()).isEqualTo("foo;\n"); - } - - @Test - public void should_add_space_if_ends_with_a_text() { - BlockBuilder blockBuilder = blockBuilder(); - - blockBuilder.append("foo").addAtTheEndIfEndsWithAChar(" "); - BDDAssertions.then(blockBuilder.toString()).isEqualTo("foo "); - } - - @Test - public void should_not_add_space_if_does_not_end_with_a_text() { - BlockBuilder blockBuilder = blockBuilder(); - - blockBuilder.append("foo\n").addAtTheEndIfEndsWithAChar(" "); - BDDAssertions.then(blockBuilder.toString()).isEqualTo("foo\n"); - } - - private BlockBuilder blockBuilder() { - BlockBuilder blockBuilder = new BlockBuilder("\t"); - blockBuilder.setupLineEnding(";"); - return blockBuilder; - } - -} \ No newline at end of file diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/BookReturned.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/BookReturned.groovy deleted file mode 100644 index 1ec9c81e55..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/BookReturned.groovy +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder - -import com.fasterxml.jackson.annotation.JsonCreator -import groovy.transform.CompileStatic - -@CompileStatic -class BookReturned implements Serializable { - final String bookName - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - BookReturned(String bookName) { - this.bookName = bookName - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ClassBuilderSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ClassBuilderSpec.groovy deleted file mode 100644 index 96282f9996..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ClassBuilderSpec.groovy +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder - - -import spock.lang.Issue -import spock.lang.Specification - -/** - * @author Marcin Grzejszczak - */ -class ClassBuilderSpec extends Specification { - - def "should return explicit base class if provided and no default package for base classes is provided"() { - given: - Map baseClassMappings = null - String packageWithBaseClasses = null - String baseClassForTests = 'a.b.Class' - expect: - 'a.b.Class' == new BaseClassProvider().retrieveBaseClass(baseClassMappings, packageWithBaseClasses, baseClassForTests, 'com/example/foo') - } - - def "should return a class from the generated path by taking two last folders when package with base classes is provided"() { - given: - Map baseClassMappings = null - String packageWithBaseClasses = 'com.example.base' - String baseClassForTests = null - String contractRelativeFolder = ['com', 'example', 'some', 'superpackage'].join(File.separator) - expect: - new BaseClassProvider().retrieveBaseClass(baseClassMappings, packageWithBaseClasses, baseClassForTests, contractRelativeFolder) == 'com.example.base.SomeSuperpackageBase' - } - - def "should return a class from the generated path by taking two last folders when package with base classes is provided and contains invalid chars"() { - given: - Map baseClassMappings = null - String packageWithBaseClasses = 'com.example.base' - String baseClassForTests = null - String contractRelativeFolder = ['com', 'example', 'beer-api-producer-external', 'beer-api-consumer'].join(File.separator) - expect: - new BaseClassProvider().retrieveBaseClass(baseClassMappings, packageWithBaseClasses, baseClassForTests, contractRelativeFolder) == 'com.example.base.Beer_api_producer_externalBeer_api_consumerBase' - } - - def "should return a class from the generated path by taking a single folder when package with base classes is provided and there are not enough package elements"() { - given: - Map baseClassMappings = null - String packageWithBaseClasses = 'com.example.base' - String baseClassForTests = null - String contractRelativeFolder = 'superpackage' - expect: - new BaseClassProvider().retrieveBaseClass(baseClassMappings, packageWithBaseClasses, baseClassForTests, contractRelativeFolder) == 'com.example.base.SuperpackageBase' - } - - def "should return a class from mappings regardless of other entries if mapping exists"() { - given: - Map baseClassMappings = ['.*': 'com.example.base.SuperClass'] - String packageWithBaseClasses = 'com.example.base' - String baseClassForTests = null - String contractRelativeFolder = 'superpackage' - expect: - new BaseClassProvider().retrieveBaseClass(baseClassMappings, packageWithBaseClasses, baseClassForTests, contractRelativeFolder) == 'com.example.base.SuperClass' - } - - @Issue("701") - def "should match base class when mapping regex has multiple folders"() { - given: - Map baseClassMappings = ['.*bar.baz.some.*': 'com.example.base.SuperClass'] - String packageWithBaseClasses = null - String baseClassForTests = null - String contractRelativeFolder = 'foo/bar/baz/some/package'.split("/").join(File.separator) - expect: - new BaseClassProvider().retrieveBaseClass(baseClassMappings, packageWithBaseClasses, baseClassForTests, contractRelativeFolder) == 'com.example.base.SuperClass' - } - - def "should return the first matching base class when provided mapping doesn't match"() { - given: - Map baseClassMappings = ['patternNotMatchingAnything': 'com.example.base.SuperClass'] - String packageWithBaseClasses = 'com.example.base' - String baseClassForTests = 'a.b.Class' - String contractRelativeFolder = 'superpackage' - expect: - new BaseClassProvider().retrieveBaseClass(baseClassMappings, packageWithBaseClasses, baseClassForTests, contractRelativeFolder) == 'com.example.base.SuperpackageBase' - } - - def "should return a class from the generated path by when external contracts are picked"() { - given: - Map baseClassMappings = null - String packageWithBaseClasses = 'foo.Bar' - String baseClassForTests = null - String contractRelativeFolder = ["org", "springframework", "cloud", "contract", "verifier", "tests", "META_INF", "com.example", "hello_world", "0.1.0_dev.1.uncommitted+d1174dd"].join(File.separator) - expect: - new BaseClassProvider().retrieveBaseClass(baseClassMappings, packageWithBaseClasses, baseClassForTests, contractRelativeFolder) == 'foo.Bar.Hello_world0_1_0_dev_1_uncommitted_d1174ddBase' - } - -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy deleted file mode 100644 index 954e58e51f..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder - -import spock.lang.Shared -import spock.lang.Specification - -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties -import org.springframework.cloud.contract.verifier.config.TestFramework -import org.springframework.cloud.contract.verifier.config.TestMode -import org.springframework.cloud.contract.verifier.file.ContractMetadata -import org.springframework.cloud.contract.verifier.util.SyntaxChecker - -/** - * Tests used for the documentation - * - * @author Marcin Grzejszczak - */ -class ContractHttpDocsSpec extends Specification { - - @Shared - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties(assertJsonSize: true) - - @Shared - GeneratedClassDataForMethod generatedClassDataForMethod = new GeneratedClassDataForMethod( - new SingleTestGenerator.GeneratedClassData("foo", "bar", new File(".").toPath()), "method") - - @Shared - SingleTestGenerator.GeneratedClassData generatedClassData = - new SingleTestGenerator.GeneratedClassData("foo", "com.example", new File(".").toPath()) - - def setup() { - properties = new ContractVerifierConfigProperties( - assertJsonSize: true - ) - } - - private String singleTestGenerator(Contract contractDsl) { - return new JavaTestGenerator() { - @Override - ClassBodyBuilder classBodyBuilder(BlockBuilder builder, GeneratedClassMetaData metaData, SingleMethodBuilder methodBuilder) { - return super.classBodyBuilder(builder, metaData, methodBuilder).field(new Field() { - @Override - boolean accept() { - return metaData.configProperties.testMode == TestMode.JAXRSCLIENT - } - - @Override - Field call() { - builder.addLine("WebTarget webTarget") - return this - } - }) - } - }.buildClass(properties, [contractMetadata(contractDsl)], "foo", generatedClassData) - } - - private ContractMetadata contractMetadata(Contract contractDsl) { - return new ContractMetadata(new File(".").toPath(), false, 0, null, contractDsl) - } - - org.springframework.cloud.contract.spec.Contract httpDsl = - // tag::http_dsl[] - org.springframework.cloud.contract.spec.Contract.make { - // Definition of HTTP request part of the contract - // (this can be a valid request or invalid depending - // on type of contract being specified). - request { - method GET() - url "/foo" - //... - } - - // Definition of HTTP response part of the contract - // (a service implementing this contract should respond - // with following response after receiving request - // specified in "request" part above). - response { - status 200 - //... - } - - // Contract priority, which can be used for overriding - // contracts (1 is highest). Priority is optional. - priority 1 - } - // end::http_dsl[] - - org.springframework.cloud.contract.spec.Contract methodDsl = - org.springframework.cloud.contract.spec.Contract.make { - request { - // tag::method[] - method GET() - // end::method[] - url "/foo" - } - - response { - status 200 - } - - priority 1 - } - - org.springframework.cloud.contract.spec.Contract request = - // tag::request[] - org.springframework.cloud.contract.spec.Contract.make { - request { - // HTTP request method (GET/POST/PUT/DELETE). - method 'GET' - - // Path component of request URL is specified as follows. - urlPath('/users') - } - - response { - //... - status 200 - } - } - // end::request[] - - org.springframework.cloud.contract.spec.Contract url = - // tag::url[] - org.springframework.cloud.contract.spec.Contract.make { - request { - method 'GET' - - // Specifying `url` and `urlPath` in one contract is illegal. - url('http://localhost:8888/users') - } - - response { - //... - status 200 - } - } - // end::url[] - - org.springframework.cloud.contract.spec.Contract urlPaths = - // tag::urlpath[] - org.springframework.cloud.contract.spec.Contract.make { - request { - //... - method GET() - - urlPath('/users') { - - // Each parameter is specified in form - // `'paramName' : paramValue` where parameter value - // may be a simple literal or one of matcher functions, - // all of which are used in this example. - queryParameters { - - // If a simple literal is used as value - // default matcher function is used (equalTo) - parameter 'limit': 100 - - // `equalTo` function simply compares passed value - // using identity operator (==). - parameter 'filter': equalTo("email") - - // `containing` function matches strings - // that contains passed substring. - parameter 'gender': value(consumer(containing("[mf]")), producer('mf')) - - // `matching` function tests parameter - // against passed regular expression. - parameter 'offset': value(consumer(matching("[0-9]+")), producer(123)) - - // `notMatching` functions tests if parameter - // does not match passed regular expression. - parameter 'loginStartsWith': value(consumer(notMatching(".{0,2}")), producer(3)) - } - } - - //... - } - - response { - //... - status 200 - } - } - // end::urlpath[] - - org.springframework.cloud.contract.spec.Contract headers = - // tag::headers[] - org.springframework.cloud.contract.spec.Contract.make { - request { - //... - method GET() - url "/foo" - - // Each header is added in form `'Header-Name' : 'Header-Value'`. - // there are also some helper methods - headers { - header 'key': 'value' - contentType(applicationJson()) - } - - //... - } - - response { - //... - status 200 - } - } - // end::headers[] - - org.springframework.cloud.contract.spec.Contract cookies = - // tag::cookies[] - org.springframework.cloud.contract.spec.Contract.make { - request { - //... - method GET() - url "/foo" - - // Each Cookies is added in form `'Cookie-Key' : 'Cookie-Value'`. - // there are also some helper methods - cookies { - cookie 'key': 'value' - cookie('another_key', 'another_value') - } - - //... - } - - response { - //... - status 200 - } - } - // end::cookies[] - - org.springframework.cloud.contract.spec.Contract body = - // tag::body[] - org.springframework.cloud.contract.spec.Contract.make { - request { - //... - method GET() - url "/foo" - - // Currently only JSON format of request body is supported. - // Format will be determined from a header or body's content. - body '''{ "login" : "john", "name": "John The Contract" }''' - } - - response { - //... - status 200 - } - } - // end::body[] - - org.springframework.cloud.contract.spec.Contract bodyAsXml = - // tag::bodyAsXml[] - org.springframework.cloud.contract.spec.Contract.make { - request { - //... - method GET() - url "/foo" - - // In this case body will be formatted as XML. - body equalToXml( - '''johnJohn The Contract''' - ) - } - - response { - //... - status 200 - } - } - // end::bodyAsXml[] - - org.springframework.cloud.contract.spec.Contract response = - // tag::response[] - org.springframework.cloud.contract.spec.Contract.make { - request { - //... - method GET() - url "/foo" - } - response { - // Status code sent by the server - // in response to request specified above. - status OK() - } - } - // end::response[] - - org.springframework.cloud.contract.spec.Contract regex = - // tag::regex[] - org.springframework.cloud.contract.spec.Contract.make { - request { - method('GET') - url $(consumer(~/\/[0-9]{2}/), producer('/12')) - } - response { - status OK() - body( - id: $(anyNumber()), - surname: $( - consumer('Kowalsky'), - producer(regex('[a-zA-Z]+')) - ), - name: 'Jan', - created: $(consumer('2014-02-02 12:23:43'), producer(execute('currentDate(it)'))), - correlationId: value(consumer('5d1f9fef-e0dc-4f3d-a7e4-72d2220dd827'), - producer(regex('[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}')) - ) - ) - headers { - header 'Content-Type': 'text/plain' - } - } - } - // end::regex[] - - org.springframework.cloud.contract.spec.Contract optionals = - // tag::optionals[] - org.springframework.cloud.contract.spec.Contract.make { - priority 1 - name "optionals" - request { - method 'POST' - url '/users/password' - headers { - contentType(applicationJson()) - } - body( - email: $(consumer(optional(regex(email()))), producer('abc@abc.com')), - callback_url: $(consumer(regex(hostname())), producer('https://partners.com')) - ) - } - response { - status 404 - headers { - header 'Content-Type': 'application/json' - } - body( - code: value(consumer("123123"), producer(optional("123123"))) - ) - } - } - // end::optionals[] - - def 'should convert dsl with optionals to proper Spock test'() { - given: - properties.testFramework = TestFramework.SPOCK - String test = singleTestGenerator(optionals) - expect: - String expectedTest = - """\ -// tag::optionals_test[] -package com.example - -import com.jayway.jsonpath.DocumentContext -import com.jayway.jsonpath.JsonPath -import spock.lang.Specification -import io.restassured.module.mockmvc.specification.MockMvcRequestSpecification -import io.restassured.response.ResponseOptions - -import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.* -import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson -import static io.restassured.module.mockmvc.RestAssuredMockMvc.* - -@SuppressWarnings("rawtypes") -class FooSpec extends Specification { - -\tdef validate_optionals() throws Exception { -\t\tgiven: -\t\t\tMockMvcRequestSpecification request = given() -\t\t\t\t\t.header("Content-Type", "application/json") -\t\t\t\t\t.body('''{"email":"abc@abc.com","callback_url":"https://partners.com"}''') - -\t\twhen: -\t\t\tResponseOptions response = given().spec(request) -\t\t\t\t\t.post("/users/password") - -\t\tthen: -\t\t\tresponse.statusCode() == 404 -\t\t\tresponse.header("Content-Type") == 'application/json' - -\t\tand: -\t\t\tDocumentContext parsedJson = JsonPath.parse(response.body.asString()) -\t\t\tassertThatJson(parsedJson).field("['code']").matches("(123123)?") -\t} - -} -// end::optionals_test[] -""" - - test.trim() - .replace("\\\t", "\t") == expectedTest.trim() - .replace(" ", "\t") - .replace("\\\t", "\t") - .replace("// tag::optionals_test[]\n", "") - .replace("\n// end::optionals_test[]", "") - and: - SyntaxChecker.tryToCompile("spock", test) - } - - org.springframework.cloud.contract.spec.Contract method = - // tag::methodBuilder[] - org.springframework.cloud.contract.spec.Contract.make { - request { - method 'PUT' - url $(consumer(regex('^/api/[0-9]{2}$')), producer('/api/12')) - headers { - header 'Content-Type': 'application/json' - } - body '''\ - [{ - "text": "Gonna see you at Warsaw" - }] - ''' - } - response { - body( - path: $(consumer('/api/12'), producer(regex('^/api/[0-9]{2}$'))), - correlationId: $(consumer('1223456'), producer(execute('isProperCorrelationId($it)'))) - ) - status OK() - } - } - // end::methodBuilder[] -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/GeneratedTestClassTests.java b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/GeneratedTestClassTests.java deleted file mode 100644 index 61790ecc3d..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/GeneratedTestClassTests.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Collection; -import java.util.Collections; - -import org.assertj.core.api.BDDAssertions; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties; -import org.springframework.cloud.contract.verifier.config.TestFramework; -import org.springframework.cloud.contract.verifier.file.ContractMetadata; -import org.springframework.util.FileSystemUtils; - -import static org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter.convertAsCollection; - -public class GeneratedTestClassTests { - - // @formatter:off - String contract = "org.springframework.cloud.contract.spec.Contract.make {\n" - + " name \"foo\"\n" - + " request {\n" - + " method 'PUT'\n" - + " url 'url'\n" - + " headers {\n" - + " header('foo', 'bar')\n" - + " }\n" - + " body (\n" - + " [\"foo1\":\"bar1\"]\n" - + " )\n" - + " }\n" - + " response {\n" - + " status OK()\n" - + " headers {\n" - + " header('foo2', 'bar2')\n" - + " }\n" - + " body (\n" - + " [\"foo3\":\"bar3\"]\n" - + " )\n" - + " }\n" - + "}"; - // @formatter:on - - // @formatter:off - String expectedTest = "package test;\n" -+ "\n" -+ "import BazBar;\n" -+ "import com.jayway.jsonpath.DocumentContext;\n" -+ "import com.jayway.jsonpath.JsonPath;\n" -+ "import org.junit.Test;\n" -+ "import org.junit.Rule;\n" -+ "import org.junit.Ignore;\n" -+ "import org.junit.FixMethodOrder;\n" -+ "import org.junit.runners.MethodSorters;\n" -+ "import io.restassured.module.mockmvc.specification.MockMvcRequestSpecification;\n" -+ "import io.restassured.response.ResponseOptions;\n" -+ "\n" -+ "import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat;\n" -+ "import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.*;\n" -+ "import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson;\n" -+ "import static io.restassured.module.mockmvc.RestAssuredMockMvc.*;\n" -+ "\n" -+ "@SuppressWarnings(\"rawtypes\")\n" -+ "@FixMethodOrder(MethodSorters.NAME_ASCENDING)\n" -+ "public class FooBarTest extends BazBar {\n" -+ "\n" -+ "\t@Test\n" -+ "\t@Ignore\n" -+ "\tpublic void validate_foo() throws Exception {\n" -+ "\t\t// given:\n" -+ "\t\t\tMockMvcRequestSpecification request = given()\n" -+ "\t\t\t\t\t.header(\"foo\", \"bar\")\n" -+ "\t\t\t\t\t.body(\"{\\\"foo1\\\":\\\"bar1\\\"}\");\n" -+ "\n" -+ "\t\t// when:\n" -+ "\t\t\tResponseOptions response = given().spec(request)\n" -+ "\t\t\t\t\t.put(\"url\");\n" -+ "\n" -+ "\t\t// then:\n" -+ "\t\t\tassertThat(response.statusCode()).isEqualTo(200);\n" -+ "\t\t\tassertThat(response.header(\"foo2\")).isEqualTo(\"bar2\");\n" -+ "\n" -+ "\t\t// and:\n" -+ "\t\t\tDocumentContext parsedJson = JsonPath.parse(response.getBody().asString());\n" -+ "\t\t\tassertThatJson(parsedJson).field(\"['foo3']\").isEqualTo(\"bar3\");\n" -+ "\t}\n" -+ "\n" -+ "}\n"; - // @formatter:on - - @Rule - public TemporaryFolder tmpFolder = new TemporaryFolder(); - - File file; - - File tmp; - - @Before - public void setup() throws IOException, URISyntaxException { - this.file = this.tmpFolder.newFile(); - Files.write(this.file.toPath(), this.contract.getBytes()); - this.tmp = this.tmpFolder.newFolder(); - File classpath = new File(GeneratedTestClassTests.class.getResource("/classpath/").toURI()); - FileSystemUtils.copyRecursively(classpath, this.tmp); - } - - @Test - public void should_work_for_junit4_mockmvc_json_non_binary() { - // given - JavaTestGenerator generator = new JavaTestGenerator(); - ContractVerifierConfigProperties configProperties = new ContractVerifierConfigProperties(); - configProperties.setTestFramework(TestFramework.JUNIT); - Collection contracts = Collections.singletonList( - new ContractMetadata(this.file.toPath(), true, 1, 2, convertAsCollection(new File("/"), this.file))); - String includedDirectoryRelativePath = "some/path"; - String convertedClassName = "fooBar"; - String packageName = "test"; - Path classPath = new File("/tmp").toPath(); - configProperties.setBaseClassForTests("BazBar"); - - // when - String builtClass = generator.buildClass(configProperties, contracts, includedDirectoryRelativePath, - new SingleTestGenerator.GeneratedClassData(convertedClassName, packageName, classPath)); - - // then - BDDAssertions.then(builtClass).isEqualTo(this.expectedTest); - } - -} \ No newline at end of file diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientMethodBuilderSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientMethodBuilderSpec.groovy deleted file mode 100644 index 21297a4631..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientMethodBuilderSpec.groovy +++ /dev/null @@ -1,1590 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder - -import com.jayway.jsonpath.DocumentContext -import com.jayway.jsonpath.JsonPath -import spock.lang.Issue -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll -import spock.util.environment.RestoreSystemProperties - -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties -import org.springframework.cloud.contract.verifier.config.TestFramework -import org.springframework.cloud.contract.verifier.config.TestMode -import org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockStubStrategy -import org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockStubVerifier -import org.springframework.cloud.contract.verifier.file.ContractMetadata -import org.springframework.cloud.contract.verifier.util.SyntaxChecker - -class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStubVerifier { - - @Shared - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties( - assertJsonSize: true - ) - - @Shared - SingleTestGenerator.GeneratedClassData generatedClassData = - new SingleTestGenerator.GeneratedClassData("foo", "com.example", new File(".").toPath()) - - @Shared - GeneratedClassDataForMethod generatedClassDataForMethod = new GeneratedClassDataForMethod( - new SingleTestGenerator.GeneratedClassData("foo", "bar", new File(".").toPath()), "method") - - def setup() { - properties = new ContractVerifierConfigProperties( - assertJsonSize: true, - testMode: TestMode.JAXRSCLIENT - ) - } - - private String singleTestGenerator(Contract contractDsl) { - return new JavaTestGenerator() { - @Override - ClassBodyBuilder classBodyBuilder(BlockBuilder builder, GeneratedClassMetaData metaData, SingleMethodBuilder methodBuilder) { - return super.classBodyBuilder(builder, metaData, methodBuilder).field(new Field() { - @Override - boolean accept() { - return metaData.configProperties.testMode == TestMode.JAXRSCLIENT - } - - @Override - Field call() { - builder.addLine("WebTarget webTarget") - return this - } - }) - } - }.buildClass(properties, [contractMetadata(contractDsl)], "foo", generatedClassData) - } - - private GeneratedClassMetaData generatedClassMetaData(Contract contractDsl) { - new GeneratedClassMetaData(properties, [contractMetadata(contractDsl)], "foo", generatedClassData) - } - - ContractMetadata contractMetadata(Contract contractDsl) { - return new ContractMetadata(new File(".").toPath(), false, 0, null, contractDsl) - } - - @Shared - // tag::contract_with_cookies[] - Contract contractDslWithCookiesValue = Contract.make { - request { - method "GET" - url "/foo" - headers { - header 'Accept': 'application/json' - } - cookies { - cookie 'cookie-key': 'cookie-value' - } - } - response { - status 200 - headers { - header 'Content-Type': 'application/json' - } - cookies { - cookie 'cookie-key': 'new-cookie-value' - } - body([status: 'OK']) - } - } - // end::contract_with_cookies[] - - @Shared - Contract contractDslWithCookiesPattern = Contract.make { - request { - method "GET" - url "/foo" - headers { - header 'Accept': 'application/json' - } - cookies { - cookie 'cookie-key': regex('[A-Za-z]+') - } - } - response { - status 200 - headers { - header 'Content-Type': 'application/json' - } - cookies { - cookie 'cookie-key': regex('[A-Za-z]+') - } - body([status: 'OK']) - } - } - - @Shared - Contract contractDslWithAbsentCookies = Contract.make { - request { - method "GET" - url "/foo" - cookies { - cookie 'cookie-key': absent() - } - } - response { - status 200 - body([status: 'OK']) - } - } - - def "should generate assertions for simple response body with #methodBuilderName"() { - given: - Contract contractDsl = Contract.make { - request { - method "GET" - url "test" - } - response { - status OK() - body """{ - "property1": "a", - "property2": "b" -}""" - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("a")""") - test.contains("""assertThatJson(parsedJson).field("['property2']").isEqualTo("b")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - } - - @Issue("#187") - def "should generate assertions for null and boolean values with #methodBuilderName"() { - given: - Contract contractDsl = Contract.make { - request { - method "GET" - url "test" - } - response { - status OK() - body """{ - "property1": "true", - "property2": null, - "property3": false -}""" - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).field("['property3']").isEqualTo(false)""") - test.contains("""assertThatJson(parsedJson).field("['property2']").isNull()""") - test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("true")""") - and: - stubMappingIsValidWireMockStub(new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, contractDsl), contractDsl).toWireMockClientStub()) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - } - - @Issue("#79") - def "should generate assertions for simple response body constructed from map with a list with #methodBuilderName"() { - given: - Contract contractDsl = Contract.make { - request { - method "GET" - url "test" - } - response { - status OK() - body( - property1: 'a', - property2: [ - [a: 'sth'], - [b: 'sthElse'] - ] - ) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("a")""") - test.contains("""assertThatJson(parsedJson).array("['property2']").contains("['a']").isEqualTo("sth")""") - test.contains("""assertThatJson(parsedJson).array("['property2']").contains("['b']").isEqualTo("sthElse")""") - and: - stubMappingIsValidWireMockStub(new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, contractDsl), contractDsl).toWireMockClientStub()) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - } - - @Issue("#79") - @RestoreSystemProperties - def "should generate assertions for simple response body constructed from map with a list with #methodBuilderName with array size check"() { - given: - System.setProperty('spring.cloud.contract.verifier.assert.size', 'true') - Contract contractDsl = Contract.make { - request { - method "GET" - url "test" - } - response { - status OK() - body( - property1: 'a', - property2: [ - [a: 'sth'], - [b: 'sthElse'] - ] - ) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("a")""") - test.contains("""assertThatJson(parsedJson).array("['property2']").contains("['a']").isEqualTo("sth")""") - test.contains("""assertThatJson(parsedJson).array("['property2']").hasSize(2)""") - test.contains("""assertThatJson(parsedJson).array("['property2']").contains("['b']").isEqualTo("sthElse")""") - and: - stubMappingIsValidWireMockStub(new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, contractDsl), contractDsl).toWireMockClientStub()) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - } - - @Issue("#82") - def "should generate proper request when body constructed from map with a list with #methodBuilderName"() { - given: - Contract contractDsl = Contract.make { - request { - method "GET" - url "test" - body( - items: ['HOP'] - ) - } - response { - status OK() - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains(bodyString) - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | bodyString - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } | """entity("{\\"items\\":[\\"HOP\\"]}", "application/json")""" - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } | 'entity("{\\"items\\":[\\"HOP\\"]}", "application/json")' - } - - @Issue("#88") - def "should generate proper request when body constructed from GString with #methodBuilderName"() { - given: - Contract contractDsl = Contract.make { - request { - method "GET" - url "test" - body( - "property1=VAL1" - ) - } - response { - status OK() - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains(bodyString) - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | bodyString - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } | """entity("property1=VAL1", "application/octet-stream")""" - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } | 'entity("property1=VAL1", "application/octet-stream")' - } - - def "should generate assertions for array in response body with #methodBuilderName"() { - given: - Contract contractDsl = Contract.make { - request { - method "GET" - url "test" - } - response { - status OK() - body """[ -{ - "property1": "a" -}, -{ - "property2": "b" -}]""" - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).array().contains("['property1']").isEqualTo("a")""") - test.contains("""assertThatJson(parsedJson).array().contains("['property2']").isEqualTo("b")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - } - - def "should generate assertions for array inside response body element with #methodBuilderName"() { - given: - Contract contractDsl = Contract.make { - request { - method "GET" - url "test" - } - response { - status OK() - body """{ - "property1": [ - { "property2": "test1"}, - { "property3": "test2"} - ] -}""" - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).array("['property1']").contains("['property2']").isEqualTo("test1")""") - test.contains("""assertThatJson(parsedJson).array("['property1']").contains("['property3']").isEqualTo("test2")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - } - - def "should generate assertions for nested objects in response body with #methodBuilderName"() { - given: - Contract contractDsl = Contract.make { - request { - method "GET" - url "test" - } - response { - status OK() - body '''\ -{ - "property1": "a", - "property2": {"property3": "b"} -} -''' - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).field("['property2']").field("['property3']").isEqualTo("b")""") - test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("a")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - } - - @Unroll - def "should generate regex assertions for map objects in response body with #methodBuilderName"() { - given: - Contract contractDsl = Contract.make { - request { - method "GET" - url "test" - } - response { - status OK() - body( - property1: "a", - property2: value( - consumer('123'), - producer(regex('[0-9]{3}')) - ) - ) - headers { - header('Content-Type': 'application/json') - } - - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).field("['property2']").matches("[0-9]{3}")""") - test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("a")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - } - - def "should generate regex assertions for string objects in response body with #methodBuilderName"() { - given: - Contract contractDsl = Contract.make { - request { - method "GET" - url "test" - } - response { - status OK() - body("""{"property1":"a","property2":"${value(consumer('123'), producer(regex('[0-9]{3}')))}"}""") - headers { - header('Content-Type': 'application/json') - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).field("['property2']").matches("[0-9]{3}")""") - test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("a")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - } - - def "should ignore 'Accept' header and use 'request' method with #methodBuilderName"() { - given: - Contract contractDsl = Contract.make { - request { - method "GET" - url "test" - headers { - header("Accept", "text/plain") - } - } - response { - status OK() - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains(requestString) - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | requestString - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } | 'request("text/plain")' - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } | 'request("text/plain")' - } - - def "should ignore 'Content-Type' header and use 'entity' method with #methodBuilderName"() { - given: - Contract contractDsl = Contract.make { - request { - method "GET" - url "test" - headers { - header("Content-Type", "text/plain") - header("Timer", "123") - } - body '' - } - response { - status OK() - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - for (String requestString : requestStrings) { - test.contains(requestString) - } - !test.contains("""Content Type""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | requestStrings - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } | ["""entity('', 'text/plain')""", """header('Timer', '123')"""] - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } | ['entity("\\"\\"", "text/plain")', 'header("Timer", "123")'] - } - - def "should generate a call with an url path and query parameters with jaxrs"() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath('/users') { - queryParameters { - parameter 'limit': $(consumer(equalTo("20")), producer(equalTo("10"))) - parameter 'offset': $(consumer(containing("20")), producer(equalTo("20"))) - parameter 'filter': "email" - parameter 'sort': equalTo("name") - parameter 'search': $(consumer(notMatching(~/^\/[0-9]{2}$/)), producer("55")) - parameter 'age': $(consumer(notMatching("^\\w*\$")), producer("99")) - parameter 'name': $(consumer(matching("Denis.*")), producer("Denis.Stepanov")) - parameter 'nameWithDoubleQuote': '"quote"' - parameter 'nameWithQuote': "'quote'" - parameter 'email': "bob@email.com" - parameter 'hello': $(consumer(matching("Denis.*")), producer(absent())) - parameter 'hello': absent() - } - } - } - response { - status OK() - body """ - { - "property1": "a", - "property2": "b" - } - """ - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('''queryParam("limit", "10"''') - test.contains('''queryParam("offset", "20"''') - test.contains('''queryParam("filter", "email"''') - test.contains('''queryParam("sort", "name"''') - test.contains('''queryParam("search", "55"''') - test.contains('''queryParam("age", "99"''') - test.contains('''queryParam("name", "Denis.Stepanov"''') - test.contains('''queryParam("nameWithDoubleQuote", "\\"quote\\""''') - test.contains('''queryParam("nameWithQuote", "'quote'"''') - test.contains('''queryParam("email", "bob@email.com"''') - test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("a")""") - test.contains("""assertThatJson(parsedJson).field("['property2']").isEqualTo("b")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - } - - def "should generate a call with an url path and query parameters with jaxrs-spock"() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath('/users') { - queryParameters { - parameter 'limit': $(consumer(equalTo("20")), producer(equalTo("10"))) - parameter 'offset': $(consumer(containing("20")), producer(equalTo("20"))) - parameter 'filter': "email" - parameter 'sort': equalTo("name") - parameter 'search': $(consumer(notMatching(~/^\/[0-9]{2}$/)), producer("55")) - parameter 'age': $(consumer(notMatching("^\\w*\$")), producer("99")) - parameter 'name': $(consumer(matching("Denis.*")), producer("Denis.Stepanov")) - parameter 'nameWithDoubleQuote': '"quote"' - parameter 'nameWithQuote': "'quote'" - parameter 'email': "bob@email.com" - parameter 'hello': $(consumer(matching("Denis.*")), producer(absent())) - parameter 'hello': absent() - } - } - } - response { - status OK() - body """ - { - "property1": "a", - "property2": "b" - } - """ - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('''queryParam("limit", '10\'''') - test.contains('''queryParam("offset", '20\'''') - test.contains('''queryParam("filter", 'email\'''') - test.contains('''queryParam("sort", 'name\'''') - test.contains('''queryParam("search", '55\'''') - test.contains('''queryParam("age", '99\'''') - test.contains('''queryParam("name", 'Denis.Stepanov\'''') - test.contains("""queryParam("nameWithDoubleQuote", '''"quote"'''""") - test.contains("""queryParam("nameWithQuote", '''\\'quote\\''''""") - test.contains('''queryParam("email", 'bob@email.com\'''') - test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("a")""") - test.contains("""assertThatJson(parsedJson).field("['property2']").isEqualTo("b")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - } - - @Issue('#169') - def "should generate a call with an url path and query parameters with url containing a pattern with #methodBuilderName"() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url($(consumer(regex('/foo/[0-9]+')), producer('/foo/123456'))) { - queryParameters { - parameter 'limit': $(consumer(equalTo("20")), producer(equalTo("10"))) - parameter 'offset': $(consumer(containing("20")), producer(equalTo("20"))) - parameter 'filter': "email" - parameter 'sort': equalTo("name") - parameter 'search': $(consumer(notMatching(~/^\/[0-9]{2}$/)), producer("55")) - parameter 'age': $(consumer(notMatching("^\\w*\$")), producer("99")) - parameter 'name': $(consumer(matching("Denis.*")), producer("Denis.Stepanov")) - parameter 'email': "bob@email.com" - parameter 'hello': $(consumer(matching("Denis.*")), producer(absent())) - parameter 'hello': absent() - } - } - } - response { - status OK() - body """ - { - "property1": "a", - "property2": "b" - } - """ - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains(modifyStringIfRequired.call('''queryParam("limit", '10\'''')) - test.contains(modifyStringIfRequired.call('''queryParam("offset", '20\'''')) - test.contains(modifyStringIfRequired.call('''queryParam("filter", 'email\'''')) - test.contains(modifyStringIfRequired.call('''queryParam("sort", 'name\'''')) - test.contains(modifyStringIfRequired.call('''queryParam("search", '55\'''')) - test.contains(modifyStringIfRequired.call('''queryParam("age", '99\'''')) - test.contains(modifyStringIfRequired.call('''queryParam("name", 'Denis.Stepanov\'''')) - test.contains(modifyStringIfRequired.call('''queryParam("email", 'bob@email.com\'''')) - test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("a")""") - test.contains("""assertThatJson(parsedJson).field("['property2']").isEqualTo("b")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | modifyStringIfRequired - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } | { String paramString -> paramString } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } | { String paramString -> paramString.replace("'", "\"") } - } - - def "should generate test for empty body with #methodBuilderName"() { - given: - Contract contractDsl = Contract.make { - request { - method('POST') - url("/ws/payments") - body("") - } - response { - status 406 - } - } - - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains(bodyString) - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | bodyString - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } | """entity("", "application/octet-stream")""" - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } | """entity("", "application/octet-stream")""" - } - - def "should not parse the response body if there is no response body specified in the contract"() { - given: - Contract contractDsl = Contract.make { - request { - method "HEAD" - url "head" - } - response { - status OK() - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - !test.contains(bodyParsingString) - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | bodyParsingString - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } | "String responseAsString = response.readEntity(String)" - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } | "String responseAsString = response.readEntity(String.class);" - } - - def "should generate test for String in response body with #methodBuilderName"() { - given: - Contract contractDsl = Contract.make { - request { - method "POST" - url "test" - } - response { - status OK() - body "test" - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains(bodyDefinitionString) - test.contains(bodyEvaluationString) - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | bodyDefinitionString | bodyEvaluationString - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } | "String responseAsString = response.readEntity(String)" | 'responseBody == "test"' - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } | 'String responseBody = responseAsString;' | 'assertThat(responseBody).isEqualTo("test");' - } - - @Issue('#171') - def "should generate test with uppercase method name with #methodBuilderName"() { - given: - Contract contractDsl = Contract.make { - request { - method "get" - url "/v1/some_cool_requests/e86df6f693de4b35ae648464c5b0dc08" - } - response { - status OK() - headers { - contentType(applicationJson()) - } - body """ -{"id":"789fgh","other_data":1268} -""" - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains(methodString) - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | methodString - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } | '.build("GET")' - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } | 'build("GET")' - } - - def "should generate a call with an url path and query parameters with JUnit - we'll put it into docs"() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath('/users') { - queryParameters { - parameter 'limit': $(consumer(equalTo("20")), producer(equalTo("10"))) - parameter 'offset': $(consumer(containing("20")), producer(equalTo("20"))) - parameter 'filter': "email" - parameter 'sort': equalTo("name") - parameter 'search': $(consumer(notMatching(~/^\/[0-9]{2}$/)), producer("55")) - parameter 'age': $(consumer(notMatching("^\\w*\$")), producer("99")) - parameter 'name': $(consumer(matching("Denis.*")), producer("Denis.Stepanov")) - parameter 'email': "bob@email.com" - parameter 'hello': $(consumer(matching("Denis.*")), producer(absent())) - parameter 'hello': absent() - } - } - } - response { - status OK() - body """ - { - "property1": "a" - } - """ - } - } - properties.testFramework = TestFramework.JUNIT - when: - String test = singleTestGenerator(contractDsl) - then: - String expectedResponse = - """\ -// tag::jaxrs[] -package com.example; - -import com.jayway.jsonpath.DocumentContext; -import com.jayway.jsonpath.JsonPath; -import org.junit.Test; -import org.junit.Rule; -import javax.ws.rs.client.Entity; -import javax.ws.rs.core.Response; - -import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat; -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.*; -import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson; -import static javax.ws.rs.client.Entity.*; - -@SuppressWarnings("rawtypes") -public class FooTest { - WebTarget webTarget; - - @Test - public void validate_() throws Exception { - - // when: - Response response = webTarget - .path("/users") - .queryParam("limit", "10") - .queryParam("offset", "20") - .queryParam("filter", "email") - .queryParam("sort", "name") - .queryParam("search", "55") - .queryParam("age", "99") - .queryParam("name", "Denis.Stepanov") - .queryParam("email", "bob@email.com") - .request() - .build("GET") - .invoke(); - String responseAsString = response.readEntity(String.class); - - // then: - assertThat(response.getStatus()).isEqualTo(200); - - // and: - DocumentContext parsedJson = JsonPath.parse(responseAsString); - assertThatJson(parsedJson).field("['property1']").isEqualTo("a"); - } - -} - -// end::jaxrs[] -""" - test.trim() - .replace("\\\t", "\t") == expectedResponse.trim() - .replace(" ", "\t") - .replace("\\\t", "\t") - .replace("// tag::jaxrs[]\n", "") - .replace("\n\n// end::jaxrs[]", "") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompileJava("jaxrs", test) - } - - @Issue('#85') - def "should execute custom method for complex structures on the response side"() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/get' - } - response { - status OK() - body([ - fraudCheckStatus: "OK", - rejectionReason : [ - title: $(consumer(null), producer(execute('assertThatRejectionReasonIsNull($it)'))) - ] - ]) - } - } - properties.testFramework = TestFramework.JUNIT - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThatRejectionReasonIsNull(parsedJson.read("$.rejectionReason.title"));') - } - - String sampleJson = ''' - - [ - { - "name" : "iPhone", - "number": "0123-4567-8888" - }, - { - "name" : "home", - "number": "0123-4567-8910" - } - ] -''' - - @Issue('#85') - def "should execute custom method for more complex structures on the response side when using Spock"() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/get' - } - response { - status OK() - body([ - [ - name: $(consumer("userName 1"), producer(execute('assertThatUserNameIsNotNull($it)'))) - ], - [ - name: $(consumer("userName 2"), producer(execute('assertThatUserNameIsNotNull($it)'))) - ] - ]) - } - } - properties.testFramework = TestFramework.JUNIT - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('''assertThatUserNameIsNotNull(parsedJson.read("$.[0].name")''') - test.contains('''assertThatUserNameIsNotNull(parsedJson.read("$.[1].name")''') - and: - DocumentContext context = JsonPath.parse(sampleJson) - context.read('$.[0].name') == 'iPhone' - } - - @Issue('#85') - def "should execute custom method for more complex structures on the response side when using JUnit"() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/get' - } - response { - status OK() - body([ - [ - name: $(consumer("userName 1"), producer(execute('assertThatUserNameIsNotNull($it)'))) - ], - [ - name: $(consumer("userName 2"), producer(execute('assertThatUserNameIsNotNull($it)'))) - ] - ]) - } - } - properties.testFramework = TestFramework.JUNIT - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('''assertThatUserNameIsNotNull(parsedJson.read("$.[0].name")''') - test.contains('''assertThatUserNameIsNotNull(parsedJson.read("$.[1].name")''') - } - - @Issue('#150') - def "should support body matching in response"() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url '/get' - } - response { - status OK() - status OK() - body(value(stub("HELLO FROM STUB"), server(regex(".*")))) - } - } - properties.testFramework = TestFramework.JUNIT - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("assertThat(responseBody).matches(\".*\");") - and: - SyntaxChecker.tryToCompileJava("jaxrs", test) - } - - @Issue('#150') - def "should support body matching in response in Spock"() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url '/get' - } - response { - status OK() - status OK() - body(value(stub("HELLO FROM STUB"), server(regex(".*")))) - } - } - properties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('responseBody ==~ java.util.regex.Pattern.compile(".*")') - and: - SyntaxChecker.tryToCompileGroovy("jaxrs", test) - } - - @Issue('#150') - def "should support custom method execution in response"() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url '/get' - } - response { - status OK() - status OK() - body(value(stub("HELLO FROM STUB"), server(execute('foo($it)')))) - } - } - properties.testFramework = TestFramework.JUNIT - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("foo(responseBody);") - } - - @Issue('#150') - def "should support custom method execution in response in Spock"() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url '/get' - } - response { - status OK() - status OK() - body(value(stub("HELLO FROM STUB"), server(execute('foo($it)')))) - } - } - properties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("foo(responseBody)") - and: - // no static compilation due to bug in Groovy https://issues.apache.org/jira/browse/GROOVY-8055 - SyntaxChecker.tryToCompileGroovy("jaxrs", test, false) - } - - def "should allow c/p version of consumer producer"() { - given: - Contract contractDsl = Contract.make { - request { - method "GET" - url "test" - } - response { - status OK() - body( - property1: "a", - property2: $( - c('123'), - p(regex('[0-9]{3}')) - ) - ) - headers { - header('Content-Type': 'application/json') - } - - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).field("['property2']").matches("[0-9]{3}")""") - test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("a")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - } - - @Issue('#149') - @Unroll - def "should allow easier way of providing dynamic values for [#methodBuilderName]"() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/get' - body([ - alpha : $(anyAlphaUnicode()), - number : $(anyNumber()), - positiveInt : $(positiveInt()), - aDouble : $(anyDouble()), - aBoolean : $(aBoolean()), - ip : $(anyIpAddress()), - hostname : $(anyHostname()), - email : $(anyEmail()), - url : $(anyUrl()), - httpsUrl : $(anyHttpsUrl()), - uuid : $(anyUuid()), - date : $(anyDate()), - dateTime : $(anyDateTime()), - time : $(anyTime()), - iso8601WithOffset: $(anyIso8601WithOffset()), - nonBlankString : $(anyNonBlankString()), - nonEmptyString : $(anyNonEmptyString()), - anyOf : $(anyOf('foo', 'bar')) - ]) - headers { - contentType(applicationJson()) - } - } - response { - status OK() - body([ - alpha : $(anyAlphaUnicode()), - number : $(anyNumber()), - positiveInt : $(positiveInt()), - aDouble : $(anyDouble()), - aBoolean : $(aBoolean()), - ip : $(anyIpAddress()), - hostname : $(anyHostname()), - email : $(anyEmail()), - url : $(anyUrl()), - httpsUrl : $(anyHttpsUrl()), - uuid : $(anyUuid()), - date : $(anyDate()), - dateTime : $(anyDateTime()), - time : $(anyTime()), - iso8601WithOffset: $(anyIso8601WithOffset()), - nonBlankString : $(anyNonBlankString()), - nonEmptyString : $(anyNonEmptyString()), - anyOf : $(anyOf('foo', 'bar')) - ]) - headers { - contentType(applicationJson()) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThatJson(parsedJson).field("[\'aBoolean\']").matches("(true|false)")') - test.contains('assertThatJson(parsedJson).field("[\'alpha\']").matches("[\\\\p{L}]*")') - test.contains('assertThatJson(parsedJson).field("[\'hostname\']").matches("((http[s]?|ftp):/)/?([^:/\\\\s]+)(:[0-9]{1,5})?")') - test.contains('assertThatJson(parsedJson).field("[\'url\']").matches("^(?:(?:[A-Za-z][+-.\\\\w^_]*:/{2})?(?:\\\\S+(?::\\\\S*)?@)?(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|(?:(?:[a-z\\\\u00a1-\\\\uffff0-9]-*)*[a-z\\\\u00a1-\\\\uffff0-9]+)(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff0-9]-*)*[a-z\\\\u00a1-\\\\uffff0-9]+)*(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff]{2,}))|(?:localhost))(?::\\\\d{2,5})?(?:/\\\\S*)?)') - test.contains('assertThatJson(parsedJson).field("[\'httpsUrl\']").matches("^(?:https:/{2}(?:\\\\S+(?::\\\\S*)?@)?(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|(?:(?:[a-z\\\\u00a1-\\\\uffff0-9]-*)*[a-z\\\\u00a1-\\\\uffff0-9]+)(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff0-9]-*)*[a-z\\\\u00a1-\\\\uffff0-9]+)*(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff]{2,}))|(?:localhost))(?::\\\\d{2,5})?(?:/\\\\S*)?)') - test.contains('assertThatJson(parsedJson).field("[\'number\']").matches("-?(\\\\d*\\\\.\\\\d+|\\\\d+)")') - test.contains('assertThatJson(parsedJson).field("[\'positiveInt\']").matches("([1-9]\\\\d*)")') - test.contains('assertThatJson(parsedJson).field("[\'aDouble\']").matches("-?(\\\\d*\\\\.\\\\d+)")') - test.contains('assertThatJson(parsedJson).field("[\'email\']").matches("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,6}")') - test.contains('assertThatJson(parsedJson).field("[\'ip\']").matches("([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])\\\\.([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])\\\\.([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])\\\\.([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])")') - test.contains('assertThatJson(parsedJson).field("[\'uuid\']").matches("[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}")') - test.contains('assertThatJson(parsedJson).field("[\'date\']").matches("(\\\\d\\\\d\\\\d\\\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])")') - test.contains('assertThatJson(parsedJson).field("[\'dateTime\']").matches("([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])")') - test.contains('assertThatJson(parsedJson).field("[\'time\']").matches("(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])")') - test.contains('assertThatJson(parsedJson).field("[\'iso8601WithOffset\']").matches("([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\\\\.\\\\d+)?(Z|[+-][01]\\\\d:[0-5]\\\\d)")') - test.contains('assertThatJson(parsedJson).field("[\'nonBlankString\']").matches("^\\\\s*\\\\S[\\\\S\\\\s]*")') - test.contains('assertThatJson(parsedJson).field("[\'nonEmptyString\']").matches("[\\\\S\\\\s]+")') - test.contains('assertThatJson(parsedJson).field("[\'anyOf\']").matches("^foo' + endOfLineRegexSymbol + '|^bar' + endOfLineRegexSymbol + '")') - !test.contains('cursor') - !test.contains('REGEXP>>') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | endOfLineRegexSymbol - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } | '\\$' - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } | '$' - } - - @Issue('#173') - @Unroll - def "should resolve Optional object when used in query parameters for [#methodBuilderName]"() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath('/blacklist') { - queryParameters { - parameter 'isActive': value(consumer(optional(regex('(true|false)')))) - parameter 'limit': value(consumer(optional(regex('([0-9]{1,10})')))) - parameter 'offset': value(consumer(optional(regex('([0-9]{1,10})')))) - } - } - headers { - header 'Content-Type': 'application/json' - } - } - response { - status(200) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - !test.contains('org.springframework.cloud.contract.spec.internal.OptionalProperty') - test.contains('(([0-9]{1,10}))?') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - } - - @Issue('#1388') - @Unroll - def "should keep the custom content type that includes the +json suffix [#methodBuilderName]"() { - given: - Contract contractDsl = Contract.make { - request { - method("POST") - url("/ping") - headers { - header('Content-Type': 'application/my-content-type+json') - } - body($(test(value: "test"), stub(anyNonEmptyString()))) - } - response { - status 200 - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('"application/my-content-type+json")') - !test.contains('"application/json")') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - } - - @Issue('#261') - @Unroll - def "should not produce any additional quotes for [#methodBuilderName]"() { - given: - Contract contractDsl = Contract.make { - request { - method "POST" - url "/v2/applications/a-TEST-upload/documents" - headers { - header 'Authorization': "foo" - header 'Content-Type': "multipart/form-data;boundary=Boundary_1_1831312172_1491482784697" - } - body $(''' ---Boundary_1_1831312172_1491482784697 -Content-Disposition: form-data; name="file" - -DATA ---Boundary_1_1831312172_1491482784697-- -''') - } - response { - status 400 - body "File name is required" - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - !test.contains('entity("\\"\\n') - test.contains('''entity("\\n--Boundary_1_1831312172_1491482784697\\nContent-Disposition: form-data; name=\\"file\\"\\n\\nDATA\\n--Boundary_1_1831312172_1491482784697--\\n", "multipart/form-data;boundary=Boundary_1_1831312172_1491482784697"))''') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - } - - @Issue('#261') - @Unroll - def "should not produce any additional quotes for json body [#methodBuilderName]"() { - given: - Contract contractDsl = Contract.make { - request { - method "POST" - url "/foo" - headers { - header 'Content-Type': "application/json" - } - body $('''{ "foo": "bar"}''') - } - response { - status 400 - body "File name is required" - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - !test.contains('entity("\\"\\n') - test.contains('''.build("POST", entity("{\\"foo\\":\\"bar\\"}", "application/json"))''') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - } - - def "should generate test for cookies with string value in JAX-RS JUnit test"() { - given: - properties.testFramework = TestFramework.JUNIT - when: - String test = singleTestGenerator(contractDslWithCookiesValue) - then: - test.contains('''.cookie("cookie-key", "cookie-value")''') - test.contains('''assertThat(response.getCookies().get("cookie-key")).isNotNull();''') - test.contains('''assertThat(response.getCookies().get("cookie-key").getValue()).isEqualTo("new-cookie-value");''') - and: - SyntaxChecker.tryToCompile("jaxrs", test) - } - - def "should generate test for cookies with pattern in JAX-RS JUnit test"() { - given: - properties.testFramework = TestFramework.JUNIT - when: - String test = singleTestGenerator(contractDslWithCookiesPattern) - then: - !test.contains('''.cookie("cookie-key", "[A-Za-z]+")''') - test.contains('''.cookie("cookie-key", "''') - test.contains('''assertThat(response.getCookies().get("cookie-key")).isNotNull();''') - test.contains('''assertThat(response.getCookies().get("cookie-key").getValue()).matches("[A-Za-z]+");''') - and: - SyntaxChecker.tryToCompile("jaxrs", test) - } - - def "should not generate cookie assertions with absent value in JAX-RS JUnit test"() { - given: - properties.testFramework = TestFramework.JUNIT - when: - String test = singleTestGenerator(contractDslWithAbsentCookies) - then: - !test.contains("cookie") - and: - SyntaxChecker.tryToCompile("jaxrs", test) - } - - def "should generate test for cookies with string value in JAX-RS Spock test"() { - given: - properties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDslWithCookiesValue) - then: - test.contains('''.cookie('cookie-key', 'cookie-value')''') - test.contains('''response.getCookies().get("cookie-key") != null''') - test.contains('response.getCookies().get("cookie-key").getValue() == "new-cookie-value"') - and: - SyntaxChecker.tryToCompile("jaxrs-spock", test) - } - - def "should generate test for cookies with pattern in JAX-RS Spock test"() { - given: - properties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDslWithCookiesPattern) - then: - !test.contains('''.cookie('cookie-key', '[A-Za-z]+')''') - test.contains('''.cookie('cookie-key', ''') - test.contains('''response.getCookies().get("cookie-key") != null''') - test.contains('''response.getCookies().get("cookie-key").getValue() ==~ java.util.regex.Pattern.compile("[A-Za-z]+")''') - and: - SyntaxChecker.tryToCompile("jaxrs-spock", test) - } - - def "should not generate cookie assertions with absent value in JAX-RS Spock test"() { - given: - properties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDslWithAbsentCookies) - then: - !test.contains("cookie") - and: - SyntaxChecker.tryToCompile("jaxrs-spock", test) - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/JsonAssertTests.java b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/JsonAssertTests.java deleted file mode 100644 index 807e5bf01c..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/JsonAssertTests.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder; - -import com.jayway.jsonpath.DocumentContext; -import com.jayway.jsonpath.JsonPath; -import org.junit.Test; - -import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson; - -/** - * @author Marcin Grzejszczak - */ -public class JsonAssertTests { - - // #537 - @Test - public void should_compare_big_decimals() { - DocumentContext context = JsonPath.parse("{\"foo\": 55534673.56}"); - assertThatJson(context).field("['foo']").isEqualTo(55534673.56); - } - -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy deleted file mode 100644 index 9260686b86..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy +++ /dev/null @@ -1,1128 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder - -import spock.lang.Issue -import spock.lang.Shared -import spock.lang.Specification - -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties -import org.springframework.cloud.contract.verifier.config.TestFramework -import org.springframework.cloud.contract.verifier.config.TestMode -import org.springframework.cloud.contract.verifier.file.ContractMetadata -import org.springframework.cloud.contract.verifier.util.SyntaxChecker - -/** - * @author Marcin Grzejszczak - * @author Tim Ysewyn - */ -class MessagingMethodBodyBuilderSpec extends Specification { - - @Shared - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties( - assertJsonSize: true - ) - - @Shared - SingleTestGenerator.GeneratedClassData generatedClassData = - new SingleTestGenerator.GeneratedClassData("foo", "com.example", new File(MessagingMethodBodyBuilderSpec.getResource(".").toURI()).toPath()) - - def setup() { - properties = new ContractVerifierConfigProperties( - assertJsonSize: true, - generatedTestSourcesDir: new File(MessagingMethodBodyBuilderSpec.getResource(".").toURI()), - generatedTestResourcesDir: new File(MessagingMethodBodyBuilderSpec.getResource(".").toURI()) - ) - } - - private String singleTestGenerator(Contract contractDsl) { - return new JavaTestGenerator() { - @Override - ClassBodyBuilder classBodyBuilder(BlockBuilder builder, GeneratedClassMetaData metaData, SingleMethodBuilder methodBuilder) { - return super.classBodyBuilder(builder, metaData, methodBuilder).field(new Field() { - @Override - boolean accept() { - return metaData.configProperties.testMode == TestMode.JAXRSCLIENT - } - - @Override - Field call() { - builder.addLine("WebTarget webTarget") - return this - } - }) - } - }.buildClass(properties, [contractMetadata(contractDsl)], "foo", generatedClassData) - } - - private ContractMetadata contractMetadata(Contract contractDsl) { - return new ContractMetadata(new File(".").toPath(), false, 0, null, contractDsl) - } - - def "should work for triggered based messaging with Spock"() { - given: -// tag::trigger_method_dsl[] - def contractDsl = Contract.make { - name "foo" - label 'some_label' - input { - triggeredBy('bookReturnedTriggered()') - } - outputMessage { - sentTo('activemq:output') - body('''{ "bookName" : "foo" }''') - headers { - header('BOOK-NAME', 'foo') - messagingContentType(applicationJson()) - } - } - } -// end::trigger_method_dsl[] - properties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDsl) - then: - String expectedMessage = - '''\ -// tag::trigger_method_test[] -package com.example - -import com.jayway.jsonpath.DocumentContext -import com.jayway.jsonpath.JsonPath -import spock.lang.Specification -import javax.inject.Inject -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging - -import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.* -import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson -import static org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.fileToBytes - -@SuppressWarnings("rawtypes") -class FooSpec extends Specification { - @Inject ContractVerifierMessaging contractVerifierMessaging - @Inject ContractVerifierObjectMapper contractVerifierObjectMapper - - def validate_foo() throws Exception { - when: - bookReturnedTriggered() - - then: - ContractVerifierMessage response = contractVerifierMessaging.receive("activemq:output", - contract(this, "foo.yml")) - response != null - - and: - response.getHeader("BOOK-NAME") != null - response.getHeader("BOOK-NAME").toString() == 'foo' - response.getHeader("contentType") != null - response.getHeader("contentType").toString() == 'application/json' - - and: - DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.getPayload())) - assertThatJson(parsedJson).field("['bookName']").isEqualTo("foo") - } - -} -// end::trigger_method_test[] -''' - test.trim() == messageWithoutTags(expectedMessage, "trigger_method_test") - } - - - String messageWithoutTags(String message) { - return messageWithoutTags(message, "invalidTag") - } - - String messageWithoutTags(String message, String tagName) { - return message.trim() - .replace(" ", " ") - .replace("\\ ", " ") - .replace("// tag::${tagName}[]\n", "") - .replace("\n// end::${tagName}[]", "") - } - - def "should work for triggered based messaging with JUnit"() { - given: - def contractDsl = Contract.make { - name "foo" - label 'some_label' - input { - triggeredBy('bookReturnedTriggered()') - } - outputMessage { - sentTo('activemq:output') - body('''{ "bookName" : "foo" }''') - headers { - header('BOOK-NAME', 'foo') - messagingContentType(applicationJson()) - } - } - } - - properties.testFramework = TestFramework.JUNIT - when: - String test = singleTestGenerator(contractDsl) - then: - String expectedMessage = - '''\ -// tag::trigger_method_junit_test[] -package com.example; - -import com.jayway.jsonpath.DocumentContext; -import com.jayway.jsonpath.JsonPath; -import org.junit.Test; -import org.junit.Rule; -import javax.inject.Inject; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging; - -import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat; -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.*; -import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson; -import static org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers; -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.fileToBytes; - -@SuppressWarnings("rawtypes") -public class FooTest { - @Inject ContractVerifierMessaging contractVerifierMessaging; - @Inject ContractVerifierObjectMapper contractVerifierObjectMapper; - - @Test - public void validate_foo() throws Exception { - // when: - bookReturnedTriggered(); - - // then: - ContractVerifierMessage response = contractVerifierMessaging.receive("activemq:output", - contract(this, "foo.yml")); - assertThat(response).isNotNull(); - - // and: - assertThat(response.getHeader("BOOK-NAME")).isNotNull(); - assertThat(response.getHeader("BOOK-NAME").toString()).isEqualTo("foo"); - assertThat(response.getHeader("contentType")).isNotNull(); - assertThat(response.getHeader("contentType").toString()).isEqualTo("application/json"); - - // and: - DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.getPayload())); - assertThatJson(parsedJson).field("['bookName']").isEqualTo("foo"); - } - -} -// end::trigger_method_junit_test[] -''' - test.trim() == messageWithoutTags(expectedMessage, "trigger_method_junit_test") - } - - @Issue("336") - def "should generate tests with message headers containing regular expression for JUnit"() { - given: - def contractDsl = - org.springframework.cloud.contract.spec.Contract.make { - name "foo" - label 'trigger_event' - - input { - triggeredBy('requestIsCalled()') - } - - outputMessage { - sentTo 'topic.rateablequote' - headers { - header('processId', value(producer(regex('[0-9]+')), consumer('123'))) - } - body([ - eventId: value(producer(regex('[0-9]+')), consumer('1')) - ]) - } - } - - properties.testFramework = TestFramework.JUNIT - when: - String test = singleTestGenerator(contractDsl) - then: - String expectedMessage = - """\ -package com.example; - -import com.jayway.jsonpath.DocumentContext; -import com.jayway.jsonpath.JsonPath; -import org.junit.Test; -import org.junit.Rule; -import javax.inject.Inject; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging; - -import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat; -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.*; -import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson; -import static org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers; -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.fileToBytes; - -@SuppressWarnings("rawtypes") -public class FooTest { - @Inject ContractVerifierMessaging contractVerifierMessaging; - @Inject ContractVerifierObjectMapper contractVerifierObjectMapper; - - @Test - public void validate_foo() throws Exception { - // when: - requestIsCalled(); - - // then: - ContractVerifierMessage response = contractVerifierMessaging.receive("topic.rateablequote", - contract(this, "foo.yml")); - assertThat(response).isNotNull(); - - // and: - assertThat(response.getHeader("processId")).isNotNull(); - assertThat(response.getHeader("processId").toString()).matches("[0-9]+"); - - // and: - DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.getPayload())); - assertThatJson(parsedJson).field("['eventId']").matches("[0-9]+"); - } - -} - -""" - test.trim() == messageWithoutTags(expectedMessage, "expectedMsg") - } - - @Issue("567") - def "should generate tests with message headers containing regular expression with backslashes for JUnit"() { - given: - def contractDsl = - org.springframework.cloud.contract.spec.Contract.make { - name "foo" - label 'trigger_event' - - input { - triggeredBy('requestIsCalled()') - } - - outputMessage { - sentTo 'topic.rateablequote' - headers { - header('processId', value(producer(regex('\\d+')), consumer('123'))) - } - body([ - eventId: value(producer(regex('\\d+')), consumer('1')) - ]) - } - } - - properties.testFramework = TestFramework.JUNIT - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThat(response.getHeader("processId").toString()).matches("\\\\d+");') - } - - - @Issue('#587') - def "should allow easier way of providing dynamic values for [#methodBuilderName]"() { - given: - //tag::regex_creating_props[] - Contract contractDsl = Contract.make { - name "foo" - label 'trigger_event' - input { - triggeredBy('toString()') - } - outputMessage { - sentTo 'topic.rateablequote' - body([ - alpha : $(anyAlphaUnicode()), - number : $(anyNumber()), - anInteger : $(anyInteger()), - positiveInt : $(anyPositiveInt()), - aDouble : $(anyDouble()), - aBoolean : $(aBoolean()), - ip : $(anyIpAddress()), - hostname : $(anyHostname()), - email : $(anyEmail()), - url : $(anyUrl()), - httpsUrl : $(anyHttpsUrl()), - uuid : $(anyUuid()), - date : $(anyDate()), - dateTime : $(anyDateTime()), - time : $(anyTime()), - iso8601WithOffset: $(anyIso8601WithOffset()), - nonBlankString : $(anyNonBlankString()), - nonEmptyString : $(anyNonEmptyString()), - anyOf : $(anyOf('foo', 'bar')) - ]) - } - } - //end::regex_creating_props[] - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThatJson(parsedJson).field("[\'aBoolean\']").matches("(true|false)")') - test.contains('assertThatJson(parsedJson).field("[\'alpha\']").matches("[\\\\p{L}]*")') - test.contains('assertThatJson(parsedJson).field("[\'hostname\']").matches("((http[s]?|ftp):/)/?([^:/\\\\s]+)(:[0-9]{1,5})?")') - test.contains('assertThatJson(parsedJson).field("[\'url\']").matches("^(?:(?:[A-Za-z][+-.\\\\w^_]*:/{2})?(?:\\\\S+(?::\\\\S*)?@)?(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|(?:(?:[a-z\\\\u00a1-\\\\uffff0-9]-*)*[a-z\\\\u00a1-\\\\uffff0-9]+)(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff0-9]-*)*[a-z\\\\u00a1-\\\\uffff0-9]+)*(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff]{2,}))|(?:localhost))(?::\\\\d{2,5})?(?:/\\\\S*)?)') - test.contains('assertThatJson(parsedJson).field("[\'number\']").matches("-?(\\\\d*\\\\.\\\\d+|\\\\d+)")') - test.contains('assertThatJson(parsedJson).field("[\'anInteger\']").matches("-?(\\\\d+)")') - test.contains('assertThatJson(parsedJson).field("[\'positiveInt\']").matches("([1-9]\\\\d*)")') - test.contains('assertThatJson(parsedJson).field("[\'aDouble\']").matches("-?(\\\\d*\\\\.\\\\d+)")') - test.contains('assertThatJson(parsedJson).field("[\'email\']").matches("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,6}")') - test.contains('assertThatJson(parsedJson).field("[\'ip\']").matches("([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])\\\\.([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])\\\\.([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])\\\\.([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])")') - test.contains('assertThatJson(parsedJson).field("[\'httpsUrl\']").matches("^(?:https:/{2}(?:\\\\S+(?::\\\\S*)?@)?(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|(?:(?:[a-z\\\\u00a1-\\\\uffff0-9]-*)*[a-z\\\\u00a1-\\\\uffff0-9]+)(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff0-9]-*)*[a-z\\\\u00a1-\\\\uffff0-9]+)*(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff]{2,}))|(?:localhost))(?::\\\\d{2,5})?(?:/\\\\S*)?)') - test.contains('assertThatJson(parsedJson).field("[\'uuid\']").matches("[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}")') - test.contains('assertThatJson(parsedJson).field("[\'date\']").matches("(\\\\d\\\\d\\\\d\\\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])') - test.contains('assertThatJson(parsedJson).field("[\'dateTime\']").matches("([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])') - test.contains('assertThatJson(parsedJson).field("[\'time\']").matches("(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])")') - test.contains('assertThatJson(parsedJson).field("[\'iso8601WithOffset\']").matches("([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\\\\.\\\\d+)?(Z|[+-][01]\\\\d:[0-5]\\\\d)")') - test.contains('assertThatJson(parsedJson).field("[\'nonBlankString\']").matches("^\\\\s*\\\\S[\\\\S\\\\s]*")') - test.contains('assertThatJson(parsedJson).field("[\'nonEmptyString\']").matches("[\\\\S\\\\s]+")') - test.contains('assertThatJson(parsedJson).field("[\'anyOf\']").matches("^foo' + endOfLineRegExSymbol + '|^bar' + endOfLineRegExSymbol + '")') - !test.contains('cursor') - !test.contains('REGEXP>>') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | endOfLineRegExSymbol - "spock" | { properties.testFramework = TestFramework.SPOCK } | '\\$' - "junit" | { properties.testFramework = TestFramework.JUNIT } | '$' - } - - @Issue("587") - def "should generate tests with message headers containing regular expression with escapes for JUnit"() { - given: - def contractDsl = - org.springframework.cloud.contract.spec.Contract.make { - name "foo" - label 'trigger_event' - - input { - triggeredBy('requestIsCalled()') - } - - outputMessage { - sentTo 'topic.rateablequote' - headers { - header('processId', value(producer(regex(nonEmpty())), consumer('123'))) - } - body([ - eventId: value(producer(regex(nonEmpty())), consumer('1')) - ]) - } - } - - properties.testFramework = TestFramework.JUNIT - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('ContractVerifierMessage response = contractVerifierMessaging.receive("topic.rateablequote"') - test.contains('contract(this, "foo.yml"))') - test.contains('assertThat(response).isNotNull()') - test.contains('assertThat(response.getHeader("processId")).isNotNull()') - test.contains('assertThat(response.getHeader("processId").toString()).matches("[\\\\S\\\\s]+")') - test.contains('DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.getPayload()))') - test.contains('assertThatJson(parsedJson).field("[\'eventId\']").matches("[\\\\S\\\\s]+")') - } - - @Issue("336") - def "should generate tests with message headers containing regular expression for Spock"() { - given: - def contractDsl = - org.springframework.cloud.contract.spec.Contract.make { - name "foo" - label 'trigger_event' - - input { - triggeredBy('requestIsCalled()') - } - - outputMessage { - sentTo 'topic.rateablequote' - headers { - header('processId', value(producer(regex('[0-9]+')), consumer('123'))) - } - body([ - eventId: value(producer(regex('[0-9]+')), consumer('1')) - ]) - } - } - properties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDsl) - then: - String expectedMessage = - """\ -package com.example - -import com.jayway.jsonpath.DocumentContext -import com.jayway.jsonpath.JsonPath -import spock.lang.Specification -import javax.inject.Inject -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging - -import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.* -import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson -import static org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.fileToBytes - -@SuppressWarnings("rawtypes") -class FooSpec extends Specification { - @Inject ContractVerifierMessaging contractVerifierMessaging - @Inject ContractVerifierObjectMapper contractVerifierObjectMapper - - def validate_foo() throws Exception { - when: - requestIsCalled() - - then: - ContractVerifierMessage response = contractVerifierMessaging.receive("topic.rateablequote", - contract(this, "foo.yml")) - response != null - - and: - response.getHeader("processId") != null - response.getHeader("processId").toString() ==~ java.util.regex.Pattern.compile('[0-9]+') - - and: - DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.getPayload())) - assertThatJson(parsedJson).field("['eventId']").matches("[0-9]+") - } - -} -""" - test.trim() == messageWithoutTags(expectedMessage, "expectedMsg") - } - - @Issue("587") - def "should generate tests with message headers containing regular expression with escapes for Spock"() { - given: - def contractDsl = - org.springframework.cloud.contract.spec.Contract.make { - name "foo" - label 'trigger_event' - - input { - triggeredBy('requestIsCalled()') - } - - outputMessage { - sentTo 'topic.rateablequote' - headers { - header('processId', value(producer(regex(nonEmpty())), consumer('123'))) - } - body([ - eventId: value(producer(regex(nonEmpty())), consumer('1')) - ]) - } - } - properties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDsl) - then: - String expectedMessage = - """\ -package com.example - -import com.jayway.jsonpath.DocumentContext -import com.jayway.jsonpath.JsonPath -import spock.lang.Specification -import javax.inject.Inject -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging - -import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.* -import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson -import static org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.fileToBytes - -@SuppressWarnings("rawtypes") -class FooSpec extends Specification { - @Inject ContractVerifierMessaging contractVerifierMessaging - @Inject ContractVerifierObjectMapper contractVerifierObjectMapper - - def validate_foo() throws Exception { - when: - requestIsCalled() - - then: - ContractVerifierMessage response = contractVerifierMessaging.receive("topic.rateablequote", - contract(this, "foo.yml")) - response != null - - and: - response.getHeader("processId") != null - response.getHeader("processId").toString() ==~ java.util.regex.Pattern.compile('[\\\\S\\\\s]+') - - and: - DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.getPayload())) - assertThatJson(parsedJson).field("['eventId']").matches("[\\\\S\\\\s]+") - } - -} -""" - test.trim() == messageWithoutTags(expectedMessage, "expectedMsg") - } - - @Issue("440") - def "should generate tests with sentTo having a method execution for Spock"() { - given: - def contractDsl = - org.springframework.cloud.contract.spec.Contract.make { - name "foo" - label 'trigger_event' - - input { - triggeredBy('requestIsCalled()') - } - - outputMessage { - sentTo $(producer(execute("toString()")), consumer('topic.rateablequote')) - headers { - header('processId', value(producer(regex('[0-9]+')), consumer('123'))) - } - body([ - eventId: value(producer(regex('[0-9]+')), consumer('1')) - ]) - } - } - properties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDsl) - then: - String expectedMessage = - """\ -package com.example - -import com.jayway.jsonpath.DocumentContext -import com.jayway.jsonpath.JsonPath -import spock.lang.Specification -import javax.inject.Inject -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging - -import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.* -import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson -import static org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.fileToBytes - -@SuppressWarnings("rawtypes") -class FooSpec extends Specification { - @Inject ContractVerifierMessaging contractVerifierMessaging - @Inject ContractVerifierObjectMapper contractVerifierObjectMapper - - def validate_foo() throws Exception { - when: - requestIsCalled() - - then: - ContractVerifierMessage response = contractVerifierMessaging.receive(toString(), - contract(this, "foo.yml")) - response != null - - and: - response.getHeader("processId") != null - response.getHeader("processId").toString() ==~ java.util.regex.Pattern.compile('[0-9]+') - - and: - DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.getPayload())) - assertThatJson(parsedJson).field("['eventId']").matches("[0-9]+") - } - -} -""" - test.trim() == messageWithoutTags(expectedMessage, "expectedMsg") - } - - @Issue("440") - def "should generate tests with sentTo having a method execution for JUnit"() { - given: - def contractDsl = - org.springframework.cloud.contract.spec.Contract.make { - name "foo" - label 'trigger_event' - - input { - triggeredBy('requestIsCalled()') - } - - outputMessage { - sentTo $(producer(execute("toString()")), consumer('topic.rateablequote')) - headers { - header('processId', value(producer(regex('[0-9]+')), consumer('123'))) - } - body([ - eventId: value(producer(regex('[0-9]+')), consumer('1')) - ]) - } - } - - properties.testFramework = TestFramework.JUNIT - when: - String test = singleTestGenerator(contractDsl) - then: - String expectedMessage = - """\ -package com.example; - -import com.jayway.jsonpath.DocumentContext; -import com.jayway.jsonpath.JsonPath; -import org.junit.Test; -import org.junit.Rule; -import javax.inject.Inject; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging; - -import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat; -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.*; -import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson; -import static org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers; -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.fileToBytes; - -@SuppressWarnings("rawtypes") -public class FooTest { - @Inject ContractVerifierMessaging contractVerifierMessaging; - @Inject ContractVerifierObjectMapper contractVerifierObjectMapper; - - @Test - public void validate_foo() throws Exception { - // when: - requestIsCalled(); - - // then: - ContractVerifierMessage response = contractVerifierMessaging.receive(toString(), - contract(this, "foo.yml")); - assertThat(response).isNotNull(); - - // and: - assertThat(response.getHeader("processId")).isNotNull(); - assertThat(response.getHeader("processId").toString()).matches("[0-9]+"); - - // and: - DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.getPayload())); - assertThatJson(parsedJson).field("['eventId']").matches("[0-9]+"); - } - -} -""" - test.trim() == messageWithoutTags(expectedMessage, "expectedMsg") - } - - @Issue('#620') - def "should generate tests with message headers containing regular expression which compile for [#methodBuilderName]"() { - given: - Contract contractDsl = Contract.make { - name "foo" - label 'shouldPublishMessage' - // input to the contract - input { - // the contract will be triggered by a methodBuilder - triggeredBy('foo()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo('messageExchange') - // the body of the output message - body([ - "field": "value" - ]) - headers { - header('Authorization', value(regex('Bearer [A-Za-z0-9\\-\\._~\\+\\/]+=*'))) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - !test.contains('cursor') - !test.contains('REGEXP>>') - test.trim() == expectedTest.trim() - where: - methodBuilderName | methodBuilder | expectedTest - "spock" | { properties.testFramework = TestFramework.SPOCK } | """\ -package com.example - -import com.jayway.jsonpath.DocumentContext -import com.jayway.jsonpath.JsonPath -import spock.lang.Specification -import javax.inject.Inject -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging - -import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.* -import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson -import static org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.fileToBytes - -@SuppressWarnings("rawtypes") -class FooSpec extends Specification { - @Inject ContractVerifierMessaging contractVerifierMessaging - @Inject ContractVerifierObjectMapper contractVerifierObjectMapper - - def validate_foo() throws Exception { - when: - foo() - - then: - ContractVerifierMessage response = contractVerifierMessaging.receive("messageExchange", - contract(this, "foo.yml")) - response != null - - and: - response.getHeader("Authorization") != null - response.getHeader("Authorization").toString() ==~ java.util.regex.Pattern.compile('Bearer [A-Za-z0-9\\\\-\\\\._~\\\\+\\\\/]+=*') - - and: - DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.getPayload())) - assertThatJson(parsedJson).field("['field']").isEqualTo("value") - } - -} -""" - "junit" | { properties.testFramework = TestFramework.JUNIT } | """\ -package com.example; - -import com.jayway.jsonpath.DocumentContext; -import com.jayway.jsonpath.JsonPath; -import org.junit.Test; -import org.junit.Rule; -import javax.inject.Inject; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging; - -import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat; -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.*; -import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson; -import static org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers; -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.fileToBytes; - -@SuppressWarnings("rawtypes") -public class FooTest { - @Inject ContractVerifierMessaging contractVerifierMessaging; - @Inject ContractVerifierObjectMapper contractVerifierObjectMapper; - - @Test - public void validate_foo() throws Exception { - // when: - foo(); - - // then: - ContractVerifierMessage response = contractVerifierMessaging.receive("messageExchange", - contract(this, "foo.yml")); - assertThat(response).isNotNull(); - - // and: - assertThat(response.getHeader("Authorization")).isNotNull(); - assertThat(response.getHeader("Authorization").toString()).matches("Bearer [A-Za-z0-9\\\\-\\\\._~\\\\+\\\\/]+=*"); - - // and: - DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.getPayload())); - assertThatJson(parsedJson).field("['field']").isEqualTo("value"); - } - -} -""" - } - - @Issue('#650') - def "should generate output for message [#methodBuilderName]"() { - given: - Contract contractDsl = org.springframework.cloud.contract.spec.Contract.make { - name "foo" - description 'issue #650' - label 'trigger' - input { - triggeredBy('createNewPerson()') - } - outputMessage { - sentTo 'personEventsTopic' - headers { - [ - header('contentType': 'application/json'), - header('type': 'person'), - header('eventType': 'PersonChangedEvent'), - header('customerId': $(producer(regex(uuid())))) - ] - } - body([ - "type" : 'CREATED', - "personId" : $(producer(regex(uuid())), consumer('0fd552ba-8043-42da-ab97-4fc77e1057c9')), - "userId" : $(producer(optional(regex(uuid()))), consumer('f043ccf1-0b72-423b-ad32-4ef123718897')), - "firstName" : $(regex(nonEmpty())), - "middleName": $(optional(regex(nonEmpty()))), - "lastName" : $(regex(nonEmpty())), - "version" : $(producer(regex(number())), consumer(0l)), - "uid" : $(producer(regex(uuid()))) - ]) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - !test.contains('cursor') - !test.contains('REGEXP>>') - test.trim() == expectedTest.trim() - where: - methodBuilderName | methodBuilder | expectedTest - "spock" | { properties.testFramework = TestFramework.SPOCK } | """\ -package com.example - -import com.jayway.jsonpath.DocumentContext -import com.jayway.jsonpath.JsonPath -import spock.lang.Specification -import javax.inject.Inject -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging - -import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.* -import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson -import static org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.fileToBytes - -@SuppressWarnings("rawtypes") -class FooSpec extends Specification { - @Inject ContractVerifierMessaging contractVerifierMessaging - @Inject ContractVerifierObjectMapper contractVerifierObjectMapper - - def validate_foo() throws Exception { - when: - createNewPerson() - - then: - ContractVerifierMessage response = contractVerifierMessaging.receive("personEventsTopic", - contract(this, "foo.yml")) - response != null - - and: - response.getHeader("contentType") != null - response.getHeader("contentType").toString() == 'application/json' - response.getHeader("type") != null - response.getHeader("type").toString() == 'person' - response.getHeader("eventType") != null - response.getHeader("eventType").toString() == 'PersonChangedEvent' - response.getHeader("customerId") != null - response.getHeader("customerId").toString() ==~ java.util.regex.Pattern.compile('[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}') - - and: - DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.getPayload())) - assertThatJson(parsedJson).field("['type']").isEqualTo("CREATED") - assertThatJson(parsedJson).field("['personId']").matches("[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}") - assertThatJson(parsedJson).field("['userId']").matches("([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})?") - assertThatJson(parsedJson).field("['firstName']").matches("[\\\\S\\\\s]+") - assertThatJson(parsedJson).field("['middleName']").matches("([\\\\S\\\\s]+)?") - assertThatJson(parsedJson).field("['lastName']").matches("[\\\\S\\\\s]+") - assertThatJson(parsedJson).field("['version']").matches("-?(\\\\d*\\\\.\\\\d+|\\\\d+)") - assertThatJson(parsedJson).field("['uid']").matches("[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}") - } - -} -""" - "junit" | { properties.testFramework = TestFramework.JUNIT } | """\ -package com.example; - -import com.jayway.jsonpath.DocumentContext; -import com.jayway.jsonpath.JsonPath; -import org.junit.Test; -import org.junit.Rule; -import javax.inject.Inject; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging; - -import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat; -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.*; -import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson; -import static org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers; -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.fileToBytes; - -@SuppressWarnings("rawtypes") -public class FooTest { - @Inject ContractVerifierMessaging contractVerifierMessaging; - @Inject ContractVerifierObjectMapper contractVerifierObjectMapper; - - @Test - public void validate_foo() throws Exception { - // when: - createNewPerson(); - - // then: - ContractVerifierMessage response = contractVerifierMessaging.receive("personEventsTopic", - contract(this, "foo.yml")); - assertThat(response).isNotNull(); - - // and: - assertThat(response.getHeader("contentType")).isNotNull(); - assertThat(response.getHeader("contentType").toString()).isEqualTo("application/json"); - assertThat(response.getHeader("type")).isNotNull(); - assertThat(response.getHeader("type").toString()).isEqualTo("person"); - assertThat(response.getHeader("eventType")).isNotNull(); - assertThat(response.getHeader("eventType").toString()).isEqualTo("PersonChangedEvent"); - assertThat(response.getHeader("customerId")).isNotNull(); - assertThat(response.getHeader("customerId").toString()).matches("[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"); - - // and: - DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.getPayload())); - assertThatJson(parsedJson).field("['type']").isEqualTo("CREATED"); - assertThatJson(parsedJson).field("['personId']").matches("[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"); - assertThatJson(parsedJson).field("['userId']").matches("([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})?"); - assertThatJson(parsedJson).field("['firstName']").matches("[\\\\S\\\\s]+"); - assertThatJson(parsedJson).field("['middleName']").matches("([\\\\S\\\\s]+)?"); - assertThatJson(parsedJson).field("['lastName']").matches("[\\\\S\\\\s]+"); - assertThatJson(parsedJson).field("['version']").matches("-?(\\\\d*\\\\.\\\\d+|\\\\d+)"); - assertThatJson(parsedJson).field("['uid']").matches("[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"); - } - -} -""" - } - - @Issue('#1701') - def "should generate output for message whose body is json and contains string that looks like json [#methodBuilderName]"() { - given: - Contract contractDsl = org.springframework.cloud.contract.spec.Contract.make { - name "foo" - description 'issue #650' - label 'trigger' - input { - triggeredBy('toString()') - } - outputMessage { - sentTo("foo") - headers { - messagingContentType(applicationJson()) - } - body(fileAsBytes('messageResponse.json')) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - !test.contains('cursor') - !test.contains('REGEXP>>') - test.trim() == expectedTest.trim() - where: - methodBuilderName | methodBuilder | expectedTest - "spock" | { properties.testFramework = TestFramework.SPOCK } | """\ -package com.example - -import com.jayway.jsonpath.DocumentContext -import com.jayway.jsonpath.JsonPath -import spock.lang.Specification -import javax.inject.Inject -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging - -import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.* -import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson -import static org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.fileToBytes - -@SuppressWarnings("rawtypes") -class FooSpec extends Specification { - @Inject ContractVerifierMessaging contractVerifierMessaging - @Inject ContractVerifierObjectMapper contractVerifierObjectMapper - - def validate_foo() throws Exception { - when: - toString() - - then: - ContractVerifierMessage response = contractVerifierMessaging.receive("foo", - contract(this, "foo.yml")) - response != null - - and: - response.getHeader("contentType") != null - response.getHeader("contentType").toString() == 'application/json' - - and: - response.getPayloadAsByteArray() == fileToBytes(this, "foo_response_messageResponse.json") - } - -} -""" - "junit" | { properties.testFramework = TestFramework.JUNIT } | """\ -package com.example; - -import com.jayway.jsonpath.DocumentContext; -import com.jayway.jsonpath.JsonPath; -import org.junit.Test; -import org.junit.Rule; -import javax.inject.Inject; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage; -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging; - -import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat; -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.*; -import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson; -import static org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers; -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.fileToBytes; - -@SuppressWarnings("rawtypes") -public class FooTest { - @Inject ContractVerifierMessaging contractVerifierMessaging; - @Inject ContractVerifierObjectMapper contractVerifierObjectMapper; - - @Test - public void validate_foo() throws Exception { - // when: - toString(); - - // then: - ContractVerifierMessage response = contractVerifierMessaging.receive("foo", - contract(this, "foo.yml")); - assertThat(response).isNotNull(); - - // and: - assertThat(response.getHeader("contentType")).isNotNull(); - assertThat(response.getHeader("contentType").toString()).isEqualTo("application/json"); - - // and: - assertThat(response.getPayloadAsByteArray()).isEqualTo(fileToBytes(this, "foo_response_messageResponse.json")); - } - -} -""" - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilderSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilderSpec.groovy deleted file mode 100644 index 9324536523..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilderSpec.groovy +++ /dev/null @@ -1,2284 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.springframework.cloud.contract.verifier.builder - -import org.junit.Rule -import spock.lang.Issue -import spock.lang.Shared -import spock.lang.Specification - -import org.springframework.boot.test.system.OutputCaptureRule -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties -import org.springframework.cloud.contract.verifier.config.TestFramework -import org.springframework.cloud.contract.verifier.config.TestMode -import org.springframework.cloud.contract.verifier.converter.YamlContractConverter -import org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockStubVerifier -import org.springframework.cloud.contract.verifier.file.ContractMetadata -import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter -import org.springframework.cloud.contract.verifier.util.SyntaxChecker - -class MethodBodyBuilderSpec extends Specification implements WireMockStubVerifier { - - @Rule - OutputCaptureRule capture = new OutputCaptureRule() - - @Shared - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties( - assertJsonSize: true, generatedTestSourcesDir: new File("."), - generatedTestResourcesDir: new File(".") - ) - - @Shared - SingleTestGenerator.GeneratedClassData generatedClassData = - new SingleTestGenerator.GeneratedClassData("foo", "com.example", new File(MethodBodyBuilderSpec.getResource(".").toURI()).toPath()) - - def setup() { - properties = new ContractVerifierConfigProperties( - assertJsonSize: true, - generatedTestSourcesDir: new File(MethodBodyBuilderSpec.getResource(".").toURI()), - generatedTestResourcesDir: new File(MethodBodyBuilderSpec.getResource(".").toURI()) - ) - } - - private String singleTestGenerator(Contract contractDsl) { - return new JavaTestGenerator() { - @Override - ClassBodyBuilder classBodyBuilder(BlockBuilder builder, GeneratedClassMetaData metaData, SingleMethodBuilder methodBuilder) { - return super.classBodyBuilder(builder, metaData, methodBuilder).field(new Field() { - @Override - boolean accept() { - return metaData.configProperties.testMode == TestMode.JAXRSCLIENT - } - - @Override - Field call() { - builder.addLine("WebTarget webTarget") - return this - } - }) - } - }.buildClass(properties, Collections.singletonList(contractMetadata(contractDsl)), "foo", generatedClassData) - } - - private ContractMetadata contractMetadata(Contract contractDsl) { - return new ContractMetadata(new File(".").toPath(), false, 0, null, contractDsl) - } - - @Issue('#251') - def 'should work with execute and arrays [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/foo' - headers { - accept(applicationJson()) - contentType(applicationJson()) - } - } - response { - status OK() - body([ - myArray: [ - [ - notABugGeneratedHere : $(c('foo'), - p(execute('assertThat((String)$it).isEqualTo("foo")'))), - anotherArrayNeededForBug : [ - [ - optionalNotEmpty: $(c('foo'), - p(execute('assertThat((String)$it).isEqualTo("12")'))) - ] - ], - yetAnotherArrayNeededForBug: [ - [ - optionalNotEmpty: $(c('foo'), - p(execute('assertThat((String)$it).isEqualTo("22")'))) - ] - ] - ], - [ - anotherArrayNeededForBug2: [ - [ - optionalNotEmpty: $(c('foo'), - p(execute('assertThat((String)$it).isEqualTo("122")'))) - ] - ] - ], - ] - ]) - headers { - contentType(applicationJson()) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('$.myArray.[0].anotherArrayNeededForBug.[0].optionalNotEmpty') - !test.contains('cursor') - !test.contains('REGEXP>>') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue('#588') - def 'should work patterns in GString [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method GET() - url("/${regex('\\d+')}") - } - response { - status 200 - body([ - ok: true - ]) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - !test.contains('d+') - !test.contains('REGEXP>>') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue('#521') - def 'should always escape generated chars [#methodBuilderName]'() { - expect: - [1..200].each { - Contract contractDsl = Contract.make { - request { - method GET() - urlPath('/v1/users') { - queryParameters { - parameter 'userId': value(regex(nonBlank())) - } - } - } - response { - status 200 - body([ - ok: value(regex(nonBlank())) - ]) - } - } - methodBuilder() - String test = singleTestGenerator(contractDsl) - - assert !test.contains('REGEXP>>') - SyntaxChecker.tryToCompile(methodBuilderName, test) - } - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue('#269') - def 'should work with execute and keys with dots [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/foo' - } - response { - status OK() - body( - foo: ["my.dotted.response": - $(c('foo'), p(execute('"foo".equals($it)')))] - ) - headers { - contentType(applicationJson()) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('''$.foo.['my.dotted.response']''') - !test.contains('cursor') - !test.contains('REGEXP>>') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue('#289') - def 'should fail on nonexistent field [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url '/something' - headers { - contentType(applicationJson()) - } - } - response { - status OK() - headers { - contentType(applicationJson()) - } - body([ - doesNotExist: $(p(anyAlphaUnicode()), c("123")) - ]) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue('#313') - def 'should allow to use execute in request body [#methodBuilderName]'() { - given: - //tag::body_execute[] - Contract contractDsl = Contract.make { - request { - method 'GET' - url '/something' - body( - $(c('foo'), p(execute('hashCode()'))) - ) - } - response { - status OK() - } - } - //end::body_execute[] - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompile(methodBuilderName, test) - !test.contains("executionCommand") - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue('#318') - def 'should assert the response headers properly [#methodBuilderName]'() { - given: - def contractDsl = org.springframework.cloud.contract.spec.Contract.make { - request { - method 'POST' - urlPath '/documents/app_statement_v1' - headers { - contentType(applicationPdf()) - } - body([ - PESEL : '77100604360', - CLIENT_NAME : 'STANISLAW STASZIC', - STATEMENT_NUMBER: '00200001/C4/2017/1' - ]) - } - response { - status OK() - headers { - contentType(applicationPdf()) - header('Content-Length': 4) - } - - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompile(methodBuilderName, test) - asserter(test) - where: - methodBuilderName | methodBuilder | asserter - "spock" | { - properties.testFramework = TestFramework.SPOCK - } | { String testBody -> - testBody.contains('response.header("Content-Length") == 4') && testBody. - contains('''response.header("Content-Type") ==~ java.util.regex.Pattern.compile('application/pdf.*')''') - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } | { String testBody -> - testBody. - contains('assertThat(response.header("Content-Length")).isEqualTo(4);') && testBody. - contains('assertThat(response.header("Content-Type")).matches("application/pdf.*");') - } - "mockmvc-testng" | { - properties.testFramework = TestFramework.TESTNG; properties.testMode = TestMode.MOCKMVC - } | { String testBody -> - testBody. - contains('assertThat(response.header("Content-Length")).isEqualTo(4);') && testBody. - contains('assertThat(response.header("Content-Type")).matches("application/pdf.*");') - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } | { String testBody -> - testBody. - contains("""response.getHeaderString("Content-Length") == 4""") && testBody. - contains("""response.getHeaderString("Content-Type") ==~ java.util.regex.Pattern.compile("application/pdf.*")""") - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } | { String testBody -> - testBody. - contains('assertThat(response.getHeaderString("Content-Length")).isEqualTo(4);') && testBody. - contains('assertThat(response.getHeaderString("Content-Type")).matches("application/pdf.*");') - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } | { String testBody -> - testBody. - contains('assertThat(response.header("Content-Length")).isEqualTo(4);') && testBody. - contains('assertThat(response.header("Content-Type")).matches("application/pdf.*");') - } - } - - def 'should put L on long values [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method GET() - url 'test' - } - response { - status OK() - body( - 'createdAt': 1502766000000, - 'updatedAt': 1499476115000 - ) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test. - contains("""assertThatJson(parsedJson).field("['createdAt']").isEqualTo(1502766000000L)""") - test. - contains("""assertThatJson(parsedJson).field("['updatedAt']").isEqualTo(1499476115000L)""") - and: - SyntaxChecker. - tryToCompileWithoutCompileStatic(methodBuilderName, test) - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue(['#424','#1647']) - def 'should not put an absent header to the request [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url '/mytest' - headers { - header('header-before', anyNonBlankString()) - header('myheader', absent()) - header('header-after', anyNonBlankString()) - } - } - response { - status OK() - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - !test.contains('myheader') - test.contains('header-before') - test.contains('header-after') - and: - SyntaxChecker. - tryToCompileWithoutCompileStatic(methodBuilderName, test) - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue('#458') - def 'should reference request from body when body is a string [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url '/mytest' - body("""{ "name": "My name" }""") - } - response { - status OK() - body fromRequest().body('$.name') - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - responseAsserter(test) - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder | responseAsserter - "spock" | { - properties.testFramework = TestFramework.SPOCK - } | { String string -> - string.contains("responseBody == '''My name'''") - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } | { String string -> - string.contains('assertThat(responseBody).isEqualTo("My name");') - } - "mockmvc-testng" | { - properties.testFramework = TestFramework.TESTNG; properties.testMode = TestMode.MOCKMVC - } | { String string -> - string.contains('assertThat(responseBody).isEqualTo("My name");') - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } | { String string -> - string.contains('responseBody == "My name"') - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } | { String string -> - string.contains('assertThat(responseBody).isEqualTo("My name");') - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } | { String string -> - string.contains('assertThat(responseBody).isEqualTo("My name");') - } - } - - @Issue('#559') - def 'should reference request from body without escaping of non-string [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url('/mytest') { - queryParameters { - parameter('foo', 'bar') - parameter('number', 1) - } - } - body("""{ "name": "My name" }""") - } - response { - status OK() - body( - foo: fromRequest().query('foo'), - number: fromRequest().query('number') - ) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - test.contains('''assertThatJson(parsedJson).field("['foo']").isEqualTo("bar")''') - test.contains('''assertThatJson(parsedJson).field("['number']").isEqualTo(1)''') - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue('#702') - def 'should generate proper type for large numbers [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'PUT' - urlPath '/example/create' - headers { - contentType applicationJson() - } - body( - [ - "name" : - $(consumer(~/.+/), producer('string-1')), - "updatedTs" : - $(consumer(regex(~/1531916906000/).asLong())), - "isDisabled": $(consumer(regex(anyBoolean())), - producer(true)) - ] - ) - } - - response { - status 200 - headers { - contentType applicationJsonUtf8() - } - body( - [ - "id" : $(consumer(2222L), producer(~/\d+/)), - "name" : fromRequest().body('name'), - "updatedTs" : fromRequest().body('updatedTs'), - "isDisabled": fromRequest().body('isDisabled') - ] - ) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - test.contains('''assertThatJson(parsedJson).field("['updatedTs']").isEqualTo(1531916906000L)''') - !test.contains('''"updatedTs":"1531916906000"''') - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue('#465') - def "should work for '/' url for [#methodBuilderName]"() { - given: - Contract contractDsl = Contract.make { - description(""" - Represents a request to the shouldReturnName service - - given: - a request to the shouldReturnName service - when: - it is a GET - then: - return Ryan - """) - request { - method 'GET' - url '/' - } - response { - status OK() - body('Ryan') - headers { - contentType(textHtml()) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - def 'should use fixed delay milliseconds in the generated test [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method GET() - url 'test' - } - response { - status OK() - async() - fixedDelayMilliseconds(10000) - body(a: 'foo') - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains(""".timeout(10000)""") - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - } - - @Issue('#493') - def 'should not escape a form URL encoded request body [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'POST' - url '/api/form-endpoint' - headers { - header("Content-Type": 'application/x-www-form-urlencoded') - } - body('a=abc&b=123') - } - response { - status OK() - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - !test.contains('a=abc&b=123') - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue('#578') - def 'should work for form parameters [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method POST() - urlPath('/oauth/token') - headers { - header(authorization(), anyNonBlankString()) - header(contentType(), applicationFormUrlencoded()) - header(accept(), applicationJson()) - } - body([ - username : 'user', - password : 'password', - grant_type: 'password' - ]) - } - response { - status 200 - headers { - header(contentType(), applicationJson()) - } - body([ - refresh_token: 'RANDOM_REFRESH_TOKEN', - access_token : 'RANDOM_ACCESS_TOKEN', - token_type : 'bearer', - expires_in : 3600, - scope : ['task'], - user : [ - id : 1, - username: 'user', - name : 'User' - ] - ]) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - test.contains('username=user&password=password&grant_type=password') - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue('#493') - def 'should not escape a form URL encoded request body another try [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method POST() - urlPath('/oauth/token') - headers { - header(authorization(), anyNonBlankString()) - header(contentType(), 'application/x-www-form-urlencoded; charset=UTF-8') - header(accept(), anyNonBlankString()) - } - body('username=user&password=password&grant_type=password') - } - response { - status 200 - headers { - header(contentType(), applicationJsonUtf8()) - } - body([ - refresh_token: 'RANDOM_REFRESH_TOKEN', - access_token : 'RANDOM_ACCESS_TOKEN', - token_type : 'bearer', - expires_in : 3600, - scope : ['task'], - user : [ - id : 1, - username: 'user', - name : 'User' - ] - ]) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - !test.contains('&') - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - def 'should work with files that have new lines [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method('PUT') - headers { - contentType(applicationJson()) - } - body(file("classpath/request.json")) - url("/1") - } - response { - status OK() - body(file("classpath/response.json")) - headers { - contentType(applicationJson()) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - test.contains('''assertThatJson(parsedJson).field("['status']").isEqualTo("RESPONSE")''') - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue('#509') - def 'classToCheck() should return class of object'() { - given: - Contract contractDsl = Contract.make { - request { - method 'POST' - url '/api/users' - } - response { - status OK() - } - } - ClassVerifier verifier = new TestClassVerifier() - when: - Map map = new LinkedHashMap<>() - Integer number = Integer.valueOf(42) - List list = new ArrayList<>() - Set set = new HashSet<>() - then: - verifier.classToCheck(map) == Map.class - and: - verifier.classToCheck(number) == Integer.class - and: - verifier.classToCheck(list) == List.class - and: - verifier.classToCheck(set) == Set.class - } - - class TestClassVerifier implements ClassVerifier { - - } - - def 'should assert null values without matchers [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method GET() - url 'test' - } - response { - status OK() - body([ - nullValue: null - ]) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test. - contains("""assertThatJson(parsedJson).field("['nullValue']").isNull()""") - and: - SyntaxChecker. - tryToCompileWithoutCompileStatic(methodBuilderName, test) - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - def 'should not escape a regex pattern when matching raw body value [#methodBuilderName]'() { - def pattern = "\\d+\\w?" - def escapedPattern = "\\\\d+\\\\w?" - - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url '/api/arbitrary-url' - } - response { - status OK() - body(value(stub("1"), test(regex(pattern)))) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains(escapedPattern) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue("#664") - def 'should work with binary payload for [#methodBuilderName]'() { - given: - File root = new File("src/test/resources/body_builder/") - Contract contractDsl = ContractVerifierDslConverter.convertAsCollection(root, - new File(root, "worksWithPdf.groovy")).first() - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - requestMatcher(test) - responseMatcher(test) - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | requestMatcher | responseMatcher - "spock" | { - properties.testFramework = TestFramework.SPOCK - } | { String string -> - string.contains('.body(fileToBytes(this, "worksWithPdf_request_request.pdf"))') - } | { String string -> - string.contains('response.body.asByteArray() == fileToBytes(this, "worksWithPdf_response_response.pdf")') - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } | { String string -> - string.contains('.body(fileToBytes(this, "worksWithPdf_request_request.pdf"));') - } | { String string -> - string.contains('assertThat(response.getBody().asByteArray()).isEqualTo(fileToBytes(this, "worksWithPdf_response_response.pdf"));') - } - "mockmvc-testng" | { - properties.testFramework = TestFramework.TESTNG; properties.testMode = TestMode.MOCKMVC - } | { String string -> - string.contains('.body(fileToBytes(this, "worksWithPdf_request_request.pdf"));') - } | { String string -> - string.contains('assertThat(response.getBody().asByteArray()).isEqualTo(fileToBytes(this, "worksWithPdf_response_response.pdf"));') - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } | { String string -> - string.contains('entity(fileToBytes(this, "worksWithPdf_request_request.pdf")') - } | { String string -> - string.contains('response.readEntity(byte[]) == fileToBytes(this, "worksWithPdf_response_response.pdf")') - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } | { String string -> - string.contains('entity(fileToBytes(this, "worksWithPdf_request_request.pdf")') - } | { String string -> - string.contains('assertThat(response.readEntity(byte[].class)).isEqualTo(fileToBytes(this, "worksWithPdf_response_response.pdf"));') - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } | { String string -> - string.contains('.body(fileToBytes(this, "worksWithPdf_request_request.pdf"));') - } | { String string -> - string.contains('assertThat(response.getBody().asByteArray()).isEqualTo(fileToBytes(this, "worksWithPdf_response_response.pdf"));') - } - } - - @Issue("#797") - def "should not create an unnecessary empty collection check [#methodBuilderName]"() { - given: - Contract contractDsl = Contract.make { - name("get_new_toy_specs") - request { - description(""" - Given: A new toy request is submitted - When: I receive the response - Then: I would receive the toy specs - """) - method 'GET' - urlPath('/toys') { - queryParameters { - parameter 'uuid': 'd4d724c4-e36e-4fd2-9baa-af7f5df17399' - } - } - } - response { - status 200 - body([ - toyUuid : "d4d724c4-e36e-4fd2-9baa-af7f5df17399", - toyDescription: [ - name : "Super Whiz Bang Toy", - stockNum : 1234, - manufacturer: "Toy Comp", - ], - toyDetails : [ - [ - inventory : 42, - description: "Toy of the year!!", - dimensions : [ - height: 45.8, - weight: 12.3, - width : 8.6, - length: 9.3 - ] - ] - ] - ]) - bodyMatchers { - //toyDescription checks - jsonPath('$.toyDetails[*].dimensions.height', byRegex(nonBlank())) - jsonPath('$.toyDetails[*].dimensions.weight', byRegex(nonBlank())) - jsonPath('$.toyDetails[*].dimensions.width', byRegex(nonBlank())) - jsonPath('$.toyDetails[*].dimensions.length', byRegex(nonBlank())) - } - headers { - contentType(applicationJson()) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - !test.contains('''assertThatJson(parsedJson).array("['toyDetails']").field("['dimensions']").isEmpty()''') - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue("#852") - def "should work with escaped quotes [#methodBuilderName]"() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url('/test') - headers { - accept(applicationJson()) - header("X-Authorization", "eyJhbGciOiJIUzI1NiJ9.eyJtZW1iZXJObyI6IjEyMzQ1In0.VdYumw6QkfxaBgFUZNyza1VfNKiZ2WW4JaxIKe-G8HA") - } - } - response { - status OK() - body([ - "test": "\"escaped\"" - ]) - headers { - contentType(applicationJson()) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - !test.contains('''.isEqualTo("\\\\"escaped\\\\"")''') - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue("#844") - def "should not leave unnecessary isEmpty when using matchers [#methodBuilderName]"() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url('/test') - headers { - accept(applicationJson()) - header("X-Authorization", "eyJhbGciOiJIUzI1NiJ9.eyJtZW1iZXJObyI6IjEyMzQ1In0.VdYumw6QkfxaBgFUZNyza1VfNKiZ2WW4JaxIKe-G8HA") - } - } - response { - status OK() - body([ - [test: 'testJson'], - [test: 'testJson'] - ]) - headers { - contentType(applicationJson()) - } - bodyMatchers { - jsonPath('$', byType { - minOccurrence(2) - maxOccurrence(2) - }) - jsonPath('$[*].test', byType { - minOccurrence(2) - maxOccurrence(2) - }) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - !test.contains('''assertThatJson(parsedJson).array().isEmpty()''') - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue("#652") - def "should not parse json in a json [#methodBuilderName]"() { - given: - Contract contractDsl = Contract.make { - name("insertSomething_ShouldReturnHttp200") - description("POST should do sth") - request { - method 'POST' - url "/foo" - body( - value: "{}" - ) - headers { - contentType(applicationJson()) - } - } - response { - status 200 - headers { contentType(applicationJson()) } - body( - value: "{}" - ) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - !test.contains(''':{}}''') - test.contains("""assertThatJson(parsedJson).field("['value']").isEqualTo("{}")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - } - - @Issue("#727") - def "should not leave empty arrays [#methodBuilderName]"() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url '/list' - } - response { - status 200 - body( - [ - content: [ - one : "two", - two : "two", - three: [ - six: "seven" - ] - ] - ] - ) - bodyMatchers { - jsonPath('$.content.three.six', byRegex(".*seven.*")) - jsonPath('$.content.one', byRegex(".*two.*")) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - !test.contains('''.isEmpty()''') - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue("#727") - def "should not leave empty arrays in a simple structure [#methodBuilderName]"() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url '/list' - } - response { - status 200 - body( - [ - content: [ - three: [ - six: "seven" - ] - ] - ] - ) - bodyMatchers { - jsonPath('$.content.three.six', byRegex(".*seven.*")) - jsonPath('$.content.one', byRegex(".*two.*")) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - !test.contains('''.isEmpty()''') - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue("#892") - def "should not unnecessarily escape non json body [#methodBuilderName]"() { - given: - Contract contractDsl = Contract.make { - request { - method GET() - url $(consumer(regex("/api/v1/files/" + uuid())), - producer("/api/v1/files/b0683f29-741a-4178-b5c6-6e62202e3cf1")) - } - response { - status OK() - body($(consumer("some-content"), producer(regex(nonBlank())))) - headers { - header(contentLength(), - $(consumer(2647691), producer(regex(positiveInt())))) - header(contentType(), $(consumer(applicationOctetStream()), - producer(regex(nonBlank())))) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompile(methodBuilderName, test) - asserter(test) - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder | asserter - "spock" | { - properties.testFramework = TestFramework.SPOCK - } | { String testContent -> - assert testContent. - contains('''response.header("Content-Length") ==~ java.util.regex.Pattern.compile('([1-9]\\\\d*)')''') && testContent. - contains('''response.header("Content-Type") ==~ java.util.regex.Pattern.compile('^\\\\s*\\\\S[\\\\S\\\\s]*')'''); return true - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } | { String testContent -> - assert testContent. - contains('''assertThat(response.header("Content-Type")).matches("^\\\\s*\\\\S[\\\\S\\\\s]*")''') && testContent. - contains('''assertThat(response.header("Content-Length")).matches("([1-9]\\\\d*)")'''); return true - } - "mockmvc-testng" | { - properties.testFramework = TestFramework.TESTNG; properties.testMode = TestMode.MOCKMVC - } | { String testContent -> - assert testContent. - contains('''assertThat(response.header("Content-Type")).matches("^\\\\s*\\\\S[\\\\S\\\\s]*")''') && testContent. - contains('''assertThat(response.header("Content-Length")).matches("([1-9]\\\\d*)")'''); return true - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } | { String testContent -> - assert testContent. - contains('''response.getHeaderString("Content-Length") ==~ java.util.regex.Pattern.compile("([1-9]\\\\d*)")''') && testContent. - contains('''response.getHeaderString("Content-Type") ==~ java.util.regex.Pattern.compile("^\\\\s*\\\\S[\\\\S\\\\s]*")'''); return true - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } | { String testContent -> - assert testContent. - contains('''assertThat(response.getHeaderString("Content-Type")).matches("^\\\\s*\\\\S[\\\\S\\\\s]*")''') && testContent. - contains('''assertThat(response.getHeaderString("Content-Length")).matches("([1-9]\\\\d*)")'''); return true - } - } - - @Issue("#1034") - def "should not escape headers as jsons [#methodBuilderName]"() { - given: - Contract contractDsl = Contract.make { - name 'my name' - request { - method POST() - urlPath '/my-url' - headers { - contentType(applicationJson()) - accept(applicationJson()) - header('my-json-header', ''' { "value": "123" } ''') - } - } - response { - status OK() - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - !test.contains('''[value:123]''') - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue("#1052") - def "should work with large numbers [#methodBuilderName]"() { - given: - String yaml = '''\ -request: - url: /numbers - queryParameters: - page: 0 - size: 2 - method: GET - headers: - Content-Type: application/json - -response: - status: 200 - headers: - Content-Type: application/json;charset=UTF-8 - body: - - number: 1541609556000 - - number: 1541609316000 - matchers: - body: - - path: $.[0].number - type: by_equality - - path: $.[1].number - type: by_equality -''' - File tmpFile = File.createTempFile("foo", ".yml") - tmpFile.createNewFile() - tmpFile.text = yaml - Contract contractDsl = new YamlContractConverter().convertFrom(tmpFile). - first() - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - !test.contains('''(1541609556000)''') - test.contains('''(1541609556000L)''') - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue("#1414") - def "should work with empty arrays after doing array matching [#methodBuilderName]"() { - given: - String yaml = '''\ -name: GET sample -description: sample -request: - method: GET - urlPath: /sample -response: - status: 200 - body: - - foo: "sample1" - bar: true - - foo: "sample2" - bar: false - headers: - Content-Type: application/json - matchers: - body: - - path: $..foo - type: by_regex - value: .* - - path: $..bar - type: by_regex - predefined: any_boolean -''' - File tmpFile = File.createTempFile("foo", ".yml") - tmpFile.createNewFile() - tmpFile.text = yaml - Contract contractDsl = new YamlContractConverter().convertFrom(tmpFile). - first() - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - !test.contains('''assertThatJson(parsedJson).array().isEmpty()''') - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue("#1441") - def "should work with query parameters that need to be escaped [#methodBuilderName]"() { - given: - Contract contractDsl = Contract.make { - request { - method 'POST' - urlPath("/rest/something") { - queryParameters { - parameter 'quote': equalTo("\"") - } - } - } - response { - status OK() - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - !test.contains('''.queryParam("quote",""")''') - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue("#854") - def "should call execute in queryParameters [#methodBuilderName]"() { - given: - Contract contractDsl = Contract.make { - request { - method 'POST' - urlPath("/rest/something") { - queryParameters { - parameter('someHashCode': $( - consumer(regex(anInteger())), - producer(execute("hashCode()"))) - ) - } - } - } - response { - status OK() - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - test.contains('''.queryParam("someHashCode",hashCode())''') | test.contains('''.queryParam("someHashCode", hashCode())''') - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue("#1262") - def "should work with the timeout flag for groovy [#methodBuilderName]"() { - given: - Contract contractDsl = Contract.make { - request { - method(GET()) - url("/hello") - } - response { - status(200) - fixedDelayMilliseconds(5000) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - and: - test.contains("timeout") - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue("#1262") - def "should work with the timeout flag for yaml [#methodBuilderName]"() { - given: - String yaml = '''\ -request: - method: GET - url: /hello - queryParameters: - name: LuLu -response: - status: 200 - fixedDelayMilliseconds: 5000 - body: "Hello LuLu" - async: true -''' - File tmpFile = File.createTempFile("foo", ".yml") - tmpFile.createNewFile() - tmpFile.text = yaml - Contract contractDsl = new YamlContractConverter().convertFrom(tmpFile). - first() - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - and: - test.contains("timeout") - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue("#1049") - def "should work with body having new lines [#methodBuilderName]"() { - given: - Contract contractDsl = Contract.make { - request { - method GET() - url "/foo" - } - response { - status OK() - headers { - contentType('application/x-research-info-systems;charset=UTF-8') - } - body("1\n2\n3\n") - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - def 'should resolve headers from request correctly'() { - given: - Contract contractDsl = Contract.make { - request { - method PUT() - url '/frauds/name' - body([ - name: $(anyAlphaUnicode()) - ]) - headers { - contentType("application/json") - } - } - response { - status OK() - body([ - result: "Don't worry ${fromRequest().body('$.name')} you're not a fraud" - ]) - headers { - header(contentType(), "${fromRequest().header(contentType())};charset=UTF-8") - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - and: - test.contains($/assertThatJson(parsedJson).field("['result']").isEqualTo("Don't worry/$) - test.contains("you're not a fraud") - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - def 'should work with an array of uuids'() { - given: - Contract contractDsl = Contract.make { - description "TEST ARRAY" - request { - method POST() - urlPath($(c('/TEST'), p('/TEST'))) - body([ - $(c(anyUuid()), p("00000000-0000-0000-0000-000000000002")), - $(c(anyUuid()), p("00000000-0000-0000-0000-000000000001")) - ]) - } - response { - status OK() - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - and: - !test.contains('singleValue') - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue("1635") - def 'should work with anyOf that contains special chars'() { - given: - Contract contractDsl = Contract.make { - name 'anyOf test' - request { - method 'POST' - url ("hello") - body( - type: anyOf("VAL", "VAL+VAL") - ) - } - response { - status OK() - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - and: - !test.contains('singleValue') - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } - } - - @Issue("1808") - def "should correctly process optional of DslProperty parameters"() { - given: - Contract contractDsl = Contract.make { - request { - method('GET') - url("/api/foo") - headers { - header 'Content-Type': 'application/json' - header 'Accept': 'application/json' - } - body([ - key1: $(client(optional(anyOf("foo", "bar"))), server("bar")), - key2: $(client(optional(anyNonBlankString())), server("bar")), - key3: $(client(optional(anyEmail())), server("foo@bar.com")), - key4: $(optional(anyNumber())) - ]) - } - response { - status OK() - headers { - header 'Content-Type': 'application/json' - } - body([ - key1: $(client("bar"), server(optional(anyOf("foo", "bar")))), - key2: $(client("bar"), server(optional(anyNonBlankString()))), - key3: $(client("foo@bar.com"), server(optional(anyEmail()))), - key4: $(optional(anyNumber())) - ]) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompile(methodBuilderName, test) - then: - test.contains('assertThatJson(parsedJson).field("[\'key1\']").matches("(^foo' + endOfLineRegexSymbol + '|^bar' + endOfLineRegexSymbol + ')?")') - test.contains('assertThatJson(parsedJson).field("[\'key2\']").matches("(^\\\\s*\\\\S[\\\\S\\\\s]*)?")') - test.contains('assertThatJson(parsedJson).field("[\'key3\']").matches("([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,6})?")') - test.contains('assertThatJson(parsedJson).field("[\'key4\']").matches("(-?(\\\\d*\\\\.\\\\d+|\\\\d+))?")') - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder | endOfLineRegexSymbol - "spock" | { - properties.testFramework = TestFramework.SPOCK - } | '\\$' - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } | '\$' - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } | '\\$' - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } | '\$' - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } | '\$' - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } | '\$' - } - - @Issue("1808") - def "should correctly work with Form URL encoded request body"() { - given: - Contract contractDsl = Contract.make { - request { - method 'POST' - url '/exportData' - headers { - header("Content-Type": 'application/x-www-form-urlencoded; charset=UTF-8') - } - body('fromDt=16-Aug-2023&toDt=25-Aug-2023') - } - response { - status 200 - } - } - - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompile(methodBuilderName, test) - then: - testAssertion(test) - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder | testAssertion - "spock" | { - properties.testFramework = TestFramework.SPOCK - } | { it -> it.contains(""".body('''fromDt=16-Aug-2023&toDt=25-Aug-2023''')""")} - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } | { it -> it.contains(""".body("fromDt=16-Aug-2023&toDt=25-Aug-2023")""")} - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } | { it -> it.contains('.build("POST", entity("fromDt=16-Aug-2023&toDt=25-Aug-2023", "application/x-www-form-urlencoded; charset=UTF-8"))')} - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } | { it -> it.contains('.build("POST", entity("fromDt=16-Aug-2023&toDt=25-Aug-2023", "application/x-www-form-urlencoded; charset=UTF-8"))')} - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } | { it -> it.contains('.body("fromDt=16-Aug-2023&toDt=25-Aug-2023")') } - "testNG" | { - properties.testFramework = TestFramework.TESTNG - } | { it -> it.contains('.body("fromDt=16-Aug-2023&toDt=25-Aug-2023")') } - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MethodBuilderSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MethodBuilderSpec.groovy deleted file mode 100644 index e33dde4867..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MethodBuilderSpec.groovy +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder - - -import spock.lang.Issue -import spock.lang.Specification - -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.file.ContractMetadata -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata - -class MethodBuilderSpec extends Specification { - - @Issue('#518') - def "should map create valid method name from file name containing illegal chars"() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/foo' - } - response { - status OK() - body(foo: "foo") - headers { - contentType(applicationJson()) - } - } - } - File stubFile = new File("invalid-method;name.groovy") - - ContractMetadata metadata = new ContractMetadata(stubFile.toPath(), false, 0, null, contractDsl) - SingleContractMetadata singleContractMetadata = new SingleContractMetadata(contractDsl, metadata) - when: - - String methodName = new NameProvider().methodName(singleContractMetadata) - then: - methodName == "validate_invalid_method_name" - } - -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderWithMatchersSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderWithMatchersSpec.groovy deleted file mode 100644 index c14890632e..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderWithMatchersSpec.groovy +++ /dev/null @@ -1,790 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder - -import org.junit.Rule -import org.mdkt.compiler.CompilationException -import spock.lang.Issue -import spock.lang.Shared -import spock.lang.Specification - -import org.springframework.boot.test.system.OutputCaptureRule -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties -import org.springframework.cloud.contract.verifier.config.TestFramework -import org.springframework.cloud.contract.verifier.config.TestMode -import org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockStubVerifier -import org.springframework.cloud.contract.verifier.file.ContractMetadata -import org.springframework.cloud.contract.verifier.util.SyntaxChecker - -class MockMvcMethodBodyBuilderWithMatchersSpec extends Specification implements WireMockStubVerifier { - - @Rule - OutputCaptureRule outputCapture = new OutputCaptureRule() - - @Shared - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties( - assertJsonSize: true - ) - - @Shared - GeneratedClassDataForMethod generatedClassDataForMethod = new GeneratedClassDataForMethod( - new SingleTestGenerator.GeneratedClassData("foo", "bar", new File(".").toPath()), "method") - - @Shared - SingleTestGenerator.GeneratedClassData generatedClassData = - new SingleTestGenerator.GeneratedClassData("foo", "com.example", new File(".").toPath()) - - private String singleTestGenerator(Contract contractDsl) { - return new JavaTestGenerator() { - @Override - ClassBodyBuilder classBodyBuilder(BlockBuilder builder, GeneratedClassMetaData metaData, SingleMethodBuilder methodBuilder) { - return super.classBodyBuilder(builder, metaData, methodBuilder).field(new Field() { - @Override - boolean accept() { - return metaData.configProperties.testMode == TestMode.JAXRSCLIENT - } - - @Override - Field call() { - builder.addLine("WebTarget webTarget") - return this - } - }) - } - }.buildClass(properties, [contractMetadata(contractDsl)], "foo", generatedClassData) - } - - private ContractMetadata contractMetadata(Contract contractDsl) { - return new ContractMetadata(new File(".").toPath(), false, 0, null, contractDsl) - } - - def setup() { - properties = new ContractVerifierConfigProperties( - assertJsonSize: true - ) - } - - @Issue('#185') - def 'should allow to set dynamic values via stub / test matchers for [#methodBuilderName]'() { - given: - //tag::matchers[] - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/get' - body([ - duck : 123, - alpha : 'abc', - number : 123, - aBoolean : true, - date : '2017-01-01', - dateTime : '2017-01-01T01:23:45', - time : '01:02:34', - valueWithoutAMatcher: 'foo', - valueWithTypeMatch : 'string', - key : [ - 'complex.key': 'foo' - ] - ]) - bodyMatchers { - jsonPath('$.duck', byRegex("[0-9]{3}").asInteger()) - jsonPath('$.duck', byEquality()) - jsonPath('$.alpha', byRegex(onlyAlphaUnicode()).asString()) - jsonPath('$.alpha', byEquality()) - jsonPath('$.number', byRegex(number()).asInteger()) - jsonPath('$.aBoolean', byRegex(anyBoolean()).asBooleanType()) - jsonPath('$.date', byDate()) - jsonPath('$.dateTime', byTimestamp()) - jsonPath('$.time', byTime()) - jsonPath("\$.['key'].['complex.key']", byEquality()) - } - headers { - contentType(applicationJson()) - } - } - response { - status OK() - body([ - duck : 123, - alpha : 'abc', - number : 123, - positiveInteger : 1234567890, - negativeInteger : -1234567890, - positiveDecimalNumber: 123.4567890, - negativeDecimalNumber: -123.4567890, - aBoolean : true, - date : '2017-01-01', - dateTime : '2017-01-01T01:23:45', - time : "01:02:34", - valueWithoutAMatcher : 'foo', - valueWithTypeMatch : 'string', - valueWithMin : [ - 1, 2, 3 - ], - valueWithMax : [ - 1, 2, 3 - ], - valueWithMinMax : [ - 1, 2, 3 - ], - valueWithMinEmpty : [], - valueWithMaxEmpty : [], - key : [ - 'complex.key': 'foo' - ], - nullValue : null - ]) - bodyMatchers { - // asserts the jsonpath value against manual regex - jsonPath('$.duck', byRegex("[0-9]{3}").asInteger()) - // asserts the jsonpath value against the provided value - jsonPath('$.duck', byEquality()) - // asserts the jsonpath value against some default regex - jsonPath('$.alpha', byRegex(onlyAlphaUnicode()).asString()) - jsonPath('$.alpha', byEquality()) - jsonPath('$.number', byRegex(number()).asInteger()) - jsonPath('$.positiveInteger', byRegex(anInteger()).asInteger()) - jsonPath('$.negativeInteger', byRegex(anInteger()).asInteger()) - jsonPath('$.positiveDecimalNumber', byRegex(aDouble()).asDouble()) - jsonPath('$.negativeDecimalNumber', byRegex(aDouble()).asDouble()) - jsonPath('$.aBoolean', byRegex(anyBoolean()).asBooleanType()) - // asserts vs inbuilt time related regex - jsonPath('$.date', byDate()) - jsonPath('$.dateTime', byTimestamp()) - jsonPath('$.time', byTime()) - // asserts that the resulting type is the same as in response body - jsonPath('$.valueWithTypeMatch', byType()) - jsonPath('$.valueWithMin', byType { - // results in verification of size of array (min 1) - minOccurrence(1) - }) - jsonPath('$.valueWithMax', byType { - // results in verification of size of array (max 3) - maxOccurrence(3) - }) - jsonPath('$.valueWithMinMax', byType { - // results in verification of size of array (min 1 & max 3) - minOccurrence(1) - maxOccurrence(3) - }) - jsonPath('$.valueWithMinEmpty', byType { - // results in verification of size of array (min 0) - minOccurrence(0) - }) - jsonPath('$.valueWithMaxEmpty', byType { - // results in verification of size of array (max 0) - maxOccurrence(0) - }) - // will execute a method `assertThatValueIsANumber` - jsonPath('$.duck', byCommand('assertThatValueIsANumber($it)')) - jsonPath("\$.['key'].['complex.key']", byEquality()) - jsonPath('$.nullValue', byNull()) - } - headers { - contentType(applicationJson()) - header('Some-Header', $(c('someValue'), p(regex('[a-zA-Z]{9}')))) - } - } - } - //end::matchers[] - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThat(parsedJson.read("' + rootElement + '.duck", String.class)).matches("[0-9]{3}")') - test.contains('assertThat(parsedJson.read("' + rootElement + '.duck", Integer.class)).isEqualTo(123)') - test.contains('assertThat(parsedJson.read("' + rootElement + '.alpha", String.class)).matches("[\\\\p{L}]*")') - test.contains('assertThat(parsedJson.read("' + rootElement + '.alpha", String.class)).isEqualTo("abc")') - test.contains('assertThat(parsedJson.read("' + rootElement + '.number", String.class)).matches("-?(\\\\d*\\\\.\\\\d+|\\\\d+)")') - test.contains('assertThat(parsedJson.read("' + rootElement + '.positiveInteger", String.class)).matches("-?(\\\\d+)")') - test.contains('assertThat(parsedJson.read("' + rootElement + '.negativeInteger", String.class)).matches("-?(\\\\d+)")') - test.contains('assertThat(parsedJson.read("' + rootElement + '.positiveDecimalNumber", String.class)).matches("-?(\\\\d*\\\\.\\\\d+)")') - test.contains('assertThat(parsedJson.read("' + rootElement + '.negativeDecimalNumber", String.class)).matches("-?(\\\\d*\\\\.\\\\d+)")') - test.contains('assertThat(parsedJson.read("' + rootElement + '.aBoolean", String.class)).matches("(true|false)")') - test.contains('assertThat(parsedJson.read("' + rootElement + '.date", String.class)).matches("(\\\\d\\\\d\\\\d\\\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])")') - test.contains('assertThat(parsedJson.read("' + rootElement + '.dateTime", String.class)).matches("([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])")') - test.contains('assertThat(parsedJson.read("' + rootElement + '.time", String.class)).matches("(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])")') - test.contains('assertThat((Object) parsedJson.read("' + rootElement + '.valueWithTypeMatch")).isInstanceOf(java.lang.String.class)') - test.contains('assertThat((Object) parsedJson.read("' + rootElement + '.valueWithMin")).isInstanceOf(java.util.List.class)') - test.contains('assertThat((java.lang.Iterable) parsedJson.read("' + rootElement + '.valueWithMin", java.util.Collection.class)).as("' + rootElement + '.valueWithMin").hasSizeGreaterThanOrEqualTo(1)') - test.contains('assertThat((Object) parsedJson.read("' + rootElement + '.valueWithMax")).isInstanceOf(java.util.List.class)') - test.contains('assertThat((java.lang.Iterable) parsedJson.read("' + rootElement + '.valueWithMax", java.util.Collection.class)).as("' + rootElement + '.valueWithMax").hasSizeLessThanOrEqualTo(3)') - test.contains('assertThat((Object) parsedJson.read("' + rootElement + '.valueWithMinMax")).isInstanceOf(java.util.List.class)') - test.contains('assertThat((java.lang.Iterable) parsedJson.read("' + rootElement + '.valueWithMinMax", java.util.Collection.class)).as("' + rootElement + '.valueWithMinMax").hasSizeBetween(1, 3)') - test.contains('assertThat((Object) parsedJson.read("' + rootElement + '.valueWithMinEmpty")).isInstanceOf(java.util.List.class)') - test.contains('assertThat((java.lang.Iterable) parsedJson.read("' + rootElement + '.valueWithMinEmpty", java.util.Collection.class)).as("' + rootElement + '.valueWithMinEmpty").hasSizeGreaterThanOrEqualTo(0)') - test.contains('assertThat((Object) parsedJson.read("' + rootElement + '.valueWithMaxEmpty")).isInstanceOf(java.util.List.class)') - test.contains('assertThat((java.lang.Iterable) parsedJson.read("' + rootElement + '.valueWithMaxEmpty", java.util.Collection.class)).as("' + rootElement + '.valueWithMaxEmpty").hasSizeLessThanOrEqualTo(0)') - test.contains('assertThatValueIsANumber(parsedJson.read("' + rootElement + '.duck")') - test.contains('assertThat(parsedJson.read("' + rootElement + '''.['key'].['complex.key']", String.class)).isEqualTo("foo")''') - test.contains('assertThat((Object) parsedJson.read("' + rootElement + '.nullValue")).isNull()') - !test.contains('cursor') - and: - try { - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - } - catch (CompilationException classFormatError) { - String output = classFormatError.message - assert output.contains('cannot find symbol') - assert output.contains('assertThatValueIsANumber') - } - where: - methodBuilderName | methodBuilder | rootElement - "spock" | { properties.testFramework = TestFramework.SPOCK } | '\\$' - "testng" | { properties.testFramework = TestFramework.TESTNG }| '$' - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } | '$' - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } | '\\$' - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } | '$' - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } | '$' - } - - @Issue('#217') - def 'should allow complex matchers for [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url 'person' - } - response { - status OK() - body([ - "firstName" : 'Jane', - "lastName" : 'Doe', - "isAlive" : true, - "address" : [ - "postalCode": '98101', - ], - "phoneNumbers": [ - [ - "type" : 'home', - "number": '999 999-9999', - ] - ], - "gender" : [ - "type": 'female', - ], - "children" : [ - [ - "firstName": 'Kid', - "age" : 55, - ] - ], - ]) - bodyMatchers { - jsonPath('$.phoneNumbers', byType { - minOccurrence(0) // min occurrence of 1 - maxOccurrence(4) // max occurrence of 3 - }) - jsonPath('$.phoneNumbers[*].number', byRegex("^[0-9]{3} [0-9]{3}-[0-9]{4}\$")) - jsonPath('$..number', byRegex("^[0-9]{3} [0-9]{3}-[0-9]{4}\$")) - } - headers { - contentType('application/json') - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThat((java.lang.Iterable) parsedJson.read("' + rootElement + '.phoneNumbers[*].number", java.util.Collection.class)).as("' + rootElement + '.phoneNumbers[*].number").allElementsMatch("^[0-9]{3} [0-9]{3}-[0-9]{4}' + rootElement + '")') - test.contains('assertThat((java.lang.Iterable) parsedJson.read("' + rootElement + '..number", java.util.Collection.class)).as("' + rootElement + '..number").allElementsMatch("^[0-9]{3} [0-9]{3}-[0-9]{4}' + rootElement + '")') - !test.contains('cursor') - and: - try { - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - } - catch (NoClassDefFoundError error) { - // that's actually expected since we're creating an anonymous class - } - where: - methodBuilderName | methodBuilder | rootElement - "spock" | { properties.testFramework = TestFramework.SPOCK } | '\\$' - "testng" | { properties.testFramework = TestFramework.TESTNG }| '$' - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } | '$' - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } | '\\$' - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } | '$' - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } | '$' - } - - - @Issue('#217') - def 'should use the flattened assertions when jsonpath contains [*] for [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url 'person' - } - response { - status OK() - body([ - "phoneNumbers": [ - number: 'foo' - ] - ]) - bodyMatchers { - jsonPath('$.phoneNumbers[*].number', byType { - minOccurrence(0) - maxOccurrence(4) - }) - jsonPath('$.phoneNumbers[*].number', byType { - minOccurrence(0) - }) - jsonPath('$.phoneNumbers[*].number', byType { - maxOccurrence(4) - }) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThat((java.lang.Iterable) parsedJson.read("' + rootElement + '.phoneNumbers[*].number", java.util.Collection.class)).as("' + rootElement + '.phoneNumbers[*].number").hasFlattenedSizeBetween(0, 4)') - test.contains('assertThat((java.lang.Iterable) parsedJson.read("' + rootElement + '.phoneNumbers[*].number", java.util.Collection.class)).as("' + rootElement + '.phoneNumbers[*].number").hasFlattenedSizeGreaterThanOrEqualTo(0)') - test.contains('assertThat((java.lang.Iterable) parsedJson.read("' + rootElement + '.phoneNumbers[*].number", java.util.Collection.class)).as("' + rootElement + '.phoneNumbers[*].number").hasFlattenedSizeLessThanOrEqualTo(4)') - !test.contains('cursor') - and: - try { - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - } - catch (NoClassDefFoundError error) { - // that's actually expected since we're creating an anonymous class - } - where: - methodBuilderName | methodBuilder | rootElement - "spock" | { properties.testFramework = TestFramework.SPOCK } | '\\$' - "testng" | { properties.testFramework = TestFramework.TESTNG }| '$' - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } | '$' - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } | '\\$' - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } | '$' - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } | '$' - } - - @Issue('#217') - def 'should allow matcher with command to execute [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url 'person' - } - response { - status OK() - body([ - "phoneNumbers": [ - number: 'foo' - ] - ]) - bodyMatchers { - jsonPath('$.phoneNumbers[*].number', byCommand('foo($it)')) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('foo(parsedJson.read("' + rootElement + '.phoneNumbers[*].number")') - where: - methodBuilderName | methodBuilder | rootElement - "spock" | { properties.testFramework = TestFramework.SPOCK } | '\\$' - "testng" | { properties.testFramework = TestFramework.TESTNG }| '$' - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } | '$' - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } | '\\$' - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } | '$' - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } | '$' - } - - @Issue('#217') - def 'should throw an exception when command to execute references a non existing entry in the body [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url 'person' - } - response { - status OK() - body([ - "phoneNumbers": [ - number: 'foo' - ] - ]) - bodyMatchers { - jsonPath('$.nonExistingPhoneNumbers[*].number', byCommand('foo($it)')) - } - } - } - methodBuilder() - when: - singleTestGenerator(contractDsl) - then: - IllegalStateException e = thrown(IllegalStateException) - e.message.contains('Entry for the provided JSON path <$.nonExistingPhoneNumbers[*].number> doesn\'t exist in the body') - where: - methodBuilderName | methodBuilder | rootElement - "spock" | { properties.testFramework = TestFramework.SPOCK } | '\\$' - "testng" | { properties.testFramework = TestFramework.TESTNG }| '$' - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } | '$' - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } | '\\$' - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } | '$' - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } | '$' - } - - @Issue('#229') - def 'should work for matchers and body with json array[#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url '/api/v1/xxxx' - body(12000) - } - response { - status OK() - body([[ - [access_token: '123'] - ]]) - headers { - contentType(applicationJson()) - } - bodyMatchers { - jsonPath('''$[0][0].access_token''', byEquality()) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - SyntaxChecker.tryToCompile(methodBuilderName, test) - then: - test.contains('assertThat(parsedJson.read("' + rootElement + '[0][0].access_token", String.class)).isEqualTo("123")') - where: - methodBuilderName | methodBuilder | rootElement - "spock" | { properties.testFramework = TestFramework.SPOCK } | '\\$' - "testng" | { properties.testFramework = TestFramework.TESTNG }| '$' - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } | '$' - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } | '\\$' - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } | '$' - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } | '$' - } - - @Issue('#391') - def 'should work for matchers and body with multiline string for [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - name 'ISSUE 391' - method 'GET' - urlPath '/item/factsheet?size=2&page=1' - headers { header 'accept', 'application/...json' } - } - response { - status OK() - body(''' - { - "items": [ - { - "id": "35309", - "title": "lorem ipsum" - } - ] - } - ''') - bodyMatchers { - jsonPath('$.items[*].id', byRegex(nonBlank())) - jsonPath('$.items[*].title', byRegex(nonBlank())) - jsonPath('$.items[*]', byType { occurrence(2) }) - } - headers { header 'content-type', 'application/...json;charset=UTF-8' } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - SyntaxChecker.tryToCompile(methodBuilderName, test) - then: - !test.contains('''assertThatJson(parsedJson).array("['items']").isEmpty()''') - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "testng" | { properties.testFramework = TestFramework.TESTNG } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - } - - @Issue('#391') - def 'should work for matchers and body with multiline string with map body for [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - name "ISSUE 391" - method 'GET' - urlPath '/item/factsheet?size=2&page=1' - headers { header 'accept', 'application/...json' } - } - response { - status OK() - body([ - "items": [ - "id" : "35309", - "title": "lorem ipsum" - ] - ]) - bodyMatchers { - jsonPath('$.items[*].id', byRegex(nonBlank())) - jsonPath('$.items[*].title', byRegex(nonBlank())) - jsonPath('$.items[*]', byType { minOccurrence(2); maxOccurrence(2) }) - } - headers { header 'content-type', 'application/...json;charset=UTF-8' } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - SyntaxChecker.tryToCompile(methodBuilderName, test) - then: - !test.contains('''assertThatJson(parsedJson).array("['items']").isEmpty()''') - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "testng" | { properties.testFramework = TestFramework.TESTNG } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - } - - @Issue('#1091') - def 'should work for map with array value where matchers cover all array fields for [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - name "ISSUE 1091" - method 'GET' - url '/test' - headers { - contentType(applicationJson()) - } - } - response { - status OK() - body(''' - { - "prices": [ - { - "country" : "ES", - "originalPrice": "1500" - } - ] - } - ''') - bodyMatchers { - jsonPath('$.prices[0].country', byRegex(nonBlank())) - jsonPath('$.prices[0].originalPrice', byRegex(number())) - } - headers { - contentType(applicationJsonUtf8()) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - then: - !test.contains('isEmpty()') - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "testng" | { properties.testFramework = TestFramework.TESTNG } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; - properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; - properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - } - - @Issue('#1091') - def 'should work for array containing map with array value where matchers cover all array fields for [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - name "ISSUE 1091" - method 'GET' - url '/test' - headers { - contentType(applicationJson()) - } - } - response { - status OK() - body(''' - { - "test": [ - { - "prices": [ - { - "country" : "ES", - "originalPrice": 1500 - } - ] - } - ] - } - ''') - bodyMatchers { - jsonPath('$.test[0].barcode', byRegex(nonBlank())) - jsonPath('$.test[0].id', byRegex(nonBlank())) - jsonPath('$.test[0].prices[0].country', byRegex(nonBlank())) - jsonPath('$.test[0].prices[0].originalPrice', byRegex(nonBlank())) - jsonPath('$.test[0].prices[?(@.originalPrice==1500)].originalPrice', - byRegex(nonBlank())) - } - headers { - contentType(applicationJsonUtf8()) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - then: - !test.contains('isEmpty()') - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "testng" | { properties.testFramework = TestFramework.TESTNG } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; - properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; - properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - } - - @Issue('#880') - def 'should not generate a null statement when there is no content type in the response [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - description 'Should return 200' - request { - method POST() - url("/get") - headers { - contentType("application/json;charset=UTF-8") - } - } - response { - status OK() - body(file("getBody.json")) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - then: - !test.contains('null') - test.contains('''.array("['array']")''') - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "testng" | { properties.testFramework = TestFramework.TESTNG } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; - properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; - properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - } - -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/QueryParamsResolverSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/QueryParamsResolverSpec.groovy deleted file mode 100644 index 3fa8266a49..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/QueryParamsResolverSpec.groovy +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder - -import org.springframework.cloud.contract.spec.internal.DslProperty -import org.springframework.cloud.contract.spec.internal.MatchingStrategy -import org.springframework.cloud.contract.spec.internal.OptionalProperty -import org.springframework.cloud.contract.spec.internal.QueryParameter -import org.springframework.cloud.contract.spec.internal.RegexProperty -import spock.lang.Specification - -import java.util.regex.Pattern - -class QueryParamsResolverSpec extends Specification { - - def 'should return serverValue for QueryParameter'() { - given: - Object parameter = new QueryParameter("some_param", dslProperty) - when: - String resolved = new QueryParamsResolver() {}.resolveParamValue(parameter) - then: - resolved == expected - where: - dslProperty | expected - new DslProperty("client", "server") | "server" - new DslProperty(null, "server") | "server" - new DslProperty("client", null) | "null" - new DslProperty(null, null) | "null" - } - - def 'should return optionalPattern for OptionalProperty'() { - given: - Object parameter = new OptionalProperty(value) - when: - String resolved = new QueryParamsResolver() {}.resolveParamValue(parameter) - then: - resolved == expected - where: - value | expected - "server" | "(server)?" - null | "()?" - new RegexProperty(Pattern.compile(".*")) | "(.*)?" - new RegexProperty(null, Pattern.compile(".*")) | "(.*)?" - new RegexProperty(Pattern.compile(".*"), null) | "(.*)?" - new RegexProperty("", Pattern.compile(".*")) | "(.*)?" - new RegexProperty(Pattern.compile(".*"), "") | "(.*)?" - } - - def 'should return serverValue for MatchingStrategy'() { - given: - Object parameter = new MatchingStrategy(value, MatchingStrategy.Type.EQUAL_TO) - when: - String resolved = new QueryParamsResolver() {}.resolveParamValue(parameter) - then: - resolved == expected - where: - value | expected - "server" | "server" - null | "null" - new DslProperty("client", "server") | "server" - new DslProperty(null, "server") | "server" - new DslProperty("client", null) | "null" - new DslProperty(null, null) | "null" - } - - def 'should return serverValue for DslProperty'() { - when: - String resolved = new QueryParamsResolver() {}.resolveParamValue(parameter) - then: - resolved == expected - where: - parameter | expected - new DslProperty("client", "server") | "server" - new DslProperty(null, "server") | "server" - new DslProperty("client", null) | "null" - new DslProperty(null, null) | "null" - } - - def 'should return \"null\" for null'() { - when: - String resolved = new QueryParamsResolver() {}.resolveParamValue(null) - then: - resolved == "null" - } - -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGeneratorSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGeneratorSpec.groovy deleted file mode 100644 index 663faa2e57..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGeneratorSpec.groovy +++ /dev/null @@ -1,1143 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder - - -import org.junit.Rule -import org.junit.rules.TemporaryFolder -import spock.lang.Issue -import spock.lang.Specification - -import org.springframework.cloud.contract.verifier.TestGenerator -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties -import org.springframework.cloud.contract.verifier.config.TestFramework -import org.springframework.cloud.contract.verifier.file.ContractMetadata -import org.springframework.cloud.contract.verifier.util.SyntaxChecker -import org.springframework.util.FileSystemUtils - -import static org.springframework.cloud.contract.verifier.config.TestFramework.JUNIT -import static org.springframework.cloud.contract.verifier.config.TestFramework.JUNIT5 -import static org.springframework.cloud.contract.verifier.config.TestFramework.SPOCK -import static org.springframework.cloud.contract.verifier.config.TestFramework.TESTNG -import static org.springframework.cloud.contract.verifier.config.TestMode.EXPLICIT -import static org.springframework.cloud.contract.verifier.config.TestMode.JAXRSCLIENT -import static org.springframework.cloud.contract.verifier.config.TestMode.MOCKMVC -import static org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter.convertAsCollection -import static org.springframework.util.StringUtils.countOccurrencesOf - -class SingleTestGeneratorSpec extends Specification { - - @Rule - TemporaryFolder tmpFolder = new TemporaryFolder() - File file - File tmp - - private static final List mockMvcJUnitRestAssured3ClassStrings = ['import com.jayway.jsonpath.DocumentContext;', 'import com.jayway.jsonpath.JsonPath;', - 'import org.junit.FixMethodOrder;', 'import org.junit.Ignore;', 'import org.junit.Test;', 'import org.junit.runners.MethodSorters;', - 'import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson;', 'import static io.restassured.module.mockmvc.RestAssuredMockMvc.*;', - '@FixMethodOrder(MethodSorters.NAME_ASCENDING)', '@Test', '@Ignore', 'import io.restassured.module.mockmvc.specification.MockMvcRequestSpecification;', - 'import io.restassured.response.ResponseOptions;', 'import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat'] - - private static final List explicitJUnitRestAssured3ClassStrings = ['import com.jayway.jsonpath.DocumentContext;', 'import com.jayway.jsonpath.JsonPath;', - 'import org.junit.FixMethodOrder;', 'import org.junit.Ignore;', 'import org.junit.Test;', 'import org.junit.runners.MethodSorters;', - 'import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson;', 'import static io.restassured.RestAssured.*;', - '@FixMethodOrder(MethodSorters.NAME_ASCENDING)', '@Test', '@Ignore', 'import io.restassured.specification.RequestSpecification;', - 'import io.restassured.response.Response;', 'import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat'] - - private static - final List mockMvcJUnit5RestAssured3ClassStrings = ['import com.jayway.jsonpath.DocumentContext;', 'import com.jayway.jsonpath.JsonPath;', - 'import org.junit.jupiter.api.Disabled;', 'import org.junit.jupiter.api.Test;', - 'import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson;', 'import static io.restassured.module.mockmvc.RestAssuredMockMvc.*;', - '@Test', '@Disabled', 'import io.restassured.module.mockmvc.specification.MockMvcRequestSpecification;', - 'import io.restassured.response.ResponseOptions;', 'import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat', - 'import org.junit.jupiter.api.TestMethodOrder', 'import org.junit.jupiter.api.MethodOrderer', '@TestMethodOrder(MethodOrderer.Alphanumeric.class)'] - - private static - final List explicitJUnit5RestAssured3ClassStrings = ['import com.jayway.jsonpath.DocumentContext;', 'import com.jayway.jsonpath.JsonPath;', - 'import org.junit.jupiter.api.Disabled;', 'import org.junit.jupiter.api.Test;', - 'import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson;', 'import static io.restassured.RestAssured.*;', - '@Test', '@Disabled', 'import io.restassured.specification.RequestSpecification;', - 'import io.restassured.response.Response;', 'import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat', - 'org.junit.jupiter.api.TestMethodOrder', 'org.junit.jupiter.api.MethodOrderer', '@TestMethodOrder(MethodOrderer.Alphanumeric.class)'] - - private static - final List mockMvcTestNGRestAssured3ClassStrings = ['import com.jayway.jsonpath.DocumentContext;', 'import com.jayway.jsonpath.JsonPath;', - 'import org.testng.annotations.Test;', - 'import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson;', 'import static io.restassured.module.mockmvc.RestAssuredMockMvc.*;', - '@Test', 'import io.restassured.module.mockmvc.specification.MockMvcRequestSpecification;', - 'import io.restassured.response.ResponseOptions;', 'import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat'] - - private static - final List explicitTestNGRestAssured3ClassStrings = ['import com.jayway.jsonpath.DocumentContext;', 'import com.jayway.jsonpath.JsonPath;', - 'import org.testng.annotations.Test;', - 'import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson;', 'import static io.restassured.RestAssured.*;', - '@Test', 'import io.restassured.specification.RequestSpecification;', - 'import io.restassured.response.Response;', 'import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat'] - - private static final List spockClassRestAssured3Strings = ['import com.jayway.jsonpath.DocumentContext', 'import com.jayway.jsonpath.JsonPath', - 'import spock.lang.Ignore', 'import spock.lang.Specification', 'import spock.lang.Stepwise', - 'import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson', 'import static io.restassured.module.mockmvc.RestAssuredMockMvc.*', - '@Stepwise', '@Ignore', 'org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat'] - - private static final List explicitSpockRestAssured2ClassStrings = ['import com.jayway.jsonpath.DocumentContext', 'import com.jayway.jsonpath.JsonPath', - 'import spock.lang.Ignore', 'import spock.lang.Specification', 'import spock.lang.Stepwise', - 'import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson', 'import static com.jayway.restassured.RestAssured.*', - '@Stepwise', '@Ignore', 'org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat'] - - private static final List explicitSpockRestAssured3ClassStrings = ['import com.jayway.jsonpath.DocumentContext', 'import com.jayway.jsonpath.JsonPath', - 'import spock.lang.Ignore', 'import spock.lang.Specification', 'import spock.lang.Stepwise', - 'import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson', 'import static io.restassured.RestAssured.*', - '@Stepwise', '@Ignore', 'org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat'] - - public static final Closure JAVA_ASSERTER = { String classToTest -> - String name = Math.abs(new Random().nextInt()) - String changedTest = classToTest - .replace('public class Test', "public class Test${name}") - .replace('public class ContractsTest', "public class Test${name}") - String fqn = FQN(classToTest) - SyntaxChecker.tryToCompileJavaWithoutImports("${fqn}${name}", changedTest) - } - - static String FQN(String classToTest) { - return classToTest.contains('0_1_0_dev_1_uncommitted_d1174dd') ? - 'org.springframework.cloud.contract.verifier.tests.com_uscm.dale_api44_spec._0_1_0_dev_1_uncommitted_d1174dd.Test' : - 'test.Test' - } - - public static final Closure JAVA_JAXRS_ASSERTER = { String classToTest -> - String name = Math.abs(new Random().nextInt()) - String changedTest = classToTest - .replace('public class Test {', "public class Test${name} {\njavax.ws.rs.client.WebTarget webTarget;\n") - .replace('public class ContractsTest {', "public class Test${name} {\njavax.ws.rs.client.WebTarget webTarget;\n") - String fqn = FQN(classToTest) - SyntaxChecker.tryToCompileJavaWithoutImports("${fqn}${name}", changedTest) - } - - public static final Closure GROOVY_ASSERTER = { String classToTest -> - SyntaxChecker.tryToCompileGroovyWithoutImports(classToTest) - } - - def setup() { - file = tmpFolder.newFile() - writeContract(file) - tmp = tmpFolder.newFolder() - File classpath = new File(SingleTestGeneratorSpec.class.getResource('/classpath/').toURI()) - FileSystemUtils.copyRecursively(classpath, tmp) - def resource = SingleTestGeneratorSpec.class.getResource('/request.json')?.toURI() - if (resource != null) { - new File(resource)?.delete() - } - resource = SingleTestGeneratorSpec.class.getResource('/response.json')?.toURI() - if (resource != null) { - new File(resource)?.delete() - } - } - - private static writeContract(File file) { - file.write(''' - org.springframework.cloud.contract.spec.Contract.make { - request { - method 'PUT' - url 'url' - } - response { - status OK() - body(["foo" : "bar"]) - } - } -''') - } - - def 'should build test class for #testFramework and mode #mode'() { - given: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() - properties.testFramework = testFramework - properties.testMode = mode - ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2, - convertAsCollection(new File('/'), file)) - JavaTestGenerator testGenerator = new JavaTestGenerator() - - when: - String clazz = testGenerator.buildClass(properties, [contract], 'com/foo', new SingleTestGenerator.GeneratedClassData('test', 'test', file.toPath())) - - then: - classStrings.each { assert clazz.contains(it) } - and: - asserter(clazz) - where: - testFramework | mode | classStrings | asserter - JUNIT | MOCKMVC | mockMvcJUnitRestAssured3ClassStrings | JAVA_ASSERTER - JUNIT | EXPLICIT | explicitJUnitRestAssured3ClassStrings | JAVA_ASSERTER - JUNIT5 | MOCKMVC | mockMvcJUnit5RestAssured3ClassStrings | JAVA_ASSERTER - JUNIT5 | EXPLICIT | explicitJUnit5RestAssured3ClassStrings | JAVA_ASSERTER - TESTNG | MOCKMVC | mockMvcTestNGRestAssured3ClassStrings | JAVA_ASSERTER - TESTNG | EXPLICIT | explicitTestNGRestAssured3ClassStrings | JAVA_ASSERTER - SPOCK | MOCKMVC | spockClassRestAssured3Strings | GROOVY_ASSERTER - SPOCK | EXPLICIT | explicitSpockRestAssured3ClassStrings | GROOVY_ASSERTER - } - - def 'should build test class for #testFramework when the path contains bizarre signs'() { - given: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() - properties.testFramework = testFramework - properties.basePackageForTests = 'org.springframework.cloud.contract.verifier.tests' - and: - File newFolder = tmpFolder.newFolder('META_INF') - File subfolders = new File(newFolder, '/com.uscm/dale_api44_spec/0.1.0_dev.1.uncommitted+d1174dd/contracts/') - subfolders.mkdirs() - File newFile = new File(subfolders, 'contract.groovy') - newFile.createNewFile() - writeContract(newFile) - properties.contractsDslDir = newFolder - properties.generatedTestSourcesDir = newFolder.parentFile - properties.generatedTestResourcesDir = newFolder.parentFile - when: - int size = new TestGenerator(properties).generate() - then: - size > 0 - asserter(new File(newFolder.parent, '/org/springframework/cloud/contract/verifier/tests/com_uscm/dale_api44_spec/_0_1_0_dev_1_uncommitted_d1174dd/' + testName).text) - where: - testFramework | mode | asserter | testName - JUNIT | MOCKMVC | JAVA_ASSERTER | 'ContractsTest.java' - JUNIT | EXPLICIT | JAVA_ASSERTER | 'ContractsTest.java' - JUNIT5 | MOCKMVC | JAVA_ASSERTER | 'ContractsTest.java' - JUNIT5 | EXPLICIT | JAVA_ASSERTER | 'ContractsTest.java' - TESTNG | MOCKMVC | JAVA_ASSERTER | 'ContractsTest.java' - TESTNG | EXPLICIT | JAVA_ASSERTER | 'ContractsTest.java' - SPOCK | MOCKMVC | GROOVY_ASSERTER | 'ContractsSpec.groovy' - SPOCK | EXPLICIT | GROOVY_ASSERTER | 'ContractsSpec.groovy' - } - - def 'should build test class for #testFramework and mode #mode with two files'() { - given: - File file = tmpFolder.newFile() - file.write(''' - org.springframework.cloud.contract.spec.Contract.make { - request { - method 'PUT' - url 'url1' - headers { - contentType(applicationJson()) - } - } - response { - status OK() - body(foo:"foo", bar:"bar") - headers { - contentType(applicationJson()) - } - } - } - ''') - and: - File file2 = tmpFolder.newFile() - file2.write(''' - org.springframework.cloud.contract.spec.Contract.make { - request { - method 'PUT' - url 'url2' - headers { - contentType(applicationJson()) - } - } - response { - status OK() - body(foo:"foo", bar:"bar") - headers { - contentType(applicationJson()) - } - } - } -''') - and: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() - properties.testFramework = testFramework - ContractMetadata contract = new ContractMetadata(file.toPath(), false, 1, null, - convertAsCollection(new File('/'), file)) - contract.ignored >> false - and: - ContractMetadata contract2 = new ContractMetadata(file2.toPath(), false, 1, null, - convertAsCollection(new File('/'), file2)) - contract2.ignored >> false - and: - JavaTestGenerator testGenerator = new JavaTestGenerator() - - when: - String clazz = testGenerator.buildClass(properties, [contract, contract2], 'com/foo', new SingleTestGenerator.GeneratedClassData('test', 'test', file.toPath())) - - then: - classStrings.each { clazz.contains(it) } - and: - asserter(clazz) - and: - textAssertion(clazz) - where: - testFramework | mode | classStrings | asserter | textAssertion - JUNIT | MOCKMVC | mockMvcJUnitRestAssured3ClassStrings | JAVA_ASSERTER | { String test -> countOccurrencesOf(test, '\t\t\tMockMvcRequestSpecification') == 2 } - JUNIT | EXPLICIT | explicitJUnitRestAssured3ClassStrings | JAVA_ASSERTER | { String test -> countOccurrencesOf(test, '\t\t\tMockMvcRequestSpecification') == 2 } - JUNIT5 | MOCKMVC | mockMvcJUnit5RestAssured3ClassStrings | JAVA_ASSERTER | { String test -> countOccurrencesOf(test, '\t\t\tMockMvcRequestSpecification') == 2 } - JUNIT5 | EXPLICIT | explicitJUnit5RestAssured3ClassStrings | JAVA_ASSERTER | { String test -> countOccurrencesOf(test, '\t\t\tMockMvcRequestSpecification') == 2 } - TESTNG | MOCKMVC | mockMvcTestNGRestAssured3ClassStrings | JAVA_ASSERTER | { String test -> countOccurrencesOf(test, '\t\t\tMockMvcRequestSpecification') == 2 } - TESTNG | EXPLICIT | explicitTestNGRestAssured3ClassStrings | JAVA_ASSERTER | { String test -> countOccurrencesOf(test, '\t\t\tMockMvcRequestSpecification') == 2 } - SPOCK | MOCKMVC | spockClassRestAssured3Strings | GROOVY_ASSERTER | { String test -> countOccurrencesOf(test, '\t\t\tMockMvcRequestSpecification') == 2 } - SPOCK | EXPLICIT | explicitSpockRestAssured2ClassStrings | GROOVY_ASSERTER | { String test -> countOccurrencesOf(test, '\t\t\tMockMvcRequestSpecification request') == 2 } - } - - def 'should build JaxRs test class for #testFramework'() { - given: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() - properties.testMode = JAXRSCLIENT - properties.testFramework = testFramework - ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, null, convertAsCollection(new File('/'), file)) - contract.ignored >> true - SingleTestGenerator testGenerator = new JavaTestGenerator() - - when: - String clazz = testGenerator.buildClass(properties, [contract], 'com/foo', new SingleTestGenerator.GeneratedClassData('test', 'test', file.toPath())) - - then: - classStrings.each { clazz.contains(it) } - - and: - asserter(clazz) - - where: - testFramework | classStrings | asserter - JUNIT | ['import static javax.ws.rs.client.Entity.*', 'import javax.ws.rs.core.Response'] | JAVA_JAXRS_ASSERTER - JUNIT5 | ['import static javax.ws.rs.client.Entity.*', 'import javax.ws.rs.core.Response'] | JAVA_JAXRS_ASSERTER - TESTNG | ['import static javax.ws.rs.client.Entity.*', 'import javax.ws.rs.core.Response'] | JAVA_JAXRS_ASSERTER - SPOCK | ['import static javax.ws.rs.client.Entity.*'] | GROOVY_ASSERTER - } - - def 'should work if there is messaging and rest in one folder #testFramework'() { - given: - File secondFile = tmpFolder.newFile() - secondFile.write(''' - org.springframework.cloud.contract.spec.Contract.make { - ignored() - label 'some_label' - input { - triggeredBy("hashCode()") - assertThat('hashCode()') - } - } - ''') - and: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties( - generatedTestResourcesDir: file.parentFile, - generatedTestSourcesDir: file.parentFile - ) - properties.testFramework = testFramework - ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2, - convertAsCollection(new File('/'), file)) - contract.ignored >> true - and: - ContractMetadata contract2 = new ContractMetadata(secondFile. - toPath(), true, 1, 2, convertAsCollection(new File('/'), secondFile)) - contract2.ignored >> true - and: - JavaTestGenerator testGenerator = new JavaTestGenerator() - - when: - String clazz = testGenerator.buildClass(properties, [contract, contract2], 'com/foo', new SingleTestGenerator.GeneratedClassData('test', 'test', file.toPath())) - - then: - classStrings.each { clazz.contains(it) } - clazz.contains('@Inject ContractVerifierMessaging') - - and: - asserter(clazz) - - where: - testFramework | classStrings | asserter - JUNIT | mockMvcJUnitRestAssured3ClassStrings | JAVA_ASSERTER - JUNIT5 | mockMvcJUnit5RestAssured3ClassStrings | JAVA_ASSERTER - TESTNG | mockMvcTestNGRestAssured3ClassStrings | JAVA_ASSERTER - SPOCK | spockClassRestAssured3Strings | GROOVY_ASSERTER - } - - @Issue('#30') - def 'should ignore a test if the contract is ignored in the dsl'() { - given: - File secondFile = tmpFolder.newFile() - secondFile.write(''' - org.springframework.cloud.contract.spec.Contract.make { - ignored() - request { - method 'PUT' - url 'url' - } - response { - status OK() - } - } - ''') - and: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() - properties.testFramework = testFramework - and: - ContractMetadata contract2 = new ContractMetadata(secondFile. - toPath(), true, 1, 2, convertAsCollection(new File('/'), file)) - contract2.ignored >> false - and: - JavaTestGenerator testGenerator = new JavaTestGenerator() - - when: - String clazz = testGenerator.buildClass(properties, [contract2], 'com/foo', new SingleTestGenerator.GeneratedClassData('test', 'test', file.toPath())) - - then: - classStrings.each { clazz.contains(it) } - clazz.contains(ignoreAnnotation) - - and: - asserter(clazz) - - where: - testFramework | classStrings | ignoreAnnotation | asserter - JUNIT | mockMvcJUnitRestAssured3ClassStrings | '@Ignore' | JAVA_ASSERTER - JUNIT5 | mockMvcJUnit5RestAssured3ClassStrings | '@Disabled' | JAVA_ASSERTER - TESTNG | mockMvcTestNGRestAssured3ClassStrings | '@Test(enabled = false)' | JAVA_ASSERTER - SPOCK | spockClassRestAssured3Strings | '@Ignore' | GROOVY_ASSERTER - } - - @Issue('#1326') - def 'should only ignore test for ignored contract if contract is ignored by configuration #testFramework'() { - given: - File fileToIgnore = tmpFolder.newFile("toIgnore.groovy") - writeContract(fileToIgnore) - ContractMetadata contractToIgnore = new ContractMetadata(fileToIgnore.toPath(), - true, 2, 1, convertAsCollection(new File('/'), fileToIgnore)) - and: - File fileToCheck = tmpFolder.newFile("toCheck.groovy") - writeContract(fileToCheck) - ContractMetadata contractToCheck = new ContractMetadata(fileToCheck.toPath(), - false, 2, 2, convertAsCollection(new File('/'), fileToCheck)) - and: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() - properties.testFramework = testFramework - properties.ignoredFiles = [fileToIgnore.name] - and: - JavaTestGenerator testGenerator = new JavaTestGenerator() - - when: - String clazz = testGenerator.buildClass(properties, [contractToCheck, contractToIgnore], 'com/foo', - new SingleTestGenerator.GeneratedClassData('test', 'test', file.toPath())) - - then: - countOccurrencesOf(clazz, ignoreAnnotation) == 1 - - where: - testFramework | ignoreAnnotation - JUNIT | '@Ignore' - JUNIT5 | '@Disabled' - TESTNG | '@Test(enabled = false)' - SPOCK | '@Ignore' - } - - def 'should not allow the usage of ignore annotations for TestNG '() { - given: - TestFramework testNG = TESTNG - - when: - testNG.getIgnoreClass() - then: - thrown UnsupportedOperationException - - when: - testNG.getIgnoreAnnotation() - then: - thrown UnsupportedOperationException - } - - @Issue('#1346') - def 'should ignore 1 test if only 1-of-2 contracts is ignored in Contract dsl for #testFramework'() { - given: - File firstFile = tmpFolder.newFile() - firstFile.write(''' - org.springframework.cloud.contract.spec.Contract.make { - request { - method 'GET' - url 'url' - } - response { - status OK() - } - } - ''') - - File secondFile = tmpFolder.newFile() - secondFile.write(''' - org.springframework.cloud.contract.spec.Contract.make { - ignored() - request { - method 'POST' - url 'url' - } - response { - status OK() - } - } - ''') - and: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() - properties.testFramework = testFramework - and: - ContractMetadata firstContract = new ContractMetadata(firstFile. - toPath(), false, 1, null, convertAsCollection(new File('/'), firstFile)) - firstContract.ignored >> false - and: - ContractMetadata secondContract = new ContractMetadata(secondFile. - toPath(), false, 1, null, convertAsCollection(new File('/'), secondFile)) - secondContract.ignored >> false - and: - JavaTestGenerator testGenerator = new JavaTestGenerator() - - when: - String clazz = testGenerator.buildClass(properties, [secondContract, firstContract], 'com/foo', new SingleTestGenerator.GeneratedClassData('test', 'test', secondFile.toPath())) - - then: - classStrings.each { clazz.contains(it) } - countOccurrencesOf(clazz, ignoreAnnotation) == 1 - - and: - asserter(clazz) - - where: - testFramework | classStrings | ignoreAnnotation | asserter - JUNIT | mockMvcJUnitRestAssured3ClassStrings | '@Ignore' | JAVA_ASSERTER - JUNIT5 | mockMvcJUnit5RestAssured3ClassStrings | '@Disabled' | JAVA_ASSERTER - TESTNG | mockMvcTestNGRestAssured3ClassStrings | '@Test(enabled = false)' | JAVA_ASSERTER - SPOCK | spockClassRestAssured3Strings | '@Ignore' | GROOVY_ASSERTER - } - - @Issue('#1346') - def 'should ignore 2 tests if 2 contracts are ignored in Contract dsl for #testFramework'() { - given: - File firstFile = tmpFolder.newFile() - firstFile.write(''' - org.springframework.cloud.contract.spec.Contract.make { - ignored() - request { - method 'GET' - url 'url' - } - response { - status OK() - } - } - ''') - - File secondFile = tmpFolder.newFile() - secondFile.write(''' - org.springframework.cloud.contract.spec.Contract.make { - ignored() - request { - method 'POST' - url 'url' - } - response { - status OK() - } - } - ''') - and: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() - properties.testFramework = testFramework - and: - ContractMetadata firstContract = new ContractMetadata(firstFile. - toPath(), false, 1, null, convertAsCollection(new File('/'), firstFile)) - firstContract.ignored >> false - and: - ContractMetadata secondContract = new ContractMetadata(secondFile. - toPath(), false, 1, null, convertAsCollection(new File('/'), secondFile)) - secondContract.ignored >> false - and: - JavaTestGenerator testGenerator = new JavaTestGenerator() - - when: - String clazz = testGenerator.buildClass(properties, [secondContract, firstContract], 'com/foo', new SingleTestGenerator.GeneratedClassData('test', 'test', secondFile.toPath())) - - then: - classStrings.each { clazz.contains(it) } - countOccurrencesOf(clazz, ignoreAnnotation) == 2 - - and: - asserter(clazz) - - where: - testFramework | classStrings | ignoreAnnotation | asserter - JUNIT | mockMvcJUnitRestAssured3ClassStrings | '@Ignore' | JAVA_ASSERTER - JUNIT5 | mockMvcJUnit5RestAssured3ClassStrings | '@Disabled' | JAVA_ASSERTER - TESTNG | mockMvcTestNGRestAssured3ClassStrings | '@Test(enabled = false)' | JAVA_ASSERTER - SPOCK | spockClassRestAssured3Strings | '@Ignore' | GROOVY_ASSERTER - } - - @Issue('#1346') - def 'should ignore 2 tests if 2 contracts are ignored in Contract dsl and in Configuration for #testFramework'() { - given: - File firstFile = tmpFolder.newFile() - firstFile.write(''' - org.springframework.cloud.contract.spec.Contract.make { - ignored() - request { - method 'GET' - url 'url' - } - response { - status OK() - } - } - ''') - - File secondFile = tmpFolder.newFile() - secondFile.write(''' - org.springframework.cloud.contract.spec.Contract.make { - ignored() - request { - method 'POST' - url 'url' - } - response { - status OK() - } - } - ''') - and: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() - properties.testFramework = testFramework - and: - ContractMetadata firstContract = new ContractMetadata(firstFile. - toPath(), true, 1, null, convertAsCollection(new File('/'), firstFile)) - firstContract.ignored >> true - and: - ContractMetadata secondContract = new ContractMetadata(secondFile. - toPath(), true, 1, null, convertAsCollection(new File('/'), secondFile)) - secondContract.ignored >> true - and: - JavaTestGenerator testGenerator = new JavaTestGenerator() - - when: - String clazz = testGenerator.buildClass(properties, [secondContract, firstContract], 'com/foo', new SingleTestGenerator.GeneratedClassData('test', 'test', secondFile.toPath())) - - then: - classStrings.each { clazz.contains(it) } - countOccurrencesOf(clazz, ignoreAnnotation) == 2 - - and: - asserter(clazz) - - where: - testFramework | classStrings | ignoreAnnotation | asserter - JUNIT | mockMvcJUnitRestAssured3ClassStrings | '@Ignore' | JAVA_ASSERTER - JUNIT5 | mockMvcJUnit5RestAssured3ClassStrings | '@Disabled' | JAVA_ASSERTER - TESTNG | mockMvcTestNGRestAssured3ClassStrings | '@Test(enabled = false)' | JAVA_ASSERTER - SPOCK | spockClassRestAssured3Strings | '@Ignore' | GROOVY_ASSERTER - } - - @Issue('#1346') - def 'should ignore 1 tests if 1 of 2 contract is ignored in Contract dsl and in Configuration for #testFramework'() { - given: - File firstFile = tmpFolder.newFile() - firstFile.write(''' - org.springframework.cloud.contract.spec.Contract.make { - ignored() - request { - method 'GET' - url 'url' - } - response { - status OK() - } - } - ''') - - File secondFile = tmpFolder.newFile() - secondFile.write(''' - org.springframework.cloud.contract.spec.Contract.make { - request { - method 'POST' - url 'url' - } - response { - status OK() - } - } - ''') - and: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() - properties.testFramework = testFramework - and: - ContractMetadata firstContract = new ContractMetadata(firstFile. - toPath(), true, 1, null, convertAsCollection(new File('/'), firstFile)) - firstContract.ignored >> true - and: - ContractMetadata secondContract = new ContractMetadata(secondFile. - toPath(), false, 1, null, convertAsCollection(new File('/'), secondFile)) - secondContract.ignored >> false - and: - JavaTestGenerator testGenerator = new JavaTestGenerator() - - when: - String clazz = testGenerator.buildClass(properties, [secondContract, firstContract], 'com/foo', new SingleTestGenerator.GeneratedClassData('test', 'test', secondFile.toPath())) - - then: - classStrings.each { clazz.contains(it) } - countOccurrencesOf(clazz, ignoreAnnotation) == 1 - - and: - asserter(clazz) - - where: - testFramework | classStrings | ignoreAnnotation | asserter - JUNIT | mockMvcJUnitRestAssured3ClassStrings | '@Ignore' | JAVA_ASSERTER - JUNIT5 | mockMvcJUnit5RestAssured3ClassStrings | '@Disabled' | JAVA_ASSERTER - TESTNG | mockMvcTestNGRestAssured3ClassStrings | '@Test(enabled = false)' | JAVA_ASSERTER - SPOCK | spockClassRestAssured3Strings | '@Ignore' | GROOVY_ASSERTER - } - - @Issue('#1346') - def 'should ignore 2 tests if 1st contracts is ignored in Contract dsl and 2nd is ignored in Configuration for #testFramework'() { - given: - File firstFile = tmpFolder.newFile() - firstFile.write(''' - org.springframework.cloud.contract.spec.Contract.make { - ignored() - request { - method 'GET' - url 'url' - } - response { - status OK() - } - } - ''') - - File secondFile = tmpFolder.newFile() - secondFile.write(''' - org.springframework.cloud.contract.spec.Contract.make { - request { - method 'POST' - url 'url' - } - response { - status OK() - } - } - ''') - and: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() - properties.testFramework = testFramework - and: - ContractMetadata firstContract = new ContractMetadata(firstFile. - toPath(), false, 1, null, convertAsCollection(new File('/'), firstFile)) - firstContract.ignored >> false - and: - ContractMetadata secondContract = new ContractMetadata(secondFile. - toPath(), true, 1, null, convertAsCollection(new File('/'), secondFile)) - secondContract.ignored >> true - and: - JavaTestGenerator testGenerator = new JavaTestGenerator() - - when: - String clazz = testGenerator.buildClass(properties, [secondContract, firstContract], 'com/foo', new SingleTestGenerator.GeneratedClassData('test', 'test', secondFile.toPath())) - - then: - classStrings.each { clazz.contains(it) } - countOccurrencesOf(clazz, ignoreAnnotation) == 2 - - and: - asserter(clazz) - - where: - testFramework | classStrings | ignoreAnnotation | asserter - JUNIT | mockMvcJUnitRestAssured3ClassStrings | '@Ignore' | JAVA_ASSERTER - JUNIT5 | mockMvcJUnit5RestAssured3ClassStrings | '@Disabled' | JAVA_ASSERTER - TESTNG | mockMvcTestNGRestAssured3ClassStrings | '@Test(enabled = false)' | JAVA_ASSERTER - SPOCK | spockClassRestAssured3Strings | '@Ignore' | GROOVY_ASSERTER - } - - @Issue('#1346') - def 'should ignore 0 tests if 0 contracts are ignored in Contract dsl and in Configuration for #testFramework'() { - given: - File firstFile = tmpFolder.newFile() - firstFile.write(''' - org.springframework.cloud.contract.spec.Contract.make { - request { - method 'GET' - url 'url' - } - response { - status OK() - } - } - ''') - - File secondFile = tmpFolder.newFile() - secondFile.write(''' - org.springframework.cloud.contract.spec.Contract.make { - request { - method 'POST' - url 'url' - } - response { - status OK() - } - } - ''') - and: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() - properties.testFramework = testFramework - and: - ContractMetadata firstContract = new ContractMetadata(firstFile. - toPath(), false, 1, null, convertAsCollection(new File('/'), firstFile)) - firstContract.ignored >> false - and: - ContractMetadata secondContract = new ContractMetadata(secondFile. - toPath(), false, 1, null, convertAsCollection(new File('/'), secondFile)) - secondContract.ignored >> false - and: - JavaTestGenerator testGenerator = new JavaTestGenerator() - - when: - String clazz = testGenerator.buildClass(properties, [secondContract, firstContract], 'com/foo', new SingleTestGenerator.GeneratedClassData('test', 'test', secondFile.toPath())) - - then: - classStrings.each { clazz.contains(it) } - countOccurrencesOf(clazz, ignoreAnnotation) == 0 - - and: - asserter(clazz) - - where: - testFramework | classStrings | ignoreAnnotation | asserter - JUNIT | mockMvcJUnitRestAssured3ClassStrings | '@Ignore' | JAVA_ASSERTER - JUNIT5 | mockMvcJUnit5RestAssured3ClassStrings | '@Disabled' | JAVA_ASSERTER - TESTNG | mockMvcTestNGRestAssured3ClassStrings | '@Test(enabled = false)' | JAVA_ASSERTER - SPOCK | spockClassRestAssured3Strings | '@Ignore' | GROOVY_ASSERTER - } - - @Issue('#117') - def 'should generate test in explicit test mode using JUnit'() { - given: - String baseClass = ''' - // tag::context_path_baseclass[] - import io.restassured.RestAssured; - import org.junit.Before; - import org.springframework.boot.test.context.SpringBootTest; - import org.springframework.boot.test.web.server.LocalServerPort; - - @SpringBootTest(classes = ContextPathTestingBaseClass.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) - class ContextPathTestingBaseClass { - - @LocalServerPort int port; - - @Before - public void setup() { - RestAssured.baseURI = "http://localhost"; - RestAssured.port = this.port; - } - } - // end::context_path_baseclass[] - ''' - SyntaxChecker.tryToCompileJavaWithoutImports('test.ContextPathTestingBaseClass', "package test;\n${baseClass}") - and: - File secondFile = tmpFolder.newFile() - secondFile.write(''' - // tag::context_path_contract[] - org.springframework.cloud.contract.spec.Contract.make { - request { - method 'GET' - url '/my-context-path/url' - } - response { - status OK() - } - } - // end::context_path_contract[] - ''') - and: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() - properties.testFramework = JUNIT - properties.testMode = EXPLICIT - properties.baseClassForTests = 'test.ContextPathTestingBaseClass' - and: - ContractMetadata contract = new ContractMetadata(file.toPath(), false, 1, - null, convertAsCollection(new File('/'), file)) - and: - SingleTestGenerator testGenerator = new JavaTestGenerator() - when: - String clazz = testGenerator.buildClass(properties, [contract], 'com/foo', new SingleTestGenerator.GeneratedClassData('test', 'test', file.toPath())) - then: - clazz.contains('RequestSpecification request = given();') - clazz.contains('Response response = given().spec(request)') - } - - def "should pick the contract's name as the test method for #testFramework"() { - given: - File secondFile = tmpFolder.newFile() - secondFile.write(''' - org.springframework.cloud.contract.spec.Contract.make { - name("MySuperMethod") - request { - method 'PUT' - url 'url' - } - response { - status OK() - } - } - ''') - and: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() - properties.testFramework = testFramework - ContractMetadata contract = new ContractMetadata(secondFile.toPath(), false, 1, null, convertAsCollection(new File('/'), secondFile)) - JavaTestGenerator testGenerator = new JavaTestGenerator() - when: - String clazz = testGenerator.buildClass(properties, [contract], 'com/foo', new SingleTestGenerator.GeneratedClassData('test', 'test', file.toPath())) - then: - clazz.contains('validate_mySuperMethod()') - where: - testFramework << [JUNIT, JUNIT5, TESTNG, SPOCK] - } - - def "should pick the contract's name as the test method when there are multiple contracts for #testFramework"() { - given: - File secondFile = tmpFolder.newFile() - secondFile.write(''' - (1..2).collect { int index -> - org.springframework.cloud.contract.spec.Contract.make { - name("shouldHaveIndex${index}") - request { - method(PUT()) - headers { - contentType(applicationJson()) - } - url "/${index}" - } - response { - status OK() - } - } -}''') - and: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() - properties.testFramework = testFramework - ContractMetadata contract = new ContractMetadata(secondFile.toPath(), false, 1, null, convertAsCollection(new File('/'), secondFile)) - JavaTestGenerator testGenerator = new JavaTestGenerator() - when: - String clazz = testGenerator.buildClass(properties, [contract], 'com/foo', new SingleTestGenerator.GeneratedClassData('test', 'test', file.toPath())) - then: - clazz.contains('validate_shouldHaveIndex1()') - clazz.contains('validate_shouldHaveIndex2()') - where: - testFramework << [JUNIT, JUNIT5, TESTNG, SPOCK] - } - - def 'should generate the test method when there are multiple contracts without name field for #testFramework'() { - given: - File secondFile = tmpFolder.newFile() - secondFile.write(''' - (1..2).collect { int index -> - org.springframework.cloud.contract.spec.Contract.make { - request { - method(PUT()) - headers { - contentType(applicationJson()) - } - url "/${index}" - } - response { - status OK() - } - } -}''') - and: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() - properties.testFramework = testFramework - ContractMetadata contract = new ContractMetadata(secondFile.toPath(), false, 1, null, convertAsCollection(new File('/'), secondFile)) - JavaTestGenerator testGenerator = new JavaTestGenerator() - when: - String clazz = testGenerator.buildClass(properties, [contract], 'com/foo', new SingleTestGenerator.GeneratedClassData('test', 'test', file.toPath())) - then: - clazz.contains('_0() throws Exception') - clazz.contains('_1() throws Exception') - where: - testFramework << [JUNIT, JUNIT5, TESTNG, SPOCK] - } - - @Issue('#359') - def 'should generate tests from a contract that references a file for [#testFramework]'() { - given: - File output = new File(tmp, 'readFromFile.groovy') - File contractLocation = output - File temp = tmpFolder.newFolder() - and: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties( - testFramework: testFramework, - contractsDslDir: contractLocation.parentFile, - basePackageForTests: 'a.b', - generatedTestSourcesDir: temp, - generatedTestResourcesDir: tmpFolder.newFolder() - ) - TestGenerator testGenerator = new TestGenerator(properties) - when: - int count = testGenerator.generate() - then: - count == 1 - and: - String test = new File(temp, "a/b/ContractVerifier${getTestName(testFramework)}").text - test.contains('readFromFile_request_request.json') - test.contains('RESPONSE') - where: - testFramework << [JUNIT, JUNIT5, TESTNG, SPOCK] - } - - @Issue('#260') - def 'should generate tests in a folder taken from basePackageForTests when it is set for [#testFramework]'() { - given: - File output = new File(tmp, 'readFromFile.groovy') - File contractLocation = output - File temp = tmpFolder.newFolder() - and: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties( - testFramework: testFramework, contractsDslDir: contractLocation.parentFile, - basePackageForTests: 'a.b', generatedTestSourcesDir: temp, - generatedTestResourcesDir: tmpFolder.newFolder() - ) - TestGenerator testGenerator = new TestGenerator(properties) - when: - int count = testGenerator.generate() - then: - count == 1 - and: - String test = new File(temp, "a/b/ContractVerifier${getTestName(testFramework)}").text - test.contains('readFromFile_request_request.json') - test.contains('RESPONSE') - where: - testFramework << [JUNIT, JUNIT5, TESTNG, SPOCK] - } - - @Issue('#1199') - def 'should generate tests with body from file with custom charset [#testFramework]'() { - given: - file = tmpFolder.newFile() - writeContract(file) - tmp = tmpFolder.newFolder() - File classpath = new File(SingleTestGeneratorSpec.class.getResource('/charset/').toURI()) - FileSystemUtils.copyRecursively(classpath, tmp) - and: - File output = new File(tmp, 'readFromFileWithCharset.groovy') - File contractLocation = output - File temp = tmpFolder.newFolder() - and: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties( - testFramework: testFramework, contractsDslDir: contractLocation.parentFile, - basePackageForTests: 'a.b', generatedTestSourcesDir: temp, - generatedTestResourcesDir: tmpFolder.newFolder() - ) - TestGenerator testGenerator = new TestGenerator(properties) - when: - int count = testGenerator.generate() - then: - count == 1 - and: - String test = new File(temp, "a/b/ContractVerifier${getTestName(testFramework)}").text - test.contains('readFromFileWithCharset_request_request.json') - test.contains('RESPONSE') - test.contains('body(new String(fileToBytes(this, "readFromFileWithCharset_request_request.json"), "US-ASCII"))') - where: - testFramework << [JUNIT, JUNIT5, SPOCK] - } - - @Issue('#260') - def "should generate tests in a folder taken from baseClassForTests's package when it is set for [#testFramework]"() { - given: - File output = new File(tmp, 'readFromFile.groovy') - File contractLocation = output - File temp = tmpFolder.newFolder() - and: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties( - testFramework: testFramework, contractsDslDir: contractLocation.parentFile, - baseClassForTests: 'a.b.SomeClass', generatedTestSourcesDir: temp, - generatedTestResourcesDir: tmpFolder.newFolder() - ) - TestGenerator testGenerator = new TestGenerator(properties) - when: - int count = testGenerator.generate() - then: - count == 1 - and: - String test = new File(temp, "a/b/ContractVerifier${getTestName(testFramework)}").text - test.contains('readFromFile_request_request.json') - test.contains('RESPONSE') - where: - testFramework << [JUNIT, JUNIT5, TESTNG, SPOCK] - } - - @Issue('#260') - def 'should generate tests in a folder taken from packageWithBaseClasses when it is set for [#testFramework]'() { - given: - File output = new File(tmp, 'readFromFile.groovy') - File contractLocation = output - File temp = tmpFolder.newFolder() - and: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties( - testFramework: testFramework, contractsDslDir: contractLocation.parentFile, - packageWithBaseClasses: 'a.b', generatedTestSourcesDir: temp, - generatedTestResourcesDir: tmpFolder.newFolder() - ) - TestGenerator testGenerator = new TestGenerator(properties) - when: - int count = testGenerator.generate() - then: - count == 1 - and: - String test = new File(temp, "a/b/ContractVerifier${getTestName(testFramework)}").text - test.contains('readFromFile_request_request.json') - test.contains('RESPONSE') - where: - testFramework << [JUNIT, JUNIT5, TESTNG, SPOCK] - } - - @Issue('#260') - def 'should generate tests in a default folder when no property was passed for [#testFramework]'() { - given: - File output = new File(tmp, 'readFromFile.groovy') - File contractLocation = output - File temp = tmpFolder.newFolder() - and: - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties( - testFramework: testFramework, contractsDslDir: contractLocation.parentFile, - generatedTestSourcesDir: temp, generatedTestResourcesDir: tmpFolder.newFolder() - ) - TestGenerator testGenerator = new TestGenerator(properties) - when: - int count = testGenerator.generate() - then: - count == 1 - and: - String test = new File(temp, "org/springframework/cloud/contract/verifier/tests/ContractVerifier${getTestName(testFramework)}").text - test.contains('readFromFile_request_request.json') - test.contains('RESPONSE') - where: - testFramework << [JUNIT, JUNIT5, TESTNG, SPOCK] - } - - private static String getTestName(TestFramework testFramework) { - testFramework == SPOCK ? 'Spec.groovy' : 'Test.java' - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SpringTestMethodBodyBuildersSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SpringTestMethodBodyBuildersSpec.groovy deleted file mode 100644 index 74ab805013..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SpringTestMethodBodyBuildersSpec.groovy +++ /dev/null @@ -1,3403 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder - -import java.util.regex.Pattern - -import org.junit.Rule -import spock.lang.Issue -import spock.lang.Shared -import spock.lang.Specification -import spock.util.environment.RestoreSystemProperties - -import org.springframework.boot.test.system.OutputCaptureRule -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties -import org.springframework.cloud.contract.verifier.config.TestFramework -import org.springframework.cloud.contract.verifier.config.TestMode -import org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockStubVerifier -import org.springframework.cloud.contract.verifier.file.ContractMetadata -import org.springframework.cloud.contract.verifier.util.SyntaxChecker -/** - * @author Jakub Kubrynski, codearte.io - * @author Tim Ysewyn - */ -class SpringTestMethodBodyBuildersSpec extends Specification implements WireMockStubVerifier { - - @Rule - OutputCaptureRule capture = new OutputCaptureRule() - - @Shared - ContractVerifierConfigProperties configProperties = newProps() - - private static ContractVerifierConfigProperties newProps() { - new ContractVerifierConfigProperties( - assertJsonSize: true, - generatedTestResourcesDir: new File("./target/generated-test-resources"), - generatedTestSourcesDir: new File("./target/generated-test-sources") - ) - } - - @Shared - SingleTestGenerator.GeneratedClassData generatedClassData = - new SingleTestGenerator.GeneratedClassData("foo", "com.example", new File("./target/generated-test-sources").toPath()) - - @Shared - Contract contractDslWithCookiesValue = Contract.make { - request { - method "GET" - url "/foo" - headers { - header 'Accept': 'application/json' - } - cookies { - cookie 'cookie-key': 'cookie-value' - } - } - response { - status 200 - headers { - header 'Content-Type': 'application/json' - } - cookies { - cookie 'cookie-key': 'new-cookie-value' - } - body([status: 'OK']) - } - } - - @Shared - Contract contractDslWithCookiesPattern = Contract.make { - request { - method "GET" - url "/foo" - headers { - header 'Accept': 'application/json' - } - cookies { - cookie 'cookie-key': regex('[A-Za-z]+') - } - } - response { - status 200 - headers { - header 'Content-Type': 'application/json' - } - cookies { - cookie 'cookie-key': regex('[A-Za-z]+') - } - body([status: 'OK']) - } - } - - @Shared - Contract contractDslWithAbsentCookies = Contract.make { - request { - method "GET" - url "/foo" - cookies { - cookie 'cookie-key': absent() - } - } - response { - status 200 - body([status: 'OK']) - } - } - - @Shared - // tag::contract_with_regex[] - Contract dslWithOptionalsInString = Contract.make { - priority 1 - request { - method POST() - url '/users/password' - headers { - contentType(applicationJson()) - } - body( - email: $(consumer(optional(regex(email()))), producer('abc@abc.com')), - callback_url: $(consumer(regex(hostname())), producer('http://partners.com')) - ) - } - response { - status 404 - headers { - contentType(applicationJson()) - } - body( - code: value(consumer("123123"), producer(optional("123123"))), - message: "User not found by email = [${value(producer(regex(email())), consumer('not.existing@user.com'))}]" - ) - } - } - // end::contract_with_regex[] - - @Shared - Contract dslWithOptionals = Contract.make { - priority 1 - request { - method POST() - url '/users/password' - headers { - contentType(applicationJson()) - } - body( - """ { - "email" : "${ - value(consumer(optional(regex(email()))), producer('abc@abc.com')) - }", - "callback_url" : "${ - value(consumer(regex(hostname())), producer('http://partners.com')) - }" - } - """ - ) - } - response { - status 404 - headers { - contentType(applicationJson()) - } - body( - """ { - "code" : "${value(consumer(123123), producer(optional(123123)))}", - "message" : "User not found by email = [${ - value(producer(regex(email())), consumer('not.existing@user.com')) - }]" - } - """ - ) - } - } - - def setup() { - configProperties = newProps() - configProperties.generatedTestResourcesDir.mkdirs() - configProperties.generatedTestSourcesDir.mkdirs() - } - - def 'should generate assertions for simple response body with #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method GET() - url "test" - } - response { - status OK() - body """{ - "property1": "a", - "property2": "b" -}""" - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("a")""") - test.contains("""assertThatJson(parsedJson).field("['property2']").isEqualTo("b")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - private String singleTestGenerator(Contract contractDsl) { - return singleTestGenerator(Collections.singletonList(contractDsl)) - } - - private String singleTestGenerator(Collection contractDsls) { - return new JavaTestGenerator() { - @Override - ClassBodyBuilder classBodyBuilder(BlockBuilder builder, GeneratedClassMetaData metaData, SingleMethodBuilder methodBuilder) { - return super.classBodyBuilder(builder, metaData, methodBuilder).field(new Field() { - @Override - boolean accept() { - return metaData.configProperties.testMode == TestMode.JAXRSCLIENT - } - - @Override - Field call() { - builder.addLine("WebTarget webTarget") - return this - } - }) - } - }.buildClass(configProperties, Collections.singletonList(contractMetadata(contractDsls)), "foo", generatedClassData) - } - - ContractMetadata contractMetadata(Collection contractDsls) { - return new ContractMetadata(new File("./target/").toPath(), false, 0, null, contractDsls) - } - - @Issue('#187') - def 'should generate assertions for null and boolean values with #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method GET() - url 'test' - } - response { - status OK() - body """{ - "property1": "true", - "property2": null, - "property3": false -}""" - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("true")""") - test.contains("""assertThatJson(parsedJson).field("['property2']").isNull()""") - test.contains("""assertThatJson(parsedJson).field("['property3']").isEqualTo(false)""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - @Issue('#79') - def 'should generate assertions for simple response body constructed from map with a list with #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method "GET" - url "test" - } - response { - status OK() - body( - property1: 'a', - property2: [ - [a: 'sth'], - [b: 'sthElse'] - ] - ) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("a")""") - test.contains("""assertThatJson(parsedJson).array("['property2']").contains("['a']").isEqualTo("sth")""") - test.contains("""assertThatJson(parsedJson).array("['property2']").contains("['b']").isEqualTo("sthElse")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - @Issue('#79') - @RestoreSystemProperties - def 'should generate assertions for simple response body constructed from map with a list with #methodBuilderName with array size check'() { - given: - System.setProperty('spring.cloud.contract.verifier.assert.size', 'true') - Contract contractDsl = Contract.make { - request { - method 'GET' - url 'test' - } - response { - status OK() - body( - property1: 'a', - property2: [ - [a: 'sth'], - [b: 'sthElse'] - ] - ) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("a")""") - test.contains("""assertThatJson(parsedJson).array("['property2']").contains("['a']").isEqualTo("sth")""") - test.contains("""assertThatJson(parsedJson).array("['property2']").hasSize(2)""") - test.contains("""assertThatJson(parsedJson).array("['property2']").contains("['b']").isEqualTo("sthElse")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - @Issue('#82') - def 'should generate proper request when body constructed from map with a list #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method "GET" - url "test" - body( - items: ['HOP'] - ) - } - response { - status OK() - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains(bodyString) - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | bodyString - "spock" | { configProperties.testFramework = TestFramework.SPOCK } | """.body('''{\"items\":[\"HOP\"]}''')""" - "mockmvc" | { - configProperties.testMode = TestMode.MOCKMVC - } | '.body("{\\"items\\":[\\"HOP\\"]}")' - "testng" | { - configProperties.testFramework = TestFramework.TESTNG - } | '.body("{\\"items\\":[\\"HOP\\"]}")' - "webclient" | { - configProperties.testMode = TestMode.WEBTESTCLIENT - } | '.body("{\\"items\\":[\\"HOP\\"]}")' - } - - @Issue('#88') - def 'should generate proper request when body constructed from GString with #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url 'test' - body( - 'property1=VAL1' - ) - } - response { - status OK() - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains(bodyString) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder | bodyString - "spock" | { configProperties.testFramework = TestFramework.SPOCK } | """.body('''property1=VAL1''')""" - "testng" | { configProperties.testFramework = TestFramework.TESTNG }| '.body("property1=VAL1")' - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } | '.body("property1=VAL1")' - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } | '.body("property1=VAL1")' - } - - @Issue('185') - def 'should generate assertions for a response body containing map with integers as keys with #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url 'test' - } - response { - status OK() - body( - property: [ - 14: 0.0, - 7 : 0.0 - ] - ) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).field("['property']").field(7).isEqualTo(0.0)""") - test.contains("""assertThatJson(parsedJson).field("['property']").field(14).isEqualTo(0.0)""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - def 'should generate assertions for array in response body with #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url 'test' - } - response { - status OK() - body """[ -{ - "property1": "a" -}, -{ - "property2": "b" -}]""" - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).array().contains("['property2']").isEqualTo("b")""") - test.contains("""assertThatJson(parsedJson).array().contains("['property1']").isEqualTo("a")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - def 'should generate assertions for array inside response body element with #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method "GET" - url "test" - } - response { - status OK() - body """{ - "property1": [ - { "property2": "test1"}, - { "property3": "test2"} - ] -}""" - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).array("['property1']").contains("['property2']").isEqualTo("test1")""") - test.contains("""assertThatJson(parsedJson).array("['property1']").contains("['property3']").isEqualTo("test2")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - def 'should generate assertions for nested objects in response body with #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method "GET" - url "test" - } - response { - status OK() - body '''\ -{ - "property1": "a", - "property2": {"property3": "b"} -} -''' - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).field("['property2']").field("['property3']").isEqualTo("b")""") - test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("a")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - @Issue('#1423') - def 'should generate assertions for a response body containing an empty list with #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method "GET" - url "/url" - } - response { - status OK() - body("[]") - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).isEmpty()""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "testng" | { properties.testFramework = TestFramework.TESTNG } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } - } - - @Issue('#1423') - def 'should generate assertions for a response body containing an empty map with #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method "GET" - url "/url" - } - response { - status OK() - body("{}") - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).isEmpty()""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "testng" | { properties.testFramework = TestFramework.TESTNG } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } - } - - def 'should generate regex assertions for map objects in response body with #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method "GET" - url "test" - } - response { - status OK() - body( - property1: "a", - property2: value( - consumer('123'), - producer(regex('[0-9]{3}')) - ) - ) - headers { - contentType(applicationJson()) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).field("['property2']").matches("[0-9]{3}")""") - test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("a")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - def 'should generate regex assertions for string objects in response body with #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url 'test' - } - response { - status OK() - body("""{"property1":"a","property2":"${ - value(consumer('123'), producer(regex('[0-9]{3}'))) - }"}""") - headers { - contentType(applicationJson()) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).field("['property2']").matches("[0-9]{3}")""") - test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("a")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - @Issue(['#126', '#143']) - def 'should generate escaped regex assertions for string objects in response body with #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url 'test' - } - response { - status OK() - body("""{"property":" ${ - value(consumer('123'), producer(regex('\\d+'))) - }"}""") - headers { - contentType(applicationJson()) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).field("['property']").matches("\\\\d+")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - def 'should generate a call with an url path and query parameters with #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath("/users/${value(regex("1"))}") { - queryParameters { - parameter 'limit': $(consumer(equalTo('20')), producer(equalTo('10'))) - parameter 'offset': $(consumer(containing("20")), producer(equalTo('20'))) - parameter 'filter': 'email' - parameter 'sort': equalTo("name") - parameter 'search': $(consumer(notMatching(~/^\/[0-9]{2}$/)), producer('55')) - parameter 'age': $(consumer(notMatching("^\\w*\$")), producer('99')) - parameter 'name': $(consumer(matching('Denis.*')), producer('Denis.Stepanov')) - parameter 'email': 'bob@email.com' - parameter 'hello': $(consumer(matching('Denis.*')), producer(absent())) - parameter 'hello': absent() - } - } - } - response { - status OK() - body """ - { - "property1": "a", - "property2": "b" - } - """ - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('''.queryParam("limit","10")''') - test.contains('''.queryParam("offset","20")''') - test.contains('''.queryParam("filter","email")''') - test.contains('''.queryParam("sort","name")''') - test.contains('''.queryParam("search","55")''') - test.contains('''.queryParam("age","99")''') - test.contains('''.queryParam("name","Denis.Stepanov")''') - test.contains('''.queryParam("email","bob@email.com")''') - test.contains('''.get("/users/1")''') - test.contains('assertThatJson(parsedJson).field("[\'property1\']").isEqualTo("a")') - test.contains('assertThatJson(parsedJson).field("[\'property2\']").isEqualTo("b")') - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - @Issue('#169') - def 'should generate a call with an url path and query parameters with url containing a pattern with #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url($(consumer(regex('/foo/[0-9]+')), producer('/foo/123456'))) { - queryParameters { - parameter 'limit': $(consumer(equalTo('20')), producer(equalTo('10'))) - parameter 'offset': $(consumer(containing('20')), producer(equalTo('20'))) - parameter 'filter': 'email' - parameter 'sort': equalTo('name') - parameter 'search': $(consumer(notMatching(~/^\/[0-9]{2}$/)), producer('55')) - parameter 'age': $(consumer(notMatching("^\\w*\$")), producer('99')) - parameter 'name': $(consumer(matching('Denis.*')), producer('Denis.Stepanov')) - parameter 'email': 'bob@email.com' - parameter 'hello': $(consumer(matching('Denis.*')), producer(absent())) - parameter 'hello': absent() - } - } - } - response { - status OK() - body """ - { - "property1": "a", - "property2": "b" - } - """ - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('''.queryParam("limit","10")''') - test.contains('''.queryParam("offset","20")''') - test.contains('''.queryParam("filter","email")''') - test.contains('''.queryParam("sort","name")''') - test.contains('''.queryParam("search","55")''') - test.contains('''.queryParam("age","99")''') - test.contains('''.queryParam("name","Denis.Stepanov")''') - test.contains('''.queryParam("email","bob@email.com")''') - test.contains('''.get("/foo/123456")''') - test.contains('assertThatJson(parsedJson).field("[\'property1\']").isEqualTo("a")') - test.contains('assertThatJson(parsedJson).field("[\'property2\']").isEqualTo("b")') - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - def 'should generate test for empty body with #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method(POST()) - url('/ws/payments') - body("") - } - response { - status 406 - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains(bodyString) - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | bodyString - "spock" | { configProperties.testFramework = TestFramework.SPOCK } | ".body('''''')" - "testng" | { configProperties.testFramework = TestFramework.TESTNG }| '.body("")' - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } | '.body("")' - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } | '.body("")' - } - - def 'should generate test for String in response body with #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method 'POST' - url 'test' - } - response { - status OK() - body 'test' - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains(bodyDefinitionString) - test.contains(bodyEvaluationString) - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | bodyDefinitionString | bodyEvaluationString - "spock" | { - configProperties.testFramework = TestFramework.SPOCK - } | 'String responseBody = response.body.asString()' | "responseBody == 'test'" - "testng" | { - configProperties.testFramework = TestFramework.TESTNG - } | 'String responseBody = response.getBody().asString();' | 'assertThat(responseBody).isEqualTo("test");' - "mockmvc" | { - configProperties.testMode = TestMode.MOCKMVC - } | 'String responseBody = response.getBody().asString();' | 'assertThat(responseBody).isEqualTo("test");' - "webclient" | { - configProperties.testMode = TestMode.WEBTESTCLIENT - } | 'String responseBody = response.getBody().asString();' | 'assertThat(responseBody).isEqualTo("test");' - } - - @Issue('113') - def 'should generate regex test for String in response header with #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method 'POST' - url $(consumer(regex('/partners/[0-9]+/users')), producer('/partners/1000/users')) - headers { contentType(applicationJson()) } - body( - first_name: 'John', - last_name: 'Smith', - personal_id: '12345678901', - phone_number: '500500500', - invitation_token: '00fec7141bb94793bfe7ae1d0f39bda0', - password: 'john' - ) - } - response { - status 201 - headers { - header 'Location': $(consumer('http://localhost/partners/1000/users/1001'), producer(regex('http://localhost/partners/[0-9]+/users/[0-9]+'))) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains(headerEvaluationString) - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | headerEvaluationString - "spock" | { configProperties.testFramework = TestFramework.SPOCK } | '''response.header("Location") ==~ java.util.regex.Pattern.compile('http://localhost/partners/[0-9]+/users/[0-9]+')''' - "testng" | { - configProperties.testFramework = TestFramework.TESTNG - } | 'assertThat(response.header("Location")).matches("http://localhost/partners/[0-9]+/users/[0-9]+");' - "mockmvc" | { - configProperties.testMode = TestMode.MOCKMVC - } | 'assertThat(response.header("Location")).matches("http://localhost/partners/[0-9]+/users/[0-9]+");' - "webclient" | { - configProperties.testMode = TestMode.WEBTESTCLIENT - } | 'assertThat(response.header("Location")).matches("http://localhost/partners/[0-9]+/users/[0-9]+");' - } - - @Issue('115') - def 'should generate regex with helper method with #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method 'POST' - url $(consumer(regex('/partners/[0-9]+/users')), producer('/partners/1000/users')) - headers { contentType(applicationJson()) } - body( - first_name: 'John', - last_name: 'Smith', - personal_id: '12345678901', - phone_number: '500500500', - invitation_token: '00fec7141bb94793bfe7ae1d0f39bda0', - password: 'john' - ) - } - response { - status 201 - headers { - header 'Location': $(consumer('http://localhost/partners/1000/users/1001'), producer(regex("^${hostname()}/partners/[0-9]+/users/[0-9]+"))) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains(headerEvaluationString) - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | headerEvaluationString - "spock" | { configProperties.testFramework = TestFramework.SPOCK } | '''response.header("Location") ==~ java.util.regex.Pattern.compile('^((http[s]?|ftp):/)/?([^:/\\\\s]+)(:[0-9]{1,5})?/partners/[0-9]+/users/[0-9]+')''' - "testng" | { - configProperties.testFramework = TestFramework.TESTNG - } | 'assertThat(response.header("Location")).matches("^((http[s]?|ftp):/)/?([^:/\\\\s]+)(:[0-9]{1,5})?/partners/[0-9]+/users/[0-9]+");' - "mockmvc" | { - configProperties.testMode = TestMode.MOCKMVC - } | 'assertThat(response.header("Location")).matches("^((http[s]?|ftp):/)/?([^:/\\\\s]+)(:[0-9]{1,5})?/partners/[0-9]+/users/[0-9]+");' - "webclient" | { - configProperties.testMode = TestMode.WEBTESTCLIENT - } | 'assertThat(response.header("Location")).matches("^((http[s]?|ftp):/)/?([^:/\\\\s]+)(:[0-9]{1,5})?/partners/[0-9]+/users/[0-9]+");' - } - - def 'should work with more complex stuff and jsonpaths with #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - priority 10 - request { - method 'POST' - url '/validation/client' - headers { - contentType(applicationJson()) - } - body( - bank_account_number: '0014282912345698765432161182', - email: 'foo@bar.com', - phone_number: '100299300', - personal_id: 'ABC123456' - ) - } - - response { - status OK() - body(errors: [ - [property: "bank_account_number", message: "incorrect_format"] - ]) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).array("['errors']").contains("['property']").isEqualTo("bank_account_number")""") - test.contains("""assertThatJson(parsedJson).array("['errors']").contains("['message']").isEqualTo("incorrect_format")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - def 'should work properly with GString url with #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - - request { - method PUT() - url "/partners/${value(consumer(regex('^[0-9]*$')), producer('11'))}/agents/11/customers/09665703Z" - headers { - contentType(applicationJson()) - } - body( - first_name: 'Josef', - ) - } - response { - status 422 - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('''/partners/11/agents/11/customers/09665703Z''') - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - def 'should resolve configProperties in GString with regular expression with #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - priority 1 - request { - method POST() - url '/users/password' - headers { - contentType(applicationJson()) - } - body( - email: $(consumer(regex(email())), producer('not.existing@user.com')), - callback_url: $(consumer(regex(hostname())), producer('http://partners.com')) - ) - } - response { - status 404 - headers { - contentType(applicationJson()) - } - body( - code: 4, - message: "User not found by email = [${value(producer(regex(email())), consumer('not.existing@user.com'))}]" - ) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).field("['message']").matches("User not found by email = \\\\\\\\[[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\\\\\.[a-zA-Z]{2,6}\\\\\\\\]")""") - and: - // no static compilation due to bug in Groovy https://issues.apache.org/jira/browse/GROOVY-8055 - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - @Issue('42') - def 'should not omit the optional field in the test creation with MockMvcSpockMethodBodyBuilder'() { - given: - configProperties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('''"email":"abc@abc.com"''') - test.contains("""assertThatJson(parsedJson).field("['code']").matches("(123123)?")""") - !test.contains('''REGEXP''') - !test.contains('''OPTIONAL''') - !test.contains('''OptionalProperty''') - and: - SyntaxChecker.tryToCompileGroovy("spock", test) - where: - contractDsl << [dslWithOptionals, dslWithOptionalsInString] - } - - @Issue('42') - def "should not omit the optional field in the test creation with MockMvcJUnitMethodBodyBuilder"() { - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('\\"email\\":\\"abc@abc.com\\"') - test.contains('assertThatJson(parsedJson).field("[\'code\']").matches("(123123)?");') - !test.contains('''REGEXP''') - !test.contains('''OPTIONAL''') - !test.contains('''OptionalProperty''') - and: - SyntaxChecker.tryToCompileJava("mockmvc", test) - where: - contractDsl << [dslWithOptionals, dslWithOptionalsInString] - } - - @Issue('72') - def 'should make the execute method work with #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method """PUT""" - url """/fraudcheck""" - body(""" - { - "clientPesel":"${ - value(consumer(regex('[0-9]{10}')), producer('1234567890')) - }", - "loanAmount":123.123 - } - """ - ) - headers { - header("""Content-Type""", """application/vnd.fraud.v1+json""") - } - - } - response { - status OK() - body("""{ - "fraudCheckStatus": "OK", - "rejectionReason": ${ - value(consumer(null), producer(execute('assertThatRejectionReasonIsNull($it)'))) - } -}""") - headers { - header('Content-Type': 'application/vnd.fraud.v1+json') - header 'Location': value( - consumer(null), - producer(execute('assertThatLocationIsNull($it)')) - ) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - assertionStrings.each { String assertionString -> - assert test.contains(assertionString) - } - where: - methodBuilderName | methodBuilder | assertionStrings - "spock" | { - configProperties.testFramework = TestFramework.SPOCK - } | ['''assertThatRejectionReasonIsNull(parsedJson.read("\\$.rejectionReason"))''', '''assertThatLocationIsNull(response.header("Location"))'''] - "testng" | { - configProperties.testFramework = TestFramework.TESTNG - } | ['''assertThatRejectionReasonIsNull(parsedJson.read("$.rejectionReason"))''', '''assertThatLocationIsNull(response.header("Location"))'''] - "mockmvc" | { - configProperties.testMode = TestMode.MOCKMVC - } | ['''assertThatRejectionReasonIsNull(parsedJson.read("$.rejectionReason"))''', '''assertThatLocationIsNull(response.header("Location"))'''] - "webclient" | { - configProperties.testMode = TestMode.WEBTESTCLIENT - } | ['''assertThatRejectionReasonIsNull(parsedJson.read("$.rejectionReason"))''', '''assertThatLocationIsNull(response.header("Location"))'''] - } - - def 'should support inner map and list definitions with #methodBuilderName'() { - given: - - Pattern PHONE_NUMBER = Pattern.compile(/[+\w]*/) - Pattern ANYSTRING = Pattern.compile(/.*/) - Pattern NUMBERS = Pattern.compile(/[\d\.]*/) - Pattern DATETIME = ANYSTRING - - Contract contractDsl = Contract.make { - request { - method "PUT" - url "/v1/payments/e86df6f693de4b35ae648464c5b0dc09/client_data" - headers { - contentType(applicationJson()) - } - body( - client: [ - first_name : $(consumer(regex(onlyAlphaUnicode())), producer('Denis')), - last_name : $(consumer(regex(onlyAlphaUnicode())), producer('FakeName')), - email : $(consumer(regex(email())), producer('fakemail@fakegmail.com')), - fax : $(consumer(PHONE_NUMBER), producer('+xx001213214')), - phone : $(consumer(PHONE_NUMBER), producer('2223311')), - data_of_birth: $(consumer(DATETIME), producer('2002-10-22T00:00:00Z')) - ], - client_id_card: [ - id : $(consumer(ANYSTRING), producer('ABC12345')), - date_of_issue: $(consumer(ANYSTRING), producer('2002-10-02T00:00:00Z')), - address : [ - street : $(consumer(ANYSTRING), producer('Light Street')), - city : $(consumer(ANYSTRING), producer('Fire')), - region : $(consumer(ANYSTRING), producer('Skys')), - country: $(consumer(ANYSTRING), producer('HG')), - zip : $(consumer(NUMBERS), producer('658965')) - ] - ], - incomes_and_expenses: [ - monthly_income : $(consumer(NUMBERS), producer('0.0')), - monthly_loan_repayments: $(consumer(NUMBERS), producer('100')), - monthly_living_expenses: $(consumer(NUMBERS), producer('22')) - ], - additional_info: [ - allow_to_contact: $(consumer(optional(regex(anyBoolean()))), producer('true')) - ] - ) - } - response { - status OK() - headers { - contentType(applicationJson()) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains bodyString - !test.contains("clientValue") - !test.contains("cursor") - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | bodyString - "spock" | { configProperties.testFramework = TestFramework.SPOCK } | '"street":"Light Street"' - "testng" | { configProperties.testFramework = TestFramework.TESTNG }| '\\"street\\":\\"Light Street\\"' - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } | '\\"street\\":\\"Light Street\\"' - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } | '\\"street\\":\\"Light Street\\"' - - } - - def 'should work with optional fields that have null #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method "PUT" - url "/v1/payments/e86df6f693de4b35ae648464c5b0dc09/client_data" - headers { - contentType(applicationJson()) - } - } - response { - status OK() - headers { - contentType(applicationJson()) - } - body( - code: $(optional(regex('123123'))) - ) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | bodyString - "spock" | { configProperties.testFramework = TestFramework.SPOCK } | '"street":"Light Street"' - "testng" | { configProperties.testFramework = TestFramework.TESTNG }| '\\"street\\":\\"Light Street\\"' - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } | '\\"street\\":\\"Light Street\\"' - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } | '\\"street\\":\\"Light Street\\"' - - } - - def "shouldn't generate unicode escape characters with #methodBuilderName"() { - given: - Pattern ONLY_ALPHA_UNICODE = Pattern.compile(/[\p{L}]*/) - - Contract contractDsl = Contract.make { - request { - method "PUT" - url '/v1/payments/e86df6f693de4b35ae648464c5b0dc09/енев' - headers { - contentType(applicationJson()) - } - body( - client: [ - first_name: $(consumer(ONLY_ALPHA_UNICODE), producer('Пенева')), - last_name : $(consumer(ONLY_ALPHA_UNICODE), producer('Пенева')) - ] - ) - } - response { - status OK() - headers { - contentType(applicationJson()) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - !test.contains("\\u041f") - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - @Issue('177') - def 'should generate proper test code when having multiline body with #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method 'PUT' - url '/multiline' - body('''hello, -World.''') - } - response { - status OK() - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains(bodyString) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | bodyString - "spock" | { configProperties.testFramework = TestFramework.SPOCK } | """'''hello, -World.'''""" - "testng" | { configProperties.testFramework = TestFramework.TESTNG }| '"hello,\\nWorld."' - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } | '"hello,\\nWorld."' - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } | '"hello,\\nWorld."' - } - - @Issue('180') - def 'should generate proper test code when having multipart parameters with #methodBuilderName'() { - given: - // tag::multipartdsl[] - org.springframework.cloud.contract.spec.Contract contractDsl = org.springframework.cloud.contract.spec.Contract.make { - request { - method 'PUT' - url '/multipart' - headers { - contentType('multipart/form-data;boundary=AaB03x') - } - multipart( - // key (parameter name), value (parameter value) pair - formParameter: $(c(regex('".+"')), p('"formParameterValue"')), - someBooleanParameter: $(c(regex(anyBoolean())), p('true')), - // a named parameter (e.g. with `file` name) that represents file with - // `name` and `content`. You can also call `named("fileName", "fileContent")` - file: named( - // name of the file - name: $(c(regex(nonEmpty())), p('filename.csv')), - // content of the file - content: $(c(regex(nonEmpty())), p('file content')), - // content type for the part - contentType: $(c(regex(nonEmpty())), p('application/json'))) - ) - } - response { - status OK() - } - } - // end::multipartdsl[] - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - for (String requestString : requestStrings) { - assert test.contains(requestString) - } - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | requestStrings - "spock" | { - configProperties.testFramework = TestFramework.SPOCK - } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', - """.param('formParameter', '''"formParameterValue"'''""", - """.param('someBooleanParameter', 'true')""", - """.multiPart('file', 'filename.csv', 'file content'.bytes, 'application/json')"""] - "testng" | { - configProperties.testFramework = TestFramework.TESTNG - } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', - '.param("formParameter", "\\"formParameterValue\\"")', - '.param("someBooleanParameter", "true")', - '.multiPart("file", "filename.csv", "file content".getBytes(), "application/json");'] - "mockmvc" | { - configProperties.testMode = TestMode.MOCKMVC - } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', - '.param("formParameter", "\\"formParameterValue\\"")', - '.param("someBooleanParameter", "true")', - '.multiPart("file", "filename.csv", "file content".getBytes(), "application/json")'] - "webclient" | { - configProperties.testMode = TestMode.WEBTESTCLIENT - } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', - '.param("formParameter", "\\"formParameterValue\\"")', - '.param("someBooleanParameter", "true")', - '.multiPart("file", "filename.csv", "file content".getBytes(), "application/json")'] - - } - - @Issue('180') - def 'should generate proper test code when having multipart parameters without content type with #methodBuilderName'() { - given: - org.springframework.cloud.contract.spec.Contract contractDsl = org.springframework.cloud.contract.spec.Contract.make { - request { - method 'PUT' - url '/multipart' - headers { - contentType('multipart/form-data;boundary=AaB03x') - } - multipart( - // key (parameter name), value (parameter value) pair - formParameter: $(c(regex('".+"')), p('"formParameterValue"')), - someBooleanParameter: $(c(regex(anyBoolean())), p('true')), - // a named parameter (e.g. with `file` name) that represents file with - // `name` and `content`. You can also call `named("fileName", "fileContent")` - file: named( - // name of the file - name: $(c(regex(nonEmpty())), p('filename.csv')), - // content of the file - content: $(c(regex(nonEmpty())), p('file content'))) - ) - } - response { - status OK() - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - for (String requestString : requestStrings) { - assert test.contains(requestString) - } - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | requestStrings - "spock" | { - configProperties.testFramework = TestFramework.SPOCK - } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', - """.param('formParameter', '''"formParameterValue"'''""", - """.param('someBooleanParameter', 'true')""", - """.multiPart('file', 'filename.csv', 'file content'.bytes)"""] - "testng" | { - configProperties.testFramework = TestFramework.TESTNG - } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', - '.param("formParameter", "\\"formParameterValue\\"")', - '.param("someBooleanParameter", "true")', - '.multiPart("file", "filename.csv", "file content".getBytes());'] - "mockmvc" | { - configProperties.testMode = TestMode.MOCKMVC - } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', - '.param("formParameter", "\\"formParameterValue\\"")', - '.param("someBooleanParameter", "true")', - '.multiPart("file", "filename.csv", "file content".getBytes())'] - "webclient" | { - configProperties.testMode = TestMode.WEBTESTCLIENT - } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', - '.param("formParameter", "\\"formParameterValue\\"")', - '.param("someBooleanParameter", "true")', - '.multiPart("file", "filename.csv", "file content".getBytes())'] - } - - @Issue('546') - def 'should generate test code when having multipart parameters with byte array #methodBuilderName'() { - given: - // tag::multipartdsl[] - org.springframework.cloud.contract.spec.Contract contractDsl = org.springframework.cloud.contract.spec.Contract.make { - request { - method "PUT" - url "/multipart" - headers { - contentType('multipart/form-data;boundary=AaB03x') - } - multipart( - file: named( - name: value(stub(regex('.+')), test('file')), - content: value(stub(regex('.+')), test([100, 117, 100, 97] as byte[])) - ) - ) - } - response { - status 200 - } - } - // end::multipartdsl[] - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - for (String requestString : requestStrings) { - assert test.contains(requestString) - } - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | requestStrings - "spock" | { - configProperties.testFramework = TestFramework.SPOCK - } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', - """.multiPart('file', 'file', [100, 117, 100, 97] as byte[])"""] - "testng" | { - configProperties.testFramework = TestFramework.TESTNG - } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', - '.multiPart("file", "file", new byte[] {100, 117, 100, 97});'] - "mockmvc" | { - configProperties.testMode = TestMode.MOCKMVC - } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', - '.multiPart("file", "file", new byte[] {100, 117, 100, 97});'] - "webclient" | { - configProperties.testMode = TestMode.WEBTESTCLIENT - } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', - '.multiPart("file", "file", new byte[] {100, 117, 100, 97});'] - - } - - @Issue('541') - def 'should generate proper test code when having multipart parameters that use execute with #methodBuilderName'() { - given: - org.springframework.cloud.contract.spec.Contract contractDsl = org.springframework.cloud.contract.spec.Contract.make { - request { - method "PUT" - url "/multipart" - headers { - contentType('multipart/form-data;boundary=AaB03x') - } - multipart( - formParameter: $(c(regex('".+"')), p('"formParameterValue"')), - someBooleanParameter: $(c(regex(anyBoolean())), p('true')), - file: named( - name: $(c(regex(nonEmpty())), p(execute('toString()'))), - content: $(c(regex(nonEmpty())), p('file content'))) - ) - } - response { - status OK() - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - for (String requestString : requestStrings) { - assert test.contains(requestString) - } - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | requestStrings - "spock" | { - configProperties.testFramework = TestFramework.SPOCK - } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', - """.param('formParameter', '''"formParameterValue"'''""", - """.param('someBooleanParameter', 'true')""", - """.multiPart('file', toString(), 'file content'.bytes)"""] - "testng" | { - configProperties.testFramework = TestFramework.TESTNG - } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', - '.param("formParameter", "\\"formParameterValue\\"")', - '.param("someBooleanParameter", "true")', - '.multiPart("file", toString(), "file content".getBytes());'] - "mockmvc" | { - configProperties.testMode = TestMode.MOCKMVC - } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', - '.param("formParameter", "\\"formParameterValue\\"")', - '.param("someBooleanParameter", "true")', - '.multiPart("file", toString(), "file content".getBytes())'] - "webclient" | { - configProperties.testMode = TestMode.WEBTESTCLIENT - } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', - '.param("formParameter", "\\"formParameterValue\\"")', - '.param("someBooleanParameter", "true")', - '.multiPart("file", toString(), "file content".getBytes())'] - - } - - @Issue(['180', '1667']) - def 'should generate proper test code when having multipart parameters with named as map with #methodBuilderName'() { - given: - org.springframework.cloud.contract.spec.Contract contractDsl = org.springframework.cloud.contract.spec.Contract.make { - request { - method 'PUT' - url "/multipart" - headers { - contentType('multipart/form-data;boundary=AaB03x') - } - multipart( - // key (parameter name), value (parameter value) pair - formParameter: $(c(regex('".+"')), p('"formParameterValue"')), - someBooleanParameter: $(c(regex(anyBoolean())), p('true')), - // a named parameter (e.g. with `file` name) that represents file with - // `name` and `content`. You can also call `named("fileName", "fileContent")` - file: named( - // name of the file - name: $(c(regex(nonEmpty())), p('filename.csv')), - // content of the file - content: $(c(regex(nonEmpty())), p('file content'))) - ) - } - response { - status OK() - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('.multiPart') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - "spock-mockmvc" | { - configProperties.testFramework = TestFramework.SPOCK; configProperties.testMode = TestMode.MOCKMVC - } - "spock-explicit" | { - configProperties.testFramework = TestFramework.SPOCK; configProperties.testMode = TestMode.EXPLICIT - } - "spock-webclient" | { - configProperties.testFramework = TestFramework.SPOCK; configProperties.testMode = TestMode.WEBTESTCLIENT - } - } - - @Issue('#216') - def 'should parse JSON with arrays using Spock'() { - given: - Contract contractDsl = Contract.make { - request { - method "GET" - urlPath('/auth/oauth/check_token') { - queryParameters { - parameter 'token': value( - consumer(regex('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}')), - producer('6973b31d-7140-402a-bca6-1cdb954e03a7') - ) - } - } - } - response { - status OK() - body( - authorities: [ - value(consumer('ROLE_ADMIN'), producer(regex('^[a-zA-Z0-9_\\- ]+$'))) - ] - ) - } - } - configProperties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('''assertThatJson(parsedJson).array("[\'authorities']").arrayField().matches("^[a-zA-Z0-9_\\\\- ]+\\$").value()''') - and: - SyntaxChecker.tryToCompileGroovy("spock", test) - } - - @Issue('#216') - def 'should parse JSON with arrays using JUnit'() { - given: - Contract contractDsl = Contract.make { - request { - method "GET" - urlPath('/auth/oauth/check_token') { - queryParameters { - parameter 'token': value( - consumer(regex('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}')), - producer('6973b31d-7140-402a-bca6-1cdb954e03a7') - ) - } - } - } - response { - status OK() - body( - authorities: [ - value(consumer('ROLE_ADMIN'), producer(regex('^[a-zA-Z0-9_\\- ]+$'))) - ] - ) - } - } - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('''assertThatJson(parsedJson).array("[\'authorities']").arrayField().matches("^[a-zA-Z0-9_\\\\- ]+$").value()''') - and: - SyntaxChecker.tryToCompileJava("mockmvc", test) - } - - def 'should work with execution property with #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method 'PUT' - url '/fraudcheck' - } - response { - status OK() - body( - fraudCheckStatus: "OK", - rejectionReason: $(consumer(null), producer(execute('assertThatRejectionReasonIsNull($it)'))) - ) - } - - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - !test.contains('''assertThatJson(parsedJson).field("[\'rejectionReason']").isEqualTo("assertThatRejectionReasonIsNull("''') - test.contains('''assertThatRejectionReasonIsNull(''') - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - @Issue('262') - def 'should generate proper test code with map inside list'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/foos' - } - response { - status OK() - body([[id: value( - consumer('123'), - producer(regex('[0-9]+')) - )], [id: value( - consumer('567'), - producer(regex('[0-9]+')) - )]]) - headers { - contentType(applicationJsonUtf8()) - } - } - } - configProperties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThatJson(parsedJson).array().contains("[\'id\']").matches("[0-9]+")') - and: - SyntaxChecker.tryToCompileGroovy("mockmvc", test) - } - - @Issue('266') - def 'should generate proper test code with top level array using #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/api/tags' - } - response { - status OK() - body(["Java", "Java8", "Spring", "SpringBoot", "Stream"]) - headers { - header('Content-Type': 'application/json;charset=UTF-8') - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThatJson(parsedJson).arrayField().contains("Java8").value()') - test.contains('assertThatJson(parsedJson).arrayField().contains("Spring").value()') - test.contains('assertThatJson(parsedJson).arrayField().contains("Java").value()') - test.contains('assertThatJson(parsedJson).arrayField().contains("Stream").value()') - test.contains('assertThatJson(parsedJson).arrayField().contains("SpringBoot").value()') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - @Issue('266') - @RestoreSystemProperties - def 'should generate proper test code with top level array using #methodBuilderName with array size check'() { - given: - System.setProperty('spring.cloud.contract.verifier.assert.size', 'true') - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/api/tags' - } - response { - status OK() - body(['Java', 'Java8', 'Spring', 'SpringBoot', 'Stream']) - headers { - header('Content-Type': 'application/json;charset=UTF-8') - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThatJson(parsedJson).hasSize(5)') - test.contains('assertThatJson(parsedJson).arrayField().contains("Java8").value()') - test.contains('assertThatJson(parsedJson).arrayField().contains("Spring").value()') - test.contains('assertThatJson(parsedJson).arrayField().contains("Java").value()') - test.contains('assertThatJson(parsedJson).arrayField().contains("Stream").value()') - test.contains('assertThatJson(parsedJson).arrayField().contains("SpringBoot").value()') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - @Issue('266') - def 'should generate proper test code with top level array or arrays using #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/api/categories' - } - response { - status OK() - body([["Programming", "Java"], ["Programming", "Java", "Spring", "Boot"]]) - headers { - header('Content-Type': 'application/json;charset=UTF-8') - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThatJson(parsedJson).array().array().arrayField().isEqualTo("Programming").value()') - test.contains('assertThatJson(parsedJson).array().array().arrayField().isEqualTo("Java").value()') - test.contains('assertThatJson(parsedJson).array().array().arrayField().isEqualTo("Spring").value()') - test.contains('assertThatJson(parsedJson).array().array().arrayField().isEqualTo("Boot").value()') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - @Issue('1630') - def 'should generate proper test code with top level map of sets using #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - description('get map') - name('assert map response') - request { - method 'GET' - urlPath '/some-path' - } - response { - status OK() - body(["key": ["value1", "value2"] as Set]) - headers { - header('Content-Type': 'application/json;charset=UTF-8') - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).array("['key']").hasSize(2)""") - test.contains("""assertThatJson(parsedJson).array("['key']").arrayField().isEqualTo("value1").value()""") - test.contains("""assertThatJson(parsedJson).array("['key']").arrayField().isEqualTo("value2").value()""") - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - @Issue('47') - def 'should generate async body when async flag set in response'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url '/test' - } - response { - status OK() - async() - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains(bodyDefinitionString) - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | bodyDefinitionString - "spock" | { configProperties.testFramework = TestFramework.SPOCK } | '.when().async()' - "testng" | { configProperties.testFramework = TestFramework.TESTNG }| '.when().async()' - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } | '.when().async()' - } - - @Issue('372') - def "should generate async body after queryParams when async flag set in response and queryParams set in request"() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url('/test') { - queryParameters { - parameter("param", "value") - } - } - } - response { - status OK() - async() - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - def strippedTest = test.replace('\n', '').replace(' ', '').replaceAll("\t", "").stripIndent().stripMargin() - then: - strippedTest.contains('.queryParam("param","value").when().async().get("/test")') - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - } - - def 'should generate proper test code with array of primitives using #methodBuilderName'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/api/tags' - } - response { - status OK() - body('''{ - "partners":[ - { - "payment_methods":[ "BANK", "CASH" ] - } - ] - } - ''') - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThatJson(parsedJson).array("[\'partners\']").array("[\'payment_methods\']").arrayField().isEqualTo("BANK").value()') - test.contains('assertThatJson(parsedJson).array("[\'partners\']").array("[\'payment_methods\']").arrayField().isEqualTo("CASH").value()') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - @Issue('#273') - def "should not escape dollar in Spock regex tests"() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/get' - } - response { - status OK() - body(code: 9, message: $(consumer('Wrong credentials'), producer(regex('^(?!\\s*$).+')))) - } - } - configProperties.testFramework = TestFramework.SPOCK - when: - - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThatJson(parsedJson).field("[\'message\']").matches("^(?!\\\\s*\\$).+")') - and: - SyntaxChecker.tryToCompileGroovy("mockmvc", test, false) - } - - Contract dslForDocs = - // tag::dsl_example[] - org.springframework.cloud.contract.spec.Contract.make { - request { - method 'PUT' - url '/api/12' - headers { - header 'Content-Type': 'application/vnd.org.springframework.cloud.contract.verifier.twitter-places-analyzer.v1+json' - } - body '''\ - [{ - "created_at": "Sat Jul 26 09:38:57 +0000 2014", - "id": 492967299297845248, - "id_str": "492967299297845248", - "text": "Gonna see you at Warsaw", - "place": - { - "attributes":{}, - "bounding_box": - { - "coordinates": - [[ - [-77.119759,38.791645], - [-76.909393,38.791645], - [-76.909393,38.995548], - [-77.119759,38.995548] - ]], - "type":"Polygon" - }, - "country":"United States", - "country_code":"US", - "full_name":"Washington, DC", - "id":"01fbe706f872cb32", - "name":"Washington", - "place_type":"city", - "url": "https://api.twitter.com/1/geo/id/01fbe706f872cb32.json" - } - }] - ''' - } - response { - status OK() - } - } - // end::dsl_example[] - - Contract dslWithOnlyOneSideForDocs = - // tag::dsl_one_side_data_generation_example[] - org.springframework.cloud.contract.spec.Contract.make { - request { - method 'PUT' - url value(consumer(regex('/foo/[0-9]{5}'))) - body([ - requestElement: $(consumer(regex('[0-9]{5}'))) - ]) - headers { - header('header', $(consumer(regex('application\\/vnd\\.fraud\\.v1\\+json;.*')))) - } - } - response { - status OK() - body([ - responseElement: $(producer(regex('[0-9]{7}'))) - ]) - headers { - contentType("application/vnd.fraud.v1+json") - } - } - } - // end::dsl_one_side_data_generation_example[] - - @Issue('#32') - def 'should generate the regular expression for the other side of communication'() { - given: - configProperties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(dslWithOnlyOneSideForDocs) - def strippedTest = test.replace('\n', '').stripIndent().stripMargin() - then: - strippedTest.matches(""".*header\\("header", "application\\/vnd\\.fraud\\.v1\\+json;.*"\\).*""") - strippedTest.matches(""".*body\\('''\\{"requestElement":"[0-9]{5}"\\}'''\\).*""") - strippedTest.matches(""".*put\\("/foo/[0-9]{5}"\\).*""") - strippedTest.contains("""response.header("Content-Type") ==~ java.util.regex.Pattern.compile('application/vnd\\\\.fraud\\\\.v1\\\\+json.*')""") - "application/vnd.fraud.v1+json;charset=UTF-8".matches('application/vnd\\.fraud\\.v1\\+json.*') - strippedTest.contains("""assertThatJson(parsedJson).field("['responseElement']").matches("[0-9]{7}")""") - and: - SyntaxChecker.tryToCompileGroovy("spock", test) - } - - @Issue('#85') - def 'should execute custom method for complex structures on the response side'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/get' - } - response { - status OK() - body([ - fraudCheckStatus: "OK", - rejectionReason : [ - title: $(consumer(null), producer(execute('assertThatRejectionReasonIsNull($it)'))) - ] - ]) - } - } - configProperties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThatRejectionReasonIsNull(parsedJson.read("\\$.rejectionReason.title"))') - and: - SyntaxChecker.tryToCompileGroovy("spock", test) - } - - @Issue('#85') - def 'should execute custom method for more complex structures on the response side when using Spock'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/get' - } - response { - status OK() - body([ - [ - name: $(consumer("userName 1"), producer(execute('assertThatUserNameIsNotNull($it)'))) - ], - [ - name: $(consumer("userName 2"), producer(execute('assertThatUserNameIsNotNull($it)'))) - ] - ]) - } - } - configProperties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('''assertThatUserNameIsNotNull(parsedJson.read("\\$.[0].name")''') - test.contains('''assertThatUserNameIsNotNull(parsedJson.read("\\$.[1].name")''') - and: - SyntaxChecker.tryToCompileGroovy("spock", test) - } - - @Issue('#85') - def 'should execute custom method for more complex structures on the response side when using JUnit'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/get' - } - response { - status OK() - body([ - [ - name: $(consumer("userName 1"), producer(execute('assertThatUserNameIsNotNull($it)'))) - ], - [ - name: $(consumer("userName 2"), producer(execute('assertThatUserNameIsNotNull($it)'))) - ] - ]) - } - } - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('''assertThatUserNameIsNotNull(parsedJson.read("$.[0].name")''') - test.contains('''assertThatUserNameIsNotNull(parsedJson.read("$.[1].name")''') - } - - @Issue('#111') - def 'should execute custom method for request headers'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/get' - headers { - header('authorization', value(consumer('Bearer token'), producer(execute('getOAuthTokenHeader()')))) - } - } - response { - status OK() - body([ - fraudCheckStatus: "OK", - rejectionReason : [ - title: $(consumer(null), producer(execute('assertThatRejectionReasonIsNull($it)'))) - ] - ]) - } - } - configProperties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('.header("authorization", getOAuthTokenHeader())') - and: - SyntaxChecker.tryToCompileGroovy("spock", test) - } - - @Issue('#150') - def 'should support body matching in response'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url '/get' - } - response { - status OK() - body(value(stub("HELLO FROM STUB"), server(regex(".*")))) - } - } - configProperties.testFramework = TestFramework.SPOCK - when: - - String test = singleTestGenerator(contractDsl) - then: - test.contains("responseBody ==~ java.util.regex.Pattern.compile('.*')") - and: - SyntaxChecker.tryToCompileGroovy("spock", test) - } - - @Issue('#150') - def 'should support custom method execution in response'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url '/get' - } - response { - status OK() - body(value(stub("HELLO FROM STUB"), server(execute('foo($it)')))) - } - } - configProperties.testFramework = TestFramework.SPOCK - when: - - String test = singleTestGenerator(contractDsl) - then: - test.contains("foo(responseBody)") - and: - SyntaxChecker.tryToCompileGroovy("spock", test) - } - - @Issue('#149') - def 'should allow c/p version of consumer producer'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/get' - headers { - header('authorization', $(c('Bearer token'), p(execute('getOAuthTokenHeader()')))) - } - } - response { - status OK() - body([ - fraudCheckStatus: "OK", - rejectionReason : [ - title: $(c(null), p(execute('assertThatRejectionReasonIsNull($it)'))) - ] - ]) - } - } - configProperties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('.header("authorization", getOAuthTokenHeader())') - and: - SyntaxChecker.tryToCompileGroovy("spock", test) - } - - @Issue('#149') - def 'should allow easier way of providing dynamic values for [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/get' - body([ - duck : $(regex("[0-9]")), - alpha : $(anyAlphaUnicode()), - number : $(anyNumber()), - anInteger : $(anyInteger()), - positiveInt : $(positiveInt()), - aDouble : $(anyDouble()), - aBoolean : $(aBoolean()), - ip : $(anyIpAddress()), - hostname : $(anyHostname()), - email : $(anyEmail()), - url : $(anyUrl()), - httpsUrl : $(anyHttpsUrl()), - uuid : $(anyUuid()), - date : $(anyDate()), - dateTime : $(anyDateTime()), - time : $(anyTime()), - iso8601WithOffset: $(anyIso8601WithOffset()), - nonBlankString : $(anyNonBlankString()), - nonEmptyString : $(anyNonEmptyString()), - anyOf : $(anyOf('foo', 'bar')) - ]) - headers { - contentType(applicationJson()) - } - } - response { - status OK() - body([ - alpha : $(anyAlphaUnicode()), - number : $(anyNumber()), - anInteger : $(anyInteger()), - positiveInt : $(positiveInt()), - aDouble : $(anyDouble()), - aBoolean : $(aBoolean()), - ip : $(anyIpAddress()), - hostname : $(anyHostname()), - email : $(anyEmail()), - url : $(anyUrl()), - httpsUrl : $(anyHttpsUrl()), - uuid : $(anyUuid()), - date : $(anyDate()), - dateTime : $(anyDateTime()), - time : $(anyTime()), - iso8601WithOffset: $(anyIso8601WithOffset()), - nonBlankString : $(anyNonBlankString()), - nonEmptyString : $(anyNonEmptyString()), - anyOf : $(anyOf('foo', 'bar')) - ]) - headers { - contentType(applicationJson()) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThatJson(parsedJson).field("[\'aBoolean\']").matches("(true|false)")') - test.contains('assertThatJson(parsedJson).field("[\'alpha\']").matches("[\\\\p{L}]*")') - test.contains('assertThatJson(parsedJson).field("[\'hostname\']").matches("((http[s]?|ftp):/)/?([^:/\\\\s]+)(:[0-9]{1,5})?")') - test.contains('assertThatJson(parsedJson).field("[\'number\']").matches("-?(\\\\d*\\\\.\\\\d+|\\\\d+)")') - test.contains('assertThatJson(parsedJson).field("[\'anInteger\']").matches("-?(\\\\d+)")') - test.contains('assertThatJson(parsedJson).field("[\'positiveInt\']").matches("([1-9]\\\\d*)")') - test.contains('assertThatJson(parsedJson).field("[\'aDouble\']").matches("-?(\\\\d*\\\\.\\\\d+)")') - test.contains('assertThatJson(parsedJson).field("[\'email\']").matches("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,6}")') - test.contains('assertThatJson(parsedJson).field("[\'ip\']").matches("([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])\\\\.([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])\\\\.([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])\\\\.([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])")') - test.contains('assertThatJson(parsedJson).field("[\'url\']").matches("^(?:(?:[A-Za-z][+-.\\\\w^_]*:/{2})?(?:\\\\S+(?::\\\\S*)?@)?(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|(?:(?:[a-z\\\\u00a1-\\\\uffff0-9]-*)*[a-z\\\\u00a1-\\\\uffff0-9]+)(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff0-9]-*)*[a-z\\\\u00a1-\\\\uffff0-9]+)*(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff]{2,}))|(?:localhost))(?::\\\\d{2,5})?(?:/\\\\S*)?)') - test.contains('assertThatJson(parsedJson).field("[\'httpsUrl\']").matches("^(?:https:/{2}(?:\\\\S+(?::\\\\S*)?@)?(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|(?:(?:[a-z\\\\u00a1-\\\\uffff0-9]-*)*[a-z\\\\u00a1-\\\\uffff0-9]+)(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff0-9]-*)*[a-z\\\\u00a1-\\\\uffff0-9]+)*(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff]{2,}))|(?:localhost))(?::\\\\d{2,5})?(?:/\\\\S*)?)') - test.contains('assertThatJson(parsedJson).field("[\'uuid\']").matches("[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}")') - test.contains('assertThatJson(parsedJson).field("[\'date\']").matches("(\\\\d\\\\d\\\\d\\\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])') - test.contains('assertThatJson(parsedJson).field("[\'dateTime\']").matches("([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])') - test.contains('assertThatJson(parsedJson).field("[\'time\']").matches("(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])")') - test.contains('assertThatJson(parsedJson).field("[\'iso8601WithOffset\']").matches("([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\\\\.\\\\d+)?(Z|[+-][01]\\\\d:[0-5]\\\\d)")') - test.contains('assertThatJson(parsedJson).field("[\'nonBlankString\']").matches("^\\\\s*\\\\S[\\\\S\\\\s]*")') - test.contains('assertThatJson(parsedJson).field("[\'nonEmptyString\']").matches("[\\\\S\\\\s]+")') - test.contains('assertThatJson(parsedJson).field("[\'anyOf\']").matches("^foo' + endOfLineRegExSymbol + '|^bar' + endOfLineRegExSymbol + '")') - !test.contains('cursor') - !test.contains('REGEXP>>') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - and: - String jsonSample = '''\ -String json = "{\\"duck\\":\\"8\\",\\"alpha\\":\\"YAJEOWYGMFBEWPMEMAZI\\",\\"number\\":-2095030871,\\"anInteger\\":1780305902,\\"positiveInt\\":345,\\"aDouble\\":42.345,\\"aBoolean\\":true,\\"ip\\":\\"129.168.99.100\\",\\"hostname\\":\\"https://foo389886219.com\\",\\"email\\":\\"foo@bar1367573183.com\\",\\"url\\":\\"https://foo-597104692.com\\",\\"httpsUrl\\":\\"https://baz-486093581.com\\",\\"uuid\\":\\"e436b817-b764-49a2-908e-967f2f99eb9f\\",\\"date\\":\\"2014-04-14\\",\\"dateTime\\":\\"2011-01-11T12:23:34\\",\\"time\\":\\"12:20:30\\",\\"iso8601WithOffset\\":\\"2015-05-15T12:23:34.123Z\\",\\"nonBlankString\\":\\"EPZWVIRHSUAPBJMMQSFO\\",\\"nonEmptyString\\":\\"RVMFDSEQFHRQFVUVQPIA\\",\\"anyOf\\":\\"foo\\"}"; -DocumentContext parsedJson = JsonPath.parse(json); -''' - where: - methodBuilderName | methodBuilder | endOfLineRegExSymbol - "spock" | { configProperties.testFramework = TestFramework.SPOCK } | '\\$' - "testng" | { configProperties.testFramework = TestFramework.TESTNG }| '$' - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } | '$' - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } | '$' - } - - @Issue('#1410') - def 'should generate random boolean input in generated test'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/get' - body([ - "someBooleanInputParam" : aBoolean() - ]) - headers { - contentType applicationJson() - } - } - response { - status OK() - body([ - "someBooleanOutputParam" : $(aBoolean()) - ]) - headers { - contentType(applicationJson()) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - // The input body string looks like one of the following: - // .body("{\"someBooleanInputParam\":true|false}"); - // .body('''{"someBooleanInputParam":true|false}''') - test.findAll(~'\\.body\\((\'{3}|")\\{("|\\\\")someBooleanInputParam("|\\\\"):(true|false)\\}(\'{3}|")\\)').size().equals(1) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "testng" | { properties.testFramework = TestFramework.TESTNG } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } - } - - @Issue('#162') - def 'should escape regex properly for content type'() { - given: - Contract contractDsl = Contract.make { - request { - method GET() - url 'get' - headers { - contentType("application/vnd.fraud.v1+json") - } - } - response { - status OK() - headers { - contentType("application/vnd.fraud.v1+json") - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('application/vnd\\\\.fraud\\\\.v1\\\\+json.*') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - @Issue('#173') - def 'should resolve Optional object when used in query parameters'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath('/blacklist') { - queryParameters { - parameter 'isActive': value(consumer(optional(regex('(true|false)')))) - parameter 'limit': value(consumer(optional(regex('([0-9]{1,10})')))) - parameter 'offset': value(consumer(optional(regex('([0-9]{1,10})')))) - } - } - headers { - header 'Content-Type': 'application/json' - } - } - response { - status(200) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - !test.contains('org.springframework.cloud.contract.spec.internal.OptionalProperty') - test.contains('(([0-9]{1,10}))?') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - @Issue('#172') - def 'should resolve plain text properly via headers'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url("/foo") - } - response { - status(200) - body '{"a":1}\n{"a":2}' - headers { - contentType(textPlain()) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - !test.contains('assertThatJson(parsedJson).field("[\'a\']").isEqualTo(1)') - test.contains(expectedAssertion) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - //order is inverted cause Intellij didn't parse this properly - methodBuilderName | methodBuilder | expectedAssertion - "spock" | { configProperties.testFramework = TestFramework.SPOCK } | """responseBody == '''{"a":1}\\n{"a":2}'''""" - "testng" | { configProperties.testFramework = TestFramework.TESTNG }| '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}''' - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}''' - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}''' - } - - @Issue('#443') - def "should resolve plain text that happens to be a valid json for [#methodBuilderName]"() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url '/foo' - } - response { - status OK() - headers { - contentType(applicationJsonUtf8()) - } - body( - value(client('true'), server(regex("true|false"))) - ) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - testAssertion(test) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | testAssertion - "spock" | { - configProperties.testFramework = TestFramework.SPOCK - } | { String testContents -> testContents.contains("""responseBody ==~ java.util.regex.Pattern.compile('true|false')""") } - "testng" | { - configProperties.testFramework = TestFramework.TESTNG - } | { String testContents -> testContents.contains("""assertThat(responseBody).matches("true|false");""") } - "mockmvc" | { - configProperties.testMode = TestMode.MOCKMVC - } | { String testContents -> testContents.contains("""assertThat(responseBody).matches("true|false");""") } - "jaxrs-spock" | { - configProperties.testFramework = TestFramework.SPOCK; configProperties.testMode = TestMode.JAXRSCLIENT - } | { String testContents -> testContents.contains("""responseBody ==~ java.util.regex.Pattern.compile("true|false")""") } - "jaxrs" | { - configProperties.testFramework = TestFramework.JUNIT; configProperties.testMode = TestMode.JAXRSCLIENT - } | { String testContents -> testContents.contains("""assertThat(responseBody).matches("true|false");""") } - "webclient" | { - configProperties.testMode = TestMode.WEBTESTCLIENT - } | { String testContents -> testContents.contains("""assertThat(responseBody).matches("true|false");""") } - } - - @Issue('#169') - def 'should escape quotes properly using [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'POST' - url '/foo' - body( - xyz: 'abc' - ) - headers { header('Content-Type', 'application/json;charset=UTF-8') } - } - response { - status OK() - body( - bar: $(producer(regex('some value \u0022with quote\u0022|bar'))) - ) - headers { header('Content-Type': 'application/json;charset=UTF-8') } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThatJson(parsedJson).field("[\'bar\']").matches("some value \\"with quote\\"|bar")') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - //order is inverted cause Intellij didn't parse this properly - methodBuilderName | methodBuilder | expectedAssertion - "spock" | { configProperties.testFramework = TestFramework.SPOCK } | '''responseBody == "{\\"a\\":1}\\n{\\"a\\":2}"''' - "testng" | { configProperties.testFramework = TestFramework.TESTNG }| '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}''' - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}''' - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}''' - } - - @Issue('#169') - def 'should make the execute method work in a url for [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'POST' - url $(c("foo"), p(execute("toString()"))) - } - response { - status OK() - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompile(methodBuilderName, test) - and: - test.contains("toString()") - !test.contains("\"toString()\"") - !test.contains("'toString()'") - where: - methodBuilderName | methodBuilder - "spock" | { - configProperties.testFramework = TestFramework.SPOCK - } - "testng" | { - configProperties.testFramework = TestFramework.TESTNG - } - "mockmvc" | { - configProperties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - configProperties.testFramework = TestFramework.SPOCK; configProperties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - configProperties.testFramework = TestFramework.JUNIT; configProperties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - configProperties.testMode = TestMode.WEBTESTCLIENT - } - } - - @Issue('#203') - def 'should create an assertion for an empty list for [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url '/api/v1/xxxx' - } - response { - status OK() - body([ - status: '200', - list : [], - foo : ["bar", "baz"] - ]) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompile(methodBuilderName, test) - test.contains('assertThatJson(parsedJson).array("[\'list\']").isEmpty()') - !test.contains('assertThatJson(parsedJson).array("[\'foo\']").isEmpty()') - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "jaxrs-spock" | { - configProperties.testFramework = TestFramework.SPOCK; configProperties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - configProperties.testFramework = TestFramework.JUNIT; configProperties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - @Issue('#226') - def 'should work properly when body is an integer [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url '/api/v1/xxxx' - body(12000) - } - response { - status OK() - body(12000) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompile(methodBuilderName, test) - requestAssertion(test) - responseAssertion(test) - where: - methodBuilderName | methodBuilder | requestAssertion | responseAssertion - "spock" | { - configProperties.testFramework = TestFramework.SPOCK - } | { String body -> body.contains("body('''12000''')") } | { String body -> body.contains("responseBody == '12000'") } - "testng" | { - configProperties.testFramework = TestFramework.TESTNG - } | { String body -> body.contains('body("12000")') } | { String body -> body.contains('assertThat(responseBody).isEqualTo("12000");') } - "mockmvc" | { - configProperties.testMode = TestMode.MOCKMVC - } | { String body -> body.contains('body("12000")') } | { String body -> body.contains('assertThat(responseBody).isEqualTo("12000");') } - "jaxrs-spock" | { - configProperties.testFramework = TestFramework.SPOCK; configProperties.testMode = TestMode.JAXRSCLIENT - } | { String body -> body.contains(""".build("GET", entity("12000", "text/plain"))""") } | { String body -> body.contains('responseBody == "12000"') } - "jaxrs" | { - configProperties.testFramework = TestFramework.JUNIT; configProperties.testMode = TestMode.JAXRSCLIENT - } | { String body -> body.contains(""".build("GET", entity("12000", "text/plain"))""") } | { String body -> body.contains('assertThat(responseBody).isEqualTo("12000")') } - "webclient" | { - configProperties.testMode = TestMode.WEBTESTCLIENT - } | { String body -> body.contains('body("12000")') } | { String body -> body.contains('assertThat(responseBody).isEqualTo("12000");') } - } - - @Issue('#230') - def 'should manage to reference request in response [#methodBuilderName]'() { - given: - //tag::template_contract[] - Contract contractDsl = Contract.make { - request { - method 'GET' - url('/api/v1/xxxx') { - queryParameters { - parameter('foo', 'bar') - parameter('foo', 'bar2') - } - } - headers { - header(authorization(), 'secret') - header(authorization(), 'secret2') - } - body(foo: 'bar', baz: 5) - } - response { - status OK() - headers { - header(authorization(), "foo ${fromRequest().header(authorization())} bar") - } - body( - url: fromRequest().url(), - path: fromRequest().path(), - pathIndex: fromRequest().path(1), - param: fromRequest().query('foo'), - paramIndex: fromRequest().query('foo', 1), - authorization: fromRequest().header('Authorization'), - authorization2: fromRequest().header('Authorization', 1), - fullBody: fromRequest().body(), - responseFoo: fromRequest().body('$.foo'), - responseBaz: fromRequest().body('$.baz'), - responseBaz2: "Bla bla ${fromRequest().body('$.foo')} bla bla", - rawUrl: fromRequest().rawUrl(), - rawPath: fromRequest().rawPath(), - rawPathIndex: fromRequest().rawPath(1), - rawParam: fromRequest().rawQuery('foo'), - rawParamIndex: fromRequest().rawQuery('foo', 1), - rawAuthorization: fromRequest().rawHeader('Authorization'), - rawAuthorization2: fromRequest().rawHeader('Authorization', 1), - rawResponseFoo: fromRequest().rawBody('$.foo'), - rawResponseBaz: fromRequest().rawBody('$.baz'), - rawResponseBaz2: "Bla bla ${fromRequest().rawBody('$.foo')} bla bla" - ) - } - } - //end::template_contract[] - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - !test.contains('''DslProperty''') - !test.contains('''ERROR: ''') - test.contains('''assertThatJson(parsedJson).field("['url']").isEqualTo("/api/v1/xxxx?foo=bar&foo=bar2")''') - test.contains('''assertThatJson(parsedJson).field("['path']").isEqualTo("/api/v1/xxxx")''') - test.contains('''assertThatJson(parsedJson).field("['pathIndex']").isEqualTo("v1")''') - test.contains('''assertThatJson(parsedJson).field("['fullBody']").isEqualTo("{\\"foo\\":\\"bar\\",\\"baz\\":5}")''') - test.contains('''assertThatJson(parsedJson).field("['paramIndex']").isEqualTo("bar2")''') - test.contains('''assertThatJson(parsedJson).field("['responseFoo']").isEqualTo("bar")''') - test.contains('''assertThatJson(parsedJson).field("['authorization']").isEqualTo("secret")''') - test.contains('''assertThatJson(parsedJson).field("['authorization2']").isEqualTo("secret2")''') - test.contains('''assertThatJson(parsedJson).field("['responseBaz']").isEqualTo(5)''') - test.contains('''assertThatJson(parsedJson).field("['responseBaz2']").isEqualTo("Bla bla bar bla bla")''') - test.contains('''assertThatJson(parsedJson).field("['param']").isEqualTo("bar")''') - test.contains('''assertThatJson(parsedJson).field("['rawUrl']").isEqualTo("/api/v1/xxxx?foo=bar&foo=bar2")''') - test.contains('''assertThatJson(parsedJson).field("['rawPath']").isEqualTo("/api/v1/xxxx")''') - test.contains('''assertThatJson(parsedJson).field("['rawPathIndex']").isEqualTo("v1")''') - test.contains('''assertThatJson(parsedJson).field("['rawParamIndex']").isEqualTo("bar2")''') - test.contains('''assertThatJson(parsedJson).field("['rawResponseFoo']").isEqualTo("bar")''') - test.contains('''assertThatJson(parsedJson).field("['rawAuthorization']").isEqualTo("secret")''') - test.contains('''assertThatJson(parsedJson).field("['rawAuthorization2']").isEqualTo("secret2")''') - test.contains('''assertThatJson(parsedJson).field("['rawResponseBaz']").isEqualTo(5)''') - test.contains('''assertThatJson(parsedJson).field("['rawResponseBaz2']").isEqualTo("Bla bla bar bla bla")''') - test.contains('''assertThatJson(parsedJson).field("['rawParam']").isEqualTo("bar")''') - responseAssertion(test) - where: - methodBuilderName | methodBuilder | responseAssertion - "spock" | { - configProperties.testFramework = TestFramework.SPOCK - } | { String body -> body.contains("""response.header("Authorization") == 'foo secret bar'""") } - "testng" | { - configProperties.testFramework = TestFramework.TESTNG - } | { String body -> body.contains('assertThat(response.header("Authorization")).isEqualTo("foo secret bar");') } - "mockmvc" | { - configProperties.testMode = TestMode.MOCKMVC - } | { String body -> body.contains('assertThat(response.header("Authorization")).isEqualTo("foo secret bar");') } - "jaxrs-spock" | { - configProperties.testFramework = TestFramework.SPOCK; configProperties.testMode = TestMode.JAXRSCLIENT - } | { String body -> body.contains('''response.getHeaderString("Authorization") == "foo secret bar"''') } - "jaxrs" | { - configProperties.testFramework = TestFramework.JUNIT; configProperties.testMode = TestMode.JAXRSCLIENT - } | { String body -> body.contains('assertThat(response.getHeaderString("Authorization")).isEqualTo("foo secret bar");') } - "webclient" | { - configProperties.testMode = TestMode.WEBTESTCLIENT - } | { String body -> body.contains('''assertThat(response.header("Authorization")).isEqualTo("foo secret bar");''') } - } - - @Issue('#230') - def 'should manage to reference request in response via WireMock native entries [#methodBuilderName]'() { - given: - //tag::template_contract[] - Contract contractDsl = Contract.make { - request { - method 'GET' - url('/api/v1/xxxx') { - queryParameters { - parameter('foo', 'bar') - parameter('foo', 'bar2') - } - } - headers { - header(authorization(), 'secret') - header(authorization(), 'secret2') - } - body(foo: "bar", baz: 5) - } - response { - status OK() - headers { - contentType(applicationJson()) - } - body(''' - { - "responseFoo": "{{{ jsonPath request.body '$.foo' }}}", - "responseBaz": {{{ jsonPath request.body '$.baz' }}}, - "responseBaz2": "Bla bla {{{ jsonPath request.body '$.foo' }}} bla bla" - } - '''.toString()) - } - } - //end::template_contract[] - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - !test.contains('''DslProperty''') - test.contains('''assertThatJson(parsedJson).field("['responseFoo']").isEqualTo("bar")''') - test.contains('''assertThatJson(parsedJson).field("['responseBaz']").isEqualTo(5)''') - test.contains('''assertThatJson(parsedJson).field("['responseBaz2']").isEqualTo("Bla bla bar bla bla")''') - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "jaxrs-spock" | { - configProperties.testFramework = TestFramework.SPOCK; configProperties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - configProperties.testFramework = TestFramework.JUNIT; configProperties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - def 'should generate JUnit assertions with cookies [#methodBuilderName]'() { - given: - methodBuilder() - when: - String test = singleTestGenerator(contractDslWithCookiesValue) - then: - test.contains('''.cookie("cookie-key", "cookie-value")''') - test.contains('''assertThat(response.cookie("cookie-key")).isNotNull();''') - test.contains('''assertThat(response.cookie("cookie-key")).isEqualTo("new-cookie-value");''') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - def 'should generate JUnit assertions with cookies pattern [#methodBuilderName]'() { - given: - methodBuilder() - when: - String test = singleTestGenerator(contractDslWithCookiesPattern) - then: - !test.contains('''.cookie("cookie-key", "[A-Za-z]+")''') - test.contains('''.cookie("cookie-key", "''') - test.contains('''assertThat(response.cookie("cookie-key")).isNotNull();''') - test.contains('''assertThat(response.cookie("cookie-key")).matches("[A-Za-z]+");''') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - def 'should not generate JUnit cookie assertion with absent cookie [#methodBuilderName]'() { - given: - methodBuilder() - when: - String test = singleTestGenerator(contractDslWithAbsentCookies) - then: - !test.contains('cookie') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - def 'should generate spock assertions with cookies'() { - given: - configProperties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDslWithCookiesValue) - then: - test.contains('''.cookie("cookie-key", "cookie-value")''') - test.contains('''response.cookie("cookie-key") != null''') - test.contains('''response.cookie("cookie-key") == 'new-cookie-value''') - and: - SyntaxChecker.tryToCompile("spock", test) - } - - def 'should generate spock assertions with cookies pattern'() { - given: - configProperties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDslWithCookiesPattern) - then: - !test.contains('''.cookie("cookie-key", "[A-Za-z]+")''') - test.contains('''.cookie("cookie-key", "''') - test.contains('''response.cookie("cookie-key") != null''') - test.contains('''response.cookie("cookie-key") ==~ java.util.regex.Pattern.compile('[A-Za-z]+')''') - and: - SyntaxChecker.tryToCompile("spock", test) - } - - def 'should not generate spock cookie assertion with absent cookie'() { - given: - configProperties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDslWithAbsentCookies) - then: - !test.contains("cookie") - and: - SyntaxChecker.tryToCompile("spock", test) - } - - @Issue('#554') - def 'should create an assertion for an empty map or Object for [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - name("method") - request { - method 'GET' - url '/api/v1/xxxx' - } - response { - status 200 - body([ - aMap : ["foo": "bar"], - anEmptyMap: [:] - ]) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompile(methodBuilderName, test) - test.contains('''assertThatJson(parsedJson).field("['aMap']").field("['foo']").isEqualTo("bar")''') - test.contains('''assertThatJson(parsedJson).field("['anEmptyMap']").isEmpty()''') - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "jaxrs-spock" | { - configProperties.testFramework = TestFramework.SPOCK; configProperties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - configProperties.testFramework = TestFramework.JUNIT; configProperties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - @Issue('#1139') - def 'should have a big decimal import for [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'POST' - url '/crystals/create' - headers { - header 'Content-Type' : 'application/json' - } - body( - amount: 200 - ) - bodyMatchers { - jsonPath('$.amount', byRegex('^[0-9]{1,3}$')) - } - } - response { - status 201 - body( - amount: fromRequest().body('$.amount'), - price: 10100.0 - ) - bodyMatchers { - jsonPath('$.amount', byRegex('^\\d*$')) - jsonPath('$.price', byEquality()) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompile(methodBuilderName, test) - then: - test.contains('''$.price", java.math.BigDecimal.class)).isEqualTo("10100.0")''') - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "jaxrs-spock" | { - configProperties.testFramework = TestFramework.SPOCK; configProperties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - configProperties.testFramework = TestFramework.JUNIT; configProperties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - @Issue('#1163') - def 'should resolve from request evaluation even if there is no response body [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method PUT() - url '/frauds/name' - body([ - name: $(anyAlphaUnicode()) - ]) - headers { - contentType("application/json") - } - } - response { - status OK() - headers { - header(contentType(), "${fromRequest().header(contentType())}") - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompile(methodBuilderName, test) - and: - !test.contains('''{{{request.headers.Content-Type.[0]}}}''') - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "jaxrs-spock" | { - configProperties.testFramework = TestFramework.SPOCK; configProperties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - configProperties.testFramework = TestFramework.JUNIT; configProperties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - @Issue('#1260') - def 'should generate test methods for not in progress contracts [#methodBuilderName]'() { - given: - List contractDsl = [ - Contract.make { - name("httpContractNotInProgress") - request { - method PUT() - url '/httpContractNotInProgress' - } - response { - status OK() - } - }, - Contract.make { - name("httpContractInProgress") - inProgress() - request { - method PUT() - url '/httpContractInProgress' - } - response { - status OK() - } - }, - Contract.make { - name("messagingContractNotInProgress") - input { - triggeredBy("toString()") - } - outputMessage { - sentTo("messagingContractNotInProgress") - body([type: "messagingContractNotInProgress"]) - } - }, - Contract.make { - name("messagingContractInProgress") - inProgress() - input { - triggeredBy("toString()") - } - outputMessage { - sentTo("messagingContractNotInProgress") - body([type: "messagingContractNotInProgress"]) - } - } - ] - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompile(methodBuilderName, test) - and: - test.contains('''httpContractNotInProgress''') - test.contains('''messagingContractNotInProgress''') - and: - test.contains('''httpContractInProgress''') - test.contains('''messagingContractInProgress''') - test.count("@Ignore") == 2 || test.count("@Disabled") == 2 || test.count("@Test(enabled = false)") == 2 - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "junit5" | { configProperties.testFramework = TestFramework.JUNIT5 } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "jaxrs-spock" | { - configProperties.testFramework = TestFramework.SPOCK; configProperties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - configProperties.testFramework = TestFramework.JUNIT; configProperties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - @Issue('#1052') - def 'should work with large numbers [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - label 'storage_object_created' - input { - triggeredBy('toString()') - } - - outputMessage { - sentTo('document_uploads') - headers { - header('objectGeneration', 23094823904823) - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompile(methodBuilderName, test) - and: - test.contains('''23094823904823L''') - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "junit" | { configProperties.testFramework = TestFramework.JUNIT } - "junit5" | { configProperties.testFramework = TestFramework.JUNIT5 } - } - - @Issue('#1252') - def 'should call execute in headers instead of quoting it [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method PUT() - url '/frauds/name' - headers { - header(authorization(), value(client(anyNonBlankString()), server(execute("toString()")))) - - } - } - response { - status OK() - headers { - header(contentType(), "${fromRequest().header(contentType())}") - } - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompile(methodBuilderName, test) - then: - !test.contains('''"toString()"''') - !test.contains("""'toString()'""") - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "jaxrs-spock" | { - configProperties.testFramework = TestFramework.SPOCK; configProperties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - configProperties.testFramework = TestFramework.JUNIT; configProperties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } - - @Issue('#1263') - def 'should allow using execute in the request body [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - description "should migrate spaceship" - request { - method POST() - url('/api/migration') - headers { - accept('application/json') - contentType(applicationJson()) - } - body( - $(c([id: 4, foo:5, whatever:"hello"]), p(execute('hashCode()'))) - ) - } - response { - status OK() - headers { - contentType(applicationJson()) - } - body( - $(c([id: 4, foo:5, whatever:"hello"]), p(execute('hashCode()'))) - ) - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompile(methodBuilderName, test) - then: - // 1 in the request and 1 in the response - test.findAll("hashCode()").size() == 2 - where: - methodBuilderName | methodBuilder - "spock" | { configProperties.testFramework = TestFramework.SPOCK } - "testng" | { configProperties.testFramework = TestFramework.TESTNG } - "mockmvc" | { configProperties.testMode = TestMode.MOCKMVC } - "jaxrs-spock" | { - configProperties.testFramework = TestFramework.SPOCK; configProperties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - configProperties.testFramework = TestFramework.JUNIT; configProperties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT } - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/XmlMethodBodyBuilderSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/XmlMethodBodyBuilderSpec.groovy deleted file mode 100644 index a60cfe614b..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/XmlMethodBodyBuilderSpec.groovy +++ /dev/null @@ -1,479 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder - -import org.junit.Rule -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll - -import org.springframework.boot.test.system.OutputCaptureRule -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties -import org.springframework.cloud.contract.verifier.config.TestFramework -import org.springframework.cloud.contract.verifier.config.TestMode -import org.springframework.cloud.contract.verifier.file.ContractMetadata -import org.springframework.cloud.contract.verifier.util.SyntaxChecker - -/** - * @author Olga Maciaszek-Sharma - * @author Chris Bono - * @since 2.1.0 - */ -class XmlMethodBodyBuilderSpec extends Specification { - - @Rule - OutputCaptureRule capture = new OutputCaptureRule() - - @Shared - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties( - assertJsonSize: true, generatedTestSourcesDir: new File("."), - generatedTestResourcesDir: new File(".") - ) - - @Shared - GeneratedClassDataForMethod generatedClassDataForMethod = new GeneratedClassDataForMethod( - new SingleTestGenerator.GeneratedClassData("foo", "bar", new File(".").toPath()), "method") - - @Shared - SingleTestGenerator.GeneratedClassData generatedClassData = - new SingleTestGenerator.GeneratedClassData("foo", "com.example", new File(".").toPath()) - - def setup() { - properties = new ContractVerifierConfigProperties( - assertJsonSize: true - ) - } - - private String singleTestGenerator(Contract contractDsl) { - return new JavaTestGenerator() { - @Override - ClassBodyBuilder classBodyBuilder(BlockBuilder builder, GeneratedClassMetaData metaData, SingleMethodBuilder methodBuilder) { - return super.classBodyBuilder(builder, metaData, methodBuilder).field(new Field() { - @Override - boolean accept() { - return metaData.configProperties.testMode == TestMode.JAXRSCLIENT - } - - @Override - Field call() { - builder.addLine("WebTarget webTarget") - return this - } - }) - } - }.buildClass(properties, [contractMetadata(contractDsl)], "foo", generatedClassData) - } - - private ContractMetadata contractMetadata(Contract contractDsl) { - return new ContractMetadata(new File(".").toPath(), false, 0, null, contractDsl) - } - - @Unroll - def 'should generate correct verification from xml with body matchers [#methodBuilderName]'() { - given: - Contract contractDsl = - // tag::xmlgroovy[] - Contract.make { - request { - method GET() - urlPath '/get' - headers { - contentType(applicationXml()) - } - } - response { - status(OK()) - headers { - contentType(applicationXml()) - } - body """ - -123 -abc - -abc -def -ghi - -123 -true -2017-01-01 -2017-01-01T01:23:45 - -foo -foo -""" - bodyMatchers { - xPath('/test/duck/text()', byRegex("[0-9]{3}")) - xPath('/test/duck/text()', byCommand('equals($it)')) - xPath('/test/duck/xxx', byNull()) - xPath('/test/duck/text()', byEquality()) - xPath('/test/alpha/text()', byRegex(onlyAlphaUnicode())) - xPath('/test/alpha/text()', byEquality()) - xPath('/test/number/text()', byRegex(number())) - xPath('/test/date/text()', byDate()) - xPath('/test/dateTime/text()', byTimestamp()) - xPath('/test/time/text()', byTime()) - xPath('/test/*/complex/text()', byEquality()) - xPath('/test/duck/@type', byEquality()) - } - } - } - // end::xmlgroovy[] - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThat(valueFromXPath(parsedXml, "/test/list/elem/text()")).isEqualTo("abc")') - test.contains('assertThat(valueFromXPath(parsedXml, "/test/list/elem[2]/text()")).isEqualTo("def")') - test.contains('assertThat(valueFromXPath(parsedXml, "/test/list/elem[3]/text()")).isEqualTo("ghi")') - test.contains('assertThat(valueFromXPath(parsedXml, "/test/aBoolean/text()")).isEqualTo("true")') - test.contains('assertThat(valueFromXPath(parsedXml, "/test/valueWithoutAMatcher/text()")).isEqualTo("foo")') - test.contains('assertThat(valueFromXPath(parsedXml, "/test/duck/text()")).matches("[0-9]{3}")') - test.contains('equals("123")') - test.contains('assertThat(nodeFromXPath(parsedXml, "/test/duck/xxx")).isNull()') - test.contains('assertThat(valueFromXPath(parsedXml, "/test/duck/text()")).isEqualTo("123")') - test.contains('assertThat(valueFromXPath(parsedXml, "/test/alpha/text()")).matches("[\\\\p{L}]*")') - test.contains('assertThat(valueFromXPath(parsedXml, "/test/alpha/text()")).isEqualTo("abc")') - test.contains('assertThat(valueFromXPath(parsedXml, "/test/number/text()")).matches("-?(\\\\d*\\\\.\\\\d+|\\\\d+)")') - test.contains('assertThat(valueFromXPath(parsedXml, "/test/date/text()")).matches("(\\\\d\\\\d\\\\d\\\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])")') - test.contains('assertThat(valueFromXPath(parsedXml, "/test/dateTime/text()")).matches("([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])")') - test.contains('assertThat(valueFromXPath(parsedXml, "/test/time/text()")).matches("(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])")') - test.contains('assertThat(valueFromXPath(parsedXml, "/test/*/complex/text()")).isEqualTo("foo")') - test.contains('assertThat(valueFromXPath(parsedXml, "/test/duck/@type")).isEqualTo("xtype")') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "testng" | { - properties.testFramework = TestFramework.TESTNG - } - "junit" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - } - - @Unroll - def 'should generate correct verification from xml with namespace [#methodBuilderName]'() { - given: - Contract contractDsl = - Contract.make { - request { - method GET() - urlPath '/get' - headers { - contentType(applicationXml()) - } - } - response { - status(OK()) - headers { - contentType(applicationXml()) - } - body """ - - - - 1 - - - """ - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThat(valueFromXPath(parsedXml, "/soap:Envelope/soap:Body/ns2:Res/ns2:ID/text()")).isEqualTo("1")') - test.contains('assertThat(valueFromXPath(parsedXml, "/soap:Envelope/namespace::soap")).isEqualTo("http://schemas.xmlsoap.org/soap/envelope/")') - test.contains('valueFromXPath(parsedXml, "/soap:Envelope/soap:Body/ns2:Res/namespace::ns2")).isEqualTo("http://*******/****/****/******/schema"') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "testng" | { - properties.testFramework = TestFramework.TESTNG - } - "junit" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - } - - @Unroll - def 'should generate correct verification from named xml with body matchers [#methodBuilderName]'() { - given: - Contract contractDsl = - // tag::xmlgroovy[] - Contract.make { - request { - method GET() - urlPath '/get' - headers { - contentType(applicationXml()) - } - } - response { - status(OK()) - headers { - contentType(applicationXml()) - } - body """ - - - - duck5150 - - - -""" - bodyMatchers { - xPath('/test/duck/text()', byRegex("[0-9]{3}")) - xPath('/test/duck/text()', byCommand('equals($it)')) - xPath('/test/duck/xxx', byNull()) - xPath('/test/duck/text()', byEquality()) - xPath('/test/alpha/text()', byRegex(onlyAlphaUnicode())) - xPath('/test/alpha/text()', byEquality()) - xPath('/test/number/text()', byRegex(number())) - xPath('/test/date/text()', byDate()) - xPath('/test/dateTime/text()', byTimestamp()) - xPath('/test/time/text()', byTime()) - xPath('/test/duck/@type', byEquality()) - } - } - } - // end::xmlgroovy[] - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThat(valueFromXPath(parsedXml, "/ns1:test/ns1:header/duck-bucket/duck/text()")).isEqualTo("duck5150")') - test.contains('assertThat(valueFromXPath(parsedXml, "/ns1:test/namespace::ns1")).isEqualTo("http://demo.com/testns")') - test.contains('assertThat(valueFromXPath(parsedXml, "/ns1:test/ns1:header/duck-bucket/@type")).isEqualTo("bigbucket")') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "testng" | { - properties.testFramework = TestFramework.TESTNG - } - "junit" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - } - - @Unroll - def 'should generate correct verification from complex named xml with body matchers [#methodBuilderName]'() { - given: - Contract contractDsl = - // tag::xmlgroovy[] - Contract.make { - request { - method GET() - urlPath '/get' - headers { - contentType(applicationXml()) - } - } - response { - status(OK()) - headers { - contentType(applicationXml()) - } - body """ - - - - 1234 - - - -""" - bodyMatchers { - xPath('//*[local-name()=\'RsHeader\' and namespace-uri()=\'http://schemas.xmlsoap.org/soap/custom\']/*[local-name()=\'MsgSeqId\']/text()', byEquality()) - } - } - } - // end::xmlgroovy[] - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThat(valueFromXPath(parsedXml, "//*[local-name()=\'RsHeader\' and namespace-uri()=\'http://schemas.xmlsoap.org/soap/custom\']/*[local-name()=\'MsgSeqId\']/text()")).isEqualTo("1234")') - test.contains('assertThat(valueFromXPath(parsedXml, "/SOAP-ENV:Envelope/namespace::SOAP-ENV")).isEqualTo("http://schemas.xmlsoap.org/soap/envelope/")') - !test.contains('assertThat(valueFromXPath(parsedXml, "/SOAP-ENV:Envelope/SOAP-ENV:Header/*[local-name()=\'RsHeader\' and namespace-uri()=\'http://schemas.xmlsoap.org/soap/custom\']/@xmlns")).isEqualTo"') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "testng" | { - properties.testFramework = TestFramework.TESTNG - } - "junit" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - } - - @Unroll - def 'should generate correct verification from very complex named xml without body matchers [#methodBuilderName]'() { - given: - Contract contractDsl = - // tag::xmlgroovy[] - Contract.make { - request { - method GET() - urlPath '/get' - headers { - contentType(applicationXml()) - } - } - response { - status(OK()) - headers { - contentType(applicationXml()) - } - body """ - - customer@test.com - - Krombopulous -

- - 51 - 50 - -
- - -""" - } - } - // end::xmlgroovy[] - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThat(valueFromXPath(parsedXml, "/ns1:customer/namespace::ns1")).isEqualTo("http://demo.com/customer")') - test.contains('assertThat(valueFromXPath(parsedXml, "/ns1:customer/namespace::addr")).isEqualTo("http://demo.com/address")') - test.contains('assertThat(valueFromXPath(parsedXml, "/ns1:customer/email/text()")).isEqualTo("customer@test.com")') - test.contains('assertThat(valueFromXPath(parsedXml, "/ns1:customer/*[local-name()=\'contact-info\' and namespace-uri()=\'http://demo.com/contact-info\']/*[local-name()=\'name\']/text()")).isEqualTo("Krombopulous")') - test.contains('assertThat(valueFromXPath(parsedXml, "/ns1:customer/*[local-name()=\'contact-info\' and namespace-uri()=\'http://demo.com/contact-info\']/*[local-name()=\'address\']/addr:gps/*[local-name()=\'lat\']/text()")).isEqualTo("51")') - test.contains('assertThat(valueFromXPath(parsedXml, "/ns1:customer/*[local-name()=\'contact-info\' and namespace-uri()=\'http://demo.com/contact-info\']/*[local-name()=\'address\']/addr:gps/addr:lon/text()")).isEqualTo("50")') - !test.contains('assertThat(valueFromXPath(parsedXml,"/ns1:customer/*[local-name()=\'contact-info\' and namespace-uri()=\'http://demo.com/contact-info\']/@xmlns")).isEqualTo"') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "testng" | { - properties.testFramework = TestFramework.TESTNG - } - "junit" | { - properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } - } - - def 'should throw exception for verification by type'() { - given: - Contract contractDsl = Contract.make { - request { - method GET() - urlPath '/get' - headers { - contentType(applicationXml()) - } - } - response { - status(OK()) - headers { - contentType(applicationXml()) - } - body """ - -123 -""" - bodyMatchers { - xPath('/test/duck/text()', byType()) - } - } - } - properties.testMode = TestMode.MOCKMVC - when: - singleTestGenerator(contractDsl) - then: - thrown UnsupportedOperationException - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/YamlMockMvcMethodBodyBuilderSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/YamlMockMvcMethodBodyBuilderSpec.groovy deleted file mode 100644 index f8c579cb48..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/YamlMockMvcMethodBodyBuilderSpec.groovy +++ /dev/null @@ -1,2022 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder - -import org.junit.Rule -import spock.lang.Issue -import spock.lang.Shared -import spock.lang.Specification -import spock.util.environment.RestoreSystemProperties - -import org.springframework.boot.test.system.OutputCaptureRule -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties -import org.springframework.cloud.contract.verifier.config.TestFramework -import org.springframework.cloud.contract.verifier.config.TestMode -import org.springframework.cloud.contract.verifier.converter.YamlContractConverter -import org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockStubVerifier -import org.springframework.cloud.contract.verifier.file.ContractMetadata -import org.springframework.cloud.contract.verifier.util.SyntaxChecker - -/** - * @author Jakub Kubrynski, codearte.io - * @author Tim Ysewyn - */ -class YamlMockMvcMethodBodyBuilderSpec extends Specification implements WireMockStubVerifier { - - @Rule - OutputCaptureRule capture = new OutputCaptureRule() - - @Shared - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties( - assertJsonSize: true - ) - - @Shared - GeneratedClassDataForMethod generatedClassDataForMethod = new GeneratedClassDataForMethod( - new SingleTestGenerator.GeneratedClassData("foo", "bar", new File(".").toPath()), "method") - - @Shared - SingleTestGenerator.GeneratedClassData generatedClassData = - new SingleTestGenerator.GeneratedClassData("foo", "com.example", new File(".").toPath()) - - def setup() { - properties = new ContractVerifierConfigProperties( - assertJsonSize: true - ) - } - - private String singleTestGenerator(Contract contractDsl) { - return new JavaTestGenerator() { - @Override - ClassBodyBuilder classBodyBuilder(BlockBuilder builder, GeneratedClassMetaData metaData, SingleMethodBuilder methodBuilder) { - return super.classBodyBuilder(builder, metaData, methodBuilder).field(new Field() { - @Override - boolean accept() { - return metaData.configProperties.testMode == TestMode.JAXRSCLIENT - } - - @Override - Field call() { - builder.addLine("WebTarget webTarget") - return this - } - }) - } - }.buildClass(properties, [contractMetadata(contractDsl)], "foo", generatedClassData) - } - - private ContractMetadata contractMetadata(Contract contractDsl) { - return new ContractMetadata(new File(".").toPath(), false, 0, null, contractDsl) - } - - static File textToFile(String text) { - File temp = File.createTempFile("yaml", ".yml") - temp.text = text - return temp - } - - static Contract fromYaml(String text) { - return new YamlContractConverter().convertFrom(textToFile(text))[0] - } - - def 'should generate assertions for simple response body with #methodBuilderName'() { - given: - String contract = """\ ---- -request: - method: "GET" - url: "test" -response: - status: 200 - body: - "property1": "a" - "property2": "b" -""" - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("a")""") - test.contains("""assertThatJson(parsedJson).field("['property2']").isEqualTo("b")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "custom" | { properties.testMode = TestMode.CUSTOM } - } - - @Issue("#187") - def "should generate assertions for null and boolean values with #methodBuilderName"() { - given: - String contract = """\ ---- -request: - method: "GET" - url: "test" -response: - status: 200 - body: - "property1": "true" - "property2": null - "property3": false -""" - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("true")""") - test.contains("""assertThatJson(parsedJson).field("['property2']").isNull()""") - test.contains("""assertThatJson(parsedJson).field("['property3']").isEqualTo(false)""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "custom" | { properties.testMode = TestMode.CUSTOM } - } - - @Issue('#79') - def 'should generate assertions for simple response body constructed from map with a list with #methodBuilderName'() { - given: - String contract = """\ ---- -request: - method: "GET" - url: "test" -response: - status: 200 - body: - "property1": "a" - "property2": - - "a" : "sth" - - "b" : "sthElse" -""" - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("a")""") - test.contains("""assertThatJson(parsedJson).array("['property2']").contains("['a']").isEqualTo("sth")""") - test.contains("""assertThatJson(parsedJson).array("['property2']").contains("['b']").isEqualTo("sthElse")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } - "custom" | { properties.testMode = TestMode.CUSTOM } - } - - @Issue('#79') - @RestoreSystemProperties - def 'should generate assertions for simple response body constructed from map with a list with #methodBuilderName with array size check'() { - given: - System.setProperty('spring.cloud.contract.verifier.assert.size', 'true') - String contract = """\ ---- -request: - method: "GET" - url: "test" -response: - status: 200 - body: - "property1": "a" - "property2": - - "a" : "sth" - - "b" : "sthElse" -""" - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("a")""") - test.contains("""assertThatJson(parsedJson).array("['property2']").contains("['a']").isEqualTo("sth")""") - test.contains("""assertThatJson(parsedJson).array("['property2']").hasSize(2)""") - test.contains("""assertThatJson(parsedJson).array("['property2']").contains("['b']").isEqualTo("sthElse")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } - "custom" | { properties.testMode = TestMode.CUSTOM } - } - - @Issue('#82') - def 'should generate proper request when body constructed from map with a list #methodBuilderName'() { - given: - String contract = """\ ---- -request: - method: "GET" - url: "test" - body: - items: - - "HOP" -response: - status: 200 -""" - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains(bodyString) - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | bodyString - "spock" | { properties.testFramework = TestFramework.SPOCK } | """.body('''{\"items\":[\"HOP\"]}''')""" - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } | '.body("{\\"items\\":[\\"HOP\\"]}")' - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } | '.body("{\\"items\\":[\\"HOP\\"]}")' - "custom" | { - properties.testMode = TestMode.CUSTOM - } | '.body("{\\"items\\":[\\"HOP\\"]}")' - } - - @Issue('#88') - def 'should generate proper request when body constructed from GString with #methodBuilderName'() { - given: - String contract = """\ ---- -request: - method: "GET" - url: "test" - body: "property1=VAL1" -response: - status: 200 -""" - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains(bodyString) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder | bodyString - "spock" | { properties.testFramework = TestFramework.SPOCK } | """.body('''property1=VAL1''')""" - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } | '.body("property1=VAL1")' - "webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } | '.body("property1=VAL1")' - "custom" | { properties.testMode = TestMode.CUSTOM } | '.body("property1=VAL1")' - } - - @Issue('185') - def 'should generate assertions for a response body containing map with integers as keys with #methodBuilderName'() { - given: - // YAML CAN'T HAVE INTEGER KEYS - String contract = """\ ---- -request: - method: "GET" - url: "test" -response: - status: 200 - body: - property: - 14: 0.0 - 7: 0.0 -""" - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).field("['property']").field("['7']").isEqualTo(0.0)""") - test.contains("""assertThatJson(parsedJson).field("['property']").field("['14']").isEqualTo(0.0)""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } - "custom" | { properties.testMode = TestMode.CUSTOM } - } - - def 'should generate assertions for array in response body with #methodBuilderName'() { - given: - String contract = """\ ---- -request: - method: "GET" - url: "test" -response: - status: 200 - body: ' - [ - { - "property1": "a" - }, - { - "property2": "b" - } - ]' -""" - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).array().contains("['property2']").isEqualTo("b")""") - test.contains("""assertThatJson(parsedJson).array().contains("['property1']").isEqualTo("a")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } - "custom" | { properties.testMode = TestMode.CUSTOM } - } - - def 'should generate assertions for array inside response body element with #methodBuilderName'() { - given: - - String contract = """\ ---- -request: - method: "GET" - url: "test" -response: - status: 200 - body: ' - { - "property1": [ - { "property2": "test1"}, - { "property3": "test2"} - ] - }' -""" - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).array("['property1']").contains("['property2']").isEqualTo("test1")""") - test.contains("""assertThatJson(parsedJson).array("['property1']").contains("['property3']").isEqualTo("test2")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } - "custom" | { properties.testMode = TestMode.CUSTOM } - } - - def 'should generate assertions for nested objects in response body with #methodBuilderName'() { - given: - String contract = """\ ---- -request: - method: "GET" - url: "test" -response: - status: 200 - body: ' - { - "property1": "a", - "property2": {"property3": "b"} - }' -""" - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).field("['property2']").field("['property3']").isEqualTo("b")""") - test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("a")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } - "custom" | { properties.testMode = TestMode.CUSTOM } - } - - @Issue('#1423') - def 'should generate assertions for a response body containing an empty list with #methodBuilderName'() { - given: - String contract = """\ ---- -description: Returns an empty collection -request: - method: GET - urlPath: /url -response: - status: 200 - body: [] -""" - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).isEmpty()""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "testng" | { properties.testFramework = TestFramework.TESTNG } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } - } - - @Issue('#1423') - def 'should generate assertions for a response body containing an empty map with #methodBuilderName'() { - given: - String contract = """\ ---- -description: Returns an empty map -request: - method: GET - urlPath: /url -response: - status: 200 - body: {} -""" - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).isEmpty()""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "testng" | { properties.testFramework = TestFramework.TESTNG } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } - } - - def 'should generate regex assertions for map objects in response body with #methodBuilderName'() { - given: - String contract = '''\ ---- -request: - method: "GET" - url: "test" -response: - status: 200 - body: - property1: "a" - property2: "123" - matchers: - body: - - path: $.property2 - type: by_regex - value: "[0-9]{3}" - regexType: as_integer -''' - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""\$.property2", String.class)).matches("[0-9]{3}")""") - test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("a")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } - "custom" | { properties.testMode = TestMode.CUSTOM } - } - - def "should generate a call with an url path and query parameters with #methodBuilderName"() { - given: - String contract = '''\ ---- -request: - method: "GET" - urlPath: "/users" - queryParameters: - 'limit': "10" - 'offset': "20" - 'filter': "email" - 'sort': "name" - 'search': "55" - 'age': "99" - 'name': "Denis.Stepanov" - 'email': "bob@email.com" - matchers: - queryParameters: - - key: limit - type: equal_to - value: "10" - - key: offset - type: containing - value: "20" - - key: sort - type: equal_to - value: "name" - - key: sort - type: not_matching - value: "^/[0-9]{2}$" - - key: age - type: not_matching - value: '^\\w*$' - - key: name - type: matching - value: 'Denis.*' - - key: hello - type: absent -response: - status: 200 - body: - property1: "a" - property2: "b" -''' - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('''.queryParam("limit","10")''') - test.contains('''.queryParam("offset","20")''') - test.contains('''.queryParam("filter","email")''') - test.contains('''.queryParam("sort","name")''') - test.contains('''.queryParam("search","55")''') - test.contains('''.queryParam("age","99")''') - test.contains('''.queryParam("name","Denis.Stepanov")''') - test.contains('''.queryParam("email","bob@email.com")''') - test.contains('''.get("/users")''') - test.contains('assertThatJson(parsedJson).field("[\'property1\']").isEqualTo("a")') - test.contains('assertThatJson(parsedJson).field("[\'property2\']").isEqualTo("b")') - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } - "custom" | { properties.testMode = TestMode.CUSTOM } - } - - @Issue('#169') - def 'should generate a call with an url path and query parameters with url containing a pattern with #methodBuilderName'() { - given: - String contract = '''\ ---- -request: - method: "GET" - urlPath: "/foo/123456" - queryParameters: - 'limit': "10" - 'offset': "20" - 'filter': "email" - 'sort': "name" - 'search': "55" - 'age': "99" - 'name': "Denis.Stepanov" - 'email': "bob@email.com" - matchers: - url: - regex: '/foo/[0-9]+' - queryParameters: - - key: limit - type: equal_to - value: "10" - - key: offset - type: containing - value: "20" - - key: sort - type: equal_to - value: "name" - - key: sort - type: not_matching - value: "^/[0-9]{2}$" - - key: age - type: not_matching - value: '^\\w*$' - - key: name - type: matching - value: 'Denis.*' - - key: hello - type: absent -response: - status: 200 - body: - property1: "a" - property2: "b" -''' - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('''.queryParam("limit","10")''') - test.contains('''.queryParam("offset","20")''') - test.contains('''.queryParam("filter","email")''') - test.contains('''.queryParam("sort","name")''') - test.contains('''.queryParam("search","55")''') - test.contains('''.queryParam("age","99")''') - test.contains('''.queryParam("name","Denis.Stepanov")''') - test.contains('''.queryParam("email","bob@email.com")''') - test.contains('''.get("/foo/123456")''') - test.contains('assertThatJson(parsedJson).field("[\'property1\']").isEqualTo("a")') - test.contains('assertThatJson(parsedJson).field("[\'property2\']").isEqualTo("b")') - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } - "custom" | { properties.testMode = TestMode.CUSTOM } - } - - def 'should generate test for empty body with #methodBuilderName'() { - given: - String contract = '''\ ---- -request: - method: "POST" - url: "/ws/payments" - body: "" -response: - status: 406 -''' - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains(bodyString) - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | bodyString - "spock" | { properties.testFramework = TestFramework.SPOCK } | ".body('''''')" - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } | '.body("")' - "webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } | '.body("")' - "custom" | { properties.testMode = TestMode.CUSTOM } | '.body("")' - } - - def 'should generate test for String in response body with #methodBuilderName'() { - given: - String contract = '''\ ---- -request: - method: "POST" - url: "test" - body: "" -response: - status: 200 - body: "test" -''' - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains(bodyDefinitionString) - test.contains(bodyEvaluationString) - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | bodyDefinitionString | bodyEvaluationString - "spock" | { - properties.testFramework = TestFramework.SPOCK - } | 'String responseBody = response.body.asString()' | "responseBody == 'test'" - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } | 'String responseBody = response.getBody().asString();' | 'assertThat(responseBody).isEqualTo("test");' - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } | 'String responseBody = response.getBody().asString();' | 'assertThat(responseBody).isEqualTo("test");' - "custom" | { - properties.testMode = TestMode.CUSTOM - } | 'String responseBody = response.getBody().asString();' | 'assertThat(responseBody).isEqualTo("test");' - } - - @Issue('113') - def 'should generate regex test for String in response header with #methodBuilderName'() { - given: - String contract = '''\ ---- -request: - method: "POST" - url: "/partners/1000/users" - headers: - "Content-Type": "application/json" - body: - first_name: 'John' - last_name: 'Smith' - personal_id: '12345678901' - phone_number: '500500500' - invitation_token: '00fec7141bb94793bfe7ae1d0f39bda0' - password: 'john' - matchers: - headers: - - key: 'Content-Type' - regex: 'application/json.*' - url: - regex: '/partners/[0-9]+/users' -response: - status: 201 - headers: - "Location": "http://localhost/partners/1000/users/1001" - matchers: - headers: - - key: 'Location' - regex: 'http://localhost/partners/[0-9]+/users/[0-9]+' -''' - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains(headerEvaluationString) - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | headerEvaluationString - "spock" | { properties.testFramework = TestFramework.SPOCK } | '''response.header("Location") ==~ java.util.regex.Pattern.compile('http://localhost/partners/[0-9]+/users/[0-9]+')''' - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } | 'assertThat(response.header("Location")).matches("http://localhost/partners/[0-9]+/users/[0-9]+");' - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } | 'assertThat(response.header("Location")).matches("http://localhost/partners/[0-9]+/users/[0-9]+");' - "custom" | { - properties.testMode = TestMode.CUSTOM - } | 'assertThat(response.header("Location")).matches("http://localhost/partners/[0-9]+/users/[0-9]+");' - } - - def 'should work with more complex stuff and jsonpaths with #methodBuilderName'() { - given: - String contract = '''\ ---- -priority: 10 -request: - method: "POST" - url: "/validation/client" - headers: - "Content-Type": "application/json" - body: - bank_account_number: '0014282912345698765432161182' - email: 'foo@bar.com' - phone_number: '100299300' - personal_id: 'ABC123456' - matchers: - headers: - - key: 'Content-Type' - regex: 'application/json.*' - url: - regex: '/partners/[0-9]+/users' -response: - status: 201 - body: - errors: - - property: "bank_account_number" - message: "incorrect_format" -''' - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("""assertThatJson(parsedJson).array("['errors']").contains("['property']").isEqualTo("bank_account_number")""") - test.contains("""assertThatJson(parsedJson).array("['errors']").contains("['message']").isEqualTo("incorrect_format")""") - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } - "custom" | { properties.testMode = TestMode.CUSTOM } - } - - @Issue('72') - def 'should make the execute method work with #methodBuilderName'() { - given: - String contract = '''\ ---- -priority: 10 -request: - method: "PUT" - url: "/fraudcheck" -response: - status: 201 - headers: - "Location": null - body: - rejectionReason: "foo" - matchers: - body: - - path: "$.rejectionReason" - type: by_command - value: assertThatRejectionReasonIsNull($it) - headers: - - key: "Location" - command: assertThatLocationIsNull($it) -''' - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - assertionStrings.each { String assertionString -> - assert test.contains(assertionString) - } - where: - methodBuilderName | methodBuilder | assertionStrings - "spock" | { - properties.testFramework = TestFramework.SPOCK - } | ['''assertThatRejectionReasonIsNull(parsedJson.read("\\\$.rejectionReason"))''', '''assertThatLocationIsNull(response.header("Location"))'''] - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } | ['''assertThatRejectionReasonIsNull(parsedJson.read("$.rejectionReason"))''', '''assertThatLocationIsNull(response.header("Location"))'''] - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } | ['''assertThatRejectionReasonIsNull(parsedJson.read("$.rejectionReason"))''', '''assertThatLocationIsNull(response.header("Location"))'''] - "custom" | { - properties.testMode = TestMode.CUSTOM - } | ['''assertThatRejectionReasonIsNull(parsedJson.read("$.rejectionReason"))''', '''assertThatLocationIsNull(response.header("Location"))'''] - } - - def "shouldn't generate unicode escape characters with #methodBuilderName"() { - given: - String contract = '''\ ---- -priority: 10 -request: - method: "PUT" - url: "/v1/payments/e86df6f693de4b35ae648464c5b0dc09/енев" - headers: - "Content-Type": "application/json" - body: - client: - first_name: "Пенева" - last_name: "Пенева" - matchers: - headers: - - key: 'Content-Type' - regex: 'application/json.*' - regexType: as_string - body: - - path: $.first_name - type: by_regex - value: '[\\p{L}]*' - regexType: as_string - - path: $.last_name - type: by_regex - value: '[\\p{L}]*' -response: - status: 201 - matchers: - headers: - - key: 'Content-Type' - regex: 'application/json.*' -''' - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - !test.contains("\\u041f") - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } - "custom" | { properties.testMode = TestMode.CUSTOM } - } - - @Issue('180') - def 'should generate proper test code when having multipart parameters with #methodBuilderName'() { - given: - String contract = '''\ ---- -request: - method: "PUT" - url: "/multipart" - headers: - "Content-Type": 'multipart/form-data;boundary=AaB03x' - multipart: - params: - formParameter: '"formParameterValue"' - someBooleanParameter: 'true' - named: - - paramName: "file" - fileName: 'filename.csv' - fileContent: 'file content' - contentType: 'application/json' - matchers: - headers: - - key: 'Content-Type' - regex: 'multipart/form-data;boundary=AaB03x.*' - multipart: - params: - - key: formParameter - regex: ".+" - - key: someBooleanParameter - predefined: any_boolean - named: - - paramName: file - fileName: - predefined: non_empty - fileContent: - predefined: non_empty - contentType: - predefined: non_empty -response: - status: 201 - matchers: - headers: - - key: 'Content-Type' - regex: 'application/json.*' -''' - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - for (String requestString : requestStrings) { - assert test.contains(requestString) - } - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | requestStrings - "spock" | { - properties.testFramework = TestFramework.SPOCK - } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', - """.param('formParameter', '''"formParameterValue"'''""", - """.param('someBooleanParameter', 'true')""", - """.multiPart('file', 'filename.csv', 'file content'.bytes, 'application/json')"""] - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', - '.param("formParameter", "\\"formParameterValue\\"")', - '.param("someBooleanParameter", "true")', - '.multiPart("file", "filename.csv", "file content".getBytes(), "application/json")'] - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', - '.param("formParameter", "\\"formParameterValue\\"")', - '.param("someBooleanParameter", "true")', - '.multiPart("file", "filename.csv", "file content".getBytes(), "application/json")'] - - } - - @Issue('546') - def 'should generate test code when having multipart parameters with byte array #methodBuilderName'() { - given: - String contract = '''\ ---- -request: - method: "PUT" - url: "/multipart" - headers: - "Content-Type": 'multipart/form-data;boundary=AaB03x' - multipart: - params: - formParameter: '"formParameterValue"' - someBooleanParameter: 'true' - named: - - paramName: "file" - fileName: 'filename.csv' - fileContent: "file content" - contentType: 'application/json' - matchers: - headers: - - key: 'Content-Type' - regex: 'multipart/form-data;boundary=AaB03x.*' - multipart: - params: - - key: formParameter - regex: ".+" - - key: someBooleanParameter - predefined: any_boolean - named: - - paramName: file - fileName: - predefined: non_empty - fileContent: - predefined: non_empty - contentType: - predefined: non_empty -response: - status: 201 - matchers: - headers: - - key: 'Content-Type' - regex: 'application/json.*' -''' - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - for (String requestString : requestStrings) { - assert test.contains(requestString) - } - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | requestStrings - "spock" | { - properties.testFramework = TestFramework.SPOCK - } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', - """.multiPart('file', 'filename.csv', 'file content'.bytes, 'application/json')"""] - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', - '.multiPart("file", "filename.csv", "file content".getBytes(), "application/json")'] - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', - '.multiPart("file", "filename.csv", "file content".getBytes(), "application/json")'] - - } - - @Issue('541') - def 'should generate proper test code when having multipart parameters that use execute with #methodBuilderName'() { - given: - String contract = '''\ ---- -request: - method: "PUT" - url: "/multipart" - headers: - "Content-Type": 'multipart/form-data;boundary=AaB03x' - multipart: - params: - formParameter: '"formParameterValue"' - someBooleanParameter: 'true' - named: - - paramName: "file" - fileNameCommand: 'toString()' - fileContent: 'file content' - contentType: 'application/json' - matchers: - headers: - - key: 'Content-Type' - regex: 'multipart/form-data;boundary=AaB03x.*' - multipart: - params: - - key: formParameter - regex: ".+" - regexType: as_string - - key: someBooleanParameter - predefined: any_boolean - regexType: as_boolean - named: - - paramName: file - fileName: - predefined: non_empty - fileContent: - predefined: non_empty - contentType: - predefined: non_empty -response: - status: 201 - matchers: - headers: - - key: 'Content-Type' - regex: 'application/json.*' -''' - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - for (String requestString : requestStrings) { - assert test.contains(requestString) - } - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | requestStrings - "spock" | { - properties.testFramework = TestFramework.SPOCK - } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', - """.param('formParameter', '''"formParameterValue"'''""", - """.param('someBooleanParameter', 'true')""", - """.multiPart('file', toString(), 'file content'.bytes, 'application/json')"""] - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', - '.param("formParameter", "\\"formParameterValue\\"")', - '.param("someBooleanParameter", "true")', - '.multiPart("file", toString(), "file content".getBytes(), "application/json")'] - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', - '.param("formParameter", "\\"formParameterValue\\"")', - '.param("someBooleanParameter", "true")', - '.multiPart("file", toString(), "file content".getBytes(), "application/json")'] - - } - - @Issue('#216') - def 'should parse JSON with arrays using Spock'() { - given: - String contract = '''\ ---- -request: - method: "GET" - url: "/auth/oauth/check_token" -response: - status: 200 - body: - authorities: - - ROLE_ADMIN - matchers: - body: - - path: $.authorities[0] - type: by_regex - value: '^[a-zA-Z0-9_\\- ]+$' - regexType: as_string -''' - Contract contractDsl = fromYaml(contract) - properties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('''assertThat(parsedJson.read("\\$.authorities[0]", String.class)).matches("^[a-zA-Z0-9_\\\\- ]+\\$")''') - and: - SyntaxChecker.tryToCompileWithoutCompileStatic("spock", test) - } - - @Issue('#216') - def 'should parse JSON with arrays using JUnit'() { - given: - String contract = '''\ ---- -request: - method: "GET" - url: "/auth/oauth/check_token" -response: - status: 200 - body: - authorities: - - ROLE_ADMIN - matchers: - body: - - path: $.authorities[0] - type: by_regex - value: '^[a-zA-Z0-9_\\- ]+$' -''' - Contract contractDsl = fromYaml(contract) - properties.testFramework = TestFramework.JUNIT - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('''assertThat(parsedJson.read("$.authorities[0]", String.class)).matches("^[a-zA-Z0-9_\\\\- ]+$")''') - and: - SyntaxChecker.tryToCompileJava("mockmvc", test) - } - - def 'should work with execution property with #methodBuilderName'() { - given: - String contract = '''\ ---- -request: - method: "PUT" - url: "/fraudcheck" -response: - status: 200 - body: - fraudCheckStatus: "OK" - rejectionReason: null - matchers: - body: - - path: $.rejectionReason - type: by_command - value: "assertThatRejectionReasonIsNull($it)" -''' - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - !test.contains('''assertThatJson(parsedJson).field("[\'rejectionReason']").isEqualTo("assertThatRejectionReasonIsNull("''') - test.contains('''assertThatRejectionReasonIsNull(''') - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "custom" | { properties.testMode = TestMode.CUSTOM } - } - - @Issue('262') - def "should generate proper test code with map inside list"() { - given: - String contract = '''\ ---- -request: - method: "GET" - url: "/foos" -response: - status: 200 - body: - - id: "123" - - id: "567" - headers: - "Content-Type": "application/json;charset=UTF-8" - matchers: - body: - - path: $[0].id - type: by_regex - value: "[0-9]+" - - path: $[1].id - type: by_regex - value: "[0-9]+" -''' - Contract contractDsl = fromYaml(contract) - properties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThat(parsedJson.read("\\$[0].id", String.class)).matches("[0-9]+")') - test.contains('assertThat(parsedJson.read("\\$[1].id", String.class)).matches("[0-9]+")') - and: - SyntaxChecker.tryToCompileWithoutCompileStatic("spock", test) - } - - @Issue('266') - def "should generate proper test code with top level array using #methodBuilderName"() { - given: - String contract = '''\ ---- -request: - method: "GET" - url: "/api/tags" -response: - status: 200 - body: - - "Java" - - "Java8" - - "Spring" - - "SpringBoot" - - "Stream" - headers: - "Content-Type": "application/json;charset=UTF-8" -''' - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThatJson(parsedJson).arrayField().contains("Java8").value()') - test.contains('assertThatJson(parsedJson).arrayField().contains("Spring").value()') - test.contains('assertThatJson(parsedJson).arrayField().contains("Java").value()') - test.contains('assertThatJson(parsedJson).arrayField().contains("Stream").value()') - test.contains('assertThatJson(parsedJson).arrayField().contains("SpringBoot").value()') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } - "custom" | { properties.testMode = TestMode.CUSTOM } - } - - @Issue('266') - @RestoreSystemProperties - def 'should generate proper test code with top level array using #methodBuilderName with array size check'() { - given: - String contract = '''\ ---- -request: - method: "GET" - url: "/api/tags" -response: - status: 200 - body: ["Java", "Java8", "Spring", "SpringBoot", "Stream"] - headers: - "Content-Type": "application/json;charset=UTF-8" -''' - Contract contractDsl = fromYaml(contract) - System.setProperty('spring.cloud.contract.verifier.assert.size', 'true') - - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThatJson(parsedJson).hasSize(5)') - test.contains('assertThatJson(parsedJson).arrayField().contains("Java8").value()') - test.contains('assertThatJson(parsedJson).arrayField().contains("Spring").value()') - test.contains('assertThatJson(parsedJson).arrayField().contains("Java").value()') - test.contains('assertThatJson(parsedJson).arrayField().contains("Stream").value()') - test.contains('assertThatJson(parsedJson).arrayField().contains("SpringBoot").value()') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } - "custom" | { properties.testMode = TestMode.CUSTOM } - } - - @Issue('266') - def 'should generate proper test code with top level array or arrays using #methodBuilderName'() { - given: - String contract = '''\ ---- -request: - method: "GET" - url: "/api/categories" -response: - status: 200 - body: [["Programming", "Java"], ["Programming", "Java", "Spring", "Boot"]] - headers: - "Content-Type": "application/json;charset=UTF-8" -''' - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThatJson(parsedJson).array().array().arrayField().isEqualTo("Programming").value()') - test.contains('assertThatJson(parsedJson).array().array().arrayField().isEqualTo("Java").value()') - test.contains('assertThatJson(parsedJson).array().array().arrayField().isEqualTo("Spring").value()') - test.contains('assertThatJson(parsedJson).array().array().arrayField().isEqualTo("Boot").value()') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } - "custom" | { properties.testMode = TestMode.CUSTOM } - } - - @Issue('47') - def 'should generate async body when async flag set in response'() { - given: - String contract = '''\ ---- -request: - method: "GET" - url: "test" -response: - async: true - status: 200 -''' - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains(bodyDefinitionString) - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | bodyDefinitionString - "spock" | { properties.testFramework = TestFramework.SPOCK } | '.when().async()' - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } | '.when().async()' - } - - @Issue('372') - def 'should generate async body after queryParams when async flag set in response and queryParams set in request'() { - given: - String contract = '''\ ---- -request: - method: "GET" - url: "/test" - queryParameters: - param: value -response: - async: true - status: 200 -''' - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - def strippedTest = test.replace('\n', '').replace(' ', '').replaceAll("\t", "").stripIndent().stripMargin() - then: - strippedTest.contains('.queryParam("param","value").when().async().get("/test")') - and: - stubMappingIsValidWireMockStub(contractDsl) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - } - - def 'should generate proper test code with array of primitives using #methodBuilderName'() { - given: - String contract = '''\ ---- -request: - method: "GET" - url: "/api/tags" -response: - status: 200 - body: - - partners: - payment_methods: - - BANK - - CASH -''' - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThatJson(parsedJson).array().field("[\'partners\']").array("[\'payment_methods\']").arrayField().isEqualTo("BANK").value()') - test.contains('assertThatJson(parsedJson).array().field("[\'partners\']").array("[\'payment_methods\']").arrayField().isEqualTo("CASH").value()') - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } - "custom" | { properties.testMode = TestMode.CUSTOM } - } - - @Issue('#273') - def 'should not escape dollar in Spock regex tests'() { - given: - String contract = '''\ ---- -request: - method: "GET" - url: "/get" -response: - status: 200 - body: - code: 9 - message: Wrong credentials - matchers: - body: - - path: $.message - type: by_regex - value: '^(?!\\s*$).+' -''' - Contract contractDsl = fromYaml(contract) - properties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThat(parsedJson.read("\\$.message", String.class)).matches("^(?!\\\\s*\\$).+")') - and: - SyntaxChecker.tryToCompileGroovy("spock", test, - false) - } - - @Issue('#85') - def 'should execute custom method for complex structures on the response side'() { - given: - String contract = '''\ ---- -request: - method: "GET" - url: "/get" -response: - status: 200 - body: - fraudCheckStatus: "OK" - rejectionReason: - title: null - matchers: - body: - - path: $.rejectionReason.title - type: by_command - value: "assertThatRejectionReasonIsNull($it)" -''' - Contract contractDsl = fromYaml(contract) - properties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('assertThatRejectionReasonIsNull(parsedJson.read("\\\$.rejectionReason.title"))') - SyntaxChecker.tryToCompileGroovy("spock", test) - } - - @Issue('#85') - def 'should execute custom method for more complex structures on the response side when using Spock'() { - given: - String contract = '''\ ---- -request: - method: "GET" - url: "/get" -response: - status: 200 - body: - - name: "userName 1" - - name: "userName 2" - matchers: - body: - - path: $[0].name - type: by_command - value: "assertThatUserNameIsNotNull($it)" - - path: $[1].name - type: by_command - value: "assertThatUserNameIsNotNull($it)" -''' - Contract contractDsl = fromYaml(contract) - properties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('''assertThatUserNameIsNotNull(parsedJson.read("\\$[0].name"))''') - test.contains('''assertThatUserNameIsNotNull(parsedJson.read("\\$[1].name"))''') - } - - @Issue('#85') - def 'should execute custom method for more complex structures on the response side when using JUnit'() { - given: - String contract = '''\ ---- -request: - method: "GET" - url: "/get" -response: - status: 200 - body: - - name: "userName 1" - - name: "userName 2" - matchers: - body: - - path: $[0].name - type: by_command - value: "assertThatUserNameIsNotNull($it)" - - path: $[1].name - type: by_command - value: "assertThatUserNameIsNotNull($it)" -''' - Contract contractDsl = fromYaml(contract) - properties.testFramework = TestFramework.JUNIT - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('''assertThatUserNameIsNotNull(parsedJson.read("$[0].name")''') - test.contains('''assertThatUserNameIsNotNull(parsedJson.read("$[1].name")''') - } - - @Issue('#111') - def 'should execute custom method for request headers'() { - given: - String contract = '''\ ---- -request: - method: "GET" - url: "/get" - headers: - authorization: Bearer token - matchers: - headers: - - key: "authorization" - command: "getOAuthTokenHeader()" -response: - status: 200 -''' - Contract contractDsl = fromYaml(contract) - properties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('.header("authorization", getOAuthTokenHeader())') - SyntaxChecker.tryToCompileGroovy("spock", test) - } - - @Issue('#150') - def 'should support body matching in response'() { - given: - String contract = '''\ ---- -request: - method: "GET" - url: "/get" -response: - status: 200 - body: "HELLO FROM STUB" - matchers: - body: - - type: by_regex - value: ".*" -''' - Contract contractDsl = fromYaml(contract) - properties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains("responseBody ==~ java.util.regex.Pattern.compile('.*')") - and: - SyntaxChecker.tryToCompileGroovy("spock", test) - } - - @Issue('#150') - def 'should support custom method execution in response'() { - given: - String contract = '''\ ---- -request: - method: "GET" - url: "/get" -response: - status: 200 - body: "HELLO FROM STUB" - matchers: - body: - - type: by_command - value: "foo($it)" -''' - Contract contractDsl = fromYaml(contract) - properties.testFramework = TestFramework.SPOCK - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('foo(responseBody)') - SyntaxChecker.tryToCompileGroovy("spock", test) - } - - @Issue('#162') - def 'should escape regex properly for content type'() { - given: - String contract = '''\ ---- -request: - method: "GET" - url: "/get" - headers: - "Content-Type": "application/vnd.fraud.v1+json" - matchers: - headers: - - key: 'Content-Type' - regex: 'application.vnd.fraud.v1.json.*' -response: - status: 200 - headers: - "Content-Type": "application/vnd.fraud.v1+json" - matchers: - headers: - - key: 'Content-Type' - regex: 'application.vnd.fraud.v1.json.*' -''' - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - matcher(test) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | matcher - "spock" | { - properties.testFramework = TestFramework.SPOCK - } | { String s -> 'assertThat(response.header("Content-Type")).matches("application.vnd.fraud.v1.json.*")' } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } | { String s -> "response.header('Content-Type') ==~ java.util.regex.Pattern.compile('application.vnd.fraud.v1.json.*')" } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } | { String s -> "response.header('Content-Type') ==~ java.util.regex.Pattern.compile('application.vnd.fraud.v1.json.*')" } - "custom" | { - properties.testMode = TestMode.CUSTOM - } | { String s -> "response.header('Content-Type') ==~ java.util.regex.Pattern.compile('application.vnd.fraud.v1.json.*')" } - } - - @Issue('#172') - def 'should resolve plain text properly via headers with #methodBuilderName'() { - given: - String contract = '''\ ---- -request: - method: "GET" - url: "/foo" -response: - status: 200 - body: | - {"a":1} - {"a":2} - headers: - "Content-Type": "text/plain" - matchers: - headers: - - key: 'Content-Type' - regex: 'text/plain.*' -''' - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - !test.contains('assertThatJson(parsedJson).field("[\'a\']").isEqualTo(1)') - test.contains(expectedAssertion) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - //order is inverted cause Intellij didn't parse this properly - methodBuilderName | methodBuilder | expectedAssertion - "spock" | { properties.testFramework = TestFramework.SPOCK } | """responseBody == '''{"a":1}\\n{"a":2}\\n'''""" - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}\\n''' - "webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}\\n''' - "custom" | { properties.testMode = TestMode.CUSTOM } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}\\n''' - } - - @Issue('#443') - def 'should resolve plain text that happens to be a valid json for [#methodBuilderName]'() { - given: - String contract = '''\ ---- -request: - method: "GET" - url: "/foo" -response: - status: 200 - body: 'true' - headers: - "Content-Type": "application/json;charset=utf-8" - matchers: - body: - - type: by_regex - value: 'true|false' - headers: - - key: 'Content-Type' - regex: 'application/json;charset=utf-8.*' -''' - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - testAssertion(test) - and: - SyntaxChecker.tryToCompile(methodBuilderName, test) - where: - methodBuilderName | methodBuilder | testAssertion - "spock" | { - properties.testFramework = TestFramework.SPOCK - } | { String testContents -> testContents.contains("""responseBody ==~ java.util.regex.Pattern.compile('true|false')""") } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } | { String testContents -> testContents.contains("""assertThat(responseBody).matches("true|false");""") } - "mockmvc-testng" | { - properties.testFramework = TestFramework.TESTNG; properties.testMode = TestMode.MOCKMVC - } | { String testContents -> testContents.contains("""assertThat(responseBody).matches("true|false");""") } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } | { String testContents -> testContents.contains("""responseBody ==~ java.util.regex.Pattern.compile("true|false")""") } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } | { String testContents -> testContents.contains("""assertThat(responseBody).matches("true|false");""") } - "custom" | { - properties.testMode = TestMode.CUSTOM - } | { String testContents -> testContents.contains("""assertThat(responseBody).matches("true|false");""") } - } - - @Issue('#169') - def "should escape quotes properly using [#methodBuilderName]"() { - given: - String contract = '''\ ---- -request: - method: "POST" - url: "/foo" - body: - xyz: 'abc' - headers: - "Content-Type": "application/json;charset=utf-8" -response: - status: 200 - body: '{ "bar": "some value \\u0022with quote\\u0022" }' - headers: - "Content-Type": "application/json;charset=utf-8" - matchers: - body: - - path: $.bar - type: by_regex - value: 'some value "with quote"|bar' -''' - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - test.contains('.matches("some value \\"with quote\\"|bar")') - and: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - where: - //order is inverted cause Intellij didn't parse this properly - methodBuilderName | methodBuilder | expectedAssertion - "spock" | { properties.testFramework = TestFramework.SPOCK } | '''responseBody == "{\\"a\\":1}\\n{\\"a\\":2}"''' - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}''' - "custom" | { properties.testMode = TestMode.CUSTOM } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}''' - } - - @Issue('#169') - def "should make the execute method work in a url for [#methodBuilderName]"() { - given: - Contract contractDsl = Contract.make { - request { - method 'POST' - url $(c("foo"), p(execute("toString()"))) - } - response { - status OK() - } - } - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompile(methodBuilderName, test) - and: - test.contains("toString()") - !test.contains("\"toString()\"") - !test.contains("'toString()'") - where: - methodBuilderName | methodBuilder - "spock" | { - properties.testFramework = TestFramework.SPOCK - } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } - "mockmvc-testng" | { - properties.testFramework = TestFramework.TESTNG; properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "custom" | { - properties.testMode = TestMode.CUSTOM - } - } - - @Issue('#203') - def "should create an assertion for an empty list for [#methodBuilderName]"() { - given: - String contract = '''\ ---- -request: - method: "GET" - url: "/api/v1/xxxx" -response: - status: 200 - body: - status: '200' - list: [] - foo : - - "bar" - - "baz" -''' - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompile(methodBuilderName, test) - test.contains('assertThatJson(parsedJson).array("[\'list\']").isEmpty()') - !test.contains('assertThatJson(parsedJson).array("[\'foo\']").isEmpty()') - where: - methodBuilderName | methodBuilder - "spock" | { properties.testFramework = TestFramework.SPOCK } - "mockmvc" | { properties.testMode = TestMode.MOCKMVC } - "mockmvc-testng" | { - properties.testFramework = TestFramework.TESTNG; properties.testMode = TestMode.MOCKMVC - } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } - "webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } - "custom" | { properties.testMode = TestMode.CUSTOM } - } - - @Issue('#226') - def 'should work properly when body is an integer [#methodBuilderName]'() { - given: - String contract = '''\ ---- -request: - method: "GET" - url: "/api/v1/xxxx" - body: 12000 -response: - status: 200 - body: 12000 -''' - Contract contractDsl = fromYaml(contract) - methodBuilder() - when: - String test = singleTestGenerator(contractDsl) - then: - SyntaxChecker.tryToCompile(methodBuilderName, test) - requestAssertion(test) - responseAssertion(test) - where: - methodBuilderName | methodBuilder | requestAssertion | responseAssertion - "spock" | { - properties.testFramework = TestFramework.SPOCK - } | { String body -> body.contains("body('''12000''')") } | { String body -> body.contains("responseBody == '12000'") } - "mockmvc" | { - properties.testMode = TestMode.MOCKMVC - } | { String body -> body.contains('body("12000")') } | { String body -> body.contains('assertThat(responseBody).isEqualTo("12000");') } - "mockmvc-testng" | { - properties.testFramework = TestFramework.TESTNG; properties.testMode = TestMode.MOCKMVC - } | { String body -> body.contains('body("12000")') } | { String body -> body.contains('assertThat(responseBody).isEqualTo("12000");') } - "jaxrs-spock" | { - properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT - } | { String body -> body.contains(""".build("GET", entity("12000", "text/plain"))""") } | { String body -> body.contains('responseBody == "12000"') } - "jaxrs" | { - properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT - } | { String body -> body.contains(""".build("GET", entity("12000", "text/plain"))""") } | { String body -> body.contains('assertThat(responseBody).isEqualTo("12000")') } - "webclient" | { - properties.testMode = TestMode.WEBTESTCLIENT - } | { String body -> body.contains('body("12000")') } | { String body -> body.contains('assertThat(responseBody).isEqualTo("12000");') } - "custom" | { - properties.testMode = TestMode.CUSTOM - } | { String body -> body.contains('body("12000")') } | { String body -> body.contains('assertThat(responseBody).isEqualTo("12000");') } - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/messageResponse.json b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/messageResponse.json deleted file mode 100644 index f9504caa62..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/messageResponse.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "payload": "{\"propsA\":\"valueA\",\"propsB\":\"valueB\"}" -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/DslToYamlContractConverterSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/DslToYamlContractConverterSpec.groovy deleted file mode 100644 index d521dce2e5..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/DslToYamlContractConverterSpec.groovy +++ /dev/null @@ -1,692 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.converter - - -import spock.lang.Specification - -import org.springframework.cloud.contract.spec.Contract - -/** - * @author Marcin Grzejszczak - * @author Tim Ysewyn - * @author Olga Maciaszek-Sharma - */ -class DslToYamlContractConverterSpec extends Specification { - - String xmlContractBody = ''' - -123 -abc - -abc -def -ghi - -123 -true -2017-01-01 -2017-01-01T01:23:45 - -foo -string -foo - -''' - - YamlContractConverter converter = new YamlContractConverter() - - def "should convert rest DSL without request headers to YAML"() { - given: - List contracts = [Contract.make { - request { - method 'GET' - urlPath '/get' - } - response { - status(OK()) - } - }] - when: - Collection yamlContracts = converter.convertTo(contracts) - then: - yamlContracts.size() == 1 - YamlContract yamlContract = yamlContracts.first() - yamlContract.request.method == "GET" - yamlContract.request.urlPath == "/get" - yamlContract.request.headers == null - } - - def "should convert rest DSL to YAML"() { - given: - List contracts = [Contract.make { - request { - method 'GET' - urlPath '/get' - body([ - duck : 123, - alpha : "abc", - number : 123, - aBoolean : true, - date : "2017-01-01", - dateTime : "2017-01-01T01:23:45", - time : "01:02:34", - valueWithoutAMatcher: "foo", - valueWithTypeMatch : "string", - key : [ - 'complex.key': 'foo' - ] - ]) - bodyMatchers { - jsonPath('$.duck', byRegex("[0-9]{3}")) - jsonPath('$.duck', byEquality()) - jsonPath('$.alpha', byRegex(onlyAlphaUnicode())) - jsonPath('$.alpha', byEquality()) - jsonPath('$.number', byRegex(number())) - jsonPath('$.aBoolean', byRegex(anyBoolean())) - jsonPath('$.date', byDate()) - jsonPath('$.dateTime', byTimestamp()) - jsonPath('$.time', byTime()) - jsonPath("\$.['key'].['complex.key']", byEquality()) - } - headers { - header("sample", $(c(regex('foo.*')), p('foo'))) - header("Content-Type", applicationJson()) - } - } - response { - status OK() - body([ - duck : 123, - alpha : "abc", - number : 123, - positiveInteger : 1234567890, - negativeInteger : -1234567890, - positiveDecimalNumber: 123.4567890, - negativeDecimalNumber: -123.4567890, - aBoolean : true, - date : "2017-01-01", - dateTime : "2017-01-01T01:23:45", - time : "01:02:34", - valueWithoutAMatcher : "foo", - valueWithTypeMatch : "string", - valueWithMin : [ - 1, 2, 3 - ], - valueWithMax : [ - 1, 2, 3 - ], - valueWithMinMax : [ - 1, 2, 3 - ], - valueWithMinEmpty : [], - valueWithMaxEmpty : [], - key : [ - 'complex.key': 'foo' - ], - nullValue : null - ]) - bodyMatchers { - // asserts the jsonpath value against manual regex - jsonPath('$.duck', byRegex("[0-9]{3}")) - // asserts the jsonpath value against the provided value - jsonPath('$.duck', byEquality()) - // asserts the jsonpath value against some default regex - jsonPath('$.alpha', byRegex(onlyAlphaUnicode())) - jsonPath('$.alpha', byEquality()) - jsonPath('$.number', byRegex(number())) - jsonPath('$.positiveInteger', byRegex(positiveInt())) - jsonPath('$.integer', byRegex(anInteger())) - jsonPath('$.double', byRegex(aDouble())) - jsonPath('$.aBoolean', byRegex(anyBoolean())) - // asserts vs inbuilt time related regex - jsonPath('$.date', byDate()) - jsonPath('$.dateTime', byTimestamp()) - jsonPath('$.time', byTime()) - // asserts that the resulting type is the same as in response body - jsonPath('$.valueWithTypeMatch', byType()) - jsonPath('$.valueWithMin', byType { - // results in verification of size of array (min 1) - minOccurrence(1) - }) - jsonPath('$.valueWithMax', byType { - // results in verification of size of array (max 3) - maxOccurrence(3) - }) - jsonPath('$.valueWithMinMax', byType { - // results in verification of size of array (min 1 & max 3) - minOccurrence(1) - maxOccurrence(3) - }) - jsonPath('$.valueWithMinEmpty', byType { - // results in verification of size of array (min 0) - minOccurrence(0) - }) - jsonPath('$.valueWithMaxEmpty', byType { - // results in verification of size of array (max 0) - maxOccurrence(0) - }) - // will execute a method `assertThatValueIsANumber` - jsonPath('$.duck', byCommand('assertThatValueIsANumber($it)')) - jsonPath("\$.['key'].['complex.key']", byEquality()) - jsonPath('$.nullValue', byNull()) - } - headers { - contentType(applicationJson()) - header('Some-Header', $(c('someValue'), p(regex('[a-zA-Z]{9}')))) - } - } - }] - when: - Collection yamlContracts = converter.convertTo(contracts) - then: - yamlContracts.size() == 1 - YamlContract yamlContract = yamlContracts.first() - yamlContract.request.method == "GET" - yamlContract.request.urlPath == "/get" - yamlContract.request.body == [ - duck : 123, - alpha : "abc", - number : 123, - aBoolean : true, - date : "2017-01-01", - dateTime : "2017-01-01T01:23:45", - time : "01:02:34", - valueWithoutAMatcher: "foo", - valueWithTypeMatch : "string", - key : ["complex.key": 'foo'] - ] - yamlContract.request.headers == [ - sample : 'foo', - "Content-Type": "application/json" - ] - yamlContract.request.matchers.headers == [ - new YamlContract.KeyValueMatcher( - key: "sample", regex: "foo.*", regexType: YamlContract.RegexType.as_string) - ] - yamlContract.request.matchers.body == [ - new YamlContract.BodyStubMatcher( - path: '$.duck', - type: YamlContract.StubMatcherType.by_regex, - value: "[0-9]{3}"), - new YamlContract.BodyStubMatcher( - path: '$.duck', - type: YamlContract.StubMatcherType.by_equality), - new YamlContract.BodyStubMatcher( - path: '$.alpha', - type: YamlContract.StubMatcherType.by_regex, - value: "[\\p{L}]*"), - new YamlContract.BodyStubMatcher( - path: '$.alpha', - type: YamlContract.StubMatcherType.by_equality), - new YamlContract.BodyStubMatcher( - path: '$.number', - type: YamlContract.StubMatcherType.by_regex, - value: "-?(\\d*\\.\\d+|\\d+)"), - new YamlContract.BodyStubMatcher( - path: '$.aBoolean', - type: YamlContract.StubMatcherType.by_regex, - value: "(true|false)"), - new YamlContract.BodyStubMatcher( - path: '$.date', - type: YamlContract.StubMatcherType.by_date, - value: "(\\d\\d\\d\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])"), - new YamlContract.BodyStubMatcher( - path: '$.dateTime', - type: YamlContract.StubMatcherType.by_timestamp, - value: "([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])"), - new YamlContract.BodyStubMatcher( - path: '$.time', - type: YamlContract.StubMatcherType.by_time, - value: "(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])"), - new YamlContract.BodyStubMatcher( - path: "\$.['key'].['complex.key']", - type: YamlContract.StubMatcherType.by_equality), - ] - yamlContract.response.status == 200 - yamlContract.response.body == [duck : 123, - alpha : "abc", - number : 123, - aBoolean : true, - date : "2017-01-01", - dateTime : "2017-01-01T01:23:45", - time : "01:02:34", - positiveInteger : 1234567890, - negativeInteger : -1234567890, - positiveDecimalNumber: 123.4567890, - negativeDecimalNumber: -123.4567890, - valueWithoutAMatcher : "foo", - valueWithTypeMatch : "string", - valueWithMin : [1, 2, 3], - valueWithMax : [1, 2, 3], - valueWithMinMax : [1, 2, 3], - valueWithMinEmpty : [], - valueWithMaxEmpty : [], - key : ['complex.key': 'foo'], - nullValue : null - ] - yamlContract.response.headers == [ - "Content-Type": "application/json", - "Some-Header" : "someValue" - ] - yamlContract.response.matchers.headers == [ - new YamlContract.TestHeaderMatcher( - key: "Content-Type", regex: "application/json.*", regexType: YamlContract.RegexType.as_string), - new YamlContract.TestHeaderMatcher( - key: "Some-Header", regex: "[a-zA-Z]{9}", regexType: YamlContract.RegexType.as_string) - ] - yamlContract.response.matchers.body == [ - new YamlContract.BodyTestMatcher( - path: '$.duck', - type: YamlContract.TestMatcherType.by_regex, - value: "[0-9]{3}"), - new YamlContract.BodyTestMatcher( - path: '$.duck', - type: YamlContract.TestMatcherType.by_equality), - new YamlContract.BodyTestMatcher( - path: '$.alpha', - type: YamlContract.TestMatcherType.by_regex, - value: '[\\p{L}]*'), - new YamlContract.BodyTestMatcher( - path: '$.alpha', - type: YamlContract.TestMatcherType.by_equality), - new YamlContract.BodyTestMatcher( - path: '$.number', - type: YamlContract.TestMatcherType.by_regex, - value: '-?(\\d*\\.\\d+|\\d+)'), - new YamlContract.BodyTestMatcher( - path: '$.positiveInteger', - type: YamlContract.TestMatcherType.by_regex, - value: '([1-9]\\d*)'), - new YamlContract.BodyTestMatcher( - path: '$.integer', - type: YamlContract.TestMatcherType.by_regex, - value: '-?(\\d+)'), - new YamlContract.BodyTestMatcher( - path: '$.double', - type: YamlContract.TestMatcherType.by_regex, - value: '-?(\\d*\\.\\d+)'), - new YamlContract.BodyTestMatcher( - path: '$.aBoolean', - type: YamlContract.TestMatcherType.by_regex, - value: '(true|false)'), - new YamlContract.BodyTestMatcher( - path: '$.date', - type: YamlContract.TestMatcherType.by_date, - value: '(\\d\\d\\d\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])'), - new YamlContract.BodyTestMatcher( - path: '$.dateTime', - type: YamlContract.TestMatcherType.by_timestamp, - value: '([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])'), - new YamlContract.BodyTestMatcher( - path: '$.time', - type: YamlContract.TestMatcherType.by_time, - value: '(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])'), - new YamlContract.BodyTestMatcher( - path: '$.valueWithTypeMatch', - type: YamlContract.TestMatcherType.by_type), - new YamlContract.BodyTestMatcher( - path: '$.valueWithMin', - type: YamlContract.TestMatcherType.by_type, - minOccurrence: 1), - new YamlContract.BodyTestMatcher( - path: '$.valueWithMax', - type: YamlContract.TestMatcherType.by_type, - maxOccurrence: 3), - new YamlContract.BodyTestMatcher( - path: '$.valueWithMinMax', - type: YamlContract.TestMatcherType.by_type, - minOccurrence: 1, - maxOccurrence: 3), - new YamlContract.BodyTestMatcher( - path: '$.valueWithMinEmpty', - type: YamlContract.TestMatcherType.by_type, - minOccurrence: 0), - new YamlContract.BodyTestMatcher( - path: '$.valueWithMaxEmpty', - type: YamlContract.TestMatcherType.by_type, - maxOccurrence: 0), - new YamlContract.BodyTestMatcher( - path: '$.duck', - type: YamlContract.TestMatcherType.by_command, - value: 'assertThatValueIsANumber($it)'), - new YamlContract.BodyTestMatcher( - path: "\$.['key'].['complex.key']", - type: YamlContract.TestMatcherType.by_equality), - new YamlContract.BodyTestMatcher( - path: '$.nullValue', - type: YamlContract.TestMatcherType.by_null), - ] - } - - def "should convert rest DSL with dynamic entries to YAML"() { - given: - List contracts = [Contract.make { - request { // (1) - method 'PUT' // (2) - urlPath('/fraudcheck') { - queryParameters { - parameter("foo", "bar") - parameter("foo2", $(c(equalToJson('''{"foo":"bar"}''')), p("foo3"))) - } - } - body([ // (4) - "client.id": $(regex('[0-9]{10}')), - loanAmount : 99999 - ]) - headers { // (5) - contentType('application/json') - header(authorization(), $(c('Bearer SOMETOKEN'), p(execute('authToken()')))) - } - } - response { // (6) - status OK() // (7) - body([ // (8) - fraudCheckStatus : "${value(regex("FRAUD"))}", - "rejection.reason": "Amount too high" - ]) - headers { // (9) - contentType('application/json') - } - } - }] - when: - Collection yamlContracts = converter.convertTo(contracts) - then: - yamlContracts.size() == 1 - YamlContract yamlContract = yamlContracts.first() - yamlContract.request.method == "PUT" - yamlContract.request.urlPath == "/fraudcheck" - yamlContract.request.queryParameters == [ - foo2: "foo3", - foo : "bar" - ] - yamlContract.request.body["client.id"] =~ /[0-9]{10}/ - yamlContract.request.body["loanAmount"] == 99999 - yamlContract.request.headers == [ - "Content-Type" : "application/json", - "Authorization": 'Bearer SOMETOKEN' - ] - yamlContract.request.matchers.headers == [ - new YamlContract.KeyValueMatcher( - key: "Content-Type", regex: "application/json.*", regexType: YamlContract.RegexType.as_string) - ] - yamlContract.request.matchers.body == [ - new YamlContract.BodyStubMatcher( - path: "\$.['client.id']", - type: YamlContract.StubMatcherType.by_regex, - value: "[0-9]{10}", - regexType: YamlContract.RegexType.as_string), - ] - yamlContract.request.matchers.queryParameters == [ - new YamlContract.QueryParameterMatcher(key: "foo2", type: YamlContract.MatchingType.equal_to_json, value: '''{"foo":"bar"}'''), - ] - yamlContract.response.status == 200 - yamlContract.response.body == [fraudCheckStatus : "FRAUD", - "rejection.reason": "Amount too high"] - yamlContract.response.headers == [ - "Content-Type": "application/json" - ] - yamlContract.response.matchers.headers == [ - new YamlContract.TestHeaderMatcher( - key: "Content-Type", regex: "application/json.*", regexType: YamlContract.RegexType.as_string) - ] - yamlContract.response.matchers.body == [ - new YamlContract.BodyTestMatcher( - path: "\$.['fraudCheckStatus']", - type: YamlContract.TestMatcherType.by_regex, - value: "FRAUD", - regexType: YamlContract.RegexType.as_string), - ] - } - - def "should convert rest DSL with multipart entries to YAML"() { - given: - List contracts = [Contract.make { - request { - method "PUT" - url "/multipart" - headers { - contentType('multipart/form-data;boundary=AaB03x') - } - multipart( - // key (parameter name), value (parameter value) pair - formParameter: $(c(regex('".+"')), p('"formParameterValue"')), - someBooleanParameter: $(c(regex(anyBoolean())), p('true')), - // a named parameter (e.g. with `file` name) that represents file with - // `name` and `content`. You can also call `named("fileName", "fileContent")` - file: named( - // name of the file - name: $(c(regex(nonEmpty())), p('filename.csv')), - // content of the file - content: $(c(regex(nonEmpty())), p('file content')), - // content type for the part - contentType: $(c(regex(nonEmpty())), p('application/json'))) - ) - } - response { - status OK() - } - }] - when: - Collection yamlContracts = converter.convertTo(contracts) - then: - yamlContracts.size() == 1 - YamlContract yamlContract = yamlContracts.first() - yamlContract.request.method == "PUT" - yamlContract.request.url == "/multipart" - yamlContract.request.multipart == new YamlContract.Multipart( - params: [ - formParameter : '"formParameterValue"', - someBooleanParameter: 'true', - ], - named: [new YamlContract.Named(paramName: "file", - fileName: 'filename.csv', - fileContent: 'file content', - contentType: 'application/json')] - ) - yamlContract.request.headers == [ - "Content-Type": "multipart/form-data;boundary=AaB03x" - ] - yamlContract.request.matchers.multipart.params == [ - new YamlContract.KeyValueMatcher( - key: "formParameter", - regex: '".+"', - regexType: YamlContract.RegexType.as_string - ), - new YamlContract.KeyValueMatcher( - key: "someBooleanParameter", - regex: '(true|false)', - regexType: YamlContract.RegexType.as_string - ) - ] - yamlContract.request.matchers.multipart.named == [ - new YamlContract.MultipartNamedStubMatcher( - paramName: "file", - fileName: new YamlContract.ValueMatcher( - regex: "[\\S\\s]+" - ), - fileContent: new YamlContract.ValueMatcher( - regex: "[\\S\\s]+" - ), - contentType: new YamlContract.ValueMatcher( - regex: "[\\S\\s]+" - ) - ) - ] - yamlContract.response.status == 200 - } - - def "should convert REST XML DSL to YAML"() { - given: - List contracts = [Contract.make { - request { - method 'GET' - url '/get' - headers { - contentType(applicationXml()) - } - body """ - -123 -abc - -abc -def -ghi - -123 -true -2017-01-01 -2017-01-01T01:23:45 - -foo -string -foo -""" - bodyMatchers { - xPath('/test/duck/text()', byRegex("[0-9]{3}")) - } - } - response { - status(OK()) - body """ - -123 -abc - -abc -def -ghi - -123 -true -2017-01-01 -2017-01-01T01:23:45 - -foo -string -foo -""" - bodyMatchers { - xPath('/test/duck/xxx', byNull()) - } - } - }] - when: - Collection yamlContracts = converter.convertTo(contracts) - then: - yamlContracts.size() == 1 - YamlContract yamlContract = yamlContracts.first() - yamlContract.request.method == 'GET' - yamlContract.request.url == '/get' - yamlContract.request.body.replaceAll("\n", "") - .replaceAll(' ', '') == xmlContractBody.replaceAll("\n", "") - .replaceAll(' ', '') - yamlContract.request.headers == [ - "Content-Type": "application/xml" - ] - yamlContract.request.matchers.body == [ - new YamlContract.BodyStubMatcher( - path: '/test/duck/text()', - type: YamlContract.StubMatcherType.by_regex, - value: '[0-9]{3}'), - ] - yamlContract.response.status == 200 - yamlContract.response.body.replaceAll("\n", "") - .replaceAll(' ', '') == xmlContractBody.replaceAll("\n", "") - .replaceAll(' ', '') - yamlContract.response.matchers.body == [ - new YamlContract.BodyTestMatcher( - path: '/test/duck/xxx', - type: YamlContract.TestMatcherType.by_null) - ] - } - - def "should convert rest DSL to YAML with save priority property"() { - given: - List contracts = [Contract.make { - priority (1) - name "Account creating without sign" - request { - method POST() - urlPath("/account") - headers { - contentType(applicationJson()) - header("userId", anyNonBlankString()) - header("sign", "") - } - body( - "number": anyNonBlankString(), - "currency": "USD", - "owner": "owner" - ) - } - response { - status CREATED() - headers { - contentType(applicationJson()) - } - body( - "id": anyNonBlankString(), - "number": "number", - "currency": "USD", - "owner": "owner", - "balance": 0 - ) - } - }] - when: - Collection yamlContracts = converter.convertTo(contracts) - then: - yamlContracts.size() == 1 - YamlContract yamlContract = yamlContracts.first() - yamlContract.request.method == 'POST' - yamlContract.request.urlPath == '/account' - yamlContract.request.matchers.headers == [ - new YamlContract.KeyValueMatcher( - key: "Content-Type", regex: "application/json.*", regexType: YamlContract.RegexType.as_string), - new YamlContract.KeyValueMatcher( - key: "userId", regex: "^\\s*\\S[\\S\\s]*", regexType: YamlContract.RegexType.as_string) - ] - yamlContract.request.matchers.body == [ - new YamlContract.BodyStubMatcher( - path: "\$.['number']", - type: "by_regex", - value: "^\\s*\\S[\\S\\s]*", - regexType: 'as_string' - ) - ] - yamlContract.response.status == 201 - yamlContract.response.headers == [ - "Content-Type": "application/json" - ] - yamlContract.response.matchers.headers == [ - new YamlContract.TestHeaderMatcher( - key: "Content-Type", regex: "application/json.*", regexType: YamlContract.RegexType.as_string) - ] - yamlContract.response.matchers.body == [ - new YamlContract.BodyTestMatcher( - path: "\$.['id']", - type: "by_regex", - value: "^\\s*\\S[\\S\\s]*", - regexType: "as_string" - ) - ] - yamlContract.priority == 1 - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/JavaContractConverterSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/JavaContractConverterSpec.groovy deleted file mode 100644 index 7c7f87a815..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/JavaContractConverterSpec.groovy +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.converter - -import groovy.json.JsonSlurper -import spock.lang.Issue -import spock.lang.Shared -import spock.lang.Specification - -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.spec.internal.ExecutionProperty -import org.springframework.cloud.contract.spec.internal.FromFileProperty -import org.springframework.cloud.contract.spec.internal.RegexProperty -import org.springframework.cloud.contract.spec.internal.Url -import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter -import org.springframework.cloud.contract.verifier.util.MapConverter - -import static org.springframework.cloud.contract.spec.internal.MatchingType.COMMAND -import static org.springframework.cloud.contract.spec.internal.MatchingType.NULL -import static org.springframework.cloud.contract.spec.internal.MatchingType.REGEX -/** - * @author Marcin Grzejszczak - * @author Olga Maciaszek-Sharma - */ -class JavaContractConverterSpec extends Specification { - - @Shared - URL javaRest = JavaContractConverterSpec. - getResource("/contractsToCompile/contract_rest.java") - @Shared - File javaRestFile = new File(javaRest.toURI()) - - @Shared - URL javaRestWithTags = JavaContractConverterSpec. - getResource("/contractsToCompile/contract_rest_with_tags.java") - @Shared - File javaRestWithTagsFile = new File(javaRestWithTags.toURI()) - - @Shared - URL contractBody = JavaContractConverterSpec. - getResource("/contractsToCompile/contract_rest_from_file.java") - @Shared - File contractBodyFile = new File(contractBody.toURI()) - - @Shared - URL contractBodyBytes = JavaContractConverterSpec. - getResource("/contractsToCompile/contract_rest_from_pdf.java") - @Shared - File contractBodyBytesFile = new File(contractBodyBytes.toURI()) - - @Shared - URL docs = JavaContractConverterSpec. - getResource("/contractsToCompile/contract_docs_examples.java") - @Shared - File docsFile = new File(docs.toURI()) - - def "should convert Java DSL with REST to DSL for [#contractFile]"() { - when: - Collection contracts = ContractVerifierDslConverter. - convertAsCollection(contractFile.parentFile, contractFile) - then: - Contract contract = contracts.first() - contract.description == "Some description" - contract.name == "some name" - contract.priority == 8 - contract.ignored == true - Url url = contract.request.url - url.clientValue == "/foo" - url.queryParameters.parameters[0].name == "a" - url.queryParameters.parameters[0].serverValue == "b" - url.queryParameters.parameters[1].name == "b" - url.queryParameters.parameters[1].serverValue == "c" - contract.request.method.clientValue == "PUT" - contract.request.headers.entries.find { - it.name == "foo" && - ((RegexProperty) it.clientValue).pattern() == "bar" && - it.serverValue == "bar" - } - contract.request.headers.entries.find { - it.name == "fooReq" && - it.serverValue == "baz" - } - MapConverter.getStubSideValues(contract.request.body) == [foo: "bar"] - contract.request.bodyMatchers.matchers[0].path() == '$.foo' - contract.request.bodyMatchers.matchers[0].matchingType() == REGEX - contract.request.bodyMatchers.matchers[0].value().pattern() == 'bar' - and: - contract.response.status.clientValue == 200 - contract.response.delay.clientValue == 1000 - contract.response.headers.entries.find { - it.name == "foo2" && - ((RegexProperty) it.serverValue).pattern() == "bar" && - it.clientValue == "bar" - } - contract.response.headers.entries.find { - it.name == "foo3" && - ((ExecutionProperty) it.serverValue). - insertValue('foo') == "andMeToo(foo)" - } - contract.response.headers.entries.find { - it.name == "fooRes" && - it.clientValue == "baz" - } - MapConverter.getStubSideValues( - contract.response.body) == [foo2: "bar", foo3: "baz", nullValue: null] - contract.response.bodyMatchers.matchers[0].path() == '$.foo2' - contract.response.bodyMatchers.matchers[0].matchingType() == REGEX - contract.response.bodyMatchers.matchers[0].value().pattern() == 'bar' - contract.response.bodyMatchers.matchers[1].path() == '$.foo3' - contract.response.bodyMatchers.matchers[1].matchingType() == COMMAND - contract.response.bodyMatchers.matchers[1]. - value() == new ExecutionProperty('executeMe($it)') - contract.response.bodyMatchers.matchers[2].path() == '$.nullValue' - contract.response.bodyMatchers.matchers[2].matchingType() == NULL - contract.response.bodyMatchers.matchers[2].value() == null - where: - contractFile << [javaRestFile, javaRestWithTagsFile] - } - - def "should convert java with REST with body from file"() { - when: - Collection contracts = ContractVerifierDslConverter. - convertAsCollection(contractBodyFile.parentFile, contractBodyFile) - then: - contracts.size() == 1 - Contract contract = contracts.first() - new JsonSlurper().parseText(contract.request.body.clientValue.toString()) == - new JsonSlurper().parseText('''{ "hello" : "request" }''') - and: - new JsonSlurper().parseText(contract.response.body.clientValue.toString()) == - new JsonSlurper().parseText('''{ "hello" : "response" }''') - } - - def "should convert java with REST with body as bytes"() { - when: - Collection contracts = ContractVerifierDslConverter. - convertAsCollection( - contractBodyBytesFile.parentFile, contractBodyBytesFile) - then: - contracts.size() == 1 - Contract contract = contracts.first() - contract.request.body.clientValue instanceof FromFileProperty - and: - contract.response.body.clientValue instanceof FromFileProperty - } - - def "should convert java with REST for docs"() { - when: - Collection contracts = ContractVerifierDslConverter. - convertAsCollection(docsFile.parentFile, docsFile) - then: - contracts.size() == 1 - } - - @Issue("1398") - def "should work when contract starts with 'package'"() { - given: - URL packageContract = JavaContractConverterSpec. - getResource("/contractsToCompile/package_contract.java") - File packageFile = new File(packageContract.toURI()) - when: - Collection contracts = ContractVerifierDslConverter. - convertAsCollection(packageFile.parentFile, packageFile) - - then: - contracts.size() == 1 - } - - @Issue("1398") - def "should work when 'contract starts with 'package' preceded by other text"() { - given: - URL contract = JavaContractConverterSpec. - getResource("/contractsToCompile/contract.java") - File contractFile = new File(contract.toURI()) - when: - Collection contracts = ContractVerifierDslConverter. - convertAsCollection(contractFile.parentFile, contractFile) - - then: - contracts.size() == 1 - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverterSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverterSpec.groovy deleted file mode 100644 index fcb29e51f4..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverterSpec.groovy +++ /dev/null @@ -1,1205 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.converter - -import java.util.regex.Pattern - -import groovy.json.JsonSlurper -import spock.lang.Issue -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll - -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.spec.internal.ExecutionProperty -import org.springframework.cloud.contract.spec.internal.FromFileProperty -import org.springframework.cloud.contract.spec.internal.MatchingStrategy -import org.springframework.cloud.contract.spec.internal.NamedProperty -import org.springframework.cloud.contract.spec.internal.QueryParameters -import org.springframework.cloud.contract.spec.internal.RegexPatterns -import org.springframework.cloud.contract.spec.internal.Url -import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter -import org.springframework.cloud.contract.verifier.util.MapConverter - -import static org.springframework.cloud.contract.spec.internal.MatchingType.COMMAND -import static org.springframework.cloud.contract.spec.internal.MatchingType.DATE -import static org.springframework.cloud.contract.spec.internal.MatchingType.EQUALITY -import static org.springframework.cloud.contract.spec.internal.MatchingType.NULL -import static org.springframework.cloud.contract.spec.internal.MatchingType.REGEX -import static org.springframework.cloud.contract.spec.internal.MatchingType.TIME -import static org.springframework.cloud.contract.spec.internal.MatchingType.TIMESTAMP -import static org.springframework.cloud.contract.spec.internal.MatchingType.TYPE - -/** - * @author Marcin Grzejszczak - * @author Tim Ysewyn - * @author Olga Maciaszek-Sharma - */ -class YamlContractConverterSpec extends Specification { - - @Shared - URL ymlUrl = YamlContractConverterSpec.getResource("/yml/contract.yml") - @Shared - File ymlWithRest = new File(ymlUrl.toURI()) - @Shared - URL ymlUrl2 = YamlContractConverterSpec.getResource("/yml/contract_rest.yml") - @Shared - File ymlWithRest2 = new File(ymlUrl2.toURI()) - @Shared - URL ymlUrl3 = YamlContractConverterSpec.getResource("/yml/contract_rest_with_path.yml") - @Shared - File ymlWithRest3 = new File(ymlUrl3.toURI()) - URL ymlMsgUrl = YamlContractConverterSpec.getResource("/yml/contract_message.yml") - URL ymlMsgMethodUrl = YamlContractConverterSpec.getResource("/yml/contract_message_method.yml") - File ymlMessagingMethod = new File(ymlMsgMethodUrl.toURI()) - URL ymlBodyFile = YamlContractConverterSpec.getResource("/yml/contract_from_file.yml") - File ymlBody = new File(ymlBodyFile.toURI()) - URL ymlReferenceFile = YamlContractConverterSpec.getResource("/yml/contract_reference_request.yml") - File ymlReference = new File(ymlReferenceFile.toURI()) - URL ymlMultipleFile = YamlContractConverterSpec.getResource("/yml/multiple_contracts.yml") - File ymlMultiple = new File(ymlMultipleFile.toURI()) - URL ymlMessagingMatchersFile = YamlContractConverterSpec.getResource("/yml/contract_message_matchers.yml") - File ymlMessagingMatchers = new File(ymlMessagingMatchersFile.toURI()) - URL ymlCookiesUrl = YamlContractConverterSpec.getResource("/yml/contract_cookies.yml") - File ymlCookies = new File(ymlCookiesUrl.toURI()) - URL ymlBytesUrl = YamlContractConverterSpec.getResource("/yml/contract_pdf.yml") - File ymlBytes = new File(ymlBytesUrl.toURI()) - URL groovyBytesUrl = YamlContractConverterSpec.getResource("/body_builder/worksWithPdf.groovy") - File groovyBytes = new File(groovyBytesUrl.toURI()) - URL ymlMessagingBytesUrl = YamlContractConverterSpec.getResource("/yml/contract_messaging_pdf.yml") - File ymlMessagingBytes = new File(ymlMessagingBytesUrl.toURI()) - URL ymlRestXmlFile = YamlContractConverterSpec. - getResource("/yml/contract_rest_xml.yml") - File ymlRestXml = new File(ymlRestXmlFile.toURI()) - URL ymlRestNamedXmlFile = YamlContractConverterSpec. - getResource("/yml/contract_rest_named_xml.yml") - File ymlRestNamedXml = new File(ymlRestNamedXmlFile.toURI()) - URL oa3SpecUrl = YamlContractConverterSpec.getResource('/yml/oa3/openapi_petstore.yml') - File oa3File = new File(oa3SpecUrl.toURI()) - YamlContractConverter converter = new YamlContractConverter() - String xmlContractBody = ''' - -123 -abc - -abc -def -ghi - -123 -true -2017-01-01 -2017-01-01T01:23:45 - -foo -string -foo - -''' - String xmlContractBodyWithNamespaces = ''' - -customer@test.com - -''' - - def "should convert YAML with Cookies to DSL"() { - given: - assert converter.isAccepted(ymlCookies) - when: - Collection contracts = converter.convertFrom(ymlCookies) - then: - contracts.size() == 1 - Contract contract = contracts.first() - contract.description == "Contract with cookies" - contract.name == "cookies-contract" - contract.priority == 1 - contract.ignored == true - contract.request.method.clientValue == "PUT" - contract.request.url.clientValue == "/foo" - contract.request.cookies.entries.find { it.key == "foo" && it.serverValue == "bar" } - contract.request.cookies.entries.find { - it.key == "fooRegex" && ((Pattern) it.clientValue).pattern() == "reg" && it.serverValue == "reg" - } - contract.request.cookies.entries.find { - it.key == "fooPredefinedRegex" && ((Pattern) it.clientValue).pattern() == "(true|false)" && it.serverValue == true - } - and: - contract.response.status.clientValue == 200 - contract.response.cookies.entries.find { it.key == "foo" && it.clientValue == "baz" } - contract.response.cookies.entries.find { - it.key == "fooRegex" && ((Pattern) it.serverValue).pattern() == "[0-9]+" && it.clientValue == 123 - } - contract.response.cookies.entries.find { - it.key == "source" && ((Pattern) it.serverValue).pattern() == "ip_address" && it.clientValue == "ip_address" - } - contract.response.cookies.entries.find { - it.key == "fooPredefinedRegex" && ((Pattern) it.serverValue).pattern() == "(true|false)" && it.clientValue == true - } - MapConverter.getStubSideValues(contract.response.body) == ["status": "OK"] - } - - def "should convert YAML with REST to DSL for [#yamlFile]"() { - given: - assert converter.isAccepted(yamlFile) - when: - Collection contracts = converter.convertFrom(yamlFile) - then: - contracts.size() == 1 - Contract contract = contracts.first() - contract.description == "Some description" - contract.name == "some name" - contract.priority == 8 - contract.ignored == true - Url url = yamlFile == ymlWithRest3 ? - contract.request.urlPath : contract.request.url - url.clientValue == "/foo" - url.queryParameters.parameters[0].name == "a" - url.queryParameters.parameters[0].serverValue == "b" - url.queryParameters.parameters[1].name == "b" - url.queryParameters.parameters[1].serverValue == "c" - contract.request.method.clientValue == "PUT" - contract.request.headers.entries.find { - it.name == "foo" && - ((Pattern) it.clientValue).pattern() == "bar" && it.serverValue == "bar" - } - contract.request.headers.entries.find { - it.name == "fooReq" && - it.serverValue == "baz" - } - MapConverter.getStubSideValues(contract.request.body) == [foo: "bar"] - contract.request.bodyMatchers.matchers[0].path() == '$.foo' - contract.request.bodyMatchers.matchers[0].matchingType() == REGEX - contract.request.bodyMatchers.matchers[0].value().pattern() == 'bar' - and: - contract.response.status.clientValue == 200 - if (yamlFile == ymlWithRest) { - contract.response.delay.clientValue == 1000 - } - else { - !contract.response.delay - } - contract.response.headers.entries.find { - it.name == "foo2" && - ((Pattern) it.serverValue).pattern() == "bar" && it.clientValue == "bar" - } - contract.response.headers.entries.find { - it.name == "foo3" && - ((ExecutionProperty) it.serverValue).insertValue('foo') == "andMeToo(foo)" - } - contract.response.headers.entries.find { - it.name == "fooRes" && - it.clientValue == "baz" - } - MapConverter.getStubSideValues(contract.response.body) == [foo2: "bar", foo3: "baz", nullValue: null] - contract.response.bodyMatchers.matchers[0].path() == '$.foo2' - contract.response.bodyMatchers.matchers[0].matchingType() == REGEX - contract.response.bodyMatchers.matchers[0].value().pattern() == 'bar' - contract.response.bodyMatchers.matchers[1].path() == '$.foo3' - contract.response.bodyMatchers.matchers[1].matchingType() == COMMAND - contract.response.bodyMatchers.matchers[1].value() == new ExecutionProperty('executeMe($it)') - contract.response.bodyMatchers.matchers[2].path() == '$.nullValue' - contract.response.bodyMatchers.matchers[2].matchingType() == NULL - contract.response.bodyMatchers.matchers[2].value() == null - where: - yamlFile << [ymlWithRest, ymlWithRest2, ymlWithRest3] - } - - def "should convert YAML with REST to DSL with advanced request referencing"() { - given: - assert converter.isAccepted(ymlReference) - when: - Collection contracts = converter.convertFrom(ymlReference) - then: - contracts.size() == 1 - Contract contract = contracts.first() - Url url = contract.request.url - url.clientValue == "/api/v1/xxxx" - url.queryParameters.parameters[0].name == "foo" - url.queryParameters.parameters[0].serverValue == "bar" - url.queryParameters.parameters[1].name == "foo" - url.queryParameters.parameters[1].serverValue == "bar2" - contract.request.method.clientValue == "GET" - contract.request.headers.entries.findAll { it.name == "Authorization" } - .collect { it.clientValue }.flatten() == ["secret", "secret2"] - MapConverter.getStubSideValues(contract.request.body) == [foo: "bar", baz: 5] - and: - contract.response.status.clientValue == 200 - contract.response.headers.entries - .find { it.name == "Authorization" }.clientValue == '''foo {{{ request.headers.Authorization.0 }}} bar''' - with(MapConverter.getTestSideValues(contract.response.body)) { - it.url == "{{{ request.url }}}" - it.path == "{{{ request.path }}}" - it.pathIndex == "{{{ request.path.1 }}}" - it.param == "{{{ request.query.foo }}}" - it.paramIndex == "{{{ request.query.foo.1 }}}" - it.authorization == "{{{ request.headers.Authorization.0 }}}" - it.authorization2 == "{{{ request.headers.Authorization.1 }}" - it.fullBody == "{{{ request.body }}}" - it.responseFoo == '''{{{ jsonpath this '$.foo' }}}''' - it.responseBaz == '''{{{ jsonpath this '$.baz' }}}''' - it.responseBaz2 == '''Bla bla {{{ jsonpath this '$.foo' }}} bla bla''' - } - } - - @Issue('#1778') - @Unroll - def 'should convert YAML with REST matchers and path property #urlPropertyName to DSL'() { - given: - File ymlMatchers = File.createTempFile('contract_matchers', '.yml').with { - write YamlContractConverterSpec.getResource('/yml/contract_matchers.yml') - .text - .replace('\n urlPath:', "\n $urlPropertyName:") - it - } - expect: - converter.isAccepted(ymlMatchers) - when: - Collection contracts = converter.convertFrom(ymlMatchers) - then: - contracts.size() == 1 - Contract contract = contracts.first() - contract.request.headers.entries.find { - it.name == "Content-Type" && - ((Pattern) it.clientValue).pattern() == "application/json.*" && it.serverValue == "application/json" - } - def url = contract.request."$urlPropertyName" - ((Pattern) url.clientValue).pattern() == "/get/[0-9]" - url.serverValue == "/get/1" - url.queryParameters.parameters.size() == 8 - QueryParameters queryParameters = url.queryParameters - assertQueryParam(queryParameters, "limit", 10, - MatchingStrategy.Type.EQUAL_TO, 20) - assertQueryParam(queryParameters, "offset", 20, - MatchingStrategy.Type.CONTAINS, 20) - assertQueryParam(queryParameters, "sort", "name", - MatchingStrategy.Type.EQUAL_TO, "name") - assertQueryParam(queryParameters, "search", 55, - MatchingStrategy.Type.NOT_MATCHING, (~/^[0-9]{2}$/).pattern()) - assertQueryParam(queryParameters, "age", 99, - MatchingStrategy.Type.NOT_MATCHING, "^\\\\w*\$") - assertQueryParam(queryParameters, "name", "John.Doe", - MatchingStrategy.Type.MATCHING, "John.*") - assertQueryParam(queryParameters, "hello", true, - MatchingStrategy.Type.ABSENT, null) - contract.request.bodyMatchers.matchers[0].path() == '$.duck' - contract.request.bodyMatchers.matchers[0].matchingType() == REGEX - contract.request.bodyMatchers.matchers[0].value().pattern() == '[0-9]{3}' - contract.request.bodyMatchers.matchers[1].path() == '$.duck' - contract.request.bodyMatchers.matchers[1].matchingType() == EQUALITY - contract.request.bodyMatchers.matchers[2].path() == '$.alpha' - contract.request.bodyMatchers.matchers[2].matchingType() == REGEX - contract.request.bodyMatchers.matchers[2].value().pattern() == RegexPatterns.onlyAlphaUnicode().pattern() - contract.request.bodyMatchers.matchers[3].path() == '$.alpha' - contract.request.bodyMatchers.matchers[3].matchingType() == EQUALITY - contract.request.bodyMatchers.matchers[4].path() == '$.number' - contract.request.bodyMatchers.matchers[4].matchingType() == REGEX - contract.request.bodyMatchers.matchers[4].value().pattern() == RegexPatterns.number().pattern() - contract.request.bodyMatchers.matchers[5].path() == '$.aBoolean' - contract.request.bodyMatchers.matchers[5].matchingType() == REGEX - contract.request.bodyMatchers.matchers[5].value().pattern() == RegexPatterns.anyBoolean().pattern() - contract.request.bodyMatchers.matchers[6].path() == '$.date' - contract.request.bodyMatchers.matchers[6].matchingType() == DATE - contract.request.bodyMatchers.matchers[6].value().pattern() == RegexPatterns.isoDate().pattern() - contract.request.bodyMatchers.matchers[7].path() == '$.dateTime' - contract.request.bodyMatchers.matchers[7].matchingType() == TIMESTAMP - contract.request.bodyMatchers.matchers[7].value().pattern() == RegexPatterns.isoDateTime().pattern() - contract.request.bodyMatchers.matchers[8].path() == '$.time' - contract.request.bodyMatchers.matchers[8].matchingType() == TIME - contract.request.bodyMatchers.matchers[8].value().pattern() == RegexPatterns.isoTime().pattern() - contract.request.bodyMatchers.matchers[9].path() == "\$.['key'].['complex.key']" - contract.request.bodyMatchers.matchers[9].matchingType() == EQUALITY - contract.request.bodyMatchers.matchers[10].path() == '$.valueWithMin' - contract.request.bodyMatchers.matchers[10].matchingType() == TYPE - contract.request.bodyMatchers.matchers[10].minTypeOccurrence() == 1 - contract.request.bodyMatchers.matchers[11].path() == '$.valueWithMax' - contract.request.bodyMatchers.matchers[11].matchingType() == TYPE - contract.request.bodyMatchers.matchers[11].maxTypeOccurrence() == 3 - contract.request.bodyMatchers.matchers[12].path() == '$.valueWithMinMax' - contract.request.bodyMatchers.matchers[12].matchingType() == TYPE - contract.request.bodyMatchers.matchers[12].minTypeOccurrence() == 1 - contract.request.bodyMatchers.matchers[12].maxTypeOccurrence() == 3 - contract.request.cookies.entries.find { it.key == "foo" }.clientValue instanceof Pattern - contract.request.cookies.entries.find { - it.key == "bar" - }.serverValue == new ExecutionProperty('equals($it)') - and: - contract.response.status.clientValue == 200 - contract.response.bodyMatchers.matchers[0].path() == '$.duck' - contract.response.bodyMatchers.matchers[0].matchingType() == REGEX - contract.response.bodyMatchers.matchers[0].value().pattern() == '[0-9]{3}' - contract.response.bodyMatchers.matchers[1].path() == '$.duck' - contract.response.bodyMatchers.matchers[1].matchingType() == EQUALITY - contract.response.bodyMatchers.matchers[2].path() == '$.alpha' - contract.response.bodyMatchers.matchers[2].matchingType() == REGEX - contract.response.bodyMatchers.matchers[2].value().pattern() == RegexPatterns.onlyAlphaUnicode().pattern() - contract.response.bodyMatchers.matchers[3].path() == '$.alpha' - contract.response.bodyMatchers.matchers[3].matchingType() == EQUALITY - contract.response.bodyMatchers.matchers[4].path() == '$.number' - contract.response.bodyMatchers.matchers[4].matchingType() == REGEX - contract.response.bodyMatchers.matchers[4].value().pattern() == RegexPatterns.number().pattern() - contract.response.bodyMatchers.matchers[5].path() == '$.aBoolean' - contract.response.bodyMatchers.matchers[5].matchingType() == REGEX - contract.response.bodyMatchers.matchers[5].value().pattern() == RegexPatterns.anyBoolean().pattern() - contract.response.bodyMatchers.matchers[6].path() == '$.date' - contract.response.bodyMatchers.matchers[6].matchingType() == DATE - contract.response.bodyMatchers.matchers[6].value().pattern() == RegexPatterns.isoDate().pattern() - contract.response.bodyMatchers.matchers[7].path() == '$.dateTime' - contract.response.bodyMatchers.matchers[7].matchingType() == TIMESTAMP - contract.response.bodyMatchers.matchers[7].value().pattern() == RegexPatterns.isoDateTime().pattern() - contract.response.bodyMatchers.matchers[8].path() == '$.time' - contract.response.bodyMatchers.matchers[8].matchingType() == TIME - contract.response.bodyMatchers.matchers[8].value().pattern() == RegexPatterns.isoTime().pattern() - contract.response.bodyMatchers.matchers[9].path() == '$.valueWithTypeMatch' - contract.response.bodyMatchers.matchers[9].matchingType() == TYPE - contract.response.bodyMatchers.matchers[10].path() == '$.valueWithMin' - contract.response.bodyMatchers.matchers[10].matchingType() == TYPE - contract.response.bodyMatchers.matchers[10].minTypeOccurrence() == 1 - contract.response.bodyMatchers.matchers[11].path() == '$.valueWithMax' - contract.response.bodyMatchers.matchers[11].matchingType() == TYPE - contract.response.bodyMatchers.matchers[11].maxTypeOccurrence() == 3 - contract.response.bodyMatchers.matchers[12].path() == '$.valueWithMinMax' - contract.response.bodyMatchers.matchers[12].matchingType() == TYPE - contract.response.bodyMatchers.matchers[12].minTypeOccurrence() == 1 - contract.response.bodyMatchers.matchers[12].maxTypeOccurrence() == 3 - contract.response.bodyMatchers.matchers[13].path() == '$.valueWithMinEmpty' - contract.response.bodyMatchers.matchers[13].matchingType() == TYPE - contract.response.bodyMatchers.matchers[13].minTypeOccurrence() == 0 - contract.response.bodyMatchers.matchers[14].path() == '$.valueWithMaxEmpty' - contract.response.bodyMatchers.matchers[14].matchingType() == TYPE - contract.response.bodyMatchers.matchers[14].maxTypeOccurrence() == 0 - contract.response.bodyMatchers.matchers[15].path() == '$.duck' - contract.response.bodyMatchers.matchers[15].matchingType() == COMMAND - contract.response.bodyMatchers.matchers[15].value() == new ExecutionProperty('assertThatValueIsANumber($it)') - - where: - urlPropertyName << ['url', 'urlPath'] - } - - @Issue('#1921') - def 'should convert YAML to Contract and back to YAML without losing url information'() { - given: - File ymlMatchers = File.createTempFile('contract_matchers_url', '.yml').with { - write YamlContractConverterSpec.getResource('/yml/contract_matchers_url.yml') - .text - return it - } - expect: - converter.isAccepted(ymlMatchers) - when: - Collection contracts = converter.convertFrom(ymlMatchers) - List convertedBack = converter.convertTo(contracts) - then: - convertedBack.size() == 1 - convertedBack[0].request.matchers.url.regex == "/get/[0-9]" - } - - @Issue('#1921') - def 'should convert YAML to Contract and back to YAML without exceptions'() { - given: - File ymlMatchers = File.createTempFile('contract_matchers', '.yml').with { - write YamlContractConverterSpec.getResource('/yml/contract_matchers.yml') - .text - return it - } - expect: - converter.isAccepted(ymlMatchers) - when: - Collection contracts = converter.convertFrom(ymlMatchers) - List convertedBack = converter.convertTo(contracts) - then: - convertedBack.size() == 1 - } - - protected Object assertQueryParam(QueryParameters queryParameters, String queryParamName, Object serverValue, - MatchingStrategy.Type clientType, Object clientValue) { - if (clientType == MatchingStrategy.Type.ABSENT) { - return !queryParameters.parameters.find { it.name == queryParamName } - } - return queryParameters.parameters.find { - it.name == queryParamName && - it.serverValue == serverValue && - ((MatchingStrategy) it.clientValue).type == clientType && - ((MatchingStrategy) it.clientValue).clientValue == clientValue - } - } - - @Issue("#604") - def "should convert YAML with Message matchers to DSL"() { - given: - assert converter.isAccepted(ymlMessagingMatchers) - when: - Collection contracts = converter.convertFrom(ymlMessagingMatchers) - then: - contracts.size() == 1 - Contract contract = contracts[0] - and: - contract.outputMessage.bodyMatchers.matchers[0].path() == '$.duck' - contract.outputMessage.bodyMatchers.matchers[0].matchingType() == REGEX - contract.outputMessage.bodyMatchers.matchers[0].value().pattern() == '[0-9]{3}' - contract.outputMessage.bodyMatchers.matchers[1].path() == '$.duck' - contract.outputMessage.bodyMatchers.matchers[1].matchingType() == EQUALITY - contract.outputMessage.bodyMatchers.matchers[2].path() == '$.alpha' - contract.outputMessage.bodyMatchers.matchers[2].matchingType() == REGEX - contract.outputMessage.bodyMatchers.matchers[2].value().pattern() == RegexPatterns.onlyAlphaUnicode().pattern() - contract.outputMessage.bodyMatchers.matchers[3].path() == '$.alpha' - contract.outputMessage.bodyMatchers.matchers[3].matchingType() == EQUALITY - contract.outputMessage.bodyMatchers.matchers[4].path() == '$.number' - contract.outputMessage.bodyMatchers.matchers[4].matchingType() == REGEX - contract.outputMessage.bodyMatchers.matchers[4].value().pattern() == RegexPatterns.number().pattern() - contract.outputMessage.bodyMatchers.matchers[5].path() == '$.aBoolean' - contract.outputMessage.bodyMatchers.matchers[5].matchingType() == REGEX - contract.outputMessage.bodyMatchers.matchers[5].value().pattern() == RegexPatterns.anyBoolean().pattern() - contract.outputMessage.bodyMatchers.matchers[6].path() == '$.date' - contract.outputMessage.bodyMatchers.matchers[6].matchingType() == DATE - contract.outputMessage.bodyMatchers.matchers[6].value().pattern() == RegexPatterns.isoDate().pattern() - contract.outputMessage.bodyMatchers.matchers[7].path() == '$.dateTime' - contract.outputMessage.bodyMatchers.matchers[7].matchingType() == TIMESTAMP - contract.outputMessage.bodyMatchers.matchers[7].value().pattern() == RegexPatterns.isoDateTime().pattern() - contract.outputMessage.bodyMatchers.matchers[8].path() == '$.time' - contract.outputMessage.bodyMatchers.matchers[8].matchingType() == TIME - contract.outputMessage.bodyMatchers.matchers[8].value().pattern() == RegexPatterns.isoTime().pattern() - contract.outputMessage.bodyMatchers.matchers[9].path() == '$.valueWithTypeMatch' - contract.outputMessage.bodyMatchers.matchers[9].matchingType() == TYPE - contract.outputMessage.bodyMatchers.matchers[10].path() == '$.valueWithMin' - contract.outputMessage.bodyMatchers.matchers[10].matchingType() == TYPE - contract.outputMessage.bodyMatchers.matchers[10].minTypeOccurrence() == 1 - contract.outputMessage.bodyMatchers.matchers[11].path() == '$.valueWithMax' - contract.outputMessage.bodyMatchers.matchers[11].matchingType() == TYPE - contract.outputMessage.bodyMatchers.matchers[11].maxTypeOccurrence() == 3 - contract.outputMessage.bodyMatchers.matchers[12].path() == '$.valueWithMinMax' - contract.outputMessage.bodyMatchers.matchers[12].matchingType() == TYPE - contract.outputMessage.bodyMatchers.matchers[12].minTypeOccurrence() == 1 - contract.outputMessage.bodyMatchers.matchers[12].maxTypeOccurrence() == 3 - contract.outputMessage.bodyMatchers.matchers[13].path() == '$.valueWithMinEmpty' - contract.outputMessage.bodyMatchers.matchers[13].matchingType() == TYPE - contract.outputMessage.bodyMatchers.matchers[13].minTypeOccurrence() == 0 - contract.outputMessage.bodyMatchers.matchers[14].path() == '$.valueWithMaxEmpty' - contract.outputMessage.bodyMatchers.matchers[14].matchingType() == TYPE - contract.outputMessage.bodyMatchers.matchers[14].maxTypeOccurrence() == 0 - contract.outputMessage.bodyMatchers.matchers[15].path() == '$.duck' - contract.outputMessage.bodyMatchers.matchers[15].matchingType() == COMMAND - contract.outputMessage.bodyMatchers.matchers[15].value() == new ExecutionProperty('assertThatValueIsANumber($it)') - } - - def "should convert YAML with REST with response from request"() { - given: - assert converter.isAccepted(ymlBody) - when: - Collection contracts = converter.convertFrom(ymlBody) - then: - contracts.size() == 1 - Contract contract = contracts.first() - new JsonSlurper().parseText(contract.request.body.clientValue.toString()) == - new JsonSlurper().parseText('''{ "hello" : "request" }''') - and: - new JsonSlurper().parseText(contract.response.body.clientValue.toString()) == - new JsonSlurper().parseText('''{ "hello" : "response" }''') - } - - def "should convert YAML with REST with multipart"() { - given: - URL ymlUrl = YamlContractConverterSpec.getResource("/yml/contract_multipart.yml") - File yml = new File(ymlUrl.toURI()) - and: - assert converter.isAccepted(yml) - when: - Collection contracts = converter.convertFrom(yml) - then: - contracts.size() == 1 - Contract contract = contracts.first() - def stubSide = MapConverter.getStubSideValues(contract.request.multipart) - stubSide.formParameter.pattern() == ".+" - stubSide.someBooleanParameter.pattern() == RegexPatterns.anyBoolean().pattern() - def testSide = MapConverter.getTestSideValues(contract.request.multipart) - testSide.formParameter == '"formParameterValue"' - testSide.someBooleanParameter == "true" - ((NamedProperty) testSide.file).name.serverValue == "filename.csv" - ((NamedProperty) testSide.file).name.clientValue.pattern() == RegexPatterns.nonEmpty().pattern() - ((NamedProperty) testSide.file).value.serverValue == "file content" - ((NamedProperty) testSide.file).value.clientValue.pattern() == RegexPatterns.nonEmpty().pattern() - and: - contract.response.status.serverValue == 200 - } - - - def "should convert YAML with messaging triggered by a method to DSL"() { - given: - assert converter.isAccepted(ymlMessagingMethod) - when: - Collection contracts = converter.convertFrom(ymlMessagingMethod) - then: - contracts.size() == 1 - Contract contract = contracts.first() - contract.description == "Some description" - contract.label == "some_label" - contract.input.triggeredBy.toString() == "bookReturnedTriggered()" - and: - contract.outputMessage.sentTo.clientValue == "output" - contract.outputMessage.headers.entries.find { - it.name == "BOOK-NAME" && it.clientValue == "foo" - } - contract.outputMessage.body.clientValue == [bookName: "foo"] - } - - def "should convert YAML with HTTP binary body to DSL"() { - given: - assert converter.isAccepted(ymlBytes) - when: - Collection contracts = converter.convertFrom(ymlBytes) - then: - contracts.size() == 1 - Contract contract = contracts.first() - contract.request.body.clientValue instanceof FromFileProperty - ((FromFileProperty) contract.request.body.clientValue).type == byte[] - and: - contract.response.body.clientValue instanceof FromFileProperty - ((FromFileProperty) contract.response.body.clientValue).type == byte[] - } - - def "should convert YAML with messaging binary body to DSL"() { - given: - assert converter.isAccepted(ymlMessagingBytes) - when: - Collection contracts = converter.convertFrom(ymlMessagingBytes) - then: - contracts.size() == 1 - Contract contract = contracts.first() - and: - contract.outputMessage.body.clientValue instanceof FromFileProperty - ((FromFileProperty) contract.outputMessage.body.clientValue).type == byte[] - } - - def "should assert request headers when converting YAML to DSL"() { - given: - File yml = new File(YamlContractConverterSpec.getResource("/yml/contract_broken_request_headers.yml").toURI()) - and: - assert !converter.isAccepted(yml) //expecting to fail - when: - converter.convertFrom(yml) - then: - IllegalStateException e = thrown(IllegalStateException) - e.message.contains("Broken headers! A header with key [foo] with value [bar] is not matched by regex [barrrr]") - } - - def "should assert response headers when converting YAML to DSL"() { - given: - File yml = new File(YamlContractConverterSpec.getResource("/yml/contract_broken_response_headers.yml").toURI()) - and: - assert !converter.isAccepted(yml) //expecting to fail - when: - converter.convertFrom(yml) - then: - IllegalStateException e = thrown(IllegalStateException) - e.message.contains("Broken headers! A header with key [foo2] with value [bar] is not matched by regex [barrrr]") - } - - def "should parse multiple documents into a list of contracts"() { - given: - assert converter.isAccepted(ymlMultiple) - when: - Collection contracts = converter.convertFrom(ymlMultiple) - then: - contracts.size() == 3 - and: - contracts.first().request.url.clientValue == "/users/1" - contracts.last().request.url.clientValue == "/users/3" - and: - contracts.groupBy { it.name }.keySet().size() == 3 - } - - def "should dump yml as string"() { - given: - String expectedYaml1 = '''\ ---- -request: - method: "POST" - url: "/users/1" - urlPath: null - queryParameters: {} - headers: {} - cookies: {} - body: null - bodyFromFile: null - bodyFromFileAsBytes: null - matchers: - url: null - body: [] - headers: [] - queryParameters: [] - cookies: [] - multipart: null - multipart: null -response: - status: 200 - headers: {} - cookies: {} - body: null - bodyFromFile: null - bodyFromFileAsBytes: null - matchers: - body: [] - headers: [] - cookies: [] - async: null - fixedDelayMilliseconds: null -input: null -outputMessage: null -description: null -label: null -name: "post1" -priority: null -ignored: false -inProgress: false -metadata: {} -''' - String expectedYaml2 = '''\ ---- -request: - method: "POST" - url: "/users/2" - urlPath: null - queryParameters: {} - headers: {} - cookies: {} - body: null - bodyFromFile: null - bodyFromFileAsBytes: null - matchers: - url: null - body: [] - headers: [] - queryParameters: [] - cookies: [] - multipart: null - multipart: null -response: - status: 200 - headers: {} - cookies: {} - body: null - bodyFromFile: null - bodyFromFileAsBytes: null - matchers: - body: [] - headers: [] - cookies: [] - async: null - fixedDelayMilliseconds: null -input: null -outputMessage: null -description: null -label: null -name: "post2" -priority: null -ignored: false -inProgress: false -metadata: {} -''' - when: - Map strings = converter.store(yamlContracts()) - then: - strings.size() == 2 - new String(strings["post1.yml"]).trim() == expectedYaml1.trim() - new String(strings["post2.yml"]).trim() == expectedYaml2.trim() - } - - private List yamlContracts() { - return [ - new YamlContract( - name: "post1", - request: new YamlContract.Request(method: "POST", url: "/users/1"), - response: new YamlContract.Response(status: 200) - ), new YamlContract( - name: "post2", - request: new YamlContract.Request(method: "POST", url: "/users/2"), - response: new YamlContract.Response(status: 200) - )] - } - - def "should parse messaging contract for messaging scenario 1"() { - given: - URI uri = YamlContractConverterSpec.getResource("/yml/contract_message_scenario1.yml").toURI() - File file = new File(uri) - assert converter.isAccepted(file) - when: - Collection contracts = converter.convertFrom(file) - then: - contracts.size() == 1 - and: - contracts.first().input != null || contracts.first().outputMessage != null - } - - def "should convert HTTP DSL to YAML"() { - given: - assert converter.isAccepted(ymlWithRest) - and: - List contracts = [Contract.make { - request { - inProgress() - url("/foo") - method("PUT") - headers { - header("foo", "bar") - } - cookies { - cookie(foo: value(c("client"), p("server"))) - cookie("bar", value(c("client"), p("server"))) - } - body([foo: "bar"]) - } - response { - fixedDelayMilliseconds 1000 - status(200) - headers { - header("foo2", "bar") - } - cookies { - cookie(foo: value(c("client"), p("server"))) - cookie("bar", value(c("client"), p("server"))) - } - body([foo2: "bar"]) - } - }] - when: - Collection yamlContracts = converter.convertTo(contracts) - then: - yamlContracts.size() == 1 - YamlContract yamlContract = yamlContracts.first() - yamlContract.inProgress == true - yamlContract.request.url == "/foo" - yamlContract.request.method == "PUT" - yamlContract.request.headers.find { it.key == "foo" && it.value == "bar" } - yamlContract.request.cookies.find { it.key == "bar" && it.value == "server" } - yamlContract.request.cookies.find { it.key == "foo" && it.value == "server" } - yamlContract.request.body == [foo: "bar"] - yamlContract.response.status == 200 - yamlContract.response.headers.find { it.key == "foo2" && it.value == "bar" } - yamlContract.response.body == [foo2: "bar"] - yamlContract.response.cookies.find { it.key == "foo" && it.value == "client" } - yamlContract.response.cookies.find { it.key == "bar" && it.value == "client" } - yamlContract.response.fixedDelayMilliseconds == 1000 - } - - def "should convert multiple messaging DSLs to YAML"() { - given: - assert converter.isAccepted(ymlMessagingMethod) - and: - List contracts = [Contract.make { - input { - description("Some description") - label("some_label") - triggeredBy("bookReturnedTriggered()") - } - outputMessage { - sentTo("output") - body([bookName: "foo"]) - headers { - header("BOOK-NAME", "foo") - } - } - }, Contract.make { - input { - description("Some description2") - label("some_label2") - triggeredBy("bookReturnedTriggered()2") - } - outputMessage { - sentTo("output2") - body([bookName2: "foo"]) - headers { - header("BOOK-NAME2", "foo") - } - } - }] - when: - Collection yamlContracts = converter.convertTo(contracts) - then: - yamlContracts.size() == 2 - YamlContract yamlContract = yamlContracts.first() - yamlContract.description == "Some description" - yamlContract.label == "some_label" - yamlContract.input.triggeredBy == "bookReturnedTriggered()" - yamlContract.outputMessage.sentTo == "output" - yamlContract.outputMessage.body == [bookName: "foo"] - yamlContract.outputMessage.headers == ["BOOK-NAME": "foo"] - and: - YamlContract yamlContract2 = yamlContracts.last() - yamlContract2.description == "Some description2" - yamlContract2.label == "some_label2" - yamlContract2.input.triggeredBy == "bookReturnedTriggered()2" - yamlContract2.outputMessage.sentTo == "output2" - yamlContract2.outputMessage.body == [bookName2: "foo"] - yamlContract2.outputMessage.headers == ["BOOK-NAME2": "foo"] - } - - def "should convert Messaging DSL with input triggered by method to YAML"() { - given: - assert converter.isAccepted(ymlMessagingMethod) - and: - List contracts = [Contract.make { - input { - description("Some description") - label("some_label") - triggeredBy("bookReturnedTriggered()") - } - outputMessage { - sentTo("output") - body([bookName: "foo"]) - headers { - header("BOOK-NAME", "foo") - } - } - }] - when: - Collection yamlContracts = converter.convertTo(contracts) - then: - yamlContracts.size() == 1 - YamlContract yamlContract = yamlContracts.first() - yamlContract.description == "Some description" - yamlContract.label == "some_label" - yamlContract.input.triggeredBy == "bookReturnedTriggered()" - yamlContract.outputMessage.sentTo == "output" - yamlContract.outputMessage.body == [bookName: "foo"] - yamlContract.outputMessage.headers == ["BOOK-NAME": "foo"] - } - - - def "should convert Messaging with a message DSL to YAML"() { - given: - assert converter.isAccepted(ymlMessagingMatchers) - and: - List contracts = [Contract.make { - name("fooo") - label("card_rejected") - ignored() - inProgress() - input { - triggeredBy("foo()") - } - outputMessage { - sentTo("channel") - body([duck : 123, - alpha : "abc", - number : 123, - aBoolean : true, - date : "2017-01-01", - dateTime : "2017-01-01T01:23:45", - time : "01:02:34", - valueWithoutAMatcher: "foo", - valueWithTypeMatch : "string", - valueWithMin : [1, 2, 3], - valueWithMax : [1, 2, 3], - valueWithMinMax : [1, 2, 3], - valueWithMinEmpty : [], - valueWithMaxEmpty : [], - key : ['complex.key': 'foo'], - nullValue : null - ]) - bodyMatchers { - // asserts the jsonpath value against manual regex - jsonPath('$.duck', byRegex("[0-9]{3}")) - // asserts the jsonpath value against the provided value - jsonPath('$.duck', byEquality()) - // asserts the jsonpath value against some default regex - jsonPath('$.alpha', byRegex(onlyAlphaUnicode())) - jsonPath('$.alpha', byEquality()) - jsonPath('$.number', byRegex(number())) - jsonPath('$.positiveInteger', byRegex(positiveInt())) - jsonPath('$.integer', byRegex(anInteger())) - jsonPath('$.double', byRegex(aDouble())) - jsonPath('$.aBoolean', byRegex(anyBoolean())) - // asserts vs inbuilt time related regex - jsonPath('$.date', byDate()) - jsonPath('$.dateTime', byTimestamp()) - jsonPath('$.time', byTime()) - // asserts that the resulting type is the same as in response body - jsonPath('$.valueWithTypeMatch', byType()) - jsonPath('$.valueWithMin', byType { - // results in verification of size of array (min 1) - minOccurrence(1) - }) - jsonPath('$.valueWithMax', byType { - // results in verification of size of array (max 3) - maxOccurrence(3) - }) - jsonPath('$.valueWithMinMax', byType { - // results in verification of size of array (min 1 & max 3) - minOccurrence(1) - maxOccurrence(3) - }) - jsonPath('$.valueWithMinEmpty', byType { - // results in verification of size of array (min 0) - minOccurrence(0) - }) - jsonPath('$.valueWithMaxEmpty', byType { - // results in verification of size of array (max 0) - maxOccurrence(0) - }) - // will execute a method `assertThatValueIsANumber` - jsonPath('$.duck', byCommand('assertThatValueIsANumber($it)')) - jsonPath("\$.['key'].['complex.key']", byEquality()) - jsonPath('$.nullValue', byNull()) - } - headers { - messagingContentType(applicationJson()) - header('Some-Header', $(c('someValue'), p(regex('[a-zA-Z]{9}')))) - } - } - }] - when: - Collection yamlContracts = converter.convertTo(contracts) - then: - yamlContracts.size() == 1 - YamlContract yamlContract = yamlContracts.first() - yamlContract.name == "fooo" - yamlContract.ignored == true - yamlContract.inProgress == true - yamlContract.input.triggeredBy == "foo()" - yamlContract.label == "card_rejected" - yamlContract.outputMessage.sentTo == "channel" - yamlContract.outputMessage.body == [duck : 123, - alpha : "abc", - number : 123, - aBoolean : true, - date : "2017-01-01", - dateTime : "2017-01-01T01:23:45", - time : "01:02:34", - valueWithoutAMatcher: "foo", - valueWithTypeMatch : "string", - valueWithMin : [1, 2, 3], - valueWithMax : [1, 2, 3], - valueWithMinMax : [1, 2, 3], - valueWithMinEmpty : [], - valueWithMaxEmpty : [], - key : ['complex.key': 'foo'], - nullValue : null - ] - yamlContract.outputMessage.headers == [ - "contentType": "application/json", - "Some-Header": "someValue" - ] - yamlContract.outputMessage.matchers.headers == [ - new YamlContract.TestHeaderMatcher( - key: "Some-Header", regex: "[a-zA-Z]{9}", regexType: YamlContract.RegexType.as_string) - ] - yamlContract.outputMessage.matchers.body == [ - new YamlContract.BodyTestMatcher( - path: '$.duck', - type: YamlContract.TestMatcherType.by_regex, - value: "[0-9]{3}"), - new YamlContract.BodyTestMatcher( - path: '$.duck', - type: YamlContract.TestMatcherType.by_equality), - new YamlContract.BodyTestMatcher( - path: '$.alpha', - type: YamlContract.TestMatcherType.by_regex, - value: '[\\p{L}]*'), - new YamlContract.BodyTestMatcher( - path: '$.alpha', - type: YamlContract.TestMatcherType.by_equality), - new YamlContract.BodyTestMatcher( - path: '$.number', - type: YamlContract.TestMatcherType.by_regex, - value: '-?(\\d*\\.\\d+|\\d+)'), - new YamlContract.BodyTestMatcher( - path: '$.positiveInteger', - type: YamlContract.TestMatcherType.by_regex, - value: '([1-9]\\d*)'), - new YamlContract.BodyTestMatcher( - path: '$.integer', - type: YamlContract.TestMatcherType.by_regex, - value: '-?(\\d+)'), - new YamlContract.BodyTestMatcher( - path: '$.double', - type: YamlContract.TestMatcherType.by_regex, - value: '-?(\\d*\\.\\d+)'), - new YamlContract.BodyTestMatcher( - path: '$.aBoolean', - type: YamlContract.TestMatcherType.by_regex, - value: '(true|false)'), - new YamlContract.BodyTestMatcher( - path: '$.date', - type: YamlContract.TestMatcherType.by_date, - value: '(\\d\\d\\d\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])'), - new YamlContract.BodyTestMatcher( - path: '$.dateTime', - type: YamlContract.TestMatcherType.by_timestamp, - value: '([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])'), - new YamlContract.BodyTestMatcher( - path: '$.time', - type: YamlContract.TestMatcherType.by_time, - value: '(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])'), - new YamlContract.BodyTestMatcher( - path: '$.valueWithTypeMatch', - type: YamlContract.TestMatcherType.by_type), - new YamlContract.BodyTestMatcher( - path: '$.valueWithMin', - type: YamlContract.TestMatcherType.by_type, - minOccurrence: 1), - new YamlContract.BodyTestMatcher( - path: '$.valueWithMax', - type: YamlContract.TestMatcherType.by_type, - maxOccurrence: 3), - new YamlContract.BodyTestMatcher( - path: '$.valueWithMinMax', - type: YamlContract.TestMatcherType.by_type, - minOccurrence: 1, - maxOccurrence: 3), - new YamlContract.BodyTestMatcher( - path: '$.valueWithMinEmpty', - type: YamlContract.TestMatcherType.by_type, - minOccurrence: 0), - new YamlContract.BodyTestMatcher( - path: '$.valueWithMaxEmpty', - type: YamlContract.TestMatcherType.by_type, - maxOccurrence: 0), - new YamlContract.BodyTestMatcher( - path: '$.duck', - type: YamlContract.TestMatcherType.by_command, - value: 'assertThatValueIsANumber($it)'), - new YamlContract.BodyTestMatcher( - path: "\$.['key'].['complex.key']", - type: YamlContract.TestMatcherType.by_equality), - new YamlContract.BodyTestMatcher( - path: '$.nullValue', - type: YamlContract.TestMatcherType.by_null), - ] - } - - def "should convert contract with body as bytes"() { - given: - List contracts = ContractVerifierDslConverter.convertAsCollection(groovyBytes) - when: - Collection yamlContracts = converter.convertTo(contracts) - then: - yamlContracts.size() == 1 - YamlContract yamlContract = yamlContracts.first() - yamlContract.request.body == null - yamlContract.request.bodyFromFileAsBytes != null - } - - def "should read contract from bytes"() { - given: - Map strings = converter.store([new YamlContract( - name: "post1", - request: new YamlContract.Request(method: "POST", url: "/users/1"), - response: new YamlContract.Response(status: 200) - )]) - when: - List yamlContracts = converter.read(strings.values().first()) - then: - yamlContracts.size() == 1 - YamlContract yamlContract = yamlContracts.first() - yamlContract.request.method == "POST" - yamlContract.request.url == "/users/1" - yamlContract.response.status == 200 - } - - def "should convert REST YAML with XML request and response to DSL"() { - given: - assert converter.isAccepted(ymlRestXml) - when: - Collection contracts = converter.convertFrom(ymlRestXml) - then: - contracts.size() == 1 - Contract contract = contracts.first() - contract.request.headers.entries.find({ - it.name == 'Content-Type' && it.clientValue == "application/xml" && it.serverValue == "application/xml" - }) - contract.request.bodyMatchers.matchers[0].path() == '/test/duck/text()' - contract.request.bodyMatchers.matchers[0].matchingType() == REGEX - contract.request.bodyMatchers.matchers[0].value().pattern() == '[0-9]{10}' - contract.request.bodyMatchers.matchers[1].path() == '/test/duck/text()' - contract.request.bodyMatchers.matchers[1].matchingType() == EQUALITY - contract.request.bodyMatchers.matchers[2].path() == '/test/time/text()' - contract.request.bodyMatchers.matchers[2].matchingType() == TIME - contract.request.bodyMatchers.matchers[2] - .value().pattern() == RegexPatterns.isoTime().pattern() - contract.request.body.clientValue.replaceAll("\n", ""). - replaceAll(' ', '') == xmlContractBody.replaceAll("\n", ""). - replaceAll(' ', '') - contract.request.body.serverValue.replaceAll("\n", ""). - replaceAll(' ', '') == xmlContractBody.replaceAll("\n", ""). - replaceAll(' ', '') - and: - contract.response.bodyMatchers.matchers[0].path() == '/test/duck/text()' - contract.response.bodyMatchers.matchers[0].matchingType() == REGEX - contract.response.bodyMatchers.matchers[0].value().pattern() == '[0-9]{10}' - contract.response.bodyMatchers.matchers[1].path() == '/test/duck/text()' - contract.response.bodyMatchers.matchers[1].matchingType() == COMMAND - contract.response.bodyMatchers.matchers[1]. - value().executionCommand == 'test($it)' - contract.response.bodyMatchers.matchers[2].path() == '/test/duck/xxx' - contract.response.bodyMatchers.matchers[2].matchingType() == NULL - contract.response.bodyMatchers.matchers[3].path() == '/test/duck/text()' - contract.response.bodyMatchers.matchers[3].matchingType() == EQUALITY - contract.response.bodyMatchers.matchers[4].path() == '/test/time/text()' - contract.response.bodyMatchers.matchers[4].matchingType() == TIME - contract.response.bodyMatchers.matchers[4] - .value().pattern() == RegexPatterns.isoTime().pattern() - contract.response.body.clientValue.replaceAll("\n", "") - .replaceAll(' ', '') == xmlContractBody - .replaceAll("\n", "").replaceAll(' ', '') - contract.response.body.serverValue.replaceAll("\n", "") - .replaceAll(' ', '') == xmlContractBody - .replaceAll("\n", "").replaceAll(' ', '') - } - - def "should convert REST YAML with XML with namespace in request and response to DSL"() { - given: - assert converter.isAccepted(ymlRestNamedXml) - when: - Collection contracts = converter.convertFrom(ymlRestNamedXml) - then: - contracts.size() == 1 - Contract contract = contracts.first() - contract.request.headers.entries.find({ - it.name == 'Content-Type' && it.clientValue == "application/xml" && it.serverValue == "application/xml" - }) - contract.request.bodyMatchers.matchers.isEmpty() - contract.request.body.clientValue.replaceAll("\n", ""). - replaceAll(' ', '') == xmlContractBodyWithNamespaces.replaceAll("\n", ""). - replaceAll(' ', '') - contract.request.body.serverValue.replaceAll("\n", ""). - replaceAll(' ', '') == xmlContractBodyWithNamespaces.replaceAll("\n", ""). - replaceAll(' ', '') - and: - contract.response.bodyMatchers.matchers.isEmpty() - contract.response.body.clientValue.replaceAll("\n", "") - .replaceAll(' ', '') == xmlContractBodyWithNamespaces - .replaceAll("\n", "").replaceAll(' ', '') - contract.response.body.serverValue.replaceAll("\n", "") - .replaceAll(' ', '') == xmlContractBodyWithNamespaces - .replaceAll("\n", "").replaceAll(' ', '') - } - - def "should accept a yaml file that is a proper scc YAML contract"() { - when: - def accepted = converter.isAccepted(ymlWithRest3) - - then: - accepted - } - - def "should not accept a YAML file that is not a scc YAML contract"() { - when: - def accepted = converter.isAccepted(oa3File) - - then: - !accepted - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractSpec.groovy deleted file mode 100644 index 55cc36dae6..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractSpec.groovy +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.converter - -import spock.lang.Specification - -class YamlContractSpec extends Specification { - - def "should convert to matching type from string"() { - when: - YamlContract.MatchingType type = YamlContract.MatchingType.from(string) - then: - type == expectedType - where: - string || expectedType - "equalTo" || YamlContract.MatchingType.equal_to - "equalToJson" || YamlContract.MatchingType.equal_to_json - "containing" || YamlContract.MatchingType.containing - "unknown" || null - } -} - diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/TestWireMockExtensions.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/TestWireMockExtensions.groovy deleted file mode 100644 index df5d0e6e46..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/TestWireMockExtensions.groovy +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.dsl.wiremock - -import com.github.tomakehurst.wiremock.extension.Extension - -/** - * Extension that registers the default transformer and the custom one - */ -class TestWireMockExtensions implements WireMockExtensions { - @Override - List extensions() { - return [ - new DefaultResponseTransformer(), - new CustomExtension() - ] - } -} - -class CustomExtension implements Extension { - - @Override - String getName() { - return "foo-transformer" - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockGroovyDslSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockGroovyDslSpec.groovy deleted file mode 100755 index e700b83c01..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockGroovyDslSpec.groovy +++ /dev/null @@ -1,3249 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.dsl.wiremock - -import com.github.tomakehurst.wiremock.WireMockServer -import com.github.tomakehurst.wiremock.core.WireMockConfiguration -import com.github.tomakehurst.wiremock.extension.responsetemplating.ResponseTemplateTransformer -import com.github.tomakehurst.wiremock.stubbing.StubMapping -import groovy.json.JsonBuilder -import groovy.json.JsonOutput -import groovy.json.JsonSlurper -import spock.lang.Issue -import spock.lang.Specification - -import org.springframework.boot.test.web.client.TestRestTemplate -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.builder.handlebars.HandlebarsEscapeHelper -import org.springframework.cloud.contract.verifier.builder.handlebars.HandlebarsJsonPathHelper -import org.springframework.cloud.contract.verifier.converter.YamlContractConverter -import org.springframework.cloud.contract.verifier.file.ContractMetadata -import org.springframework.cloud.contract.verifier.util.AssertionUtil -import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter -import org.springframework.http.RequestEntity -import org.springframework.http.ResponseEntity -import org.springframework.cloud.test.TestSocketUtils - -class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifier { - - def 'should convert groovy dsl stub to wireMock stub for the client side'() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method('GET') - url $(consumer(~/\/[0-9]{2}/), producer('/12')) - } - response { - status OK() - body( - id: value( - consumer('123'), - producer(regex('[0-9]+')) - ), - surname: $( - consumer('Kowalsky'), - producer(regex('[a-zA-Z]+')) - ), - name: 'Jan', - created: $(consumer('2014-02-02 12:23:43'), - producer(execute('currentDate($it)'))) - ) - headers { - header 'Content-Type': 'application/json' - } - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl). - toWireMockClientStub() - then: - AssertionUtil.assertThatJsonsAreEqual(''' - { - "request" : { - "urlPattern" : "/[0-9]{2}", - "method" : "GET" - }, - "response" : { - "status" : 200, - "body" : "{\\"id\\":\\"123\\",\\"surname\\":\\"Kowalsky\\",\\"name\\":\\"Jan\\",\\"created\\":\\"2014-02-02 12:23:43\\"}", - "headers" : { - "Content-Type" : "application/json" - }, - "transformers" : [ "response-template", "foo-transformer" ] - } - } - ''', wireMockStub) - and: - stubMappingIsValidWireMockStub(wireMockStub) - } - - @Issue("#79") - def 'should convert groovy dsl stub to wireMock stub for the client side with a body containing a map'() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method 'GET' - url '/ingredients' - headers { - header 'Content-Type': 'application/vnd.pl.devoxx.aggregatr.v1+json' - } - } - response { - status OK() - body( - ingredients: [ - [type: 'MALT', quantity: 100], - [type: 'WATER', quantity: 200], - [type: 'HOP', quantity: 300], - [type: 'YIEST', quantity: 400] - ] - ) - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl). - toWireMockClientStub() - then: - AssertionUtil.assertThatJsonsAreEqual(''' -{ - "request" : { - "url" : "/ingredients", - "method" : "GET", - "headers" : { - "Content-Type" : { - "equalTo" : "application/vnd.pl.devoxx.aggregatr.v1+json" - } - } - }, - "response" : { - "status" : 200, - "body" : "{\\"ingredients\\":[{\\"type\\":\\"MALT\\",\\"quantity\\":100},{\\"type\\":\\"WATER\\",\\"quantity\\":200},{\\"type\\":\\"HOP\\",\\"quantity\\":300},{\\"type\\":\\"YIEST\\",\\"quantity\\":400}]}", - "transformers" : [ "response-template", "foo-transformer" ] - } -} -''', wireMockStub) - and: - stubMappingIsValidWireMockStub(wireMockStub) - } - - @Issue("#86") - def 'should convert groovy dsl stub with GString and regexp'() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method('POST') - url('/ws/payments') - headers { - header("Content-Type": 'application/x-www-form-urlencoded') - } - body("""paymentType=INCOMING&transferType=BANK&amount=${ - value(consumer(regex('[0-9]{3}\\.[0-9]{2}')), - producer(500.00)) - }&bookingDate=${ - value(consumer( - regex('[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])')), - producer('2015-05-18')) - }""") - } - response { - status 204 - body( - paymentId: value(consumer('4'), - producer(regex('[1-9][0-9]*'))), - foundExistingPayment: false - ) - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl). - toWireMockClientStub() - then: - AssertionUtil.assertThatJsonsAreEqual(''' -{ - "request": { - "method": "POST", - "headers": { - "Content-Type": { - "equalTo": "application/x-www-form-urlencoded" - } - }, - "url": "/ws/payments", - "bodyPatterns": [ - { - "matches": "paymentType=INCOMING&transferType=BANK&amount=[0-9]{3}\\\\.[0-9]{2}&bookingDate=[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])" - } - ] - }, - "response": { - "status": 204, - "body": "{\\"paymentId\\":\\"4\\",\\"foundExistingPayment\\":false}", - "transformers" : [ "response-template", "foo-transformer" ] - } -} -''', wireMockStub) - and: - stubMappingIsValidWireMockStub(wireMockStub) - } - - def 'should convert groovy dsl stub with Body as String to wireMock stub for the client side'() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method('GET') - url $(consumer(~/\/[0-9]{2}/), producer('/12')) - } - response { - status OK() - body("""\ - { - "id": "${value(consumer('123'), producer('321'))}", - "surname": "${ - value(consumer('Kowalsky'), producer(regex('[a-zA-Z]+'))) - }", - "name": "Jan", - "created" : "${ - $(consumer('2014-02-02 12:23:43'), - producer('2999-09-09 01:23:45')) - }" - } - """ - ) - headers { - header 'Content-Type': 'application/json' - } - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl). - toWireMockClientStub() - then: - def actual = new JsonSlurper().parseText(wireMockStub) - def expected = new JsonSlurper().parseText(''' -{ - "request" : { - "urlPattern" : "/[0-9]{2}", - "method" : "GET" - }, - "response" : { - "status" : 200, - "body" : "{\\"id\\":\\"123\\",\\"surname\\":\\"Kowalsky\\",\\"name\\":\\"Jan\\",\\"created\\":\\"2014-02-02 12:23:43\\"}", - "headers" : { - "Content-Type" : "application/json" - }, - "transformers" : [ "response-template", "foo-transformer" ] - } -} -''') - actual.request == expected.request - actual.response.status == expected.response.status - actual.response.headers == expected.response.headers - def actualBody = new JsonSlurper().parseText(actual.response.body) - def expectedBody = new JsonSlurper().parseText(expected.response.body) - actualBody == expectedBody - and: - stubMappingIsValidWireMockStub(wireMockStub) - } - - def 'should convert groovy dsl stub with simple Body as String to wireMock stub for the client side'() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method('GET') - url $(consumer(regex('/[0-9]{2}')), producer('/12')) - body """ - { - "name": "Jan" - } - """ - } - response { - status OK() - body("""\ - { - "name": "Jan" - } - """ - ) - headers { - header 'Content-Type': 'application/json' - } - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl). - toWireMockClientStub() - then: - AssertionUtil.assertThatJsonsAreEqual(''' -{ - "request" : { - "urlPattern" : "/[0-9]{2}", - "method" : "GET", - "bodyPatterns" : [ { - "matchesJsonPath" : "$[?(@.['name'] == 'Jan')]" - } ] - }, - "response" : { - "status" : 200, - "body" : "{\\"name\\":\\"Jan\\"}", - "headers" : { - "Content-Type" : "application/json" - }, - "transformers" : [ "response-template", "foo-transformer" ] - } -} -''', wireMockStub) - and: - stubMappingIsValidWireMockStub(wireMockStub) - } - - def 'should use equalToJson when body match is defined as map'() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method('GET') - url $(consumer(~/\/[0-9]{2}/), producer('/12')) - body( - id: value( - consumer(regex('[0-9]+')), - producer('123'), - ), - surname: $( - consumer(regex('[a-zA-Z]+')), - producer('Kowalsky'), - ), - name: 'Jan', - created: $(consumer('2014-02-02 12:23:43'), - producer(execute('currentDate($it)'))) - ) - } - response { - status OK() - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl). - toWireMockClientStub() - then: - AssertionUtil.assertThatJsonsAreEqual((''' -{ - "request" : { - "urlPattern" : "/[0-9]{2}", - "method" : "GET", - "bodyPatterns" : [ { - "matchesJsonPath" : "$[?(@.['created'] == '2014-02-02 12:23:43')]" - }, { - "matchesJsonPath" : "$[?(@.['surname'] =~ /[a-zA-Z]+/)]" - }, { - "matchesJsonPath" : "$[?(@.['name'] == 'Jan')]" - }, { - "matchesJsonPath" : "$[?(@.['id'] =~ /[0-9]+/)]" - } ] - }, - "response" : { - "status" : 200, - "transformers" : [ "response-template", "foo-transformer" ] - } -} - '''), wireMockStub) - and: - stubMappingIsValidWireMockStub(wireMockStub) - } - - def 'should use equalToJson when content type ends with json'() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method 'GET' - url "/users" - headers { - header "Content-Type", "customtype/json" - } - body """ - { - "name": "Jan" - } - """ - } - response { - status OK() - } - } - when: - String json = toWireMockClientJsonStub(groovyDsl) - then: - AssertionUtil.assertThatJsonsAreEqual((''' -{ - "request" : { - "url" : "/users", - "method" : "GET", - "bodyPatterns" : [ { - "matchesJsonPath" : "$[?(@.['name'] == 'Jan')]" - } ], - "headers" : { - "Content-Type" : { - "equalTo" : "customtype/json" - } - } - }, - "response" : { - "status" : 200, - "transformers" : [ "response-template", "foo-transformer" ] - } -} - '''), json) - and: - stubMappingIsValidWireMockStub(json) - } - - def 'should use xml matchers when content type ends with xml'() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method 'GET' - url "/users" - headers { - header "Content-Type", "customtype/xml" - } - body """${ - value(consumer('Jozo'), producer('Denis')) - }${ - value(consumer("<test>"), producer('1234567890')) - }""" - } - response { - status OK() - } - } - when: - String json = toWireMockClientJsonStub(groovyDsl) - then: - AssertionUtil.assertThatJsonsAreEqual((''' - { - "request": { - "url": "/users", - "method": "GET", - "headers": { - "Content-Type": { - "equalTo": "customtype/xml" - } - }, - "bodyPatterns": [ - { - "matchesXPath": { - "expression": "/foo/name/text()", - "equalTo": "Jozo" - } - }, - { - "matchesXPath": { - "expression": "/foo/jobId/text()", - "equalTo": "" - } - } - ] - }, - "response": { - "status": 200, - "transformers": [ - "response-template", - "foo-transformer" - ] - } -} - '''), json) - and: - stubMappingIsValidWireMockStub(json) - } - - def 'should use xml matchers when content type is parsable xml'() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method 'GET' - url "/users" - body """${ - value(consumer('Jozo'), producer('Denis')) - }${ - value(consumer("<test>"), producer('1234567890')) - }""" - } - response { - status OK() - } - } - when: - String json = toWireMockClientJsonStub(groovyDsl) - then: - AssertionUtil.assertThatJsonsAreEqual((''' -{ - "request": { - "url": "/users", - "method": "GET", - "bodyPatterns": [ - { - "matchesXPath": { - "expression": "/user/name/text()", - "equalTo": "Jozo" - } - }, - { - "matchesXPath": { - "expression": "/user/jobId/text()", - "equalTo": "" - } - } - ] - }, - "response": { - "status": 200, - "transformers": [ - "response-template", - "foo-transformer" - ] - } -} - '''), json) - and: - stubMappingIsValidWireMockStub(json) - } - - def 'should support xml as a response body'() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method 'GET' - url "/users" - } - response { - status OK() - body """${ - value(consumer('Jozo'), producer('Denis')) - }${ - value(consumer(""), producer('1234567890')) - }""" - } - } - when: - String json = toWireMockClientJsonStub(groovyDsl) - then: - AssertionUtil.assertThatJsonsAreEqual((''' - { - "request": { - "method": "GET", - "url": "/users" - }, - "response": { - "status": 200, - "body":"Jozo<test>", - "transformers" : [ "response-template", "foo-transformer" ] - } - } - '''), json) - and: - stubMappingIsValidWireMockStub(json) - } - - def 'should use equalToJson'() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method 'GET' - url "/users" - body equalToJson('''{"name":"Jan"}''') - } - response { - status OK() - } - } - when: - String json = toWireMockClientJsonStub(groovyDsl) - then: - AssertionUtil.assertThatJsonsAreEqual((''' - { - "request": { - "method": "GET", - "url": "/users", - "bodyPatterns": [ - { - "equalToJson":"{\\"name\\":\\"Jan\\"}" - } - ] - }, - "response": { - "status": 200, - "transformers" : [ "response-template", "foo-transformer" ] - } - } - '''), json) - and: - stubMappingIsValidWireMockStub(json) - } - - def 'should use equalToJson and bodyMatchers with json content type'() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method 'GET' - url "/users" - headers { - header 'Content-Type': 'application/json' - } - body equalToJson('''{"name":"Jan"}''') - bodyMatchers { - jsonPath('$.name', byRegex('[A-Z]{3}')) - } - } - response { - status OK() - } - } - when: - String json = toWireMockClientJsonStub(groovyDsl) - then: - AssertionUtil.assertThatJsonsAreEqual((''' - { - "request": { - "method": "GET", - "url": "/users", - "bodyPatterns": [ - { - "equalToJson":"{\\"name\\":\\"Jan\\"}" - }, - { - "matchesJsonPath" : "$[?(@.name =~ /([A-Z]{3})/)]" - } - ] - }, - "response": { - "status": 200, - "transformers" : [ "response-template", "foo-transformer" ] - } - } - '''), json) - and: - stubMappingIsValidWireMockStub(json) - } - - def 'should use equalToXml'() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method 'GET' - url "/users" - body equalToXml("""${ - value(consumer('Jozo'), producer('Denis')) - }${ - value(consumer("<test>"), producer('1234567890')) - }""") - } - response { - status OK() - } - } - when: - String json = toWireMockClientJsonStub(groovyDsl) - then: - AssertionUtil.assertThatJsonsAreEqual((''' - { - "request": { - "method": "GET", - "url": "/users", - "bodyPatterns": [ - { - "equalToXml":"Jozo<test>" - } - ] - }, - "response": { - "status": 200, - "transformers" : [ "response-template", "foo-transformer" ] - } - } - '''), json) - and: - stubMappingIsValidWireMockStub(json) - } - - def 'should use equalToXml and bodyMatchers with xml content type'() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method 'GET' - url "/users" - headers { - header "Content-Type", "customtype/xml" - } - body equalToXml( - """${ - value(consumer('Jozo'), - producer('Denis')) - }1234567890""" - ) - bodyMatchers { - xPath('/foo/jobId/text()', byRegex('[0-9]{10}')) - } - } - response { - status OK() - } - } - when: - String json = toWireMockClientJsonStub(groovyDsl) - then: - AssertionUtil.assertThatJsonsAreEqual((''' - { - "request": { - "method": "GET", - "url": "/users", - "bodyPatterns" : [ { - "equalToXml" : "Jozo1234567890" - }, { - "matchesXPath" : { - "expression" : "/foo/jobId/text()", - "matches" : "[0-9]{10}" - } - } ] - }, - "response": { - "status": 200, - "transformers" : [ "response-template", "foo-transformer" ] - } - } - '''), json) - and: - stubMappingIsValidWireMockStub(json) - } - - def 'should create stub with body from the file'() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method 'GET' - headers { - header 'Content-Type': 'application/xml' - } - url "/users" - body file('classpath/request.xml') - } - response { - status OK() - } - } - when: - String json = toWireMockClientJsonStub(groovyDsl) - then: - AssertionUtil.assertThatJsonsAreEqual((''' - { - "request": { - "method": "GET", - "url": "/users", - "bodyPatterns": [ - { - "matchesXPath": { - "expression": "/foo/name/text()", - "equalTo": "Jozo" - } - }, - { - "matchesXPath": { - "expression": "/foo/jobId/text()", - "equalTo": "123" - } - } - ] - }, - "response": { - "status": 200, - "transformers" : [ "response-template", "foo-transformer" ] - } - } - '''), json) - and: - stubMappingIsValidWireMockStub(json) - } - - def 'should convert groovy dsl stub with regexp Body as String to wireMock stub for the client side'() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method('GET') - url $(consumer(regex('/[0-9]{2}')), producer('/12')) - body """ - { - "personalId": "${ - value(consumer(regex('^[0-9]{11}$')), - producer('57593728525')) - }" - } - """ - } - response { - status OK() - body("""\ - { - "name": "Jan" - } - """ - ) - headers { - header 'Content-Type': 'application/json' - } - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl). - toWireMockClientStub() - then: - AssertionUtil.assertThatJsonsAreEqual((''' -{ - "request" : { - "urlPattern" : "/[0-9]{2}", - "method" : "GET", - "bodyPatterns" : [ { - "matchesJsonPath" : "$[?(@.['personalId'] =~ /^[0-9]{11}$/)]" - } ] - }, - "response" : { - "status" : 200, - "body" : "{\\"name\\":\\"Jan\\"}", - "headers" : { - "Content-Type" : "application/json" - }, - "transformers" : [ "response-template", "foo-transformer" ] - } -} -'''), wireMockStub) - and: - stubMappingIsValidWireMockStub(wireMockStub) - } - - def 'should convert groovy dsl stub with a regexp and an integer in request body'() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method 'PUT' - url '/fraudcheck' - body(""" - { - "clientPesel":"${ - value(consumer(regex('[0-9]{10}')), - producer('1234567890')) - }", - "loanAmount":123.123 - } - """ - ) - headers { - header('Content-Type', 'application/vnd.fraud.v1+json') - } - - } - response { - status OK() - body( - fraudCheckStatus: "OK", - rejectionReason: $(consumer(null), producer( - execute('assertThatRejectionReasonIsNull($it)'))) - ) - headers { - header('Content-Type': 'application/vnd.fraud.v1+json') - } - } - - } - when: - String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl). - toWireMockClientStub() - then: - AssertionUtil.assertThatJsonsAreEqual((''' -{ - "request" : { - "url" : "/fraudcheck", - "method" : "PUT", - "bodyPatterns" : [ { - "matchesJsonPath" : "$[?(@.['loanAmount'] == 123.123)]" - }, { - "matchesJsonPath" : "$[?(@.['clientPesel'] =~ /[0-9]{10}/)]" - } ], - "headers" : { - "Content-Type" : { - "equalTo" : "application/vnd.fraud.v1+json" - } - } - }, - "response" : { - "status" : 200, - "body" : "{\\"fraudCheckStatus\\":\\"OK\\",\\"rejectionReason\\":null}", - "headers" : { - "Content-Type" : "application/vnd.fraud.v1+json" - }, - "transformers" : [ "response-template", "foo-transformer" ] - } -} -'''), wireMockStub) - and: - stubMappingIsValidWireMockStub(wireMockStub) - } - - def "should generate request with urlPath and queryParameters for client side"() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method 'GET' - urlPath($(consumer("users"), producer("items"))) { - queryParameters { - parameter 'limit': - $(consumer(equalTo("20")), producer("10")) - parameter 'offset': - $(consumer(containing("10")), producer("10")) - parameter 'filter': "email" - parameter 'sort': $(consumer(~/^[0-9]{10}$/), - producer("1234567890")) - parameter 'search': - $(consumer(notMatching(~/^\/[0-9]{2}$/)), - producer("10")) - parameter 'age': $(consumer(notMatching("^\\w*\$")), - producer(10)) - parameter 'name': $(consumer(matching("Denis.*")), - producer("Denis")) - parameter 'credit': absent() - } - } - } - response { - status OK() - } - } - when: - def json = toWireMockClientJsonStub(groovyDsl) - then: - AssertionUtil.assertThatJsonsAreEqual((''' - { - "request": { - "method": "GET", - "urlPath": "users", - "queryParameters": { - "offset": { - "contains": "10" - }, - "limit": { - "equalTo": "20" - }, - "filter": { - "equalTo": "email" - }, - "sort": { - "matches": "^[0-9]{10}$" - }, - "search": { - "doesNotMatch": "^/[0-9]{2}$" - }, - "age": { - "doesNotMatch": "^\\\\w*$" - }, - "name": { - "matches": "Denis.*" - }, - "credit": { - "absent": true - } - } - }, - "response": { - "status": 200, - "transformers" : [ "response-template", "foo-transformer" ] - } - } - '''), json) - and: - stubMappingIsValidWireMockStub(json) - } - - @Issue("#353") - def "should generate request with absent header for client side"() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method 'GET' - urlPath('/some/path/*') - headers { - header('''Authentication''', absent()) - } - } - response { - status OK() - } - } - when: - def json = toWireMockClientJsonStub(groovyDsl) - then: - AssertionUtil.assertThatJsonsAreEqual((''' - { - "request" : { - "urlPath" : "/some/path/*", - "method" : "GET", - "headers" : { - "Authentication" : { - "absent" : true - } - } - }, - "response" : { - "status" : 200, - "transformers" : [ "response-template", "foo-transformer" ] - } - } - '''), json) - and: - stubMappingIsValidWireMockStub(json) - } - - @Issue('#230') - def "should generate request with urlPathPattern and queryParameters for client side\ - when both contains regular expressions"() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method 'GET' - urlPath($( - consumer(regex("/users/[0-9]+")), - producer("/users/1"))) { - queryParameters { - parameter 'search': - $(consumer(notMatching(~/^\/[0-9]{2}$/)), - producer("10")) - } - } - } - response { - status OK() - } - } - when: - def json = toWireMockClientJsonStub(groovyDsl) - then: - AssertionUtil.assertThatJsonsAreEqual((''' - { - "request": { - "method": "GET", - "urlPathPattern": "/users/[0-9]+", - "queryParameters": { - "search": { - "doesNotMatch": "^/[0-9]{2}$" - } - } - }, - "response": { - "status": 200, - "transformers" : [ "response-template", "foo-transformer" ] - } - } - '''), json) - and: - stubMappingIsValidWireMockStub(json) - } - - - def "should generate request with urlPath for client side"() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method 'GET' - urlPath $(consumer("boxes"), producer("items")) - } - response { - status OK() - } - } - when: - def json = toWireMockClientJsonStub(groovyDsl) - then: - AssertionUtil.assertThatJsonsAreEqual((''' - { - "request": { - "method": "GET", - "urlPath": "boxes" - }, - "response": { - "status": 200, - "transformers" : [ "response-template", "foo-transformer" ] - } - } - '''), json) - and: - stubMappingIsValidWireMockStub(json) - } - - def "should generate simple request with urlPath for client side"() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method 'GET' - urlPath "boxes" - } - response { - status OK() - } - } - when: - def json = toWireMockClientJsonStub(groovyDsl) - then: - AssertionUtil.assertThatJsonsAreEqual((''' - { - "request": { - "method": "GET", - "urlPath": "boxes" - }, - "response": { - "status": 200, - "transformers" : [ "response-template", "foo-transformer" ] - } - } - '''), json) - and: - stubMappingIsValidWireMockStub(json) - } - - def "should not allow not matching query param for server value"() { - when: - org.springframework.cloud.contract.spec.Contract.make { - request { - method 'GET' - url(regex(/users\/[0-9]*/)) { - queryParameters { - parameter 'age': notMatching("^\\w*\$") - parameter 'name': matching("Denis.*") - } - } - } - response { - status OK() - } - } - then: - def e = thrown(IllegalStateException) - e.message.contains "Query parameter 'age' can't be of a matching type: NOT_MATCHING for the server side" - } - - def "should not allow regexp in query parameter for server value"() { - when: - org.springframework.cloud.contract.spec.Contract.make { - request { - method 'GET' - url("abc") { - queryParameters { - parameter 'age': $(consumer(notMatching("^\\w*\$")), - producer(regex(".*"))) - } - } - } - response { - status OK() - } - } - then: - thrown(IllegalStateException) - } - - def "should not allow query parameter unresolvable for a server value"() { - when: - org.springframework.cloud.contract.spec.Contract.make { - request { - method 'GET' - urlPath("users") { - queryParameters { - parameter 'age': notMatching("^\\w*\$") - parameter 'name': matching("Denis.*") - } - } - } - response { - status OK() - } - } - then: - def e = thrown(IllegalStateException) - e.message.contains "Query parameter 'age' can't be of a matching type: NOT_MATCHING for the server side" - } - - def "should not allow query parameter with a different absent variation for server/client"() { - when: - org.springframework.cloud.contract.spec.Contract.make dsl - then: - def e = thrown(IllegalStateException) - e.message.contains "Absent cannot only be used only on one side" - where: - dsl << [ - { - request { - method 'GET' - urlPath("users") { - queryParameters { - parameter 'name': $(consumer(absent()), producer("")) - } - } - } - response { - status OK() - } - }, - { - request { - method 'GET' - urlPath("users") { - queryParameters { - parameter 'name': $(consumer(""), producer(absent())) - } - } - } - response { - status OK() - } - }, - { - request { - method 'GET' - urlPath("users") { - queryParameters { - parameter 'name': $(consumer(absent()), - producer(matching("abc"))) - } - } - } - response { - status OK() - } - } - ] - } - - def "should generate request with url and queryParameters for client side"() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method 'GET' - url($(consumer(regex(/users\/[0-9]*/)), - producer("users/123"))) { - queryParameters { - parameter 'age': $(consumer(notMatching("^\\w*\$")), - producer(10)) - parameter 'name': $(consumer(matching("Denis.*")), - producer("Denis")) - } - } - } - response { - status OK() - } - } - when: - def json = toWireMockClientJsonStub(groovyDsl) - then: - AssertionUtil.assertThatJsonsAreEqual((''' - { - "request": { - "method": "GET", - "urlPathPattern": "users/[0-9]*", - "queryParameters": { - "age": { - "doesNotMatch": "^\\\\w*$" - }, - "name": { - "matches": "Denis.*" - } - } - }, - "response": { - "status": 200, - "transformers" : [ "response-template", "foo-transformer" ] - } - } - '''), json) - and: - stubMappingIsValidWireMockStub(json) - } - - def 'should convert groovy dsl stub with rich tree Body as String to wireMock stub for the client side'() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method('GET') - url $(consumer(~/\/[0-9]{2}/), producer('/12')) - body """\ - { - "personalId": "${ - value(consumer(regex('[0-9]{11}')), - producer('57593728525')) - }", - "firstName": "${value(consumer(regex('.*')), producer('Bruce'))}", - "lastName": "${value(consumer(regex('.*')), producer('Lee'))}", - "birthDate": "${ - value(consumer(regex('[0-9]{4}-[0-9]{2}-[0-9]{2}')), - producer('1985-12-12')) - }", - "errors": [ - { - "propertyName": "${ - value(consumer(regex('[0-9]{2}')), producer('04')) - }", - "providerValue": "Test" - }, - { - "propertyName": "${ - value(consumer(regex('[0-9]{2}')), producer('08')) - }", - "providerValue": "Test" - } - ] - } - """ - } - response { - status OK() - body("""\ - { - "name": "Jan" - } - """ - ) - headers { - header 'Content-Type': 'application/json' - } - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl). - toWireMockClientStub() - then: - AssertionUtil.assertThatJsonsAreEqual((''' -{ - "request" : { - "urlPattern" : "/[0-9]{2}", - "method" : "GET", - "bodyPatterns" : [ { - "matchesJsonPath" : "$.['errors'][*][?(@.['propertyName'] =~ /[0-9]{2}/)]" - }, { - "matchesJsonPath" : "$.['errors'][*][?(@.['providerValue'] == 'Test')]" - }, { - "matchesJsonPath" : "$[?(@.['lastName'] =~ /.*/)]" - }, { - "matchesJsonPath" : "$[?(@.['firstName'] =~ /.*/)]" - }, { - "matchesJsonPath" : "$[?(@.['birthDate'] =~ /[0-9]{4}-[0-9]{2}-[0-9]{2}/)]" - }, { - "matchesJsonPath" : "$[?(@.['personalId'] =~ /[0-9]{11}/)]" - }] - }, - "response" : { - "status" : 200, - "body" : "{\\"name\\":\\"Jan\\"}", - "headers" : { - "Content-Type" : "application/json" - }, - "transformers" : [ "response-template", "foo-transformer" ] - } -} - '''), wireMockStub) - } - - def 'should use regexp matches when request body match is defined using a map with a pattern'() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method 'POST' - url '/reissue-payment-order' - body( - loanNumber: "999997001", - amount: value( - consumer(regex('[0-9.]+')), - producer('100.00')), - currency: "DKK", - applicationName: value(consumer(regex('.*')), - producer("Auto-Repayments")), - username: value(consumer(regex('.*')), - producer("scheduler")), - cardId: 1 - ) - } - response { - status OK() - body ''' - { - "status": "OK" - } - ''' - headers { - header 'Content-Type': 'application/json' - } - } - } - when: - def json = toWireMockClientJsonStub(groovyDsl) - then: - AssertionUtil.assertThatJsonsAreEqual((''' -{ - "request" : { - "url" : "/reissue-payment-order", - "method" : "POST", - "bodyPatterns" : [ { - "matchesJsonPath" : "$[?(@.['loanNumber'] == '999997001')]" - }, { - "matchesJsonPath" : "$[?(@.['username'] =~ /.*/)]" - }, { - "matchesJsonPath" : "$[?(@.['amount'] =~ /[0-9.]+/)]" - }, { - "matchesJsonPath" : "$[?(@.['cardId'] == 1)]" - }, { - "matchesJsonPath" : "$[?(@.['currency'] == 'DKK')]" - }, { - "matchesJsonPath" : "$[?(@.['applicationName'] =~ /.*/)]" - } ] - }, - "response" : { - "status" : 200, - "body" : "{\\"status\\":\\"OK\\"}", - "headers" : { - "Content-Type" : "application/json" - }, - "transformers" : [ "response-template", "foo-transformer" ] - } -} - '''), json) - } - - def "should generate stub for empty body"() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method('POST') - url("test") - body("") - } - response { - status 406 - } - } - when: - def json = toWireMockClientJsonStub(groovyDsl) - then: - AssertionUtil.assertThatJsonsAreEqual((''' - { - "request": { - "method": "POST", - "url": "test", - "bodyPatterns": [ - { - "equalTo": "" - } - ] - }, - "response": { - "status": 406, - "transformers" : [ "response-template", "foo-transformer" ] - } - } -'''), json) - } - - def "should generate stub with priority"() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - priority 9 - request { - method('POST') - url("test") - } - response { - status 406 - } - } - when: - def json = toWireMockClientJsonStub(groovyDsl) - then: - AssertionUtil.assertThatJsonsAreEqual((''' - { - "priority": 9, - "request": { - "method": "POST", - "url": "test" - }, - "response": { - "status": 406, - "transformers" : [ "response-template", "foo-transformer" ] - } - } - '''), json) - } - - @Issue("#127") - def 'should use "test" as an alias for "server"'() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method('POST') - url("foo") - body( - property: value(consumer("value"), producer("value")) - ) - } - response { - status OK() - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl). - toWireMockClientStub() - then: - AssertionUtil.assertThatJsonsAreEqual((''' -{ - "request" : { - "method" : "POST", - "bodyPatterns" : [ { - "matchesJsonPath" : "$[?(@.['property'] == 'value')]" - } ] - }, - "response" : { - "status" : 200, - "transformers" : [ "response-template", "foo-transformer" ] - } -} - '''), wireMockStub) - and: - stubMappingIsValidWireMockStub(wireMockStub) - } - - @Issue("#121") - def 'should generate stub with empty list as a value of a field'() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method('POST') - url("foo") - body( - values: [] - ) - } - response { - status OK() - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl). - toWireMockClientStub() - then: - AssertionUtil.assertThatJsonsAreEqual((''' - { - "request": { - "method": "POST", - "bodyPatterns": [ - { - "equalToJson": "{\\"values\\":[]}" - } - ] - }, - "response": { - "status": 200, - "transformers" : [ "response-template", "foo-transformer" ] - } - } - '''), wireMockStub) - and: - stubMappingIsValidWireMockStub(wireMockStub) - } - - def 'should generate stub properly resolving GString with regular expression'() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - priority 1 - request { - method 'POST' - url '/users/password' - headers { - header 'Content-Type': 'application/json' - } - body( - email: $( - consumer(regex(email())), - producer('not.existing@user.com')), - callback_url: $(consumer(regex(hostname())), - producer('https://partners.com')) - ) - } - response { - status 404 - headers { - header 'Content-Type': 'application/json' - } - body( - code: 4, - message: "User not found by email = [${value(producer(regex(email())), consumer('not.existing@user.com'))}]" - ) - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl). - toWireMockClientStub() - then: - AssertionUtil.assertThatJsonsAreEqual((''' - { - "request" : { - "url" : "/users/password", - "method" : "POST", - "bodyPatterns" : [ { - "matchesJsonPath" : "$[?(@.['callback_url'] =~ /((http[s]?|ftp):\\\\/)\\\\/?([^:\\\\/\\\\s]+)(:[0-9]{1,5})?/)]" - }, { - "matchesJsonPath" : "$[?(@.['email'] =~ /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,6}/)]" - } ], - "headers" : { - "Content-Type" : { - "equalTo" : "application/json" - } - } - }, - "response" : { - "status" : 404, - "body" : "{\\"code\\":4,\\"message\\":\\"User not found by email = [not.existing@user.com]\\"}", - "headers" : { - "Content-Type" : "application/json" - }, - "transformers" : [ "response-template", "foo-transformer" ] - }, - "priority" : 1 - } - '''), wireMockStub) - and: - stubMappingIsValidWireMockStub(wireMockStub) - } - - def 'should generate stub properly resolving GString with regular expression in url'() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - - request { - method 'PUT' - url "/partners/${value(consumer(regex('^[0-9]*$')), producer('11'))}/agents/11/customers/09665703Z" - headers { - header 'Content-Type': 'application/json' - } - body( - first_name: 'Josef', - ) - } - response { - status 422 - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl). - toWireMockClientStub() - then: - AssertionUtil.assertThatJsonsAreEqual((''' - { - "request" : { - "urlPattern" : "/partners/^[0-9]*$/agents/11/customers/09665703Z", - "method" : "PUT", - "bodyPatterns" : [ { - "matchesJsonPath" : "$[?(@.['first_name'] == 'Josef')]" - } ], - "headers" : { - "Content-Type" : { - "equalTo" : "application/json" - } - } - }, - "response" : { - "status" : 422, - "transformers" : [ "response-template", "foo-transformer" ] - } - } - '''), wireMockStub) - and: - stubMappingIsValidWireMockStub(wireMockStub) - } - - @Issue('42') - def 'should generate stub without optional parameters'() { - when: - String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, contractDsl), contractDsl). - toWireMockClientStub() - then: - AssertionUtil.assertThatJsonsAreEqual((''' - { - "request" : { - "url" : "/users/password", - "method" : "POST", - "bodyPatterns" : [ { - "matchesJsonPath" : "$[?(@.['callback_url'] =~ /((http[s]?|ftp):\\\\/)\\\\/?([^:\\\\/\\\\s]+)(:[0-9]{1,5})?/)]" - }, { - "matchesJsonPath" : "$[?(@.['email'] =~ /([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,6})?/)]" - } ], - "headers" : { - "Content-Type" : { - "equalTo" : "application/json" - } - } - }, - "response" : { - "status" : 404, - "body" : "{\\"code\\":\\"123123\\",\\"message\\":\\"User not found by email = [not.existing@user.com]\\"}", - "headers" : { - "Content-Type" : "application/json" - }, - "transformers" : [ "response-template", "foo-transformer" ] - }, - "priority" : 1 - } - '''), wireMockStub) - and: - stubMappingIsValidWireMockStub(wireMockStub) - where: - contractDsl << [ - org.springframework.cloud.contract.spec.Contract.make { - priority 1 - request { - method 'POST' - url '/users/password' - headers { - header 'Content-Type': 'application/json' - } - body( - email: $( - consumer(optional(regex(email()))), - producer('abc@abc.com')), - callback_url: $(consumer(regex(hostname())), - producer('https://partners.com')) - ) - } - response { - status 404 - headers { - header 'Content-Type': 'application/json' - } - body( - code: $(consumer("123123"), - producer(optional("123123"))), - message: "User not found by email = [${value(producer(regex(email())), consumer('not.existing@user.com'))}]" - ) - } - }, - org.springframework.cloud.contract.spec.Contract.make { - priority 1 - request { - method 'POST' - url '/users/password' - headers { - header 'Content-Type': 'application/json' - } - body( - """ { - "email" : "${ - value(consumer(optional(regex(email()))), - producer('abc@abc.com')) - }", - "callback_url" : "${ - value(consumer(regex(hostname())), - producer('https://partners.com')) - }" - } - """ - ) - } - response { - status 404 - headers { - header 'Content-Type': 'application/json' - } - body( - """ { - "code" : "${ - value(consumer(123123), - producer(optional(123123))) - }", - "message" : "User not found by email = [${ - value(producer(regex(email())), - consumer('not.existing@user.com')) - }]" - } - """ - ) - } - } - ] - } - - String toJsonString(value) { - new JsonBuilder(value).toPrettyString() - } - - Object parseJson(json) { - new JsonSlurper().parseText(json) - } - - String toWireMockClientJsonStub(Contract groovyDsl) { - return new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl). - toWireMockClientStub() - } - - @Issue('180') - def 'should generate stub with multipart parameters'() { - given: - // tag::multipartdsl[] - org.springframework.cloud.contract.spec.Contract contractDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method "PUT" - url "/multipart" - headers { - contentType('multipart/form-data;boundary=AaB03x') - } - multipart( - // key (parameter name), value (parameter value) pair - formParameter: $(c(regex('".+"')), - p('"formParameterValue"')), - someBooleanParameter: - $(c(regex(anyBoolean())), p('true')), - // a parameter name (e.g. file) - file: named( - // name of the file - name: $(c(regex(nonEmpty())), - p('filename.csv')), - // content of the file - content: $(c(regex(nonEmpty())), - p('file content'))) - ) - } - response { - status OK() - } - } - // end::multipartdsl[] - when: - String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, contractDsl), contractDsl). - toWireMockClientStub() - then: - println wireMockStub - AssertionUtil.assertThatJsonsAreEqual(( - // tag::multipartwiremock[] - ''' - { - "request" : { - "url" : "/multipart", - "method" : "PUT", - "headers" : { - "Content-Type" : { - "matches" : "multipart/form-data;boundary=AaB03x.*" - } - }, - "bodyPatterns" : [ { - "matches" : ".*--(.*)\\r?\\nContent-Disposition: form-data; name=\\"formParameter\\"\\r?\\n(Content-Type: .*\\r?\\n)?(Content-Transfer-Encoding: .*\\r?\\n)?(Content-Length: \\\\d+\\r?\\n)?\\r?\\n\\".+\\"\\r?\\n--.*" - }, { - "matches" : ".*--(.*)\\r?\\nContent-Disposition: form-data; name=\\"someBooleanParameter\\"\\r?\\n(Content-Type: .*\\r?\\n)?(Content-Transfer-Encoding: .*\\r?\\n)?(Content-Length: \\\\d+\\r?\\n)?\\r?\\n(true|false)\\r?\\n--.*" - }, { - "matches" : ".*--(.*)\\r?\\nContent-Disposition: form-data; name=\\"file\\"; filename=\\"[\\\\S\\\\s]+\\"\\r?\\n(Content-Type: .*\\r?\\n)?(Content-Transfer-Encoding: .*\\r?\\n)?(Content-Length: \\\\d+\\r?\\n)?\\r?\\n[\\\\S\\\\s]+\\r?\\n--.*" - } ] - }, - "response" : { - "status" : 200, - "transformers" : [ "response-template", "foo-transformer" ] - } - } - ''' - // end::multipartwiremock[] - ), wireMockStub) - and: - stubMappingIsValidWireMockStub(wireMockStub) - } - - @Issue('#219') - def "should generate request with an optional queryParameter for client side"() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method 'GET' - urlPath('/some/api') { - queryParameters { - parameter 'size': value( - consumer(regex('[0-9]+')), - producer(1) - ) - parameter 'page': value( - consumer(regex('[0-9]+')), - producer(0) - ) - parameter sort: value( - consumer(optional(regex('^[a-z]+$'))), - producer('id') - ) - } - } - } - response { - status OK() - body( - content: [[ - id : '00000000-0000-0000-0000-000000000000', - type : 'Extraordinary', - state: 'ACTIVE', - ]], - totalPages: 1, - totalElements: 1, - last: true, - sort: [[ - direction : 'ASC', - property : 'id', - ignoreCase : false, - nullHandling: 'NATIVE', - ascending : true - ]], - first: true, - numberOfElements: 1, - size: 1, - number: 0 - ) - } - } - when: - def json = toWireMockClientJsonStub(groovyDsl) - then: - AssertionUtil.assertThatJsonsAreEqual((''' - { - "request" : { - "urlPath" : "/some/api", - "method" : "GET", - "queryParameters" : { - "size" : { - "matches" : "[0-9]+" - }, - "page" : { - "matches" : "[0-9]+" - }, - "sort" : { - "matches" : "(^[a-z]+$)?" - } - } - }, - "response" : { - "status" : 200, - "body" : "{\\"content\\":[{\\"id\\":\\"00000000-0000-0000-0000-000000000000\\",\\"type\\":\\"Extraordinary\\",\\"state\\":\\"ACTIVE\\"}],\\"totalPages\\":1,\\"totalElements\\":1,\\"last\\":true,\\"sort\\":[{\\"direction\\":\\"ASC\\",\\"property\\":\\"id\\",\\"ignoreCase\\":false,\\"nullHandling\\":\\"NATIVE\\",\\"ascending\\":true}],\\"first\\":true,\\"numberOfElements\\":1,\\"size\\":1,\\"number\\":0}", - "transformers" : [ "response-template", "foo-transformer" ] - } - } - '''), json) - and: - stubMappingIsValidWireMockStub(json) - } - - @Issue('#30') - def "should not create a stub for a skipped contract"() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - ignored() - method 'GET' - urlPath('/some/api') { - queryParameters { - parameter 'size': value( - consumer(regex('[0-9]+')), - producer(1) - ) - } - } - } - response { - status OK() - body('') - } - } - when: - def json = toWireMockClientJsonStub(groovyDsl) - then: - json == null - } - - @Issue('#30') - def "should not create a stub for a contract matching ignored pattern"() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method 'GET' - urlPath('/some/api') { - queryParameters { - parameter 'size': value( - consumer(regex('[0-9]+')), - producer(1) - ) - } - } - } - response { - status OK() - body('') - } - } - when: - def json = new WireMockStubStrategy("Test", new ContractMetadata(null, true, 0, null, groovyDsl), groovyDsl). - toWireMockClientStub() - then: - json == null - } - - @Issue('#237') - def "should work with legacy mappings"() { - given: - def oldJsonMapping = ''' - { - "request" : { - "urlPath" : "/api/v1/xxxx", - "method" : "POST", - "headers" : { - "Authorization" : { - "equalTo" : "secret2" - } - }, - "cookies" : { - "foo" : { - "equalTo" : "bar" - } - }, - "queryParameters" : { - "foo" : { - "equalTo" : "bar2" - } - }, - "bodyPatterns" : [ { - "matchesJsonPath" : "$[?(@.['baz'] == 5)]" - }, { - "matchesJsonPath" : "$[?(@.['foo'] == 'bar')]" - } ] - }, - "response" : { - "status" : 200, - "body" : "{\\"authorization\\":\\"{{{request.headers.Authorization.[0]}}}\\",\\"path\\":\\"{{{request.path}}}\\",\\"responseBaz\\":{{{jsonpath this '$.baz'}}} ,\\"param\\":\\"{{{request.query.foo.[0]}}}\\",\\"pathIndex\\":\\"{{{request.path.[1]}}}\\",\\"responseBaz2\\":\\"Bla bla {{{jsonpath this '$.foo'}}} bla bla\\",\\"responseFoo\\":\\"{{{jsonpath this '$.foo'}}}\\",\\"authorization2\\":\\"{{{request.headers.Authorization.[1]}}}\\",\\"fullBody\\":\\"{{{escapejsonbody}}}\\",\\"url\\":\\"{{{request.url}}}\\",\\"paramIndex\\":\\"{{{request.query.foo.[1]}}}\\"}", - "headers" : { - "Authorization" : "{{{request.headers.Authorization.[0]}}};foo" - }, - "transformers" : [ "response-template", "foo-transformer" ] - } - } - ''' - and: - int port = TestSocketUtils.findAvailableTcpPort() - WireMockServer server = new WireMockServer(config().port(port)) - server.start() - and: - server.addStubMapping(WireMockStubMapping.buildFrom(oldJsonMapping)) - when: - ResponseEntity entity = call(port) - then: - entity.headers. - find { it.key == "Authorization" && it.value.contains("secret;foo") } - AssertionUtil.assertThatJsonsAreEqual((''' - { - "url" : "/api/v1/xxxx?foo=bar&foo=bar2", - "param" : "bar", - "paramIndex" : "bar2", - "authorization" : "secret", - "authorization2" : "secret2", - "fullBody" : "{\\"foo\\":\\"bar\\",\\"baz\\":5}", - "responseFoo" : "bar", - "responseBaz" : 5, - "responseBaz2" : "Bla bla bar bla bla" - } - '''), entity.body) - cleanup: - server?.shutdown() - } - - @Issue("#664") - def "should work with byte arrays"() { - given: - File request = new File(WireMockGroovyDslSpec. - getResource("/body_builder/request.pdf").file) - File response = new File(WireMockGroovyDslSpec. - getResource("/body_builder/response.pdf").file) - and: - File file = new File(WireMockGroovyDslSpec. - getResource("/body_builder/worksWithPdf.groovy").file) - Contract contract = ContractVerifierDslConverter.convertAsCollection( - file.parentFile, file - ).first() - and: - def json = toWireMockClientJsonStub(contract) - and: - int port = TestSocketUtils.findAvailableTcpPort() - WireMockServer server = new WireMockServer(config().port(port)) - server.start() - and: - server.addStubMapping(WireMockStubMapping.buildFrom(json)) - when: - ResponseEntity entity = callBytes(port, request) - then: - entity.statusCodeValue == 200 - entity.body == response.bytes - cleanup: - server?.shutdown() - } - - @Issue('#540') - def "should generate a stub with standard WireMock request template"() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method 'POST' - url('/api/v1/xxxx') { - queryParameters { - parameter("foo", "bar") - parameter("foo", "bar2") - } - } - headers { - header(authorization(), "secret") - header(authorization(), "secret2") - } - cookies { - cookie("foo", "bar") - } - body(foo: "bar", baz: 5) - } - response { - status OK() - headers { - header(authorization(), "${fromRequest().header(authorization())};foo") - } - body( - url: fromRequest().url(), - path: fromRequest().path(), - pathIndex: fromRequest().path(1), - param: fromRequest().query("foo"), - paramIndex: fromRequest().query("foo", 1), - authorization: fromRequest().header("Authorization"), - authorization2: - fromRequest().header("Authorization", 1), - fullBody: fromRequest().body(), - responseFoo: fromRequest().body('$.foo'), - responseBaz: fromRequest().body('$.baz'), - responseBaz2: "Bla bla ${fromRequest().body('$.foo')} bla bla", - rawUrl: fromRequest().rawUrl(), - rawPath: fromRequest().rawPath(), - rawPathIndex: fromRequest().rawPath(1), - rawParam: fromRequest().rawQuery("foo"), - rawParamIndex: fromRequest().rawQuery("foo", 1), - rawAuthorization: - fromRequest().rawHeader("Authorization"), - rawAuthorization2: - fromRequest().rawHeader("Authorization", 1), - rawResponseFoo: fromRequest().rawBody('$.foo'), - rawResponseBaz: fromRequest().rawBody('$.baz'), - rawResponseBaz2: "Bla bla ${fromRequest().rawBody('$.foo')} bla bla" - ) - } - } - when: - def json = toWireMockClientJsonStub(groovyDsl) - then: - AssertionUtil.assertThatJsonsAreEqual((''' - { - "request" : { - "urlPath" : "/api/v1/xxxx", - "method" : "POST", - "headers" : { - "Authorization" : { - "equalTo" : "secret2" - } - }, - "cookies" : { - "foo" : { - "equalTo" : "bar" - } - }, - "queryParameters" : { - "foo" : { - "equalTo" : "bar2" - } - }, - "bodyPatterns" : [ { - "matchesJsonPath" : "$[?(@.['baz'] == 5)]" - }, { - "matchesJsonPath" : "$[?(@.['foo'] == 'bar')]" - } ] - }, - "response" : { - "status" : 200, - "body" : "{\\"url\\":\\"{{{request.url}}}\\",\\"path\\":\\"{{{request.path}}}\\",\\"pathIndex\\":\\"{{{request.path.[1]}}}\\",\\"param\\":\\"{{{request.query.foo.[0]}}}\\",\\"paramIndex\\":\\"{{{request.query.foo.[1]}}}\\",\\"authorization\\":\\"{{{request.headers.Authorization.[0]}}}\\",\\"authorization2\\":\\"{{{request.headers.Authorization.[1]}}}\\",\\"fullBody\\":\\"{{{escapejsonbody}}}\\",\\"responseFoo\\":\\"{{{jsonPath request.body '$.foo'}}}\\",\\"responseBaz\\":{{{jsonPath request.body '$.baz'}}} ,\\"responseBaz2\\":\\"Bla bla {{{jsonPath request.body '$.foo'}}} bla bla\\",\\"rawUrl\\":\\"{{request.url}}\\",\\"rawPath\\":\\"{{request.path}}\\",\\"rawPathIndex\\":\\"{{request.path.[1]}}\\",\\"rawParam\\":\\"{{request.query.foo.[0]}}\\",\\"rawParamIndex\\":\\"{{request.query.foo.[1]}}\\",\\"rawAuthorization\\":\\"{{request.headers.Authorization.[0]}}\\",\\"rawAuthorization2\\":\\"{{request.headers.Authorization.[1]}}\\",\\"rawResponseFoo\\":\\"{{jsonPath request.body '$.foo'}}\\",\\"rawResponseBaz\\":{{jsonPath request.body '$.baz'}} ,\\"rawResponseBaz2\\":\\"Bla bla {{jsonPath request.body '$.foo'}} bla bla\\"}", - "headers" : { - "Authorization" : "{{{request.headers.Authorization.[0]}}};foo" - }, - "transformers" : [ "response-template", "foo-transformer" ] - } - } - '''), json) - and: - stubMappingIsValidWireMockStub(json) - and: - int port = TestSocketUtils.findAvailableTcpPort() - WireMockServer server = new WireMockServer(config().port(port)) - server.start() - server.addStubMapping(WireMockStubMapping.buildFrom(json)) - then: - ResponseEntity entity = call(port) - entity.headers. - find { it.key == "Authorization" && it.value.contains("secret;foo") } - and: - AssertionUtil.assertThatJsonsAreEqual((''' - { - "rawAuthorization2":"secret2", - "responseBaz":5, - "pathIndex":"v1", - "rawAuthorization":"secret", - "authorization2":"secret2", - "rawParam":"bar", - "url":"/api/v1/xxxx?foo=bar&foo=bar2", - "paramIndex":"bar2", - "authorization":"secret", - "path":"/api/v1/xxxx", - "rawUrl":"/api/v1/xxxx?foo=bar&foo=bar2", - "rawPath":"/api/v1/xxxx", - "rawResponseBaz2":"Bla bla bar bla bla", - "param":"bar", - "rawResponseBaz":5, - "responseBaz2":"Bla bla bar bla bla", - "rawResponseFoo":"bar", - "responseFoo":"bar", - "rawPathIndex":"v1", - "fullBody":"{\\"foo\\":\\"bar\\",\\"baz\\":5}", - "rawParamIndex":"bar2" - } - '''), entity.body) - cleanup: - server?.shutdown() - } - - @Issue('#578') - def "should generate a stub for a request with form parameters"() { - given: - Contract groovyDsl = Contract.make { - request { - method POST() - urlPath('/oauth/token') - headers { - header(authorization(), anyNonBlankString()) - header(contentType(), applicationFormUrlencoded()) - header(accept(), applicationJson()) - } - body([ - username : 'user', - password : 'password', - grant_type: 'password' - ]) - } - response { - status 200 - headers { - header(contentType(), applicationJson()) - } - body([ - refresh_token: 'RANDOM_REFRESH_TOKEN', - access_token : 'RANDOM_ACCESS_TOKEN', - token_type : 'bearer', - expires_in : 3600, - scope : ['task'], - user : [ - id : 1, - username: 'user', - name : 'User' - ] - ]) - } - } - when: - def json = toWireMockClientJsonStub(groovyDsl) - then: - AssertionUtil.assertThatJsonsAreEqual((''' - { - "request" : { - "urlPath" : "/oauth/token", - "method" : "POST", - "headers" : { - "Authorization" : { - "matches" : "^\\\\s*\\\\S[\\\\S\\\\s]*" - }, - "Content-Type" : { - "equalTo" : "application/x-www-form-urlencoded" - }, - "Accept" : { - "equalTo" : "application/json" - } - }, - "bodyPatterns" : [ { - "equalTo" : "username=user&password=password&grant_type=password" - } ] - }, - "response" : { - "status" : 200, - "body" : "{\\"refresh_token\\":\\"RANDOM_REFRESH_TOKEN\\",\\"access_token\\":\\"RANDOM_ACCESS_TOKEN\\",\\"token_type\\":\\"bearer\\",\\"expires_in\\":3600,\\"scope\\":[\\"task\\"],\\"user\\":{\\"id\\":1,\\"username\\":\\"user\\",\\"name\\":\\"User\\"}}", - "headers" : { - "Content-Type" : "application/json" - }, - "transformers" : [ "response-template", "foo-transformer" ] - } - } - '''), json) - and: - stubMappingIsValidWireMockStub(json) - } - - @Issue('#266') - def "should work with array of arrays"() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = Contract.make { - request { - method 'POST' - urlPath '/api/categories' - body([["Programming", "Java"], ["Programming", "Java", "Spring", "Boot"]]) - headers { - header('Content-Type': 'application/json;charset=UTF-8') - } - } - response { - status 200 - body([["Programming", "Java"], ["Programming", "Java", "Spring", "Boot"]]) - headers { - header('Content-Type': 'application/json;charset=UTF-8') - } - } - } - when: - def json = toWireMockClientJsonStub(groovyDsl) - then: - AssertionUtil.assertThatJsonsAreEqual((''' - { - "request" : { - "urlPath" : "/api/categories", - "method" : "POST", - "headers" : { - "Content-Type" : { - "equalTo" : "application/json;charset=UTF-8" - } - }, - "bodyPatterns" : [ { - "matchesJsonPath" : "$[*][?(@ == 'Spring')]" - }, { - "matchesJsonPath" : "$[*][?(@ == 'Boot')]" - }, { - "matchesJsonPath" : "$[*][?(@ == 'Programming')]" - }, { - "matchesJsonPath" : "$[*][?(@ == 'Java')]" - } ] - }, - "response" : { - "status" : 200, - "body" : "[\\"[\\\\\\"Programming\\\\\\",\\\\\\"Java\\\\\\"]\\",\\"[\\\\\\"Programming\\\\\\",\\\\\\"Java\\\\\\",\\\\\\"Spring\\\\\\",\\\\\\"Boot\\\\\\"]\\"]", - "headers" : { - "Content-Type" : "application/json;charset=UTF-8" - }, - "transformers" : [ "response-template", "foo-transformer" ] - } - } - '''), json) - and: - stubMappingIsValidWireMockStub(json) - and: - int port = TestSocketUtils.findAvailableTcpPort() - WireMockServer server = new WireMockServer(config().port(port)) - server.start() - server.addStubMapping(WireMockStubMapping.buildFrom(json)) - then: - ResponseEntity entity = callApiCategories(port) - and: - AssertionUtil.assertThatJsonsAreEqual((''' - ["[\\"Programming\\",\\"Java\\"]","[\\"Programming\\",\\"Java\\",\\"Spring\\",\\"Boot\\"]"] - '''), entity.getBody()) - cleanup: - server?.shutdown() - } - - @Issue('#269') - def "should create a stub for dot separated keys"() { - given: - Contract groovyDsl = org.springframework.cloud.contract.spec.Contract.make { - request { - method 'PUT' - url '/fraudcheck' - body([ // (4) - "client.id": $(regex('[0-9]{10}')), - loanAmount : 99999 - ]) - headers { - contentType('application/vnd.fraud.v1+json') - } - } - response { - status OK() - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl). - toWireMockClientStub() - then: - AssertionUtil.assertThatJsonsAreEqual(''' - { - "request" : { - "url" : "/fraudcheck", - "method" : "PUT", - "headers" : { - "Content-Type" : { - "matches" : "application/vnd\\\\.fraud\\\\.v1\\\\+json.*" - } - }, - "bodyPatterns" : [ { - "matchesJsonPath" : "$[?(@.['loanAmount'] == 99999)]" - }, { - "matchesJsonPath" : "$[?(@.['client.id'] =~ /[0-9]{10}/)]" - } ] - } - }, - "response" : { - "status" : 200 - } - } - ''', wireMockStub) - and: - stubMappingIsValidWireMockStub(wireMockStub) - } - - @Issue('#427') - def "should not fail to generate a stub when arrays are there in the request"() { - given: - Contract groovyDsl = Contract.make { - request { - method "POST" - urlPath('/batch/persons') - body(""" - [{ - "fruitsILike": [ - "apple" - ] - }, - { - "fruitsILike": [ - ] - }, - { - "fruitsILike": [ - "orange" - ] - }] - """) - } - response { - status 201 - headers { - contentType(applicationJsonUtf8()) - } - body("""{ - "id": "foo" - }" - """) - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl). - toWireMockClientStub() - then: - AssertionUtil.assertThatJsonsAreEqual(''' - { - "request" : { - "urlPath" : "/batch/persons", - "method" : "POST", - "bodyPatterns" : [ { - "matchesJsonPath" : "$[*].['fruitsILike'][?(@ == 'orange')]" - }, { - "matchesJsonPath" : "$[*].['fruitsILike'][?(@ == 'apple')]" - } ] - }, - "response" : { - "status" : 201, - "body" : "{\\"id\\":\\"foo\\"}", - "headers" : { - "Content-Type" : "application/json;charset=UTF-8" - } - } - } - ''', wireMockStub) - and: - stubMappingIsValidWireMockStub(wireMockStub) - } - - @Issue('#385') - def "should not escape unicode characters"() { - given: - Contract groovyDsl = Contract.make { - request { - method 'PUT' - url '/fraudcheck' - body([ // (4) - "client.id": $(regex('[0-9]{10}')), - loanAmount : 99999 - ]) - headers { - contentType('application/vnd.fraud.v1+json') - } - } - response { - status OK() - body(""" - { - "code": 91015, - "description": "订å•已失效", - "lastUpdateTime": "0", - "payload": null - } - """) - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl). - toWireMockClientStub() - then: - AssertionUtil.assertThatJsonsAreEqual(''' - { - "request" : { - "url" : "/fraudcheck", - "method" : "PUT", - "headers" : { - "Content-Type" : { - "matches" : "application/vnd\\\\.fraud\\\\.v1\\\\+json.*" - } - }, - "bodyPatterns" : [ { - "matchesJsonPath" : "$[?(@.['client.id'] =~ /[0-9]{10}/)]" - }, { - "matchesJsonPath" : "$[?(@.['loanAmount'] == 99999)]" - } ] - }, - "response" : { - "status" : 200, - "body" : "{\\"code\\":91015,\\"description\\":\\"订å•已失效\\",\\"lastUpdateTime\\":\\"0\\",\\"payload\\":null}", - "transformers" : [ "response-template", "foo-transformer" ] - } - } - ''', wireMockStub) - and: - stubMappingIsValidWireMockStub(wireMockStub) - - } - - @Issue('#493') - def "should not escape &"() { - given: - Contract groovyDsl = Contract.make { - request { - method POST() - urlPath('/oauth/token') - headers { - header(authorization(), anyNonBlankString()) - header(contentType(), 'application/x-www-form-urlencoded; charset=UTF-8') - header(accept(), anyNonBlankString()) - } - body('username=user&password=password&grant_type=password') - } - response { - status 200 - headers { - header(contentType(), applicationJsonUtf8()) - } - body([ - refresh_token: 'RANDOM_REFRESH_TOKEN', - access_token : 'RANDOM_ACCESS_TOKEN', - token_type : 'bearer', - expires_in : 3600, - scope : ['task'], - user : [ - id : 1, - username: 'user', - name : 'User' - ] - ]) - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl). - toWireMockClientStub() - then: - !wireMockStub.contains("&") - and: - AssertionUtil.assertThatJsonsAreEqual(''' - { - "request" : { - "urlPath" : "/oauth/token", - "method" : "POST", - "headers" : { - "Authorization" : { - "matches" : "^\\\\s*\\\\S[\\\\S\\\\s]*" - }, - "Content-Type" : { - "equalTo" : "application/x-www-form-urlencoded; charset=UTF-8" - }, - "Accept" : { - "matches" : "^\\\\s*\\\\S[\\\\S\\\\s]*" - } - }, - "bodyPatterns" : [ { - "equalTo" : "username=user&password=password&grant_type=password" - } ] - }, - "response" : { - "status" : 200, - "body" : "{\\"refresh_token\\":\\"RANDOM_REFRESH_TOKEN\\",\\"access_token\\":\\"RANDOM_ACCESS_TOKEN\\",\\"token_type\\":\\"bearer\\",\\"expires_in\\":3600,\\"scope\\":[\\"task\\"],\\"user\\":{\\"id\\":1,\\"username\\":\\"user\\",\\"name\\":\\"User\\"}}", - "headers" : { - "Content-Type" : "application/json;charset=UTF-8" - }, - "transformers" : [ "response-template", "foo-transformer" ] - } - } - ''', wireMockStub) - and: - stubMappingIsValidWireMockStub(wireMockStub) - - } - - @Issue('#667') - def "should not double escape backslashes"() { - given: - Contract groovyDsl = org.springframework.cloud.contract.spec.Contract.make { - priority 1 - request { - method 'GET' - urlPath(value(consumer( - regex(/\/data\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/)), - producer('/data/444d57b2-e309-4576-83cb-5530ee03106a'))) - } - response { - status 200 - headers { - header("Content-Type", "application/json;charset=UTF-8") - } - body([ - jsonString: '{\\"attribute\\": \\"value\\"}' - ]) - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl). - toWireMockClientStub() - then: - AssertionUtil.assertThatJsonsAreEqual(''' - { - "request" : { - "urlPathPattern" : "/data/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", - "method" : "GET" - }, - "response" : { - "status" : 200, - "body" : "{\\"jsonString\\":\\"{\\\\\\"attribute\\\\\\": \\\\\\"value\\\\\\"}\\"}", - "headers" : { - "Content-Type" : "application/json;charset=UTF-8" - }, - "transformers" : [ "response-template", "foo-transformer" ] - }, - "priority" : 1 - } - ''', wireMockStub) - and: - stubMappingIsValidWireMockStub(wireMockStub) - } - - @Issue('#708') - def "should work with boolean body"() { - given: - Contract groovyDsl = Contract.make { - request { - method('DELETE') - urlPath("/item/1") - } - response { - status(200) - headers { - contentType(applicationJsonUtf8()) - } - body("true") - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl). - toWireMockClientStub() - then: - AssertionUtil.assertThatJsonsAreEqual(''' - { - "request" : { - "urlPath" : "/item/1", - "method" : "DELETE" - }, - "response" : { - "status" : 200, - "body" : "true", - "headers" : { - "Content-Type" : "application/json;charset=UTF-8" - }, - "transformers" : [ "response-template", "foo-transformer" ] - } - } - ''', wireMockStub) - and: - stubMappingIsValidWireMockStub(wireMockStub) - } - - def should_generate_stubs_with_request_body_matchers() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/get' - body([ - duck : 123, - alpha : 'abc', - number : 123, - aBoolean : true, - date : '2017-01-01', - dateTime : '2017-01-01T01:23:45', - time : '01:02:34', - valueWithoutAMatcher: 'foo', - valueWithTypeMatch : 'string', - key : [ - 'complex.key': 'foo' - ] - ]) - bodyMatchers { - jsonPath('$.duck', byRegex("[0-9]{3}")) - jsonPath('$.duck', byEquality()) - jsonPath('$.alpha', byRegex(onlyAlphaUnicode())) - jsonPath('$.alpha', byEquality()) - jsonPath('$.number', byRegex(number())) - jsonPath('$.aBoolean', byRegex(anyBoolean())) - jsonPath('$.date', byDate()) - jsonPath('$.dateTime', byTimestamp()) - jsonPath('$.time', byTime()) - jsonPath("\$.['key'].['complex.key']", byEquality()) - } - headers { - contentType(applicationJson()) - } - } - response { - status(200) - headers { - contentType(applicationJsonUtf8()) - } - body("true") - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", - new ContractMetadata(null, false, 0, null, contractDsl), contractDsl) - .toWireMockClientStub() - - then: - stubMappingIsValidWireMockStub(wireMockStub) - } - - @Issue("#94") - def "should not produce any cursors in the stub"() { - given: - Contract contractDsl = Contract.make { - request { - method 'POST' - urlPath $(test('/resource/resourceId/another-resource/another-resource-id/sth'), stub(regex('/resource/[\\w\\.]+/another-resource/([\\w+\\.-]|%[a-fA-F0-9]{2})+/sth'))) - body($(stub(regex(".+")), test(execute("encrypt('a lot of code')")))) - } - response { - status 201 - } - // 1 is the highest - priority 1000 - } - when: - String wireMockStub = new WireMockStubStrategy("Test", - new ContractMetadata(null, false, 0, null, contractDsl), contractDsl) - .toWireMockClientStub() - - then: - stubMappingIsValidWireMockStub(wireMockStub) - - } - - @Issue("#894") - def "should not fail when matchers don't have dots"() { - given: - Contract contractDsl = Contract.make { - request { - method 'POST' - url "/example" - body([ "123", "234"]) - bodyMatchers { - jsonPath('$[*]', byRegex(nonEmpty())) - } - } - response { - status 201 - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", - new ContractMetadata(null, false, 0, null, contractDsl), contractDsl) - .toWireMockClientStub() - - then: - stubMappingIsValidWireMockStub(wireMockStub) - - } - - @Issue("#1038") - def "should deal with unicode strings"() { - given: - File file = new File(WireMockGroovyDslSpec.getResource("/yml/issue1038.yml"). - toURI()) - Contract contractDsl = new YamlContractConverter().convertFrom(file).first() - when: - String wireMockStub = new WireMockStubStrategy("Test", - new ContractMetadata(null, false, 0, null, contractDsl), contractDsl) - .toWireMockClientStub() - - then: - wireMockStub.contains('''\\"country\\":\\"日本\\"''') - stubMappingIsValidWireMockStub(wireMockStub) - - } - - @Issue("#1263") - def "should work with complex objects in the body"() { - given: - Contract contractDsl = Contract.make { - description "should migrate spaceship" - request { - method POST() - url('/api/migration') - headers { - accept('application/json') - contentType(applicationJson()) - } - body( - $(c([id: 4, foo:5, whatever:"hello"]), p(execute('hashCode()'))) - ) - } - response { - status OK() - headers { - contentType(applicationJson()) - } - body( - $(c([id: 4, foo:5, whatever:"hello"]), p(execute('hashCode()'))) - ) - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", - new ContractMetadata(null, false, 0, null, contractDsl), contractDsl) - .toWireMockClientStub() - - then: - wireMockStub.contains('''$[?(@.['whatever'] == 'hello')]''') - wireMockStub.contains('''$[?(@.['id'] == 4)]''') - wireMockStub.contains('''$[?(@.['foo'] == 5)]''') - wireMockStub.contains('''"{\\"id\\":4,\\"foo\\":5,\\"whatever\\":\\"hello\\"}"''') - stubMappingIsValidWireMockStub(wireMockStub) - - } - - @Issue("#1535") - def "should work with streams"() { - given: - Contract contractDsl = Contract.make { - description "should return all entities" - request{ - method GET() - url("/api/v1/entities") - } - response { - headers { - header 'Content-Type': 'application/stream+json' - } - body( - ''' - { - "id" : "1", - "name" : "Entity1", - "nested_data" : { - "key1" : "value1" - } - }, - { - "id" : "2", - "name" : "Entity2", - "nested_data" : { - "key1" : "value1" - } - } - ''' - ) - status 200 - } - } - - when: - String wireMockStub = new WireMockStubStrategy("Test", - new ContractMetadata(null, false, 0, null, contractDsl), contractDsl) - .toWireMockClientStub() - then: - wireMockStub.contains('Entity1') - wireMockStub.contains('Entity2') - stubMappingIsValidWireMockStub(wireMockStub) - and: - int port = TestSocketUtils.findAvailableTcpPort() - WireMockServer server = new WireMockServer(config().port(port)) - server.start() - and: - stubMappingIsValidWireMockStub(wireMockStub) - server.addStubMapping(WireMockStubMapping.buildFrom(wireMockStub)) - when: - ResponseEntity entity = callForStream(port) - then: - entity.statusCodeValue == 200 - entity.body.contains("Entity1") - entity.body.contains("Entity2") - cleanup: - server?.shutdown() - } - - @Issue("#1125") - def "should not generate assertions for [*] when all manual entries were passed"() { - given: - Contract contractDsl = Contract.make { - request { - method(GET()) - url '/operations' - body( - channedlId: "UC", - operations: [ - [ - parameters : [ - [ - name : "#POID", - value: '70000269814', - type : "DECIMAL" - ], - [ - name : "#OVID", - value: "3", - type : "DECIMAL" - ], - [ - name : "#CAMC", - value: "CC2PAY", - type : "CHAR" - ] - ] - ] - ] - ) - bodyMatchers { - jsonPath('$.operations[0].parameters[0].name', byEquality()) - jsonPath('$.operations[0].parameters[0].value', byRegex('[0-9]{11}')) - jsonPath('$.operations[0].parameters[0].type', byEquality()) - jsonPath('$.operations[0].parameters[1].name', byEquality()) - jsonPath('$.operations[0].parameters[1].value', byEquality()) - jsonPath('$.operations[0].parameters[1].type', byEquality()) - jsonPath('$.operations[0].parameters[2].name', byEquality()) - jsonPath('$.operations[0].parameters[2].value', byEquality()) - jsonPath('$.operations[0].parameters[2].type', byEquality()) - } - } - - response { - status 200 - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", - new ContractMetadata(null, false, 0, null, contractDsl), contractDsl) - .toWireMockClientStub() - - then: - !wireMockStub.contains('''$.['operations'][*]''') - stubMappingIsValidWireMockStub(wireMockStub) - } - - @Issue("#1257") - def "should work with null request element on the client side and optional stub entry"() { - given: - Contract contractDsl = Contract.make { - description("Creating user") - name("Create user") - request { - method 'POST' - url '/api/user' - body( - address: $(consumer(optional(regex(alphaNumeric()))), producer(null)), - name: $(consumer(optional(regex(alphaNumeric()))), producer('')) - ) - headers { - contentType(applicationJson()) - } - } - response { - status 201 - } - } - and: - StubMapping wireMockStub = new WireMockStubStrategy("Test", - new ContractMetadata(null, false, 0, null, contractDsl), contractDsl) - .toWireMockClientStub() - - and: - int port = TestSocketUtils.findAvailableTcpPort() - WireMockServer server = new WireMockServer(config().port(port)) - server.start() - and: - stubMappingIsValidWireMockStub(wireMockStub) - server.addStubMapping(wireMockStub) - when: - ResponseEntity entity = callWithOptionalAndEmpty(port) - then: - entity.statusCodeValue == 201 - cleanup: - server?.shutdown() - } - - def "should work with client DSL properties"() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method('GET') - url("/api/foo") - headers { - header("foo", $(client(anyAlphaNumeric()), server("123"))) - } - cookies { - cookie("cookie1", $(client("foo"), server("bar"))) - cookie("cookie2", $(client(~/[a-z]+/), server("bar"))) - cookie("cookie3", $(client(anyAlphaNumeric()), server("bar"))) - cookie("cookie4", $(anyAlphaNumeric())) - } - } - response { - status OK() - body("ok") - headers { - header 'Content-Type': 'text/plain' - } - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl). - toWireMockClientStub() - then: - AssertionUtil.assertThatJsonsAreEqual(''' - { - "request" : { - "url" : "/api/foo", - "method" : "GET", - "headers" : { - "foo" : { - "matches" : "[a-zA-Z0-9]+" - } - }, - "cookies" : { - "cookie1" : { - "equalTo" : "foo" - }, - "cookie2" : { - "matches" : "[a-z]+" - }, - "cookie3" : { - "matches" : "[a-zA-Z0-9]+" - }, - "cookie4" : { - "matches" : "[a-zA-Z0-9]+" - } - } - }, - "response" : { - "status" : 200, - "body" : "ok", - "headers" : { - "Content-Type" : "text/plain" - }, - "transformers" : [ "response-template", "foo-transformer" ] - } - } - ''', wireMockStub) - and: - stubMappingIsValidWireMockStub(wireMockStub) - } - - @Issue("1808") - def "should correctly process optional of DslProperty parameters"() { - given: - org.springframework.cloud.contract.spec.Contract groovyDsl = org.springframework.cloud.contract.spec.Contract. - make { - request { - method('GET') - url("/api/foo") - headers { - header("Content-Type", "application/json") - header("Accept", "application/json") - } - body( - key1: $(client(optional(anyOf("foo", "bar"))), server("bar")), - key2: $(client(optional(anyNonBlankString())), server("bar")), - key3: $(client(optional(anyEmail())), server("foo@bar.com")), - key4: $(optional(anyNumber())), - ) - } - response { - status OK() - body("ok") - headers { - header 'Content-Type': 'text/plain' - } - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl). - toWireMockClientStub() - then: - AssertionUtil.assertThatJsonsAreEqual(''' - { - "request" : { - "url" : "/api/foo", - "method" : "GET", - "headers" : { - "Content-Type" : { - "equalTo" : "application/json" - }, - "Accept" : { - "equalTo" : "application/json" - } - }, - "bodyPatterns" : [ { - "matchesJsonPath" : "$[?(@.['key1'] =~ /(^foo$|^bar$)?/)]" - }, { - "matchesJsonPath" : "$[?(@.['key2'] =~ /(^\\\\s*\\\\S[\\\\S\\\\s]*)?/)]" - }, { - "matchesJsonPath" : "$[?(@.['key3'] =~ /([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,6})?/)]" - }, { - "matchesJsonPath" : "$[?(@.['key4'] =~ /(-?(\\\\d*\\\\.\\\\d+|\\\\d+))?/)]" - } ] - }, - "response" : { - "status" : 200, - "body" : "ok", - "headers" : { - "Content-Type" : "text/plain" - }, - "transformers" : [ "response-template", "foo-transformer" ] - } - } - ''', wireMockStub) - and: - stubMappingIsValidWireMockStub(wireMockStub) - } - - WireMockConfiguration config() { - return new WireMockConfiguration().extensions(responseTemplateTransformer()) - } - - private ResponseTemplateTransformer responseTemplateTransformer() { - return new ResponseTemplateTransformer(false, - [(HandlebarsJsonPathHelper.NAME): new HandlebarsJsonPathHelper(), - (HandlebarsEscapeHelper.NAME) : new HandlebarsEscapeHelper()]) - } - - ResponseEntity call(int port) { - return new TestRestTemplate().exchange( - RequestEntity.post(URI. - create("http://localhost:" + port + "/api/v1/xxxx?foo=bar&foo=bar2")) - .header("Authorization", "secret") - .header("Authorization", "secret2") - .header("Cookie", "foo=bar") - .body("{\"foo\":\"bar\",\"baz\":5}"), String.class) - } - - ResponseEntity callWithOptionalAndEmpty(int port) { - return new TestRestTemplate().exchange( - RequestEntity.post(URI.create("http://localhost:" + port + "/api/user")) - .header("Content-Type", "application/json") - .body("{\"foo\":null,\"name\":\"\"}"), String.class) - } - - ResponseEntity callForStream(int port) { - return new TestRestTemplate().exchange( - RequestEntity.get(URI.create("http://localhost:" + port + "/api/v1/entities")) - .header("Content-Type", "application/stream+json").build(), String.class) - } - - ResponseEntity callBytes(int port, File request) { - return new TestRestTemplate().exchange( - RequestEntity.put(URI.create("http://localhost:" + port + "/1")) - .header("Content-Type", "application/octet-stream") - .body(request.bytes), byte[].class) - } - - ResponseEntity callApiCategories(int port) { - return new TestRestTemplate().exchange( - RequestEntity. - post(URI.create("http://localhost:" + port + "/api/categories")) - .header("Content-Type", "application/json;charset=UTF-8") - .body(JsonOutput. - toJson([["Programming", "Java"], ["Programming", "Java", "Spring", "Boot"]])), String.class) - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockRequestStubStrategySpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockRequestStubStrategySpec.groovy deleted file mode 100644 index 04e4b4eb8e..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockRequestStubStrategySpec.groovy +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.dsl.wiremock - - -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.converter.YamlContractConverter -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata -import org.springframework.cloud.contract.verifier.util.ContentType -import spock.lang.Issue -import spock.lang.Specification - -class WireMockRequestStubStrategySpec extends Specification { - - @Issue("#1666") - def "should match header regex from request YAML"() { - given: - String yaml = """ -name: upload-file -request: - method: POST - url: /user/upload-file - headers: - Content-Type: multipart/form-data;boundary=AaB03x - multipart: - params: - name: "fileName.md" - named: - - paramName: "file" - fileName: "fileName.md" - fileContent: "file content" - matchers: - headers: - - key: Content-Type - regex: "multipart/form\\\\-data.*" - multipart: - params: - - key: name - regex: ".+" - named: - - paramName: "file" - fileName: - predefined: non_empty - fileContent: - predefined: non_empty -response: - status: 200 - body: - foo: bar -""" - File tmp = File.createTempFile("foo" + System.currentTimeMillis(), ".yml") - tmp.write(yaml) - Contract contract = new YamlContractConverter().convertFrom(tmp).first() - when: - SingleContractMetadata metadata = Stub() - metadata.evaluatedOutputStubContentType >> ContentType.JSON - def subject = new WireMockRequestStubStrategy(contract, metadata) - def content = subject.buildClientRequestContent() - then: - content.getHeaders().get("Content-Type").getValuePattern().getValue() != "multipart/form-data;boundary=AaB03x" - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockResponseStubStrategySpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockResponseStubStrategySpec.groovy deleted file mode 100644 index 6091a00054..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockResponseStubStrategySpec.groovy +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.dsl.wiremock - -import groovy.json.JsonSlurper -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.converter.YamlContractConverter -import org.springframework.cloud.contract.verifier.file.SingleContractMetadata -import org.springframework.cloud.contract.verifier.util.ContentType -import org.springframework.cloud.contract.verifier.util.MapConverter -import spock.lang.Issue -import spock.lang.Shared -import spock.lang.Specification - -import java.util.function.Function - -class WireMockResponseStubStrategySpec extends Specification { - - def "should not quote floating point numbers"() { - given: - def irrelevantStatus = 200 - def contract = Contract.make { - request { - method GET() - url "/foo" - } - response { - status irrelevantStatus - body([ - value: 1.5 - ]) - } - } - when: - SingleContractMetadata metadata = Stub() - metadata.evaluatedOutputStubContentType >> ContentType.JSON - def subject = new WireMockResponseStubStrategy(contract, metadata) { - @Override - Function parsingClosureForContentType() { - return MapConverter.JSON_PARSING_FUNCTION - } - } - def content = subject.buildClientResponseContent() - then: - '{"value":1.5}' == content.body - } - - @Issue("#468") - def "should not quote generated numbers"() { - given: - def irrelevantStatus = 200 - def contract = Contract.make { - request { - method GET() - url "/foo" - } - response { - status irrelevantStatus - body([ - number : anyNumber(), - integer : anyInteger(), - positiveInt: anyPositiveInt(), - double : anyDouble(), - ]) - } - } - when: - SingleContractMetadata metadata = Stub() - metadata.evaluatedOutputStubContentType >> ContentType.JSON - def subject = new WireMockResponseStubStrategy(contract, metadata) { - @Override - Function parsingClosureForContentType() { - return MapConverter.JSON_PARSING_FUNCTION - } - } - def content = subject.buildClientResponseContent() - then: - Map body = new JsonSlurper().parseText(content.body) as Map - assert body.get("number") instanceof Number - assert body.get("integer") instanceof Integer - assert body.get("positiveInt") instanceof Integer - assert body.get("double") instanceof BigDecimal - } - - @Issue("#1656") - def "should not quote numbers, booleans, and null inside arrays"() { - given: - def irrelevantStatus = 200 - def contract = Contract.make { - request { - method GET() - url "/foo" - } - response { - status irrelevantStatus - body([ - anyPositiveInt(), - anyInteger(), - true, - anyNumber(), - null, - "value" - ]) - } - } - when: - SingleContractMetadata metadata = Stub() - metadata.evaluatedOutputStubContentType >> ContentType.JSON - def subject = new WireMockResponseStubStrategy(contract, metadata) { - @Override - Function parsingClosureForContentType() { - return MapConverter.JSON_PARSING_FUNCTION - } - } - def content = subject.buildClientResponseContent() - then: - List body = new JsonSlurper().parseText(content.body) as List - assert body.getAt(0) instanceof Integer - assert body.getAt(1) instanceof Integer - assert body.getAt(2) instanceof Boolean - assert body.getAt(3) instanceof Number - assert body.getAt(4) == null - assert body.getAt(5) instanceof String - } - - @Shared def patternsContract = Contract.make { - request { - method(GET()) - urlPath(value(regex("/info/[0-9]"))) { - queryParameters { - parameter 'limit': $(consumer(equalTo('20')), producer(equalTo('10'))) - parameter 'offset': $(consumer(containing("20")), producer(equalTo('20'))) - parameter 'filter': 'email' - parameter 'sort': equalTo("name") - parameter 'age': $(consumer(notMatching("^\\w*\$")), producer('99')) - parameter 'name': $(consumer(matching('John.*')), producer('John.Doe')) - parameter 'email': 'bob@email.com' - parameter 'hello': $(consumer(matching('John.*')), producer(absent())) - parameter 'hello2': absent() - } - } - headers { - contentType(applicationJson()) - header([ - second: "value", third: $(anyAlphaNumeric()) - ]) - } - body([ - foo1 : $(c(regex("[0-9]")), p(1)), - foo2 : $(c(regex("[0-9]"))), - foo3 : $(anyAlphaNumeric()), - foo4 : value(regex(aDouble())), - foo5 : value(anyDouble()), - foo6 : "concrete", - duck : 123, - alpha : 'abc', - number : 123, - aBoolean : true, - date : '2017-01-01', - dateTime : '2017-01-01T01:23:45', - time : '01:02:34', - valueWithoutAMatcher: 'foo', - valueWithTypeMatch : 'string', - key : [ - 'complex.key': 'foo' - ] - ]) - bodyMatchers { - jsonPath('$.duck', byRegex("[0-9]{3}")) - jsonPath('$.duck', byEquality()) - jsonPath('$.alpha', byRegex(onlyAlphaUnicode())) - jsonPath('$.alpha', byEquality()) - jsonPath('$.number', byRegex(number())) - jsonPath('$.aBoolean', byRegex(anyBoolean())) - jsonPath('$.date', byDate()) - jsonPath('$.dateTime', byTimestamp()) - jsonPath('$.time', byTime()) - jsonPath("\$.['key'].['complex.key']", byEquality()) - } - } - response { - status(OK()) - headers { - contentType(applicationJson()) - header([ - second: "value", third: $(anyAlphaNumeric()) - ]) - } - body([ - foo1 : $(p(regex("[0-9]")), c(1)), - foo2 : $(p(regex("[0-9]"))), - foo3 : $(anyAlphaNumeric()), - foo4 : value(regex(aDouble())), - foo5 : value(anyDouble()), - foo6 : "concrete", - duck : 123, - alpha : 'abc', - number : 123, - positiveInteger : 1234567890, - negativeInteger : -1234567890, - positiveDecimalNumber: 123.4567890, - negativeDecimalNumber: -123.4567890, - aBoolean : true, - date : '2017-01-01', - dateTime : '2017-01-01T01:23:45', - time : "01:02:34", - valueWithoutAMatcher : 'foo', - valueWithTypeMatch : 'string', - valueWithMin : [ - 1, 2, 3 - ], - valueWithMax : [ - 1, 2, 3 - ], - valueWithMinMax : [ - 1, 2, 3 - ], - valueWithMinEmpty : [], - valueWithMaxEmpty : [], - key : [ - 'complex.key': 'foo' - ], - nullValue : null - ]) - bodyMatchers { - // asserts the jsonpath value against manual regex - jsonPath('$.duck', byRegex("[0-9]{3}")) - // asserts the jsonpath value against the provided value - jsonPath('$.duck', byEquality()) - // asserts the jsonpath value against some default regex - jsonPath('$.alpha', byRegex(onlyAlphaUnicode())) - jsonPath('$.alpha', byEquality()) - jsonPath('$.number', byRegex(number())) - jsonPath('$.positiveInteger', byRegex(anInteger())) - jsonPath('$.negativeInteger', byRegex(anInteger())) - jsonPath('$.positiveDecimalNumber', byRegex(aDouble())) - jsonPath('$.negativeDecimalNumber', byRegex(aDouble())) - jsonPath('$.aBoolean', byRegex(anyBoolean())) - // asserts vs inbuilt time related regex - jsonPath('$.date', byDate()) - jsonPath('$.dateTime', byTimestamp()) - jsonPath('$.time', byTime()) - // asserts that the resulting type is the same as in response body - jsonPath('$.valueWithTypeMatch', byType()) - jsonPath('$.valueWithMin', byType { - // results in verification of size of array (min 1) - minOccurrence(1) - }) - jsonPath('$.valueWithMax', byType { - // results in verification of size of array (max 3) - maxOccurrence(3) - }) - jsonPath('$.valueWithMinMax', byType { - // results in verification of size of array (min 1 & max 3) - minOccurrence(1) - maxOccurrence(3) - }) - jsonPath('$.valueWithMinEmpty', byType { - // results in verification of size of array (min 0) - minOccurrence(0) - }) - jsonPath('$.valueWithMaxEmpty', byType { - // results in verification of size of array (max 0) - maxOccurrence(0) - }) - // will execute a method `assertThatValueIsANumber` - jsonPath('$.duck', byCommand('assertThatValueIsANumber($it)')) - jsonPath("\$.['key'].['complex.key']", byEquality()) - jsonPath('$.nullValue', byNull()) - } - } - } - - def "should convert patterns to proper value"() { - when: - def subject = new WireMockRequestStubStrategy(patternsContract, null) { - @Override - protected ContentType contentType(SingleContractMetadata singleContractMetadata) { - return ContentType.JSON - } - } - subject.buildClientRequestContent() - then: - noExceptionThrown() - when: - def response = new WireMockResponseStubStrategy(patternsContract, null) { - @Override - protected ContentType contentType(SingleContractMetadata singleContractMetadata) { - return ContentType.JSON - } - - @Override - Function parsingClosureForContentType() { - return MapConverter.JSON_PARSING_FUNCTION - } - } - response.buildClientResponseContent() - then: - noExceptionThrown() - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockStubMappingSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockStubMappingSpec.groovy deleted file mode 100644 index 5c4ca39863..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockStubMappingSpec.groovy +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.dsl.wiremock - -import spock.lang.Specification - -/** - * @author Marcin Grzejszczak - */ -class WireMockStubMappingSpec extends Specification { - private static final String stub_2_1_7 = """ -{ - "request" : { - "method" : "GET" - }, - "response" : { - "status" : 200 - } -} -""" - private static final String stub_2_5_1 = """ -{ - "id" : "77514bd4-a102-4478-a3c0-0fda8b905591", - "request" : { - "method" : "GET" - }, - "response" : { - "status" : 200 - }, - "uuid" : "77514bd4-a102-4478-a3c0-0fda8b905591" -} -""" - private static final String stub_2_5_1_with_transformer = """ -{ - "id" : "77514bd4-a102-4478-a3c0-0fda8b905591", - "request" : { - "method" : "GET" - }, - "response" : { - "status" : 200, - "transformers": ["response-template"] - }, - "uuid" : "77514bd4-a102-4478-a3c0-0fda8b905591" -} -""" - - def "should successfully parse a WireMock 2.1.7 stub"() { - expect: - WireMockStubMapping.buildFrom(stub_2_1_7) - } - - def "should successfully parse a WireMock 2.5.0 stub"() { - expect: - WireMockStubMapping.buildFrom(stub_2_5_1) - } - - def "should successfully parse a WireMock 2.5.0 stub that contains transformers"() { - expect: - WireMockStubMapping.buildFrom(stub_2_5_1_with_transformer) - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockStubVerifier.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockStubVerifier.groovy deleted file mode 100644 index bdf4785900..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockStubVerifier.groovy +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.dsl.wiremock - -import java.util.regex.Pattern - -import com.github.tomakehurst.wiremock.matching.RegexPattern -import com.github.tomakehurst.wiremock.stubbing.StubMapping - -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.file.ContractMetadata - -trait WireMockStubVerifier { - - void stubMappingIsValidWireMockStub(String mappingDefinition) { - StubMapping stubMapping = WireMockStubMapping.buildFrom(mappingDefinition) - stubMappingIsValidWireMockStub(stubMapping) - } - - void stubMappingIsValidWireMockStub(StubMapping mappingDefinition) { - mappingDefinition.request.bodyPatterns.findAll { it.isPresent() && it instanceof RegexPattern }.every { - Pattern.compile(it.getValue()) - } - String definition = mappingDefinition.toString() - assert !definition.contains('org.springframework.cloud.contract.spec.internal') - assert !definition.contains('cursor') - } - - void stubMappingIsValidWireMockStub(Contract contractDsl) { - stubMappingIsValidWireMockStub(new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, contractDsl), contractDsl).toWireMockClientStub()) - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockXmlStubStrategySpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockXmlStubStrategySpec.groovy deleted file mode 100644 index 0d0ba34b20..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockXmlStubStrategySpec.groovy +++ /dev/null @@ -1,400 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.dsl.wiremock - - -import spock.lang.Specification - -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.file.ContractMetadata - -/** - * @author Olga Maciaszek-Sharma - */ -class WireMockXmlStubStrategySpec extends Specification implements WireMockStubVerifier { - - def 'should generate stubs with plain xml request body'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/get' - body """ - -123 -abc - -abc -def -ghi - -123 -true -2017-01-01 -2017-01-01T01:23:45 - -foo -string -foo -""" - headers { - contentType(applicationXml()) - } - } - response { - status(OK()) - headers { - contentType(applicationXml()) - } - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", - new ContractMetadata(null, false, 0, null, contractDsl), contractDsl) - .toWireMockClientStub() - then: - stubMappingIsValidWireMockStub(wireMockStub) - wireMockStub - .replaceAll("\n", "") - .replaceAll("\r", "") - .replaceAll(' ', '') - .contains( - """ -"bodyPatterns": [ - { - "matchesXPath": { - "expression": "/test/duck/text()", - "equalTo": "123" - } - }, - { - "matchesXPath": { - "expression": "/test/alpha/text()", - "equalTo": "abc" - } - }, - { - "matchesXPath": { - "expression": "/test/list/elem/text()", - "equalTo": "abc" - } - }, - { - "matchesXPath": { - "expression": "/test/list/elem[2]/text()", - "equalTo": "def" - } - }, - { - "matchesXPath": { - "expression": "/test/list/elem[3]/text()", - "equalTo": "ghi" - } - }, - { - "matchesXPath": { - "expression": "/test/number/text()", - "equalTo": "123" - } - }, - { - "matchesXPath": { - "expression": "/test/aBoolean/text()", - "equalTo": "true" - } - }, - { - "matchesXPath": { - "expression": "/test/date/text()", - "equalTo": "2017-01-01" - } - }, - { - "matchesXPath": { - "expression": "/test/dateTime/text()", - "equalTo": "2017-01-01T01:23:45" - } - }, - { - "matchesXPath": { - "expression": "/test/time/text()", - "equalTo": "01:02:34" - } - }, - { - "matchesXPath": { - "expression": "/test/valueWithoutAMatcher/text()", - "equalTo": "foo" - } - }, - { - "matchesXPath": { - "expression": "/test/valueWithTypeMatch/text()", - "equalTo": "string" - } - }, - { - "matchesXPath": { - "expression": "/test/key/complex/text()", - "equalTo": "foo" - } - }, - { - "matchesXPath": { - "expression": "/test/duck/@type", - "equalTo": "xtype" - } - }] -""".replaceAll("\n", "").replaceAll("\r", "").replaceAll(' ', '')) - } - - def 'should generate stubs with request body matchers'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/get' - body """ - -123 -abc -123 -true -2017-01-01 -2017-01-01T01:23:45 - -foo -string -foo -""" - bodyMatchers { - xPath('/test/duck/text()', byRegex("[0-9]{3}")) - xPath('/test/duck/text()', byEquality()) - xPath('/test/alpha/text()', byRegex(onlyAlphaUnicode())) - xPath('/test/alpha/text()', byEquality()) - xPath('/test/number/text()', byRegex(number())) - xPath('/test/aBoolean/text()', byRegex(anyBoolean())) - xPath('/test/date/text()', byDate()) - xPath('/test/dateTime/text()', byTimestamp()) - xPath('/test/time/text()', byTime()) - xPath('/test/*/complex/text()', byEquality()) - xPath('/test/duck/@type', byEquality()) - } - headers { - contentType(applicationXml()) - } - } - response { - status(OK()) - headers { - contentType(applicationXml()) - } - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", - new ContractMetadata(null, false, 0, null, contractDsl), contractDsl) - .toWireMockClientStub() - then: - stubMappingIsValidWireMockStub(wireMockStub) - wireMockStub.replaceAll("\n", '').replaceAll("\r", "").replaceAll(' ', '') - .contains(""" - matchesXPath" : { - "expression" : "/test/duck/text()", - "matches" : "[0-9]{3}" - } - }, { - "matchesXPath" : { - "expression" : "/test/duck/text()", - "equalTo" : "123" - } - }, { - "matchesXPath" : { - "expression" : "/test/alpha/text()", - "matches" : "[\\\\p{L}]*" - } - }, { - "matchesXPath" : { - "expression" : "/test/alpha/text()", - "equalTo" : "abc" - } - }, { - "matchesXPath" : { - "expression" : "/test/number/text()", - "matches" : "-?(\\\\d*\\\\.\\\\d+|\\\\d+)" - } - }, { - "matchesXPath" : { - "expression" : "/test/aBoolean/text()", - "matches" : "(true|false)" - } - }, { - "matchesXPath" : { - "expression" : "/test/date/text()", - "matches" : "(\\\\d\\\\d\\\\d\\\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])" - } - }, { - "matchesXPath" : { - "expression" : "/test/dateTime/text()", - "matches" : "([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])" - } - }, { - "matchesXPath" : { - "expression" : "/test/time/text()", - "matches" : "(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])" - } - }, { - "matchesXPath" : { - "expression" : "/test/*/complex/text()", - "equalTo" : "foo" - } - }, { - "matchesXPath" : { - "expression" : "/test/duck/@type", - "equalTo" : "xtype" - } - }""".replaceAll("\n","").replaceAll("\r", "").replaceAll(' ', '')) - } - - def 'should generate stubs with both xml and body matchers in request'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/get' - body """ - -123 -abc -123 -""" - bodyMatchers { - xPath('/test/duck/text()', byEquality()) - xPath('/test/number/text()', byRegex(number())) - } - headers { - contentType(applicationXml()) - } - } - response { - status(OK()) - headers { - contentType(applicationXml()) - } - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", - new ContractMetadata(null, false, 0, null, contractDsl), contractDsl) - .toWireMockClientStub() - then: - stubMappingIsValidWireMockStub(wireMockStub) - wireMockStub.replaceAll("\n", "") - .replaceAll("\r", "") - .replaceAll(' ', '') - .contains(""" - "bodyPatterns" : [ { - "matchesXPath": { - "expression": "/test/alpha/text()", - "equalTo": "abc" - } - }, { - "matchesXPath" : { - "expression" : "/test/duck/@type", - "equalTo" : "xtype" - } - }, { - "matchesXPath": { - "expression": "/test/duck/text()", - "equalTo": "123" - } - }, { - "matchesXPath": { - "expression": "/test/number/text()", - "matches" : "-?(\\\\d*\\\\.\\\\d+|\\\\d+)" - } - } - ] -} -""".replaceAll("\n", "").replaceAll("\r", "").replaceAll(' ', '')) - } - - - def 'should generate stubs with response body matchers'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/get' - headers { - contentType(applicationXml()) - } - } - response { - status(OK()) - headers { - contentType(applicationXml()) - } - body """ - -123 -abc - -abc -def -ghi - -123 -true -2017-01-01 -2017-01-01T01:23:45 - -foo -string -foo -""" - bodyMatchers { - xPath('/test/duck/text()', byRegex("[0-9]{3}")) - xPath('/test/duck/text()', byEquality()) - xPath('/test/alpha/text()', byRegex(onlyAlphaUnicode())) - xPath('/test/alpha/text()', byEquality()) - xPath('/test/number/text()', byRegex(number())) - xPath('/test/aBoolean/text()', byRegex(anyBoolean())) - xPath('/test/date/text()', byDate()) - xPath('/test/dateTime/text()', byTimestamp()) - xPath('/test/time/text()', byTime()) - xPath('/test/*/complex/text()', byEquality()) - xPath('/test/duck/@type', byEquality()) - } - } - } - when: - String wireMockStub = new WireMockStubStrategy("Test", - new ContractMetadata(null, false, 0, null, contractDsl), contractDsl) - .toWireMockClientStub() - then: - wireMockStub.contains("\\n\\n123" + - "\\nabc\\n\\nabc\\ndef" + - "\\nghi\\n\\n123" + - "\\ntrue\\n2017-01-01" + - "\\n2017-01-01T01:23:45\\n" + - "\\nfoo" + - "\\nstring" + - "\\nfoo\\n") - } -} - diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScannerNewApiSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScannerNewApiSpec.groovy deleted file mode 100644 index 9a185af3d9..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScannerNewApiSpec.groovy +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.file - - -import java.nio.file.Path - -import org.junit.Rule -import org.junit.rules.TemporaryFolder -import spock.lang.Specification - -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.spec.ContractConverter -import org.springframework.util.FileSystemUtils -import org.springframework.util.MultiValueMap - -/** - * @author Jakub Kubrynski, codearte.io - */ -class ContractFileScannerNewApiSpec extends Specification { - - @Rule - TemporaryFolder tmp = new TemporaryFolder() - File tmpFolder - - def setup() { - tmpFolder = new File(tmp.newFolder(), "contracts") - } - - def "should find contract files"() { - given: - FileSystemUtils.copyRecursively( - new File(this.getClass().getResource("/directory/with/stubs").toURI()), - tmpFolder) - and: - File baseDir = tmpFolder - Set excluded = ["package/**"] as Set - Set ignored = ["other/different/**"] as Set - ContractFileScanner scanner = new ContractFileScanner(baseDir, excluded, ignored, [] as Set, null) - when: - MultiValueMap result = scanner.findContractsRecursively() - then: - result.keySet().size() == 3 - result.get(baseDir.toPath().resolve("different")).size() == 1 - result.get(baseDir.toPath().resolve("other")).size() == 2 - and: - Collection ignoredSet = result.get(baseDir.toPath().resolve("other").resolve("different")) - ignoredSet.size() == 1 - ignoredSet.ignored == [true] - } - - def "should find contract files in strange directories"() { - given: - File baseDir = new File(this.getClass().getResource("/strange_[3.3.3]_directory").toURI()) - Set excluded = ["foo/**"] as Set - Set ignored = ["bar/**"] as Set - ContractFileScanner scanner = new ContractFileScanner(baseDir, excluded, ignored, [] as Set, null) - when: - MultiValueMap result = scanner.findContractsRecursively() - then: - result.entrySet().size() == 2 - and: - Collection ignoredSet = result.get(baseDir.toPath().resolve("bar")) - ignoredSet.size() == 1 - ignoredSet.ignored == [true] - } - - def "should find contracts group in scenario"() { - given: - File baseDir = new File(this.getClass().getResource("/directory/with/scenario").toURI()) - ContractFileScanner scanner = new ContractFileScanner(baseDir, [] as Set, [] as Set, [] as Set, null) - when: - MultiValueMap contracts = scanner.findContractsRecursively() - then: - contracts.values().size() == 1 - def firstEntry = contracts.values().first() - firstEntry.size() == 3 - firstEntry.find { - it.path.fileName.toString().startsWith('01') - }.groupSize == 3 - firstEntry.find { - it.path.fileName.toString().startsWith('01') - }.order == 0 - firstEntry.find { - it.path.fileName.toString().startsWith('02') - }.order == 1 - firstEntry.find { - it.path.fileName.toString().startsWith('03') - }.order == 2 - } - - 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, 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: - scanner.findContractsRecursively() - then: - IllegalStateException e = thrown(IllegalStateException) - e.cause.message == "boom" - e.message.matches(".*Failed to convert file .*invalid.json.*") - } - - def "should prefer custom yaml converter over standard yaml converter"() { - given: - File baseDir = new File(this.getClass().getResource("/directory/with/custom/yml").toURI()) - ContractFileScanner scanner = new ContractFileScanner(baseDir, null, null, null, null) { - @Override - protected List converters() { - return [new ContractConverter() { - @Override - boolean isAccepted(File file) { - if (!file.name.endsWith(".yml") && !file.name.endsWith(".yaml")) { - return false - } - String line - file.withReader { - line = it.readLine() - } - return line != null && line.startsWith("custom_format: 1.0") - } - - @Override - Collection convertFrom(File file) { - return Collections.singleton(Contract.newInstance()) - } - - @Override - Object convertTo(Collection contract) { - return new Object() - } - }] - } - } - when: - MultiValueMap result = scanner.findContractsRecursively() - then: - result.keySet().size() == 1 - result.entrySet().every { it.value.convertedContract } - } - - def "should find contracts for include pattern"() { - given: - FileSystemUtils.copyRecursively( - new File(this.getClass().getResource("/directory/with/common-messaging").toURI()), - tmpFolder) - and: - File baseDir = tmpFolder - Set included = ["social-service/**", "**/coupon-collected/**/*V1*"] as Set - ContractFileScanner scanner = new ContractFileScanner(baseDir, [] as Set, [] as Set, included, null) - when: - MultiValueMap result = scanner.findContractsRecursively() - then: - result.keySet().size() == 3 - result.values().flatten().find { - (it.path.fileName.toString() == 'couponCollectedEventV1.groovy') - }.groupSize == 2 - result.values().flatten().find { - (it.convertedContract.first().label == 'couponCollectedV1') - } - result.values().flatten().findAll { - (it.path.fileName.toString() == 'couponCollectedEventV2.groovy') - }.isEmpty() - result.values().flatten().find { - (it.path.fileName.toString() == 'shouldUpdateUserInfo.groovy') - }.groupSize == 1 - result.values().flatten().find { - (it.path.fileName.toString() == 'shouldReturnEmptyFriendsWhenGetFriends.groovy') - }.groupSize == 1 - result.get(baseDir.toPath().resolve("coupon-sent")) == null - result.get(baseDir.toPath().resolve("reward-rules")) == null - } -} 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 deleted file mode 100644 index a6a7bac0ab..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScannerSpec.groovy +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.file - - -import java.nio.file.Path - -import org.junit.Rule -import org.junit.rules.TemporaryFolder -import spock.lang.Specification - -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.spec.ContractConverter -import org.springframework.util.FileSystemUtils -import org.springframework.util.MultiValueMap - -/** - * @author Jakub Kubrynski, codearte.io - */ -class ContractFileScannerSpec extends Specification { - - @Rule - TemporaryFolder tmp = new TemporaryFolder() - File tmpFolder - - def setup() { - tmpFolder = new File(tmp.newFolder(), "contracts") - } - - def "should find contract files"() { - given: - FileSystemUtils.copyRecursively( - new File(this.getClass().getResource("/directory/with/stubs").toURI()), - tmpFolder) - and: - File baseDir = tmpFolder - Set excluded = ["package/**"] as Set - Set ignored = ["other/different/**"] as Set - ContractFileScanner scanner = new ContractFileScanner(baseDir, excluded, ignored, [] as Set, "") - when: - MultiValueMap result = scanner.findContractsRecursively() - then: - result.keySet().size() == 3 - result.get(baseDir.toPath().resolve("different")).size() == 1 - result.get(baseDir.toPath().resolve("other")).size() == 2 - and: - Collection ignoredSet = result.get(baseDir.toPath().resolve("other").resolve("different")) - ignoredSet.size() == 1 - ignoredSet.ignored == [true] - } - - def "should find contract files in strange directories"() { - given: - File baseDir = new File(this.getClass().getResource("/strange_[3.3.3]_directory").toURI()) - Set excluded = ["foo/**"] as Set - Set ignored = ["bar/**"] as Set - ContractFileScanner scanner = new ContractFileScanner(baseDir, excluded, ignored, [] as Set, "") - when: - MultiValueMap result = scanner.findContractsRecursively() - then: - result.entrySet().size() == 2 - and: - Collection ignoredSet = result.get(baseDir.toPath().resolve("bar")) - ignoredSet.size() == 1 - ignoredSet.ignored == [true] - } - - def "should find contracts group in scenario"() { - given: - File baseDir = new File(this.getClass().getResource("/directory/with/scenario").toURI()) - ContractFileScanner scanner = new ContractFileScanner(baseDir, [] as Set, [] as Set, [] as Set, "") - when: - MultiValueMap contracts = scanner.findContractsRecursively() - then: - contracts.values()[0].size() == 3 - contracts.values()[0].find { - it.path.fileName.toString().startsWith('01') - }.groupSize == 3 - contracts.values()[0].find { - it.path.fileName.toString().startsWith('01') - }.order == 0 - contracts.values()[0].find { - it.path.fileName.toString().startsWith('02') - }.order == 1 - contracts.values()[0].find { - it.path.fileName.toString().startsWith('03') - }.order == 2 - } - - 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, 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: - scanner.findContractsRecursively() - then: - IllegalStateException e = thrown(IllegalStateException) - e.cause.message == "boom" - e.message.matches(".*Failed to convert file .*invalid.json.*") - } - - def "should prefer custom yaml converter over standard yaml converter"() { - given: - File baseDir = new File(this.getClass().getResource("/directory/with/custom/yml").toURI()) - ContractFileScanner scanner = new ContractFileScanner(baseDir, null, null, null, null) { - @Override - protected List converters() { - return [new ContractConverter() { - @Override - boolean isAccepted(File file) { - if (!file.name.endsWith(".yml") && !file.name.endsWith(".yaml")) { - return false - } - String line - file.withReader { - line = it.readLine() - } - return line != null && line.startsWith("custom_format: 1.0") - } - - @Override - Collection convertFrom(File file) { - return Collections.singleton(Contract.newInstance()) - } - - @Override - Object convertTo(Collection contract) { - return new Object() - } - }] - } - } - when: - MultiValueMap result = scanner.findContractsRecursively() - then: - result.keySet().size() == 1 - result.entrySet().every { it.value.convertedContract } - } - - def "should find contracts for include pattern"() { - given: - FileSystemUtils.copyRecursively( - new File(this.getClass().getResource("/directory/with/common-messaging").toURI()), - tmpFolder) - and: - File baseDir = tmpFolder - Set included = ["social-service/**", "**/coupon-collected/**/*V1*"] as Set - ContractFileScanner scanner = new ContractFileScanner(baseDir, [] as Set, [] as Set, included, null) - when: - MultiValueMap result = scanner.findContractsRecursively() - then: - result.keySet().size() == 3 - result.values()[0].find { - (it.path.fileName.toString() == 'couponCollectedEventV1.groovy') - }.groupSize == 2 - result.values()[0].find { - (it.convertedContract.first().label == 'couponCollectedV1') - } - result.values()[0].findAll { - (it.path.fileName.toString() == 'couponCollectedEventV2.groovy') - }.isEmpty() - result.values().find { list -> - list.find { it.path.fileName.toString() == 'shouldUpdateUserInfo.groovy' } - }[0].groupSize == 1 - result.values().find { list -> - list.find { it.path.fileName.toString() == 'shouldReturnEmptyFriendsWhenGetFriends.groovy' } - }[0].groupSize == 1 - result.get(baseDir.toPath().resolve("coupon-sent")) == null - result.get(baseDir.toPath().resolve("reward-rules")) == null - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/messaging/camel/ContractVerifierCamelMessageBuilderSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/messaging/camel/ContractVerifierCamelMessageBuilderSpec.groovy deleted file mode 100644 index b56ccbbe02..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/messaging/camel/ContractVerifierCamelMessageBuilderSpec.groovy +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.camel - -import org.apache.camel.CamelContext -import org.apache.camel.impl.DefaultCamelContext -import spock.lang.Specification - -/** - * @author Marcin Grzejszczak - * @since - */ -class ContractVerifierCamelMessageBuilderSpec extends Specification { - def "should not throw an exception when headers are null"() { - given: - CamelContext camelContext = new DefaultCamelContext() - ContractVerifierCamelMessageBuilder builder = new ContractVerifierCamelMessageBuilder(camelContext) - when: - builder.create(null, null) - then: - noExceptionThrown() - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierObjectMapperSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierObjectMapperSpec.groovy deleted file mode 100644 index 20ac154f9e..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierObjectMapperSpec.groovy +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.internal - - -import spock.lang.Specification - -class ContractVerifierObjectMapperSpec extends Specification { - - ContractVerifierObjectMapper mapper = new ContractVerifierObjectMapper() - - def "should convert an object into a json representation"() { - given: - MyClass input = new MyClass(foo: "bar") - when: - String result = mapper.writeValueAsString(input) - then: - result == '''{"foo":"bar"}''' - } - - def "should convert bytes into a json representation"() { - given: - String input = '''{"foo":"bar"}''' - when: - String result = mapper.writeValueAsString(input.bytes) - then: - result == '''{"foo":"bar"}''' - } - - def "should convert an object into a byte[] representation"() { - given: - MyClass input = new MyClass(foo: "bar") - when: - byte[] result = mapper.writeValueAsBytes(input) - then: - result == '''{"foo":"bar"}'''.bytes - } - - def "should convert a String into a byte[] representation"() { - when: - byte[] result = mapper.writeValueAsBytes('''{"foo":"bar"}''') - then: - result == '''{"foo":"bar"}'''.bytes - } - - def "should pass byte[] as a byte[] representation"() { - when: - byte[] result = mapper.writeValueAsBytes('''{"foo":"bar"}'''.bytes) - then: - result == '''{"foo":"bar"}'''.bytes - } - - static class MyClass { - String foo - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/messaging/stream/ContractVerifierHelperForStreamTest.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/messaging/stream/ContractVerifierHelperForStreamTest.groovy deleted file mode 100644 index a42898ff33..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/messaging/stream/ContractVerifierHelperForStreamTest.groovy +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.stream - -import spock.lang.Specification - -/** - * @author Marcin Grzejszczak - */ -class ContractVerifierHelperForStreamTest extends Specification { - - def 'should throw exception when a null payload was sent'() { - given: - ContractVerifierHelper helper = new ContractVerifierHelper(null, null) - when: - helper.convert(null) - then: - IllegalArgumentException e = thrown(IllegalArgumentException) - e.message.contains("Message must not be null") - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/messaging/stream/StreamStubMessagesWithDestinationsSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/messaging/stream/StreamStubMessagesWithDestinationsSpec.groovy deleted file mode 100644 index 105c7e74c2..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/messaging/stream/StreamStubMessagesWithDestinationsSpec.groovy +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.stream - -import spock.lang.Issue -import spock.lang.Specification - -import org.springframework.cloud.stream.binder.test.InputDestination -import org.springframework.cloud.stream.binder.test.OutputDestination -import org.springframework.cloud.stream.function.StreamFunctionProperties -import org.springframework.context.ApplicationContext -/** - * @author Marcin Grzejszczak - */ -class StreamStubMessagesWithDestinationsSpec extends Specification { - - @Issue("694") - def "should resolve input channel if input and output have same destination and receive is called"() { - given: - ApplicationContext applicationContext = Mock(ApplicationContext) - StreamFunctionProperties functionProperties = new StreamFunctionProperties(definition: 'verifications') - OutputDestination output = Mock(OutputDestination) - and: - applicationContext.getBean(OutputDestination) >> output - applicationContext.getBean(StreamFunctionProperties) >> functionProperties - and: - StreamOutputDestinationMessageReceiver messages = new StreamOutputDestinationMessageReceiver(applicationContext) - when: - messages.receive("verifications") - then: - 1 * output.receive(5000, 'verifications') >> null - } - - @Issue("694") - def "should resolve output channel if input and output have same destination and send is called"() { - given: - ApplicationContext applicationContext = Mock(ApplicationContext) - StreamFunctionProperties functionProperties = new StreamFunctionProperties(definition: 'verifications') - InputDestination input = Mock(InputDestination) - and: - applicationContext.getBean(InputDestination) >> input - applicationContext.getBean(StreamFunctionProperties) >> functionProperties - and: - StreamInputDestinationMessageSender messages = new StreamInputDestinationMessageSender(applicationContext) - when: - messages.send("foo", [:], "verifications") - then: - 1 * input.send(_, 'verifications') - } - - def "should resolve channel via destination for send"() { - given: - ApplicationContext applicationContext = Mock(ApplicationContext) - StreamFunctionProperties functionProperties = new StreamFunctionProperties(definition: 'verifications') - InputDestination input = Mock(InputDestination) - OutputDestination output = Mock(OutputDestination) - and: - applicationContext.getBean(InputDestination) >> input - applicationContext.getBean(OutputDestination) >> output - applicationContext.getBean(StreamFunctionProperties) >> functionProperties - and: - StreamStubMessages messages = new StreamStubMessages(new StreamInputDestinationMessageSender(applicationContext), new StreamOutputDestinationMessageReceiver(applicationContext)) - when: - messages.send("foo", [:], "verifications") - then: - 1 * input.send(_, 'verifications') - } - - def "should resolve channel via destination for receive"() { - given: - ApplicationContext applicationContext = Mock(ApplicationContext) - StreamFunctionProperties functionProperties = new StreamFunctionProperties(definition: 'verifications') - InputDestination input = Mock(InputDestination) - OutputDestination output = Mock(OutputDestination) - and: - applicationContext.getBean(InputDestination) >> input - applicationContext.getBean(OutputDestination) >> output - applicationContext.getBean(StreamFunctionProperties) >> functionProperties - and: - StreamStubMessages messages = new StreamStubMessages(new StreamInputDestinationMessageSender(applicationContext), new StreamOutputDestinationMessageReceiver(applicationContext)) - when: - messages.receive("verifications") - then: - 1 * output.receive(5000, 'verifications') >> null - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/BodyExtractorSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/BodyExtractorSpec.groovy deleted file mode 100644 index e45e582fef..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/BodyExtractorSpec.groovy +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util - -import org.springframework.cloud.contract.spec.internal.FromFileProperty -import spock.lang.Specification - -/** - * @author Adam BiaÅ‚as - */ -class BodyExtractorSpec extends Specification { - - def "should extract body from json file"() { - given: - def uri = BodyExtractorSpec.getResource("/classpath/response.json").toURI() - def jsonFromFile = new FromFileProperty(new File(uri), String.class) - expect: - ["status" : "RESPONSE"] == BodyExtractor.extractClientValueFromBody(jsonFromFile) - } - -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/ContentUtilsSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/ContentUtilsSpec.groovy deleted file mode 100644 index 045eac5f61..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/ContentUtilsSpec.groovy +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util - - -import org.springframework.cloud.contract.spec.internal.DslProperty -import spock.lang.Specification -import org.xml.sax.helpers.DefaultHandler -import groovy.xml.XmlSlurper - -/** - * @author Marcin Grzejszczak - * @author Konstantin Shevchuk - */ -class ContentUtilsSpec extends Specification { - - def "should return the stub side"() { - given: - DslProperty dslProperty = new DslProperty<>("stub", "test") - expect: - "stub" == ContentUtils.GET_STUB_SIDE(dslProperty) - } - - def "should return the test side"() { - given: - DslProperty dslProperty = new DslProperty<>("stub", "test") - expect: - "test" == ContentUtils.GET_TEST_SIDE(dslProperty) - } - - def "should return XmlSlurper with default error handler"() { - given: - XmlSlurper xmlSlurper = ContentUtils.getXmlSlurperWithDefaultErrorHandler() - expect: - xmlSlurper.getErrorHandler() instanceof DefaultHandler - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/ContractVerifierDslConverterSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/ContractVerifierDslConverterSpec.groovy deleted file mode 100644 index 84241ce733..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/ContractVerifierDslConverterSpec.groovy +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util - -import spock.lang.Specification - -import org.springframework.cloud.contract.spec.Contract - -/** - * @author Marcin Grzejszczak - */ -class ContractVerifierDslConverterSpec extends Specification { - - URL single = ContractVerifierDslConverterSpec.getResource("/contract.groovy") - File singleContract = new File(single.toURI()) - URL singleJava = ContractVerifierDslConverterSpec.getResource("/contractsToCompile/contract.java") - File singleContractJava = new File(singleJava.toURI()) - URL singleRestJava = ContractVerifierDslConverterSpec.getResource("/contractsToCompile/contract_rest.java") - File singleContractRestJava = new File(singleRestJava.toURI()) - URL multiple = ContractVerifierDslConverterSpec.getResource("/multiple_contracts.groovy") - File multipleContracts = new File(multiple.toURI()) - URL invalid = ContractVerifierDslConverterSpec.getResource("/contract.yml") - File invalidContract = new File(invalid.toURI()) - - Contract expectedSingleContract = Contract.make { - name("contract") - request { - method('PUT') - headers { - contentType(applicationJson()) - } - body(""" { "status" : "OK" } """) - url("/1") - } - response { - status OK() - body(""" { "status" : "OK" } """) - headers { - contentType(textPlain()) - } - } - } - - Contract expectedSingleContractForJava = Contract.make( { - description("Some description"); - name("some name"); - priority(8); - ignored(); - request( { - url("/foo", { - queryParameters({ - parameter("a", "b"); - parameter("b", "c"); - }); - }); - method(PUT()); - headers( { - header("foo", value(client(regex("bar")), server("bar"))); - header("fooReq", "baz"); - }); - body(ContractVerifierUtil.map().entry("foo", "bar")); - bodyMatchers( { - jsonPath("\$.foo", byRegex("bar")); - }); - }); - response( { - fixedDelayMilliseconds(1000); - status(OK()); - headers( { - header("foo2", value(server(regex("bar")), client("bar"))); - header("foo3", value(server(execute("andMeToo(\$it)")), - client("foo33"))); - header("fooRes", "baz"); - }); - body(ContractVerifierUtil.map().entry("foo2", "bar") - .entry("foo3", "baz").entry("nullValue", null)); - bodyMatchers( { - jsonPath("\$.foo2", byRegex("bar")); - jsonPath("\$.foo3", byCommand("executeMe(\$it)")); - jsonPath("\$.nullValue", byNull()); - }); - }); - }) - - Contract expectedSingleContractForText = Contract.make { - request { - method('PUT') - headers { - contentType(applicationJson()) - } - body(""" { "status" : "OK" } """) - url("/1") - } - response { - status OK() - body(""" { "status" : "OK" } """) - headers { - contentType(textPlain()) - } - } - } - - List expectedMultipleContracts = (1..2).collect { int index -> - Contract.make { - name("multiple_contracts_${index - 1}") - request { - method('PUT') - headers { - contentType(applicationJson()) - } - body(""" { "status" : "OK" } """) - url("/${index}") - } - response { - status OK() - body(""" { "status" : "OK" } """) - headers { - contentType(textPlain()) - } - } - } - } - - List expectedMultipleContractsForText = (1..2).collect { int index -> - Contract.make { - request { - method('PUT') - headers { - contentType(applicationJson()) - } - body(""" { "status" : "OK" } """) - url("/${index}") - } - response { - status OK() - body(""" { "status" : "OK" } """) - headers { - contentType(textPlain()) - } - } - } - } - - def "should convert file to a list of Contracts"() { - when: - List contract = ContractVerifierDslConverter.convertAsCollection(new File("/"), multipleContracts) - then: - contract == expectedMultipleContracts - } - - def "should convert text to a list of Contracts"() { - when: - Collection contract = ContractVerifierDslConverter.convertAsCollection(new File("/"), multipleContracts.text) - then: - contract == expectedMultipleContractsForText - } - - def "should throw an exception when an invalid file is parsed"() { - when: - ContractVerifierDslConverter.convertAsCollection(new File("/"), invalidContract.text) - then: - thrown(DslParseException) - } - - def "should throw an exception with file path when an invalid file is parsed"() { - when: - ContractVerifierDslConverter.convertAsCollection(new File("/"), invalidContract) - then: - DslParseException e = thrown(DslParseException) - e.toString().contains("contract.yml") - } - - def "should throw an exception when a non existent file is parsed"() { - when: - ContractVerifierDslConverter.convertAsCollection(new File("/"), new File("/foo/bar/baz.foo")) - then: - DslParseException e = thrown(DslParseException) - e.cause instanceof FileNotFoundException - } - - def "should convert file to a list of Contracts when there's only one declared contract"() { - when: - Collection contract = ContractVerifierDslConverter.convertAsCollection(new File("/"), singleContract) - then: - contract == [expectedSingleContract] - } - - def "should convert file to a list of Contracts when there's only one declared java contract"() { - when: - Collection contract = ContractVerifierDslConverter.convertAsCollection(new File("/"), singleContractJava) - then: - contract == [expectedSingleContract] - } - - def "should convert file to a list of Contracts for a REST contract for docs"() { - when: - Collection contract = ContractVerifierDslConverter.convertAsCollection(new File("/"), singleContractRestJava) - then: - contract == [expectedSingleContractForJava] - } - - def "should convert text to a list of Contracts when there's only one declared contract"() { - when: - Collection contract = ContractVerifierDslConverter.convertAsCollection(new File("/"), singleContract.text) - then: - contract == [expectedSingleContractForText] - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/JsonToJsonPathsConverterSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/JsonToJsonPathsConverterSpec.groovy deleted file mode 100644 index e99c4a7bbe..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/JsonToJsonPathsConverterSpec.groovy +++ /dev/null @@ -1,924 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util - -import java.util.regex.Pattern - -import com.jayway.jsonpath.Configuration -import com.jayway.jsonpath.DocumentContext -import com.jayway.jsonpath.JsonPath -import com.jayway.jsonpath.Option -import com.toomuchcoding.jsonassert.JsonAssertion -import groovy.json.JsonOutput -import groovy.json.JsonSlurper -import net.minidev.json.JSONArray -import spock.lang.Specification -import spock.util.environment.RestoreSystemProperties - -import org.springframework.cloud.contract.spec.internal.BodyMatcher -import org.springframework.cloud.contract.spec.internal.MatchingType - -class JsonToJsonPathsConverterSpec extends Specification { - - def 'should convert a json with list as root to a map of path to value'() { - when: - JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json)) - then: - pathAndValues.find { - it.method() == """.array().field("['some']").field("['nested']").field("['json']").isEqualTo("with value")""" && - it.jsonPath() == '''$[*].['some'].['nested'][?(@.['json'] == 'with value')]''' - } - pathAndValues.find { - it.method() == """.array().field("['some']").field("['nested']").field("['anothervalue']").isEqualTo(4)""" && - it.jsonPath() == '''$[*].['some'].['nested'][?(@.['anothervalue'] == 4)]''' - } - pathAndValues.find { - it.method() == """.array().field("['some']").field("['nested']").array("['withlist']").contains("['name']").isEqualTo("name1")""" && - it.jsonPath() == '''$[*].['some'].['nested'].['withlist'][*][?(@.['name'] == 'name1')]''' - } - pathAndValues.find { - it.method() == """.array().field("['some']").field("['nested']").array("['withlist']").contains("['name']").isEqualTo("name2")""" && - it.jsonPath() == '''$[*].['some'].['nested'].['withlist'][*][?(@.['name'] == 'name2')]''' - } - pathAndValues.find { - it.method() == """.array().field("['some']").field("['nested']").array("['withlist']").field("['anothernested']").field("['name']").isEqualTo("name3")""" && - it.jsonPath() == '''$[*].['some'].['nested'].['withlist'][*].['anothernested'][?(@.['name'] == 'name3')]''' - } - and: - assertThatJsonPathsInMapAreValid(json, pathAndValues) - where: - json << [ - ''' - [ { - "some" : { - "nested" : { - "json" : "with value", - "anothervalue": 4, - "withlist" : [ - { "name" :"name1"} , {"name": "name2"}, {"anothernested": { "name": "name3"} } - ] - } - } - }, - { - "someother" : { - "nested" : { - "json" : "with value", - "anothervalue": 4, - "withlist" : [ - { "name" :"name1"} , {"name": "name2"} - ] - } - } - } - ] - ''', - ''' - [{ - "someother" : { - "nested" : { - "json" : "with value", - "anothervalue": 4, - "withlist" : [ - { "name" :"name1"} , {"name": "name2"} - ] - } - } - }, - { - "some" : { - "nested" : { - "json" : "with value", - "anothervalue": 4, - "withlist" : [ - {"name": "name2"}, {"anothernested": { "name": "name3"} }, { "name" :"name1"} - ] - } - } - } - ]'''] - } - - def 'should convert a json with a map as root to a map of path to value'() { - given: - String json = ''' - { - "some" : { - "nested" : { - "json" : "with value", - "anothervalue": 4, - "withlist" : [ - { "name" :"name1"} , {"name": "name2"} - ] - } - } - } -''' - when: - JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json)) - then: - pathAndValues.find { - it.method() == """.field("['some']").field("['nested']").field("['json']").isEqualTo("with value")""" && - it.jsonPath() == '''$.['some'].['nested'][?(@.['json'] == 'with value')]''' - } - pathAndValues.find { - it.method() == """.field("['some']").field("['nested']").field("['anothervalue']").isEqualTo(4)""" && - it.jsonPath() == '''$.['some'].['nested'][?(@.['anothervalue'] == 4)]''' - } - pathAndValues.find { - it.method() == """.field("['some']").field("['nested']").array("['withlist']").contains("['name']").isEqualTo("name1")""" && - it.jsonPath() == '''$.['some'].['nested'].['withlist'][*][?(@.['name'] == 'name1')]''' - } - pathAndValues.find { - it.method() == """.field("['some']").field("['nested']").array("['withlist']").contains("['name']").isEqualTo("name2")""" && - it.jsonPath() == '''$.['some'].['nested'].['withlist'][*][?(@.['name'] == 'name2')]''' - } - and: - assertThatJsonPathsInMapAreValid(json, pathAndValues) - } - - def 'should convert a json with a list'() { - given: - String json = ''' - { - "items" : ["HOP"] - } -''' - when: - JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json)) - then: - pathAndValues.find { - it.method() == """.array("['items']").arrayField().isEqualTo("HOP").value()""" && - it.jsonPath() == '''$.['items'][?(@ == 'HOP')]''' - } - and: - assertThatJsonPathsInMapAreValid(json, pathAndValues) - } - - def 'should convert a json with null and boolean values'() { - given: - String json = ''' - { - "property1" : null, - "property2" : true - } -''' - when: - JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json)) - then: - pathAndValues.find { - it.method() == """.field("['property1']").isNull()""" && - it.jsonPath() == '''$[?(@.['property1'] == null)]''' - } - pathAndValues.find { - it.method() == """.field("['property2']").isEqualTo(true)""" && - it.jsonPath() == '''$[?(@.['property2'] == true)]''' - } - } - - def "should convert numbers map"() { - given: - String json = ''' { - "extensions": {"7":28.00,"14":41.00,"30":60.00} - } - ''' - when: - JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json)) - then: - pathAndValues.find { - it.method() == """.field("['extensions']").field("['7']").isEqualTo(28.00)""" && - it.jsonPath() == '''$.['extensions'][?(@.['7'] == 28.00)]''' - } - pathAndValues.find { - it.method() == """.field("['extensions']").field("['14']").isEqualTo(41.00)""" && - it.jsonPath() == '''$.['extensions'][?(@.['14'] == 41.00)]''' - } - pathAndValues.find { - it.method() == """.field("['extensions']").field("['30']").isEqualTo(60.00)""" && - it.jsonPath() == '''$.['extensions'][?(@.['30'] == 60.00)]''' - } - and: - assertThatJsonPathsInMapAreValid(json, pathAndValues) - } - - def 'should convert a json with a list of errors'() { - given: - String json = ''' - { - "errors" : [ - { "property" : "email", "message" : "inconsistent value" }, - { "property" : "email", "message" : "inconsistent value2" } - ] - } -''' - when: - JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json)) - then: - pathAndValues.find { - it.method() == """.array("['errors']").contains("['property']").isEqualTo("email")""" && - it.jsonPath() == '''$.['errors'][*][?(@.['property'] == 'email')]''' - } - pathAndValues.find { - it.method() == """.array("['errors']").contains("['message']").isEqualTo("inconsistent value")""" && - it.jsonPath() == '''$.['errors'][*][?(@.['message'] == 'inconsistent value')]''' - } - pathAndValues.find { - it.method() == """.array("['errors']").contains("['message']").isEqualTo("inconsistent value2")""" && - it.jsonPath() == '''$.['errors'][*][?(@.['message'] == 'inconsistent value2')]''' - } - and: - assertThatJsonPathsInMapAreValid(json, pathAndValues) - } - - def 'should convert a map json with a regex pattern'() { - given: - List json = [ - [some: - [nested: [ - json : "with value", - anothervalue: 4, - withlist : - [ - [name: "name2"], - [name: "name1"], - [anothernested: - [name: Pattern.compile("[a-zA-Z]+")] - ], - [age: "123456789"] - ] - ] - ] - ], - [someother: - [nested: [ - json : "with value", - anothervalue: 4, - withlist : - [ - [name: "name2"], - [name: "name1"] - ] - ] - ] - ] - ] - when: - JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(json) - then: - pathAndValues.find { - it.method() == """.array().field("['some']").field("['nested']").field("['json']").isEqualTo("with value")""" && - it.jsonPath() == '''$[*].['some'].['nested'][?(@.['json'] == 'with value')]''' - } - pathAndValues.find { - it.method() == """.array().field("['some']").field("['nested']").field("['anothervalue']").isEqualTo(4)""" && - it.jsonPath() == '''$[*].['some'].['nested'][?(@.['anothervalue'] == 4)]''' - } - pathAndValues.find { - it.method() == """.array().field("['some']").field("['nested']").array("['withlist']").contains("['name']").isEqualTo("name1")""" && - it.jsonPath() == '''$[*].['some'].['nested'].['withlist'][*][?(@.['name'] == 'name1')]''' - } - pathAndValues.find { - it.method() == """.array().field("['some']").field("['nested']").array("['withlist']").contains("['name']").isEqualTo("name2")""" && - it.jsonPath() == '''$[*].['some'].['nested'].['withlist'][*][?(@.['name'] == 'name2')]''' - } - pathAndValues.find { - it.method() == """.array().field("['some']").field("['nested']").array("['withlist']").field("['anothernested']").field("['name']").matches("[a-zA-Z]+")""" && - it.jsonPath() == '''$[*].['some'].['nested'].['withlist'][*].['anothernested'][?(@.['name'] =~ /[a-zA-Z]+/)]''' - } - when: - json.some.nested.withlist[0][2].anothernested.name = "Kowalski" - then: - assertThatJsonPathsInMapAreValid(JsonOutput.prettyPrint(JsonOutput.toJson(json)), pathAndValues) - } - - - def "should generate assertions for simple response body"() { - given: - String json = """{ - "property1": "a", - "property2": "b" - }""" - when: - JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json)) - then: - pathAndValues.find { - it.method() == """.field("['property1']").isEqualTo("a")""" && - it.jsonPath() == """\$[?(@.['property1'] == 'a')]""" - } - pathAndValues.find { - it.method() == """.field("['property2']").isEqualTo("b")""" && - it.jsonPath() == """\$[?(@.['property2'] == 'b')]""" - } - and: - pathAndValues.size() == 2 - } - - def "should generate assertions for null and boolean values"() { - given: - String json = """{ - "property1": "true", - "property2": null, - "property3": false - }""" - when: - JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json)) - then: - pathAndValues.find { - it.method() == """.field("['property1']").isEqualTo("true")""" && - it.jsonPath() == """\$[?(@.['property1'] == 'true')]""" - } - pathAndValues.find { - it.method() == """.field("['property2']").isNull()""" && - it.jsonPath() == """\$[?(@.['property2'] == null)]""" - } - pathAndValues.find { - it.method() == """.field("['property3']").isEqualTo(false)""" && - it.jsonPath() == """\$[?(@.['property3'] == false)]""" - } - and: - pathAndValues.size() == 3 - } - - def "should generate assertions for simple response body constructed from map with a list"() { - given: - Map json = [ - property1: 'a', - property2: [ - [a: 'sth'], - [b: 'sthElse'] - ] - ] - when: - JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(json) - then: - pathAndValues.find { - it.method() == """.field("['property1']").isEqualTo("a")""" && - it.jsonPath() == """\$[?(@.['property1'] == 'a')]""" - } - pathAndValues.find { - it.method() == """.array("['property2']").contains("['a']").isEqualTo("sth")""" && - it.jsonPath() == """\$.['property2'][*][?(@.['a'] == 'sth')]""" - } - pathAndValues.find { - it.method() == """.array("['property2']").contains("['b']").isEqualTo("sthElse")""" && - it.jsonPath() == """\$.['property2'][*][?(@.['b'] == 'sthElse')]""" - } - and: - pathAndValues.size() == 3 - } - - @RestoreSystemProperties - def "should generate assertions for simple response body constructed from map with a list with array size check"() { - given: - System.setProperty('spring.cloud.contract.verifier.assert.size', 'true') - Map json = [ - property1: 'a', - property2: [ - [a: 'sth'], - [b: 'sthElse'] - ] - ] - when: - JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(json) - then: - pathAndValues.find { - it.method() == """.field("['property1']").isEqualTo("a")""" && - it.jsonPath() == """\$[?(@.['property1'] == 'a')]""" - } - pathAndValues.find { - it.method() == """.array("['property2']").contains("['a']").isEqualTo("sth")""" && - it.jsonPath() == """\$.['property2'][*][?(@.['a'] == 'sth')]""" - } - pathAndValues.find { - it.method() == """.array("['property2']").hasSize(2)""" && - it.jsonPath() == """\$.['property2'][*]""" - } - pathAndValues.find { - it.method() == """.array("['property2']").contains("['b']").isEqualTo("sthElse")""" && - it.jsonPath() == """\$.['property2'][*][?(@.['b'] == 'sthElse')]""" - } - and: - pathAndValues.size() == 4 - } - - def "should generate assertions for a response body containing map with integers as keys"() { - given: - Map json = [ - property: [ - 14: 0.0, - 7 : 0.0 - ] - ] - when: - JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(json) - then: - pathAndValues.find { - it.method() == """.field("['property']").field(7).isEqualTo(0.0)""" && - it.jsonPath() == """\$.['property'][?(@.7 == 0.0)]""" - } - pathAndValues.find { - it.method() == """.field("['property']").field(14).isEqualTo(0.0)""" && - it.jsonPath() == """\$.['property'][?(@.14 == 0.0)]""" - } - and: - pathAndValues.size() == 2 - } - - def "should generate assertions for array in response body"() { - given: - String json = """[ - { - "property1": "a" - }, - { - "property2": "b" - }]""" - when: - JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json)) - then: - pathAndValues.find { - it.method() == """.array().contains("['property1']").isEqualTo("a")""" && - it.jsonPath() == """\$[*][?(@.['property1'] == 'a')]""" - } - pathAndValues.find { - it.method() == """.array().contains("['property2']").isEqualTo("b")""" && - it.jsonPath() == """\$[*][?(@.['property2'] == 'b')]""" - } - and: - pathAndValues.size() == 2 - } - - @RestoreSystemProperties - def "should generate assertions for array in response body with array size check"() { - given: - System.setProperty('spring.cloud.contract.verifier.assert.size', 'true') - String json = """[ - { - "property1": "a" - }, - { - "property2": "b" - }]""" - when: - JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json)) - then: - pathAndValues.find { - it.method() == """.array().contains("['property1']").isEqualTo("a")""" && - it.jsonPath() == """\$[*][?(@.['property1'] == 'a')]""" - } - pathAndValues.find { - it.method() == """.array().contains("['property2']").isEqualTo("b")""" && - it.jsonPath() == """\$[*][?(@.['property2'] == 'b')]""" - } - pathAndValues.find { - it.method() == """.hasSize(2)""" && - it.jsonPath() == """\$""" - } - and: - pathAndValues.size() == 3 - } - - def "should generate assertions for array inside response body element"() { - given: - String json = """{ - "property1": [ - { "property2": "test1"}, - { "property3": "test2"} - ] -}""" - when: - JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json)) - then: - pathAndValues.find { - it.method() == """.array("['property1']").contains("['property2']").isEqualTo("test1")""" && - it.jsonPath() == """\$.['property1'][*][?(@.['property2'] == 'test1')]""" - } - pathAndValues.find { - it.method() == """.array("['property1']").contains("['property3']").isEqualTo("test2")""" && - it.jsonPath() == """\$.['property1'][*][?(@.['property3'] == 'test2')]""" - } - and: - pathAndValues.size() == 2 - } - - @RestoreSystemProperties - def "should generate assertions for array inside response body element with array size check"() { - given: - System.setProperty('spring.cloud.contract.verifier.assert.size', 'true') - String json = """{ - "property1": [ - { "property2": "test1"}, - { "property3": "test2"} - ] -}""" - when: - JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json)) - then: - pathAndValues.find { - it.method() == """.array("['property1']").contains("['property2']").isEqualTo("test1")""" && - it.jsonPath() == """\$.['property1'][*][?(@.['property2'] == 'test1')]""" - } - pathAndValues.find { - it.method() == """.array("['property1']").contains("['property3']").isEqualTo("test2")""" && - it.jsonPath() == """\$.['property1'][*][?(@.['property3'] == 'test2')]""" - } - pathAndValues.find { - it.method() == """.array("['property1']").hasSize(2)""" && - it.jsonPath() == """\$.['property1'][*]""" - } - and: - pathAndValues.size() == 3 - } - - def "should generate assertions for nested objects in response body"() { - given: - String json = """{ - "property1": "a", - "property2": {"property3": "b"} - }""" - when: - JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json)) - then: - pathAndValues.find { - it.method() == """.field("['property2']").field("['property3']").isEqualTo("b")""" && - it.jsonPath() == """\$.['property2'][?(@.['property3'] == 'b')]""" - } - pathAndValues.find { - it.method() == """.field("['property1']").isEqualTo("a")""" && - it.jsonPath() == """\$[?(@.['property1'] == 'a')]""" - } - and: - pathAndValues.size() == 2 - } - - def "should generate regex assertions for map objects in response body"() { - given: - Map json = [ - property1: "a", - property2: Pattern.compile('[0-9]{3}') - ] - when: - JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(json) - then: - pathAndValues.find { - it.method() == """.field("['property2']").matches("[0-9]{3}")""" && - it.jsonPath() == """\$[?(@.['property2'] =~ /[0-9]{3}/)]""" - } - pathAndValues.find { - it.method() == """.field("['property1']").isEqualTo("a")""" && - it.jsonPath() == """\$[?(@.['property1'] == 'a')]""" - } - and: - pathAndValues.size() == 2 - } - - def "should generate escaped regex assertions for string objects in response body"() { - given: - Map json = [ - property2: Pattern.compile('\\d+') - ] - when: - JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(json) - then: - pathAndValues.find { - it.method() == """.field("['property2']").matches("\\\\d+")""" && - it.jsonPath() == """\$[?(@.['property2'] =~ /\\d+/)]""" - } - and: - pathAndValues.size() == 1 - } - - def "should work with more complex stuff and jsonpaths"() { - given: - Map json = [ - errors: [ - [property: "bank_account_number", - message : "incorrect_format"] - ] - ] - when: - JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(json) - then: - pathAndValues.find { - it.method() == """.array("['errors']").contains("['property']").isEqualTo("bank_account_number")""" && - it.jsonPath() == """\$.['errors'][*][?(@.['property'] == 'bank_account_number')]""" - } - pathAndValues.find { - it.method() == """.array("['errors']").contains("['message']").isEqualTo("incorrect_format")""" && - it.jsonPath() == """\$.['errors'][*][?(@.['message'] == 'incorrect_format')]""" - } - and: - pathAndValues.size() == 2 - } - - @RestoreSystemProperties - def "should work with more complex stuff and jsonpaths with array size check"() { - given: - System.setProperty('spring.cloud.contract.verifier.assert.size', 'true') - Map json = [ - errors: [ - [property: "bank_account_number", - message : "incorrect_format"] - ] - ] - when: - JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(json) - then: - pathAndValues.find { - it.method() == """.array("['errors']").contains("['property']").isEqualTo("bank_account_number")""" && - it.jsonPath() == """\$.['errors'][*][?(@.['property'] == 'bank_account_number')]""" - } - pathAndValues.find { - it.method() == """.array("['errors']").contains("['message']").isEqualTo("incorrect_format")""" && - it.jsonPath() == """\$.['errors'][*][?(@.['message'] == 'incorrect_format')]""" - } - pathAndValues.find { - it.method() == """.array("['errors']").hasSize(1)""" && - it.jsonPath() == """\$.['errors'][*]""" - } - and: - pathAndValues.size() == 3 - } - - def "should manage to parse a double array"() { - given: - String json = ''' - [{ - "place": - { - "bounding_box": - { - "coordinates": - [[ - [-77.119759,38.995548], - [-76.909393,38.791645] - ]] - } - } - }] - ''' - when: - JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json)) - then: - DocumentContext context = JsonPath.parse(json) - pathAndValues.each { - assert context.read(it.jsonPath(), JSONArray) - } - and: - pathAndValues.find { - it.method() == """.array().field("['place']").field("['bounding_box']").array("['coordinates']").array().array().arrayField().isEqualTo(38.995548)""" && - it.jsonPath() == """\$[*].['place'].['bounding_box'].['coordinates'][*][*][?(@ == 38.995548)]""" - } - pathAndValues.find { - it.method() == """.array().field("['place']").field("['bounding_box']").array("['coordinates']").array().array().arrayField().isEqualTo(-77.119759)""" && - it.jsonPath() == """\$[*].['place'].['bounding_box'].['coordinates'][*][*][?(@ == -77.119759)]""" - } - pathAndValues.find { - it.method() == """.array().field("['place']").field("['bounding_box']").array("['coordinates']").array().array().arrayField().isEqualTo(-76.909393)""" && - it.jsonPath() == """\$[*].['place'].['bounding_box'].['coordinates'][*][*][?(@ == -76.909393)]""" - } - pathAndValues.find { - it.method() == """.array().field("['place']").field("['bounding_box']").array("['coordinates']").array().array().arrayField().isEqualTo(38.791645)""" && - it.jsonPath() == """\$[*].['place'].['bounding_box'].['coordinates'][*][*][?(@ == 38.791645)]""" - } - and: - pathAndValues.size() == 4 - and: - pathAndValues.each { - JsonAssertion.assertThat(json).matchesJsonPath(it.jsonPath()) - } - } - - @RestoreSystemProperties - def "should manage to parse a double array with array size check"() { - given: - System.setProperty('spring.cloud.contract.verifier.assert.size', 'true') - String json = ''' - [{ - "place": - { - "bounding_box": - { - "coordinates": - [[ - [-77.119759,38.995548], - [-76.909393,38.791645] - ]] - } - } - }] - ''' - when: - JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json)) - then: - DocumentContext context = JsonPath.parse(json) - pathAndValues.each { - assert context.read(it.jsonPath(), JSONArray) - } - pathAndValues.find { - it.method() == """.hasSize(1)""" && - it.jsonPath() == """\$""" - } - pathAndValues.find { - it.method() == """.array().field("['place']").field("['bounding_box']").array("['coordinates']").array().array().arrayField().isEqualTo(-77.119759)""" && - it.jsonPath() == """\$[*].['place'].['bounding_box'].['coordinates'][*][*][?(@ == -77.119759)]""" - } - pathAndValues.find { - it.method() == """.array().field("['place']").field("['bounding_box']").array("['coordinates']").array().array().arrayField().isEqualTo(38.995548)""" && - it.jsonPath() == """\$[*].['place'].['bounding_box'].['coordinates'][*][*][?(@ == 38.995548)]""" - } - pathAndValues.find { - it.method() == """.array().field("['place']").field("['bounding_box']").array("['coordinates']").hasSize(1)""" && - it.jsonPath() == """\$[*].['place'].['bounding_box'].['coordinates'][*]""" - } - pathAndValues.find { - it.method() == """.array().field("['place']").field("['bounding_box']").array("['coordinates']").array().hasSize(2)""" && - it.jsonPath() == """\$[*].['place'].['bounding_box'].['coordinates'][*][*]""" - } - pathAndValues.find { - it.method() == """.array().field("['place']").field("['bounding_box']").array("['coordinates']").array().array().arrayField().isEqualTo(38.791645)""" && - it.jsonPath() == """\$[*].['place'].['bounding_box'].['coordinates'][*][*][?(@ == 38.791645)]""" - } - pathAndValues.find { - it.method() == """.array().field("['place']").field("['bounding_box']").array("['coordinates']").array().array().hasSize(2)""" && - it.jsonPath() == """\$[*].['place'].['bounding_box'].['coordinates'][*][*]""" - } - pathAndValues.find { - it.method() == """.array().field("['place']").field("['bounding_box']").array("['coordinates']").array().array().arrayField().isEqualTo(-76.909393)""" && - it.jsonPath() == """\$[*].['place'].['bounding_box'].['coordinates'][*][*][?(@ == -76.909393)]""" - } - and: - pathAndValues.size() == 8 - and: - pathAndValues.each { - JsonAssertion.assertThat(json).matchesJsonPath(it.jsonPath()) - } - } - - def "should convert a json path with regex to a regex checking json path"() { - given: - String jsonPath = '$.a.b.c.d' - String regexPattern = ".*" - expect: - '$.a.b.c[?(@.d =~ /(.*)/)]' == JsonToJsonPathsConverter.convertJsonPathAndRegexToAJsonPath(matcher(MatchingType.REGEX, jsonPath, regexPattern)) - } - - def "should convert a json path with regex to a regex checking json path that has a / in it"() { - given: - String jsonPath = '$.a.b.c.d' - String regexPattern = "/.*/" - expect: - '$.a.b.c[?(@.d =~ /(\\\\/.*\\\\/)/)]' == JsonToJsonPathsConverter.convertJsonPathAndRegexToAJsonPath(matcher(MatchingType.REGEX, jsonPath, regexPattern)) - } - - def "should convert a json path with value to a equality checking json path without quotes for numbers"() { - given: - String jsonPath = '$.a.b.c.d' - and: - def body = [a: [b: [c: [d: 1234]]]] - expect: - '$.a.b.c[?(@.d == 1234)]' == JsonToJsonPathsConverter.convertJsonPathAndRegexToAJsonPath(matcher(MatchingType.EQUALITY, jsonPath, null), body) - } - - def "should convert a json path with value to a equality checking for a key with dots"() { - given: - String jsonPath = '$.a.b.c.[\'d.e\']' - and: - def body = [a: [b: [c: ["d.e": 1234]]]] - expect: - '$.a.b.c[?(@.[\'d.e\'] == 1234)]' == JsonToJsonPathsConverter.convertJsonPathAndRegexToAJsonPath(matcher(MatchingType.EQUALITY, jsonPath, null), body) - } - - def "should convert a json path with value to a equality checking json path with quotes for strings"() { - given: - String jsonPath = '$.a.b.c.d' - and: - def body = [a: [b: [c: [d: "foo"]]]] - expect: - '$.a.b.c[?(@.d == \'foo\')]' == JsonToJsonPathsConverter.convertJsonPathAndRegexToAJsonPath(matcher(MatchingType.EQUALITY, jsonPath, null), body) - } - - def "should return the path if no value is provided"() { - given: - String jsonPath = '$.a.b.c.d' - expect: - '$.a.b.c.d' == JsonToJsonPathsConverter.convertJsonPathAndRegexToAJsonPath(matcher(MatchingType.REGEX, jsonPath, null)) - } - - def "should throw an exception when null body is passed to check for equality"() { - given: - String jsonPath = '$.a.b.c.d' - and: - def body = null - when: - JsonToJsonPathsConverter.convertJsonPathAndRegexToAJsonPath(matcher(MatchingType.EQUALITY, jsonPath, null), body) - then: - IllegalStateException e = thrown(IllegalStateException) - e.message.contains("Body") - } - - def "should throw an exception when nonexisting jsonpath is passed to check for equality"() { - given: - String jsonPath = '$.a.b.c.d' - and: - def body = [foo: "bar"] - when: - JsonToJsonPathsConverter.convertJsonPathAndRegexToAJsonPath(matcher(MatchingType.EQUALITY, jsonPath, null), body) - then: - IllegalStateException e = thrown(IllegalStateException) - e.message.contains("not found") - } - - def "should generate assertion for empty map"() { - given: - Map json = [ - aMap : ["foo": "bar"], - anEmptyMap: [:] - ] - when: - JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(json) - then: - pathAndValues.find { - it.method() == """.field("['aMap']").field("['foo']").isEqualTo("bar")""" && - it.jsonPath() == """\$.['aMap'][?(@.['foo'] == 'bar')]""" - } - pathAndValues.find { - it.method() == """.field("['anEmptyMap']").isEmpty()""" && - it.jsonPath() == """\$.['anEmptyMap']""" - } - and: - pathAndValues.size() == 2 - } - - def "should generate assertion for empty object"() { - given: - String json = """{ - "aMap": {"foo": "bar"}, - "anEmptyMap": {} - }""" - when: - JsonPaths pathAndValues = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json)) - then: - pathAndValues.find { - it.method() == """.field("['aMap']").field("['foo']").isEqualTo("bar")""" && - it.jsonPath() == """\$.['aMap'][?(@.['foo'] == 'bar')]""" - } - pathAndValues.find { - it.method() == """.field("['anEmptyMap']").isEmpty()""" && - it.jsonPath() == """\$.['anEmptyMap']""" - } - and: - pathAndValues.size() == 2 - } - - private BodyMatcher matcher(final MatchingType matchingType, final String jsonPath, final Object value) { - return new BodyMatcher() { - @Override - MatchingType matchingType() { - return matchingType - } - - @Override - String path() { - return jsonPath - } - - @Override - Object value() { - return value - } - - @Override - Integer minTypeOccurrence() { - return null - } - - @Override - Integer maxTypeOccurrence() { - return null - } - } - } - - private void assertThatJsonPathsInMapAreValid(String json, JsonPaths pathAndValues) { - DocumentContext parsedJson = JsonPath.using(Configuration.builder().options(Option.ALWAYS_RETURN_LIST).build()).parse(json) - pathAndValues.each { - assert !parsedJson.read(it.jsonPath(), JSONArray).empty - } - } - -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/NamesUtilSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/NamesUtilSpec.groovy deleted file mode 100644 index 86428549c7..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/NamesUtilSpec.groovy +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util - -import org.junit.Rule -import org.junit.rules.TemporaryFolder -import spock.lang.Specification - -import org.springframework.util.FileSystemUtils - -/** - * @author Marcin Grzejszczak - */ -class NamesUtilSpec extends Specification { - - @Rule - TemporaryFolder folder = new TemporaryFolder() - - def "should return the whole string before the last one"() { - given: - String string = "a.b.c.d.e" - expect: - NamesUtil.beforeLast(string, ".") == "a.b.c.d" - } - - def "should return empty string when no token was found for before last"() { - given: - String string = "a.b.c.d.e" - expect: - NamesUtil.beforeLast(string, "/") == "" - } - - def "should return first token after the last one"() { - given: - String string = "a.b.c.d.e" - expect: - NamesUtil.afterLast(string, ".") == "e" - } - - def "should return the input string when no token was found for after last"() { - given: - String string = "a.b.c.d.e" - expect: - NamesUtil.afterLast(string, "/") == string - } - - def "should return first token after the last dot"() { - given: - String string = "a.b.c.d.e" - expect: - NamesUtil.afterLastDot(string) == "e" - } - - def "should return the input string when no token was found for after last dot"() { - given: - String string = "abcde" - expect: - NamesUtil.afterLastDot(string) == string - } - - def "should return camel case version of a string"() { - given: - String string = "BlaBlaBla" - expect: - NamesUtil.camelCase(string) == "blaBlaBla" - } - - def "should return capitalized version of a string"() { - given: - String string = "blaBlaBla" - expect: - NamesUtil.capitalize(string) == "BlaBlaBla" - } - - def "should return all text to last dot"() { - given: - String string = "a.b.c.d.e" - expect: - NamesUtil.toLastDot(string) == "a.b.c.d" - } - - def "should return the input string when no token was found for to last dot"() { - given: - String string = "abcde" - expect: - NamesUtil.toLastDot(string) == string - } - - def "should convert a package notation to directory"() { - given: - String string = "a.b.c.d.e" - expect: - NamesUtil.packageToDirectory(string) == "a/b/c/d/e".replace("/", File.separator) - } - - def "should convert a directory notation to package"() { - given: - String string = "a/b/c/d/e".replace("/", File.separator) - expect: - NamesUtil.directoryToPackage(string) == "a.b.c.d.e" - } - - def "should convert a directory notation to package when folder is a digit"() { - given: - String string = "a/b/c/1.0.0/e".replace("/", File.separator) - expect: - NamesUtil.directoryToPackage(string) == "a.b.c._1_0_0.e" - } - - def "should convert a directory notation to package when folder is only a digit"() { - given: - String string = "1.0.0" - expect: - NamesUtil.directoryToPackage(string) == "_1_0_0" - } - - def "should convert all illegal package chars to legal ones"() { - given: - String string = "a-b c.1.0.x+d1174dd" - expect: - NamesUtil.convertIllegalPackageChars(string) == "a_b_c_1_0_x_d1174dd" - } - - def "should convert all illegal method chars to legal ones"() { - given: - String string = '10a-b c.1.0.x+d1174$dd' - expect: - NamesUtil.convertIllegalMethodNameChars(string) == '10a_b_c_1_0_x_d1174$dd' - } - - def "should recursively convert the names of folders to package names"() { - given: - File tmp = folder.newFolder() - URL resource = getClass().getResource("/prependFolderName") - File folder = new File(resource.toURI()) - FileSystemUtils.copyRecursively(folder, tmp) - when: - NamesUtil.recrusiveDirectoryToPackage(tmp) - then: - new File(tmp, "META-INF/1_0_0_SNAPSHOT").exists() == false - new File(tmp, "META-INF/2_0_0_SNAPSHOT").exists() == false - new File(tmp, "META-INF/1_0_0_SNAPSHOT/3_0_0_SNAPSHOT").exists() == false - new File(tmp, "META-INF/_1_0_0_SNAPSHOT").exists() == true - new File(tmp, "META-INF/_2_0_0_SNAPSHOT").exists() == true - new File(tmp, "META-INF/_1_0_0_SNAPSHOT/_3_0_0_SNAPSHOT").exists() == true - new File(tmp, "META-INF/_1_0_0_SNAPSHOT/normal").exists() == true - new File(tmp, "META-INF/_1_0_0_SNAPSHOT/_3_0_0_SNAPSHOT/normal").exists() == true - } - - def "should not throw exception if folder does not exist"() { - when: - NamesUtil.recrusiveDirectoryToPackage(new File("I/do/not/exist")) - then: - noExceptionThrown() - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/SyntaxChecker.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/SyntaxChecker.groovy deleted file mode 100644 index ceb01b0187..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/SyntaxChecker.groovy +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util - -import java.lang.reflect.Method - -import javax.inject.Inject -import javax.ws.rs.client.Entity -import javax.ws.rs.client.WebTarget -import javax.ws.rs.core.Response -import javax.xml.parsers.DocumentBuilder -import javax.xml.parsers.DocumentBuilderFactory - -import com.jayway.jsonpath.DocumentContext -import com.jayway.jsonpath.JsonPath -import com.toomuchcoding.jsonassert.JsonAssertion -import groovy.transform.CompileStatic -import groovy.util.logging.Commons -import org.codehaus.groovy.control.CompilerConfiguration -import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer -import org.codehaus.groovy.control.customizers.ImportCustomizer -import org.junit.Rule -import org.junit.Test -import org.mdkt.compiler.InMemoryJavaCompiler -import org.w3c.dom.Document -import org.xml.sax.InputSource - -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper -import org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil -import org.springframework.util.ReflectionUtils -/** - * checking the syntax of produced scripts - */ -@CompileStatic -@Commons -class SyntaxChecker { - - private static final String[] DEFAULT_IMPORTS = [ - Contract.name, - "io.restassured.response.ResponseOptions", - 'io.restassured.module.mockmvc.specification.*', - 'io.restassured.module.mockmvc.*', - Test.name, - Rule.name, - DocumentContext.name, - JsonPath.name, - Inject.name, - ContractVerifierObjectMapper.name, - ContractVerifierMessage.name, - ContractVerifierMessaging.name, - WebTarget.name, - Response.name, - "io.restassured.module.webtestclient.specification.WebTestClientRequestSpecification", - "io.restassured.module.webtestclient.response.WebTestClientResponse", - DocumentBuilder.name, - DocumentBuilderFactory.name, - Document.name, - InputSource.name, - StringReader.name - ] - - private static final String DEFAULT_IMPORTS_AS_STRING = DEFAULT_IMPORTS.collect { - "import ${it};" - }.join("\n") - - private static final String STATIC_IMPORTS = [ - "io.restassured.module.mockmvc.RestAssuredMockMvc.given", - "io.restassured.module.mockmvc.RestAssuredMockMvc.when", - "io.restassured.RestAssured.*", - "${Entity.name}.*", - "${ContractVerifierUtil.name}.*", - "${ContractVerifierMessagingUtil.name}.headers", - "${JsonAssertion.name}.assertThatJson", - "${SpringCloudContractAssertions.name}.assertThat", - ].collect { "import static ${it};" }.join("\n") - - private static final String WEB_TEST_CLIENT_STATIC_IMPORTS = [ - "io.restassured.module.webtestclient.RestAssuredWebTestClient.*", - "${Entity.name}.*", - "${ContractVerifierUtil.name}.*", - "${ContractVerifierMessagingUtil.name}.headers", - "${JsonAssertion.name}.assertThatJson", - "${SpringCloudContractAssertions.name}.assertThat" - ].collect { "import static ${it};" }.join("\n") - - private static final String dummyMethod = ''' -private void test(String test) { -\t\tassertThat(test).isEqualTo("123"); -\t}''' - - static void tryToCompile(String builderName, String test) { - try { - if (builderName.toLowerCase().contains("spock")) { - tryToCompileGroovy(builderName, test) - } - else { - tryToCompileJava(builderName, test) - } - } catch (Throwable t) { - log.error("Exception occurred while trying to compile the test [\n" + test + "\n]") - throw t - } - } - - static void tryToRun(String builderName, String test) { - try { - if (builderName.toLowerCase().contains("spock")) { - Script script = tryToCompileGroovy(builderName, test) - script.invokeMethod("validate_method()", null) - } - else { - Class clazz = tryToCompileJava(builderName, test) - Method method = ReflectionUtils.findMethod(clazz, "validate_method") - method.invoke(clazz.newInstance()) - } - } catch (Throwable t) { - log.error("Exception occurred while trying to run the test [\n" + test + "\n]") - throw t - } - } - - // no static compilation due to bug in Groovy https://issues.apache.org/jira/browse/GROOVY-8055 - static void tryToCompileWithoutCompileStatic(String builderName, String test) { - if (builderName.toLowerCase().contains("spock")) { - tryToCompileGroovy(builderName, test, false) - } - else { - tryToCompileJava(builderName, test) - } - } - - static Script tryToCompileGroovy(String builderName, String test, boolean compileStatic = false) { - def imports = new ImportCustomizer() - CompilerConfiguration configuration = new CompilerConfiguration() - if (compileStatic) { - configuration.addCompilationCustomizers( - new ASTTransformationCustomizer(CompileStatic)) - } - configuration.addCompilationCustomizers(imports) - String className = className(test) - test = updatedTest(test, className) - return new GroovyShell(SyntaxChecker.classLoader, configuration).parse(test) - } - - private static String updatedTest(String test, String className) { - test.replaceAll("class FooTest", "class " + className) - .replaceAll("import javax.ws.rs.core.Response", "import javax.ws.rs.core.Response; import javax.ws.rs.client.WebTarget;") - } - - private static GString getStaticImports(String builderName) { - if (builderName.toLowerCase().contains('webtestclient')) { - return "$WEB_TEST_CLIENT_STATIC_IMPORTS\n" - } - return "$STATIC_IMPORTS\n" - } - - static Class tryToCompileJava(String builderName, String test) { - String className = className(test) - String fqnClassName = "com.example.${className}" - test = test.replaceAll("class FooTest", "class " + className) - .replaceAll("import javax.ws.rs.core.Response", "import javax.ws.rs.core.Response; import javax.ws.rs.client.WebTarget;") - return compileJava(fqnClassName, test) - - } - - private static Class compileJava(String fqnClassName, String test) { - return InMemoryJavaCompiler.newInstance() - .ignoreWarnings() - .compile(fqnClassName, test) - } - - private static String className(String test) { - Random random = new Random() - int first = Math.abs(random.nextInt()) - int hashCode = Math.abs(test.hashCode()) - String className = "TestClass_${first}_${hashCode}" - return className - } - - static boolean tryToCompileJavaWithoutImports(String fqn, String test) { - compileJava(fqn, test) - return true - } - - static boolean tryToCompileGroovyWithoutImports(String test) { - try { - new GroovyShell(SyntaxChecker.classLoader).parse(test) - } catch (Throwable t) { - log.error("Exception occurred while trying to parse [\n${test}\n]", t) - throw t - } - return true - } - -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/ToFileContractsTransformerSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/ToFileContractsTransformerSpec.groovy deleted file mode 100644 index f02ae8e581..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/ToFileContractsTransformerSpec.groovy +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util - -import org.junit.Rule -import org.junit.rules.TemporaryFolder -import spock.lang.Specification - -import org.springframework.cloud.contract.verifier.converter.YamlContractConverter - -/** - * @author Marcin Grzejszczak - * @since - */ -class ToFileContractsTransformerSpec extends Specification { - - @Rule - TemporaryFolder tmp = new TemporaryFolder() - File folder - - def setup() { - folder = tmp.newFolder() - } - - def "should store contracts as files"() { - given: - File input = new File("src/test/resources/dsl") - String fqn = YamlContractConverter.name - when: - List files = new ToFileContractsTransformer().storeContractsAsFiles(input.absolutePath, fqn, folder.absolutePath) - then: - files.size() == 1 - files.get(0).name.endsWith(".yml") - } -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/xml/XPathSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/xml/XPathSpec.groovy deleted file mode 100644 index 75237a93be..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/xml/XPathSpec.groovy +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util.xml - -import spock.lang.Specification -import spock.lang.Unroll - -/** - * @author Marcin Grzejszczak - */ -class XPathSpec extends Specification { - - @Unroll - def "should generate [#expectedXPath] for XPath [#xPath]"() { - expect: - xPath == expectedXPath - where: - xPath || expectedXPath - XPathBuilder.builder().node("some").node("nested").node("anothervalue").isEqualTo(4).xPath() || '''/some/nested[anothervalue=4]''' - XPathBuilder.builder().node("some").node("nested").array("withlist").contains("name").isEqualTo("name1").xPath() || '''/some/nested/withlist[name='name1']''' - XPathBuilder.builder().node("some").node("nested").array("withlist").contains("name").isEqualTo("name2").xPath() || '''/some/nested/withlist[name='name2']''' - XPathBuilder.builder().node("some").node("nested").node("json").isEqualTo("with \"val'ue").xPath() || '''/some/nested[json=concat('with "val',"'",'ue')]''' - XPathBuilder.builder().node("some", "nested", "json").isEqualTo("with \"val'ue").xPath() || '''/some/nested[json=concat('with "val',"'",'ue')]''' - } - -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/xml/XmlAssertionSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/xml/XmlAssertionSpec.groovy deleted file mode 100644 index c96929eaff..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/xml/XmlAssertionSpec.groovy +++ /dev/null @@ -1,594 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util.xml - -import groovy.xml.MarkupBuilder -import spock.lang.Issue -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll - -class XmlAssertionSpec extends Specification { - - @Shared - String xml1 = ''' - - - with "val'ue - 4 - foo - - name1 - - - name2 - - - 8 - - - name3 - - - ''' - - @Unroll - def 'should convert an xml with a map as root to a map of path to value '() { - expect: - verifiable.xPath() == expectedXPath - where: - verifiable || expectedXPath - XmlAssertion.assertThat(xml1).node("some"). - node("nested").node("anothervalue").isEqualTo(4) || '''/some/nested[anothervalue=4]''' - XmlAssertion.assertThat(xml1).node("some"). - node("nested").node("anothervalue") || '''/some/nested/anothervalue''' - XmlAssertion. - assertThat(xml1).node("some").text() || '''/some/text()''' - XmlAssertion.assertThat(xml1).node("some"). - node("nested").node("withattr").withAttribute("id", "a"). - withAttribute("id2", "b") || '''/some/nested/withattr[@id='a'][@id2='b']''' - XmlAssertion.assertThat(xml1).node("some"). - node("nested").node("withattr").withAttribute("id") || '''/some/nested/withattr/@id''' - XmlAssertion.assertThat(xml1).node("some"). - node("nested").node("withattr").isEqualTo("foo"). - withAttribute("id", "a").withAttribute("id2", "b") || '''/some/nested[withattr='foo']/withattr[@id='a'][@id2='b']''' - XmlAssertion.assertThatXml(xml1).node("some"). - node("nested").node("anothervalue").isEqualTo(4) || '''/some/nested[anothervalue=4]''' - XmlAssertion.assertThat(xml1).node("some"). - node("nested").array("withlist").contains("name"). - isEqualTo("name1") || '''/some/nested/withlist[name='name1']''' - XmlAssertion.assertThat(xml1).node("some"). - node("nested").array("withlist").contains("name"). - isEqualTo("name2") || '''/some/nested/withlist[name='name2']''' - XmlAssertion.assertThat(xml1).node("some"). - node("nested").array("withlist").contains("name").isEqualTo("name3"). - withAttribute("id", "10").withAttribute("surname", "kowalski") || '''/some/nested/withlist[name='name3']/name[@id='10'][@surname='kowalski']''' - XmlAssertion.assertThat(xml1).node("some"). - node("nested").array("withlist").isEqualTo(8) || '''/some/nested/withlist[number()=8]''' - XmlAssertion.assertThat(xml1).node("some"). - node("nested").node("json").isEqualTo("with \"val'ue") || '''/some/nested[json=concat('with "val',"'",'ue')]''' - XmlAssertion.assertThat(xml1). - node("some", "nested", "json").isEqualTo("with \"val'ue") || '''/some/nested[json=concat('with "val',"'",'ue')]''' - } - - @Shared - String xml2 = ''' - - a - b - -''' - - @Unroll - def "should generate assertions for simple response body"() { - expect: - verifiable.xPath() == expectedXPath - where: - verifiable || expectedXPath - XmlAssertion.assertThat(xml2).node("root"). - node("property1").isEqualTo("a") || '''/root[property1='a']''' - XmlAssertion.assertThat(xml2).node("root"). - node("property2").isEqualTo("b") || '''/root[property2='b']''' - } - - @Shared - String xml3 = ''' - - true - - false - 5 - -''' - - @Unroll - def "should generate assertions for null and boolean values"() { - expect: - verifiable.xPath() == expectedXPath - where: - verifiable || expectedXPath - XmlAssertion.assertThat(xml3).node("root"). - node("property1").isEqualTo("true") || '''/root[property1='true']''' - XmlAssertion.assertThat(xml3).node("root"). - node("property2").isNull() || '''not(boolean(/root/property2/text()[1]))''' - XmlAssertion.assertThat(xml3).node("root"). - node("property3").isEqualTo(false) || '''/root[property3='false']''' - XmlAssertion.assertThat(xml3).node("root"). - node("property4").isEqualTo(5) || '''/root[property4=5]''' - } - - @Shared - StringWriter xml4 = new StringWriter() - @Shared - def root4 = new MarkupBuilder(xml4).root { - property1('a') - property2 { - a('sth') - b('sthElse') - } - } - - @Unroll - def "should generate assertions for simple response body constructed from map with a list"() { - expect: - verifiable.xPath() == expectedXPath - where: - verifiable || expectedXPath - XmlAssertion.assertThat(xml4.toString()). - node("root").node("property1"). - isEqualTo("a") || '''/root[property1='a']''' - XmlAssertion.assertThat(xml4.toString()). - node("root").array("property2").contains("a"). - isEqualTo("sth") || '''/root/property2[a='sth']''' - XmlAssertion.assertThat(xml4.toString()). - node("root").array("property2").contains("b"). - isEqualTo("sthElse") || '''/root/property2[b='sthElse']''' - } - - @Shared - String xml7 = ''' - - - test1 - - - test2 - - -''' - - @Unroll - def "should generate assertions for array inside response body element"() { - expect: - verifiable.xPath() == expectedXPath - where: - verifiable || expectedXPath - XmlAssertion.assertThat(xml7).node("root"). - array("property1").contains("property2").isEqualTo("test1") || '''/root/property1[property2='test1']''' - XmlAssertion.assertThat(xml7).node("root"). - array("property1").contains("property3").isEqualTo("test2") || '''/root/property1[property3='test2']''' - } - - @Shared - String xml8 = """ - - a - - b - - -""" - - def "should generate assertions for nested objects in response body"() { - expect: - verifiable.xPath() == expectedXPath - where: - verifiable || expectedXPath - XmlAssertion.assertThat(xml8).node("root"). - node("property2").node("property3").isEqualTo("b") || '''/root/property2[property3='b']''' - XmlAssertion.assertThat(xml8).node("root"). - node("property1").isEqualTo("a") || '''/root[property1='a']''' - } - - @Shared - StringWriter xml9 = new StringWriter() - @Shared - def root9 = new MarkupBuilder(xml9).root { - property1('a') - property2(123) - } - - @Unroll - def "should generate regex assertions for map objects in response body"() { - expect: - verifiable.xPath() == expectedXPath - where: - verifiable || expectedXPath - XmlAssertion.assertThat(xml9.toString()). - node("root").node("property2").matches("[0-9]{3}") || '''/root[matches(property2, '[0-9]{3}')]''' - XmlAssertion.assertThat(xml9.toString()). - node("root").node("property1").isEqualTo("a") || '''/root[property1='a']''' - } - - def "should generate escaped regex assertions for string objects in response body"() { - given: - StringWriter xml = new StringWriter() - def root = new MarkupBuilder(xml).root { - property2(123123) - } - expect: - def verifiable = XmlAssertion. - assertThat(xml.toString()).node("root").node("property2"). - matches("\\d+") - verifiable.xPath() == '''/root[matches(property2, '\\d+')]''' - } - - @Shared - StringWriter xml10 = new StringWriter() - @Shared - def root10 = new MarkupBuilder(xml10).root { - errors { - property('bank_account_number') - message('incorrect_format') - } - } - - @Unroll - def "should work with more complex stuff and xpaths"() { - expect: - verifiable.xPath() == expectedXPath - where: - verifiable || expectedXPath - XmlAssertion.assertThat(xml10.toString()). - node("root").array("errors").contains("property"). - isEqualTo("bank_account_number") || '''/root/errors[property='bank_account_number']''' - XmlAssertion.assertThat(xml10.toString()). - node("root").array("errors").contains("message"). - isEqualTo("incorrect_format") || '''/root/errors[message='incorrect_format']''' - } - - @Shared - String xml11 = ''' - - - - -77.119759 - 38.995548 - -76.909393 - 38.791645 - - - -''' - - @Unroll - def "should manage to parse a double array"() { - expect: - verifiable.xPath() == expectedXPath - where: - verifiable || expectedXPath - XmlAssertion.assertThat(xml11).node("root"). - node("place").node("bounding_box").array("coordinates"). - isEqualTo(38.995548) || '''/root/place/bounding_box/coordinates[number()=38.995548]''' - XmlAssertion.assertThat(xml11).node("root"). - node("place").node("bounding_box").array("coordinates"). - isEqualTo(-77.119759) || '''/root/place/bounding_box/coordinates[number()=-77.119759]''' - XmlAssertion.assertThat(xml11).node("root"). - node("place").node("bounding_box").array("coordinates"). - isEqualTo(-76.909393) || '''/root/place/bounding_box/coordinates[number()=-76.909393]''' - XmlAssertion.assertThat(xml11).node("root"). - node("place").node("bounding_box").array("coordinates"). - isEqualTo(38.791645) || '''/root/place/bounding_box/coordinates[number()=38.791645]''' - - } - - def "should run XPath when provided manually"() { - given: - String xml = """ - - a - - b - - -""" - and: - String xPath = '''/root/property2[property3='b']''' - expect: - XmlAssertion.assertThat(xml).matchesXPath(xPath) - } - - def "should throw exception when XPath is not matched"() { - given: - String xml = """ - - a - - b - - -""" - and: - String xPath = '''/root/property2[property3='non-existing']''' - when: - XmlAssertion.assertThat(xml).matchesXPath(xPath) - then: - IllegalStateException illegalStateException = thrown(IllegalStateException) - illegalStateException.message.contains("Parsed XML") - illegalStateException.message.contains("doesn't match the XPath") - } - - def "should not throw exception when json path is not matched and system prop overrides the check"() { - given: - String xml = """ - - a - - b - - - """ - and: - String xPath = '''/root/property2[property3='non-existing']''' - when: - XmlAssertion.assertThat(xml). - withoutThrowingException().matchesXPath(xPath) - then: - noExceptionThrown() - } - - def "should generate escaped regex assertions for text with regular expression values"() { - given: - // '"<>[]() - String xml = """ - - '"<>[]() - """ - expect: - def verifiable = XmlAssertion.assertThat(xml). - node("root").node("property1").matches('\'"<>\\[\\]\\(\\)') - verifiable.xPath() == '''/root[matches(property1, concat('',"'",'"<>\\[\\]\\(\\)'))]''' - } - - def "should escape regular expression properly"() { - given: - String xml = """ - - /api/12 - 123456 - """ - expect: - def verifiable = XmlAssertion.assertThatXml(xml). - node("root").node("path").matches("^/api/[0-9]{2}\$") - verifiable.xPath() == '''/root[matches(path, '^/api/[0-9]{2}$')]''' - } - - def "should escape single quotes in a quoted string"() { - given: - String xml = """ - - text with 'quotes' inside - - """ - expect: - def verifiable = XmlAssertion.assertThatXml(xml). - node("root").node("text").isEqualTo("text with 'quotes' inside") - verifiable.xPath() == '''/root[text=concat('text with ',"'",'quotes',"'",' inside')]''' - } - - def "should escape brackets in a string"() { - given: - String xml = """ - - <escape me> - - """ - expect: - def verifiable = XmlAssertion.assertThatXml(xml). - node("root").node("id").isEqualTo("") - verifiable.xPath() == '''/root[id='']''' - } - - def "should escape double quotes in a quoted string"() { - given: - String xml = """ - - text with "quotes" inside - - """ - expect: - def verifiable = XmlAssertion.assertThatXml(xml). - node("root").node("text").isEqualTo('''text with "quotes" inside''') - verifiable.xPath() == '''/root[text='text with "quotes" inside']''' - } - - def 'should resolve the value of XML via XPath'() { - given: - String xml = - ''' - - - - - with value - 4 - - name1 - - - name2 - - - - name3 - - - - - - - - - true - 4 - - name1 - - - name2 - - a - b - - - - ''' - expect: - XPathBuilder.builder(xml).node("root"). - array("element").node("some").node("nested").node("json"). - read() == 'with value' - XPathBuilder.builder(xml).node("root"). - array("element").node("some").node("nested").node("anothervalue"). - read() == 4.toString() - // assertThat(xml).node("root").array("element").node("some").node("nested").array("withlist").node("name").read() == ['name1', 'name2'].toString() - //assertThat(xml).node("root").array("element").node("someother").node("nested").array("withlist2").read() == ['a', 'b'].toString() - XmlAssertion.assertThat(xml).node("root"). - array("element").node("someother").node("nested").node("json"). - read() == true.toString() - } - - def 'should match array containing an array of primitives'() { - given: - String xml = ''' - - existing - - - AGENT - BANK - CASH - - - -''' - expect: - def verifiable = XmlAssertion.assertThatXml(xml). - node("root").array("elements").array("partners"). - contains("payment_methods").isEqualTo("BANK") - verifiable.xPath() == '''/root/elements/partners[payment_methods='BANK']''' - } - - def 'should match pattern in array'() { - given: - String xml = ''' - - ROLE_ADMIN - - ''' - - expect: - def verifiable = XmlAssertion.assertThatXml(xml). - node("root").array("authorities").matches("^[a-zA-Z0-9_\\- ]+\$") - verifiable.xPath() == '''/root/authorities[matches(text(), '^[a-zA-Z0-9_\\- ]+$')]''' - } - - def 'should manage to parse array with string values'() { - given: - String xml = ''' - - name1 - name2 - ''' - - expect: - def v1 = XmlAssertion.assertThat(xml). - node("root").array("some_list").isEqualTo("name1") - def v2 = XmlAssertion.assertThat(xml). - node("root").array("some_list").isEqualTo("name2") - and: - v1.xPath() == '''/root/some_list[text()='name1']''' - v2.xPath() == '''/root/some_list[text()='name2']''' - } - - @Issue("#2") - def 'should allow nested calls with counting the elements size'() { - given: - String xml = ''' - - name1 - name2 - ''' - - expect: - def v1 = XmlAssertion.assertThat(xml). - node("root").array("some_list").hasSize(2).isEqualTo("name1") - and: - v1.xPath() == '''/root/some_list[text()='name1']''' - } - - @Issue("#2") - def 'should count the elements size'() { - given: - String xml = ''' - - name1 - name2 - ''' - - expect: - def v1 = XmlAssertion.assertThat(xml). - node("root").array("some_list").hasSize(2) - and: - v1.xPath() == '''count(/root/some_list)''' - } - - @Issue("#2") - def 'should throw exception if size is wrong'() { - given: - String xml = ''' - - name1 - name2 - ''' - - when: - XmlAssertion.assertThat(xml).node("root"). - array("some_list").hasSize(1) - then: - IllegalStateException e = thrown(IllegalStateException) - e.message. - contains("has size [2] and not [1] for XPath ") - } - - @Issue("#2") - def 'should return 0 if element is missing'() { - given: - String xml = ''' - - name1 - name2 - ''' - - when: - XmlAssertion.assertThat(xml).node("root"). - array("foo").hasSize(1) - then: - IllegalStateException e = thrown(IllegalStateException) - e.message.contains("has size [0] and not [1] for XPath ") - } - -} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/xml/XmlToXPathsConverterSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/xml/XmlToXPathsConverterSpec.groovy deleted file mode 100644 index 7f2bf5eaa6..0000000000 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/xml/XmlToXPathsConverterSpec.groovy +++ /dev/null @@ -1,110 +0,0 @@ -package org.springframework.cloud.contract.verifier.util.xml - -import javax.xml.xpath.XPathExpressionException - -import spock.lang.Issue -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll - -import org.springframework.cloud.contract.spec.internal.BodyMatchers - -/** - * @author Chris Bono - * @since 2.1.0 - */ -class XmlToXPathsConverterSpec extends Specification { - @Shared - String namedXml = ''' - customer@test.com - - ''' - @Shared - String namedDefaultNamespaceXml = ''' - customer@test.com - - ''' - @Shared - String unnamedXml = ''' - customer@test.com - - ''' - @Shared - String attributesInChildXml = ''' - customer@test.com -
- - ''' - - @Unroll - def "should generate [#expectedValue] for xPath [#value]"() { - expect: - value == expectedValue - where: - value || expectedValue - XmlToXPathsConverter.retrieveValueFromBody("/customer/email/text()", unnamedXml) || '''customer@test.com''' - XmlToXPathsConverter.retrieveValueFromBody("/ns1:customer/email/text()", namedXml) || '''customer@test.com''' - XmlToXPathsConverter.retrieveValueFromBody("//email/text()", namedXml) || '''customer@test.com''' - XmlToXPathsConverter.retrieveValueFromBody("/customer/email/text()", namedXml) || '''''' - XmlToXPathsConverter.retrieveValueFromBody("/*[local-name()='customer' and namespace-uri()='http://demo.com/testns']/*[local-name()='email']/text()", namedDefaultNamespaceXml) || '''customer@test.com''' - XmlToXPathsConverter.retrieveValueFromBody("//*[local-name()='email']/text()", namedDefaultNamespaceXml) || '''customer@test.com''' - XmlToXPathsConverter.retrieveValueFromBody("/*[local-name()='customer']/*[local-name()='email']/text()", namedDefaultNamespaceXml) || '''customer@test.com''' - XmlToXPathsConverter.retrieveValueFromBody("/*[local-name()='customer' and namespace-uri()='http://demo.com/testns']/email/text()", namedDefaultNamespaceXml) || '''''' - XmlToXPathsConverter.retrieveValueFromBody("/customer/email/text()", namedDefaultNamespaceXml) || '''''' - } - - @Unroll - def "should throw exception when searching for in existent name space"() { - when: - XmlToXPathsConverter.retrieveValueFromBody("/ns1:customer/email/text()", unnamedXml) - then: - def e = thrown(XPathExpressionException) - e.message.contains('Prefix must resolve to a namespace: ns1') - } - - @Unroll - def "should generate matched path [#expectedValue] for xPath [#value]"() { - expect: - value == expectedValue - where: - value || expectedValue - XmlToXPathsConverter.mapToMatchers(attributesInChildXml).get(0).path() || '''/customer/email/text()''' - XmlToXPathsConverter.mapToMatchers(attributesInChildXml).get(1).path() || '''/customer/@first_custom_attribute''' - XmlToXPathsConverter.mapToMatchers(attributesInChildXml).get(2).path() || '''/customer/email/@second_custom_attribute''' - XmlToXPathsConverter.mapToMatchers(attributesInChildXml).get(3).path() || '''/customer/address/@third_custom_attribute''' - } - - @Unroll - def "should remove elements to [#result] for xPath [#xpath]"() { - given: - BodyMatchers m = new BodyMatchers() - m.xPath(xpath, m.byEquality()) - expect: - result == XmlToXPathsConverter.removeMatchingXPaths(xml, m) - where: - xpath || xml || result - "/customer/email/text()" || unnamedXml || '''\n \n ''' - "/customer/email/text()" || namedXml || '''\n customer@test.com\n ''' - "/ns1:customer/email/text()" || namedXml || '''\n \n ''' - "/*[local-name()='customer' and namespace-uri()='http://demo.com/testns']/*[local-name()='email']/text()" || namedDefaultNamespaceXml || '''\n \n ''' - } - - @Issue("#1546") - def "should remove multiple elements when xpath matches them"() { - given: - String test = '''\ - - - 123 - - - 234 - - -''' - BodyMatchers m = new BodyMatchers() - m.xPath("/root/*/id/text()", m.byEquality()) - expect: - XmlToXPathsConverter.removeMatchingXPaths(test, m) == '''\n \n \n \n \n \n \n''' - } -} diff --git a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/assertion/CollectionAssertTests.java b/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/assertion/CollectionAssertTests.java deleted file mode 100644 index 9d7f67de09..0000000000 --- a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/assertion/CollectionAssertTests.java +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.assertion; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.assertj.core.api.Assertions; -import org.junit.Test; - -/** - * @author Marcin Grzejszczak - */ -public class CollectionAssertTests { - - @Test - public void should_not_throw_an_exception_when_all_elements_match_regex() { - Collection collection = collection(); - - SpringCloudContractAssertions.assertThat(collection).allElementsMatch("[a-z]"); - } - - @Test - public void should_throw_an_exception_when_at_least_one_element_doesnt_match_regex() { - Collection collection = collection(); - - try { - SpringCloudContractAssertions.assertThat(collection).allElementsMatch("[0-9]"); - Assertions.fail("should throw exception"); - } - catch (AssertionError e) { - Assertions.assertThat(e).hasMessageContaining("The value doesn't match the regex <[0-9]>"); - } - } - - @Test - public void should_throw_an_exception_when_element_is_null() { - Collection collection = collectionWithNulls(); - - try { - SpringCloudContractAssertions.assertThat(collection).allElementsMatch("[0-9]"); - Assertions.fail("should throw exception"); - } - catch (AssertionError e) { - Assertions.assertThat(e).hasMessageContaining("The value doesn't match the regex <[0-9]>"); - } - } - - @Test - public void should_throw_an_exception_when_collection_is_null() { - Collection collection = null; - - try { - SpringCloudContractAssertions.assertThat(collection).allElementsMatch("foo"); - Assertions.fail("should throw exception"); - } - catch (AssertionError e) { - Assertions.assertThat(e).hasMessageContaining("Expecting actual not to be null"); - } - } - - @Test - public void should_throw_an_exception_when_collection_is_empty() { - Collection collection = new ArrayList(); - - try { - SpringCloudContractAssertions.assertThat(collection).allElementsMatch("foo"); - Assertions.fail("should throw exception"); - } - catch (AssertionError e) { - Assertions.assertThat(e).hasMessageContaining("Expecting actual not to be empty"); - } - } - - @Test - public void should_not_throw_an_exception_when_flattened_size_is_greater_than_or_equal_to_provided_size() { - Collection collection = nestedCollection(); - - SpringCloudContractAssertions.assertThat(collection).hasFlattenedSizeGreaterThanOrEqualTo(0) - .hasFlattenedSizeGreaterThanOrEqualTo(7); - } - - @Test - public void should_throw_an_exception_when_flattened_size_is_not_greater_than_or_equal_to_provided_size() { - Collection collection = nestedCollection(); - - try { - SpringCloudContractAssertions.assertThat(collection).hasFlattenedSizeGreaterThanOrEqualTo(8); - Assertions.fail("should throw exception"); - } - catch (AssertionError e) { - Assertions.assertThat(e).hasMessageContaining("The flattened size <7> is not greater or equal to <8>"); - } - } - - @Test - public void should_throw_an_exception_when_collection_is_null_for_flattened_greater_than_or_equal() { - Collection collection = null; - - try { - SpringCloudContractAssertions.assertThat(collection).hasFlattenedSizeGreaterThanOrEqualTo(1); - Assertions.fail("should throw exception"); - } - catch (AssertionError e) { - Assertions.assertThat(e).hasMessageContaining("Expecting actual not to be null"); - } - } - - @Test - public void should_not_throw_an_exception_when_flattened_size_is_less_than_or_equal_to_provided_size() { - Collection collection = nestedCollection(); - - SpringCloudContractAssertions.assertThat(collection).hasFlattenedSizeLessThanOrEqualTo(8) - .hasFlattenedSizeLessThanOrEqualTo(7); - } - - @Test - public void should_throw_an_exception_when_flattened_size_is_not_less_than_or_equal_to_provided_size() { - Collection collection = nestedCollection(); - - try { - SpringCloudContractAssertions.assertThat(collection).hasFlattenedSizeLessThanOrEqualTo(1); - Assertions.fail("should throw exception"); - } - catch (AssertionError e) { - Assertions.assertThat(e).hasMessageContaining("The flattened size <7> is not less or equal to <1>"); - } - } - - @Test - public void should_throw_an_exception_when_collection_is_null_for_flattened_less_than_or_equal() { - Collection collection = null; - - try { - SpringCloudContractAssertions.assertThat(collection).hasFlattenedSizeLessThanOrEqualTo(1); - Assertions.fail("should throw exception"); - } - catch (AssertionError e) { - Assertions.assertThat(e).hasMessageContaining("Expecting actual not to be null"); - } - } - - @Test - public void should_not_throw_an_exception_when_flattened_size_is_between_the_provided_sizes() { - Collection collection = nestedCollection(); - - SpringCloudContractAssertions.assertThat(collection).hasFlattenedSizeBetween(1, 8).hasFlattenedSizeBetween(7, - 7); - } - - @Test - public void should_throw_an_exception_when_flattened_size_is_not_between_the_provided_sizes() { - Collection collection = nestedCollection(); - - try { - SpringCloudContractAssertions.assertThat(collection).hasFlattenedSizeBetween(8, 9); - Assertions.fail("should throw exception"); - } - catch (AssertionError e) { - Assertions.assertThat(e).hasMessageContaining("The flattened size <7> is not between <8> and <9>"); - } - } - - @Test - public void should_throw_an_exception_when_collection_is_null_for_flattened_between() { - Collection collection = null; - - try { - SpringCloudContractAssertions.assertThat(collection).hasFlattenedSizeBetween(1, 2); - Assertions.fail("should throw exception"); - } - catch (AssertionError e) { - Assertions.assertThat(e).hasMessageContaining("Expecting actual not to be null"); - } - } - - @Test - public void should_not_throw_an_exception_when_size_is_greater_than_or_equal_to_provided_size() { - Collection collection = collection(); - - SpringCloudContractAssertions.assertThat(collection).hasSizeGreaterThanOrEqualTo(0) - .hasSizeGreaterThanOrEqualTo(3); - } - - @Test - public void should_throw_an_exception_when_size_is_not_greater_than_or_equal_to_provided_size() { - Collection collection = collection(); - - try { - SpringCloudContractAssertions.assertThat(collection).hasSizeGreaterThanOrEqualTo(5); - Assertions.fail("should throw exception"); - } - catch (AssertionError e) { - Assertions.assertThat(e).hasMessageContaining("The size <3> is not greater or equal to <5>"); - } - } - - @Test - public void should_throw_an_exception_when_collection_is_null_for_greater_than_or_equal() { - Collection collection = null; - - try { - SpringCloudContractAssertions.assertThat(collection).hasSizeGreaterThanOrEqualTo(1); - Assertions.fail("should throw exception"); - } - catch (AssertionError e) { - Assertions.assertThat(e).hasMessageContaining("Expecting actual not to be null"); - } - } - - @Test - public void should_not_throw_an_exception_when_size_is_less_than_or_equal_to_provided_size() { - Collection collection = collection(); - - SpringCloudContractAssertions.assertThat(collection).hasSizeLessThanOrEqualTo(4).hasSizeLessThanOrEqualTo(3); - } - - @Test - public void should_throw_an_exception_when_size_is_not_less_than_or_equal_to_provided_size() { - Collection collection = collection(); - - try { - SpringCloudContractAssertions.assertThat(collection).hasSizeLessThanOrEqualTo(1); - Assertions.fail("should throw exception"); - } - catch (AssertionError e) { - Assertions.assertThat(e).hasMessageContaining("The size <3> is not less or equal to <1>"); - } - } - - @Test - public void should_throw_an_exception_when_collection_is_null_for_less_than_or_equal() { - Collection collection = null; - - try { - SpringCloudContractAssertions.assertThat(collection).hasSizeLessThanOrEqualTo(1); - Assertions.fail("should throw exception"); - } - catch (AssertionError e) { - Assertions.assertThat(e).hasMessageContaining("Expecting actual not to be null"); - } - } - - @Test - public void should_not_throw_an_exception_when_size_is_between_the_provided_sizes() { - Collection collection = collection(); - - SpringCloudContractAssertions.assertThat(collection).hasSizeBetween(1, 4).hasSizeBetween(3, 3); - } - - @Test - public void should_throw_an_exception_when_size_is_not_between_the_provided_sizes() { - Collection collection = collection(); - - try { - SpringCloudContractAssertions.assertThat(collection).hasSizeBetween(5, 7); - Assertions.fail("should throw exception"); - } - catch (AssertionError e) { - Assertions.assertThat(e).hasMessageContaining("The size <3> is not between <5> and <7>"); - } - } - - @Test - public void should_not_break_compilation_when_using_as() { - Collection collection = collection(); - - try { - SpringCloudContractAssertions.assertThat(collection).as("for jsonpath x.y.z").hasSizeBetween(5, 7); - Assertions.fail("should throw exception"); - } - catch (AssertionError e) { - Assertions.assertThat(e) - .hasMessageContaining("[for jsonpath x.y.z] The size <3> is not between <5> and <7>"); - } - } - - @Test - public void should_throw_an_exception_when_collection_is_null_for_between() { - Collection collection = null; - - try { - SpringCloudContractAssertions.assertThat(collection).hasSizeBetween(1, 2); - Assertions.fail("should throw exception"); - } - catch (AssertionError e) { - Assertions.assertThat(e).hasMessageContaining("Expecting actual not to be null"); - } - } - - private Collection collection() { - List list = new ArrayList<>(); - list.add("a"); - list.add("b"); - list.add("c"); - return list; - } - - private Collection collectionWithNulls() { - List list = new ArrayList<>(); - list.add(null); - return list; - } - - private Collection nestedCollection() { - List list = new ArrayList(); - List list1 = new ArrayList(); - Map map1 = new HashMap<>(); - map1.put("a", "1"); - map1.put("b", "2"); - map1.put("c", "3"); - List list2 = new ArrayList<>(); - Map map2 = new HashMap<>(); - map2.put("d", "4"); - List list3 = new ArrayList(); - List innerList = Arrays.asList("A", "B", "C"); - list.add(list1); - list.add(list2); - list.add(list3); - list1.add(map1); - list2.add(map2); - list3.add(innerList); - return list; - } - -} diff --git a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/builder/XmlBodyVerificationBuilderTest.java b/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/builder/XmlBodyVerificationBuilderTest.java deleted file mode 100644 index da1d5ab56b..0000000000 --- a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/builder/XmlBodyVerificationBuilderTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.springframework.cloud.contract.verifier.builder; - -import org.junit.Test; -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.internal.BodyMatchers; - -import java.util.Optional; - -import static com.toomuchcoding.jsonassert.JsonAssertion.assertThat; - -public class XmlBodyVerificationBuilderTest { - - private static final String xml = "\r\n" + " customer@test.com\r\n" - + " "; - - @Test - public void shouldAddXmlProcessingLines() { - // Given - XmlBodyVerificationBuilder builder = new XmlBodyVerificationBuilder(new Contract(), Optional.of(";")); - BlockBuilder blockBuilder = new BlockBuilder(" "); - BodyMatchers matchers = new BodyMatchers(); - // When - builder.addXmlResponseBodyCheck(blockBuilder, xml, matchers, xml, true); - // Then - String test = blockBuilder.toString(); - assertThat(test).contains("DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();") - .contains("builderFactory.setNamespaceAware(true);") - .contains("DocumentBuilder documentBuilder = builderFactory.newDocumentBuilder();") - .contains("Document parsedXml = documentBuilder.parse(new InputSource(new StringReader(").contains(xml); - } - -} \ No newline at end of file diff --git a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/dsl/ContractVerifierMetadataTests.java b/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/dsl/ContractVerifierMetadataTests.java deleted file mode 100644 index bd9b61f8b3..0000000000 --- a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/dsl/ContractVerifierMetadataTests.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2020-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.dsl; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.dataformat.yaml.YAMLMapper; -import org.assertj.core.api.BDDAssertions; -import org.junit.jupiter.api.Test; - -class ContractVerifierMetadataTests { - - YAMLMapper mapper = new YAMLMapper(); - - @Test - void should_parse_the_metadata_entry() throws JsonProcessingException { - // @formatter:off - String yamlEntry = "verifier:\n" - + " tool: graphql"; - // @formatter:on - - ContractVerifierMetadata metadata = ContractVerifierMetadata - .fromMetadata(this.mapper.readerForMapOf(Object.class).readValue(yamlEntry)); - - String serialized = this.mapper.writer().forType(ContractVerifierMetadata.class).writeValueAsString(metadata); - BDDAssertions.then(serialized) - .isEqualToNormalizingPunctuationAndWhitespace(yamlEntry.replace("verifier:\n", "")); - } - -} diff --git a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/dsl/wiremock/GraphQLRequestMatcherTests.java b/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/dsl/wiremock/GraphQLRequestMatcherTests.java deleted file mode 100644 index b38363049f..0000000000 --- a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/dsl/wiremock/GraphQLRequestMatcherTests.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright 2020-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.dsl.wiremock; - -import com.github.tomakehurst.wiremock.http.Request; -import com.github.tomakehurst.wiremock.matching.MatchResult; -import org.assertj.core.api.BDDAssertions; -import org.junit.jupiter.api.Test; -import org.mockito.BDDMockito; - -import org.springframework.cloud.contract.verifier.converter.YamlContractConverter; - -class GraphQLRequestMatcherTests { - - // @formatter:off - private static final String YAML_WITH_INVALID_VARIABLES = "---\n" - + "request:\n" - + " method: \"POST\"\n" - + " url: \"/graphql\"\n" - + " headers:\n" - + " Content-Type: \"application/json\"\n" - + " body:\n" - + " query: \"query queryName($personName: String!) {\\n personToCheck(name: $personName)\\\n" - + " \\ {\\n name\\n age\\n }\\n}\\n\\n\\n\\n\"\n" - + " variables: This should actually be a map not a string\n" - + " operationName: \"queryName\"\n" - + " matchers:\n" - + " headers:\n" - + " - key: \"Content-Type\"\n" - + " regex: \"application/json.*\"\n" - + " regexType: \"as_string\"\n" - + "response:\n" - + " status: 200\n" - + " headers:\n" - + " Content-Type: \"application/json\"\n" - + " body:\n" - + " data:\n" - + " personToCheck:\n" - + " name: \"Old Enough\"\n" - + " age: \"40\"\n" - + " matchers:\n" - + " headers:\n" - + " - key: \"Content-Type\"\n" - + " regex: \"application/json.*\"\n" - + " regexType: \"as_string\"\n" - + "name: \"shouldRetrieveOldEnoughPerson\"\n" - + "metadata:\n" - + " verifier:\n" - + " tool: \"graphql\"\n"; - // @formatter:on - - @Test - void should_not_match_when_exception_occurs_while_trying_to_read_missing_request_body() { - GraphQlMatcher matcher = new GraphQlMatcher(); - - MatchResult result = matcher.match(YamlContractConverter.INSTANCE.read(YAML_WITH_INVALID_VARIABLES.getBytes()), - BDDMockito.mock(Request.class), null); - - BDDAssertions.then(result.isExactMatch()).isFalse(); - } - - @Test - void should_not_match_when_exception_occurs_while_trying_to_parse_graphql_entries() { - GraphQlMatcher matcher = new GraphQlMatcher(); - - MatchResult result = matcher.match(YamlContractConverter.INSTANCE.read(YAML_WITH_INVALID_VARIABLES.getBytes()), - request(), null); - - BDDAssertions.then(result.isExactMatch()).isFalse(); - } - - // @formatter:off - private static final String PROPER_YAML = "---\n" - + "request:\n" - + " method: \"POST\"\n" - + " url: \"/graphql\"\n" - + " headers:\n" - + " Content-Type: \"application/json\"\n" - + " body:\n" - + " query: \"query queryName($personName: String!) { personToCheck(name: $personName)" - + " { name age } }\"\n" - + " variables:\n" - + " personName: \"Old Enough\"\n" - + " operationName: \"queryName\"\n" - + " matchers:\n" - + " headers:\n" - + " - key: \"Content-Type\"\n" - + " regex: \"application/json.*\"\n" - + " regexType: \"as_string\"\n" - + "response:\n" - + " status: 200\n" - + " headers:\n" - + " Content-Type: \"application/json\"\n" - + " body:\n" - + " data:\n" - + " personToCheck:\n" - + " name: \"Old Enough\"\n" - + " age: \"40\"\n" - + " matchers:\n" - + " headers:\n" - + " - key: \"Content-Type\"\n" - + " regex: \"application/json.*\"\n" - + " regexType: \"as_string\"\n" - + "name: \"shouldRetrieveOldEnoughPerson\"\n" - + "metadata:\n" - + " verifier:\n" - + " tool: \"graphql\"\n"; - // @formatter:on - - @Test - void should_not_match_when_unsupported_tool() { - BDDAssertions.then(new GraphQlMatcher().isApplicable("unknown")).isFalse(); - } - - @Test - void should_match_when_the_graphql_part_matches_regardless_of_whitespace_entries_in_the_query() { - GraphQlMatcher matcher = new GraphQlMatcher(); - - MatchResult result = matcher.match(YamlContractConverter.INSTANCE.read(PROPER_YAML.getBytes()), request(), - null); - - BDDAssertions.then(result.isExactMatch()).isTrue(); - } - - // @formatter:off - private static final String NOT_MATCHING_QUERY_BODY = "{\n" - + "\"query\":\"this should not match\",\n" - + "\"variables\":{\"personName\":\"Old Enough\"},\n" - + "\"operationName\":\"queryName\"\n" - + "}"; - // @formatter:on - - @Test - void should_not_match_when_the_query_does_not_match() { - GraphQlMatcher matcher = new GraphQlMatcher(); - - MatchResult result = matcher.match(YamlContractConverter.INSTANCE.read(PROPER_YAML.getBytes()), - request(NOT_MATCHING_QUERY_BODY), null); - - BDDAssertions.then(result.isExactMatch()).isFalse(); - } - - // @formatter:off - private static final String NOT_MATCHING_VARIABLES_BODY = "{\n" - + "\"query\":\"query queryName($personName: String!) {\\n personToCheck(name: $personName) {\\n name\\n age\\n }\\n}\\n\\n\\n\\n\",\n" - + "\"variables\":{\"Not matching key\":\"Not matching value\"},\n" - + "\"operationName\":\"queryName\"\n" - + "}"; - // @formatter:on - - @Test - void should_not_match_when_the_variables_does_not_match() { - GraphQlMatcher matcher = new GraphQlMatcher(); - - MatchResult result = matcher.match(YamlContractConverter.INSTANCE.read(PROPER_YAML.getBytes()), - request(NOT_MATCHING_VARIABLES_BODY), null); - - BDDAssertions.then(result.isExactMatch()).isFalse(); - } - - // @formatter:off - private static final String NOT_MATCHING_OPERATION_NAME_BODY = "{\n" - + "\"query\":\"query queryName($personName: String!) {\\n personToCheck(name: $personName) {\\n name\\n age\\n }\\n}\\n\\n\\n\\n\",\n" - + "\"variables\":{\"personName\":\"Old Enough\"},\n" - + "\"operationName\":\"not matching operation name\"\n" - + "}"; - // @formatter:on - - @Test - void should_not_match_when_the_operation_name_does_not_match() { - GraphQlMatcher matcher = new GraphQlMatcher(); - - MatchResult result = matcher.match(YamlContractConverter.INSTANCE.read(PROPER_YAML.getBytes()), - request(NOT_MATCHING_OPERATION_NAME_BODY), null); - - BDDAssertions.then(result.isExactMatch()).isFalse(); - } - - // @formatter:off - private static final String REQUEST_BODY = "{\n" - + "\"query\":\"query queryName($personName: String!) {\\n personToCheck(name: $personName) {\\n name\\n age\\n }\\n}\\n\\n\\n\\n\",\n" - + "\"variables\":{\"personName\":\"Old Enough\"},\n" - + "\"operationName\":\"queryName\"\n" - + "}"; - // @formatter:on - - private Request request() { - return request(REQUEST_BODY); - } - - private Request request(String body) { - Request request = BDDMockito.mock(Request.class); - BDDMockito.given(request.getBody()).willReturn(body.getBytes()); - return request; - } - -} diff --git a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/dsl/wiremock/SpringCloudContractRequestMatcherTests.java b/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/dsl/wiremock/SpringCloudContractRequestMatcherTests.java deleted file mode 100644 index 3151fd723b..0000000000 --- a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/dsl/wiremock/SpringCloudContractRequestMatcherTests.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2020-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.dsl.wiremock; - -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import com.github.tomakehurst.wiremock.extension.Parameters; -import com.github.tomakehurst.wiremock.http.Request; -import com.github.tomakehurst.wiremock.matching.MatchResult; -import org.assertj.core.api.BDDAssertions; -import org.junit.jupiter.api.Test; -import org.mockito.BDDMockito; -import reactor.util.function.Tuple2; -import reactor.util.function.Tuples; - -import org.springframework.cloud.contract.verifier.converter.YamlContract; - -class SpringCloudContractRequestMatcherTests { - - @Test - void should_not_match_when_contract_missing() { - SpringCloudContractRequestMatcher matcher = new SpringCloudContractRequestMatcher() { - - @Override - List matchers() { - return Collections.singletonList((contracts, request, parameters) -> { - throw new UnsupportedOperationException("This should not be called"); - }); - } - }; - - MatchResult result = matcher.match(BDDMockito.mock(Request.class), Parameters.one("tool", "foo")); - - BDDAssertions.then(result.isExactMatch()).isFalse(); - } - - @Test - void should_not_match_when_tool_missing() { - SpringCloudContractRequestMatcher matcher = new SpringCloudContractRequestMatcher() { - - @Override - List matchers() { - return Collections.singletonList((contracts, request, parameters) -> { - throw new UnsupportedOperationException("This should not be called"); - }); - } - }; - - MatchResult result = matcher.match(BDDMockito.mock(Request.class), Parameters.one("contract", "value")); - - BDDAssertions.then(result.isExactMatch()).isFalse(); - } - - @Test - void should_not_match_when_unsupported_tool() { - SpringCloudContractRequestMatcher matcher = new SpringCloudContractRequestMatcher() { - - @Override - List matchers() { - return Collections.singletonList((contracts, request, parameters) -> { - throw new UnsupportedOperationException("This should not be called"); - }); - } - }; - - MatchResult result = matcher.match(BDDMockito.mock(Request.class), Parameters.one("contract", "value")); - - BDDAssertions.then(result.isExactMatch()).isFalse(); - } - - private static final String PROPER_YAML = "---\n" + "request:\n" + " method: \"POST\"\n" + " url: \"/graphql\"\n" - + " headers:\n" + " Content-Type: \"application/json\"\n" + " body:\n" - + " query: \"query queryName($personName: String!) { personToCheck(name: $personName)" - + " { name age } }\"\n" + " variables:\n" + " personName: \"Old Enough\"\n" - + " operationName: \"queryName\"\n" + " matchers:\n" + " headers:\n" - + " - key: \"Content-Type\"\n" + " regex: \"application/json.*\"\n" - + " regexType: \"as_string\"\n" + "response:\n" + " status: 200\n" + " headers:\n" - + " Content-Type: \"application/json\"\n" + " body:\n" + " data:\n" + " personToCheck:\n" - + " name: \"Old Enough\"\n" + " age: \"40\"\n" + " matchers:\n" + " headers:\n" - + " - key: \"Content-Type\"\n" + " regex: \"application/json.*\"\n" - + " regexType: \"as_string\"\n" + "name: \"shouldRetrieveOldEnoughPerson\"\n" + "metadata:\n" - + " verifier:\n" + " tool: \"graphql\"\n"; - - @Test - void should_not_match_when_exception_occurs_while_trying_to_parse_contract() { - SpringCloudContractRequestMatcher matcher = new SpringCloudContractRequestMatcher() { - @Override - List matchers() { - return Collections.singletonList((contracts, request, parameters) -> { - throw new UnsupportedOperationException("This should not be called"); - }); - } - }; - - MatchResult result = matcher.match(BDDMockito.mock(Request.class), - toMap(Tuples.of("tool", "unsupported"), Tuples.of("contract", PROPER_YAML))); - - BDDAssertions.then(result.isExactMatch()).isFalse(); - } - // @formatter:off - // @formatter:on - - @Test - void should_delegate_to_an_applicable_request_matcher() { - SpringCloudContractRequestMatcher matcher = new SpringCloudContractRequestMatcher() { - @Override - List matchers() { - return Collections.singletonList(new ApplicableRequestMatcher()); - } - }; - - MatchResult result = matcher.match(BDDMockito.mock(Request.class), - toMap(Tuples.of("tool", "graphql"), Tuples.of("contract", PROPER_YAML))); - - BDDAssertions.then(result.isExactMatch()).isTrue(); - } - - private Parameters toMap(Tuple2... tuple2) { - Map map = new HashMap<>(); - for (Tuple2 tuple : tuple2) { - map.put(tuple.getT1(), tuple.getT2()); - } - return Parameters.from(map); - } - -} - -class ApplicableRequestMatcher implements RequestMatcher { - - @Override - public MatchResult match(List contracts, Request request, Parameters parameters) { - return MatchResult.of(true); - } - - @Override - public boolean isApplicable(String tool) { - return true; - } - -} diff --git a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/http/RequestTests.java b/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/http/RequestTests.java deleted file mode 100644 index 486a630eda..0000000000 --- a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/http/RequestTests.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2020-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.http; - -import java.util.AbstractMap; - -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.BDDAssertions.then; - -class RequestTests { - - @Test - void should_override_entries_when_using_builder_from_request() { - Request request = Request.given().delete("/foo").header("header", "header-value") - .cookie("cookie", "cookie-value").queryParam("query", "param-value") - .protocol(ContractVerifierHttpMetaData.Protocol.HTTP_1_1) - .scheme(ContractVerifierHttpMetaData.Scheme.HTTPS).build(); - - Request changedRequest = Request.from(request).path("/bar").header("header-foo", "header-bar") - .cookie("cookie-foo", "cookie-bar").queryParam("query-foo", "query-bar").build(); - - then(changedRequest.path()).isEqualTo("/bar"); - then(changedRequest.method().name()).isEqualTo("DELETE"); - then(changedRequest.headers()).containsEntry("header-foo", "header-bar").containsEntry("header", - "header-value"); - then(changedRequest.cookies()).containsEntry("cookie-foo", "cookie-bar").containsEntry("cookie", - "cookie-value"); - then(changedRequest.queryParams()).contains(new AbstractMap.SimpleEntry<>("query", "param-value"), - new AbstractMap.SimpleEntry<>("query-foo", "query-bar")); - then(changedRequest.protocol()).isEqualTo(ContractVerifierHttpMetaData.Protocol.HTTP_1_1); - } - -} diff --git a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/http/ResponseTests.java b/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/http/ResponseTests.java deleted file mode 100644 index 42d1700e9d..0000000000 --- a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/http/ResponseTests.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2020-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.http; - -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.BDDAssertions.then; - -class ResponseTests { - - @Test - void should_override_entries_when_using_builder_from_response() { - Response response = Response.builder().statusCode(200).header("header", "header-value") - .cookie("cookie", "cookie-value").build(); - - Response changedResponse = Response.from(response).header("header-foo", "header-bar") - .cookie("cookie-foo", "cookie-bar").build(); - - then(changedResponse.statusCode()).isEqualTo(200); - then(changedResponse.headers()).containsEntry("header-foo", "header-bar").containsEntry("header", - "header-value"); - then(changedResponse.cookies()).containsEntry("cookie-foo", "cookie-bar").containsEntry("cookie", - "cookie-value"); - } - -} diff --git a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/amqp/AmqpMetadataTests.java b/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/amqp/AmqpMetadataTests.java deleted file mode 100644 index a006b4d9dc..0000000000 --- a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/amqp/AmqpMetadataTests.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2020-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.amqp; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.dataformat.yaml.YAMLMapper; -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.BDDAssertions.then; - -class AmqpMetadataTests { - - YAMLMapper mapper = new YAMLMapper(); - - @Test - void should_parse_the_metadata_entry() throws JsonProcessingException { - // @formatter:off - String yamlEntry = "amqp:\n" - + " input:\n" - + " connectToBroker:\n" - + " additionalOptions: \"foo1\"\n" - + " declareQueueWithName: \"foo2\"\n" - + " messageProperties:\n" - + " replyTo: \"foo3\"\n" - + " outputMessage:\n" - + " connectToBroker:\n" - + " additionalOptions: \"bar1\"\n" - + " declareQueueWithName: \"bar2\"\n" - + " messageProperties:\n" - + " replyTo: \"bar3\"\n"; - // @formatter:on - - AmqpMetadata metadata = AmqpMetadata - .fromMetadata(this.mapper.readerForMapOf(Object.class).readValue(yamlEntry)); - - then(metadata.getInput().getConnectToBroker().getAdditionalOptions()).isEqualTo("foo1"); - then(metadata.getInput().getConnectToBroker().getDeclareQueueWithName()).isEqualTo("foo2"); - then(metadata.getInput().getMessageProperties().getReplyTo()).isEqualTo("foo3"); - then(metadata.getOutputMessage().getConnectToBroker().getAdditionalOptions()).isEqualTo("bar1"); - then(metadata.getOutputMessage().getConnectToBroker().getDeclareQueueWithName()).isEqualTo("bar2"); - then(metadata.getOutputMessage().getMessageProperties().getReplyTo()).isEqualTo("bar3"); - - } - -} diff --git a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/boot/AutoConfigureMessageVerifierTests.java b/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/boot/AutoConfigureMessageVerifierTests.java deleted file mode 100644 index 753e47b64c..0000000000 --- a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/boot/AutoConfigureMessageVerifierTests.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2020-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.boot; - -import org.junit.Test; - -import org.springframework.amqp.rabbit.core.RabbitTemplate; -import org.springframework.boot.test.context.FilteredClassLoader; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender; -import org.springframework.cloud.contract.verifier.messaging.noop.NoOpStubMessages; -import org.springframework.cloud.stream.binder.Binder; -import org.springframework.jms.core.JmsTemplate; -import org.springframework.kafka.core.KafkaTemplate; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Tim Ysewyn - */ -public class AutoConfigureMessageVerifierTests { - - private ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withUserConfiguration(Configuration.class); - - @Test - public void shouldConfigureForNoOpWhenMissingImplementation() { - this.contextRunner.withClassLoader( - new FilteredClassLoader(org.apache.camel.Message.class, org.springframework.messaging.Message.class, - JmsTemplate.class, KafkaTemplate.class, RabbitTemplate.class, Binder.class)) - .run((context) -> { - assertThat(context.getBeansOfType(MessageVerifierSender.class)).hasSize(1); - assertThat(context.getBeansOfType(NoOpStubMessages.class)).hasSize(1); - }); - } - - @AutoConfigureMessageVerifier - private static class Configuration { - - } - -} diff --git a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/camel/ContractVerifierCamelConfigurationTests.java b/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/camel/ContractVerifierCamelConfigurationTests.java deleted file mode 100644 index 940662bcf5..0000000000 --- a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/camel/ContractVerifierCamelConfigurationTests.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2020-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.camel; - -import org.junit.Test; - -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Tim Ysewyn - */ -public class ContractVerifierCamelConfigurationTests { - - private ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(ContractVerifierCamelConfiguration.class)); - - @Test - public void shouldCreateBeansByDefault() { - this.contextRunner.run((context) -> { - assertThat(context.getBeansOfType(CamelStubMessages.class)).hasSize(1); - assertThat(context.getBeansOfType(ContractVerifierCamelHelper.class)).hasSize(1); - }); - } - - @Test - public void shouldNotCreateBeansWhenDisabled() { - this.contextRunner.withPropertyValues("stubrunner.camel.enabled=false").run((context) -> { - assertThat(context.getBeansOfType(CamelStubMessages.class)).hasSize(0); - assertThat(context.getBeansOfType(ContractVerifierCamelHelper.class)).hasSize(0); - }); - } - - @Test - public void shouldCreateBeansWhenExplicitlyEnabled() { - this.contextRunner.withPropertyValues("stubrunner.camel.enabled=true").run((context) -> { - assertThat(context.getBeansOfType(CamelStubMessages.class)).hasSize(1); - assertThat(context.getBeansOfType(ContractVerifierCamelHelper.class)).hasSize(1); - }); - } - -} diff --git a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/integration/ContractVerifierIntegrationConfigurationTests.java b/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/integration/ContractVerifierIntegrationConfigurationTests.java deleted file mode 100644 index 6087548369..0000000000 --- a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/integration/ContractVerifierIntegrationConfigurationTests.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2020-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.integration; - -import org.junit.Test; - -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Tim Ysewyn - */ -public class ContractVerifierIntegrationConfigurationTests { - - private ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(ContractVerifierIntegrationConfiguration.class)); - - @Test - public void shouldCreateBeansWhenOnClasspath() { - this.contextRunner.run((context) -> { - assertThat(context.getBeansOfType(SpringIntegrationStubMessages.class)).hasSize(1); - assertThat(context.getBeansOfType(ContractVerifierHelper.class)).hasSize(1); - }); - } - -} diff --git a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/jms/ContractVerifierJmsConfigurationTests.java b/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/jms/ContractVerifierJmsConfigurationTests.java deleted file mode 100644 index 600d98ccaa..0000000000 --- a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/jms/ContractVerifierJmsConfigurationTests.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2020-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.jms; - -import org.junit.Test; - -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Tim Ysewyn - */ -public class ContractVerifierJmsConfigurationTests { - - private ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(ContractVerifierJmsConfiguration.class)); - - @Test - public void shouldCreateBeansByDefault() { - this.contextRunner.run((context) -> { - assertThat(context.getBeansOfType(JmsStubMessages.class)).hasSize(1); - assertThat(context.getBeansOfType(ContractVerifierJmsHelper.class)).hasSize(1); - }); - } - - @Test - public void shouldNotCreateBeansWhenDisabled() { - this.contextRunner.withPropertyValues("stubrunner.jms.enabled=false").run((context) -> { - assertThat(context.getBeansOfType(JmsStubMessages.class)).hasSize(0); - assertThat(context.getBeansOfType(ContractVerifierJmsHelper.class)).hasSize(0); - }); - } - - @Test - public void shouldCreateBeansWhenExplicitlyEnabled() { - this.contextRunner.withPropertyValues("stubrunner.jms.enabled=true").run((context) -> { - assertThat(context.getBeansOfType(JmsStubMessages.class)).hasSize(1); - assertThat(context.getBeansOfType(ContractVerifierJmsHelper.class)).hasSize(1); - }); - } - -} diff --git a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/jms/JmsStubMessagesTests.java b/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/jms/JmsStubMessagesTests.java deleted file mode 100644 index c965957f49..0000000000 --- a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/jms/JmsStubMessagesTests.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2021-2021 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.jms; - -import jakarta.jms.JMSException; -import jakarta.jms.Session; -import jakarta.jms.TextMessage; -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; - -import org.springframework.jms.core.JmsTemplate; -import org.springframework.jms.core.MessageCreator; - -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class JmsStubMessagesTests { - - @Test - void should_send_message_without_headers_and_contract() throws JMSException { - final JmsTemplate jmsTemplate = mock(JmsTemplate.class); - final Session session = mock(Session.class); - final TextMessage message = mock(TextMessage.class); - - when(session.createTextMessage(anyString())).thenReturn(message); - - final JmsStubMessages springJmsStubMessages = new JmsStubMessages(jmsTemplate); - - springJmsStubMessages.send(anyString(), null, anyString(), null); - - final ArgumentCaptor messageCreatorArgumentCaptor = ArgumentCaptor - .forClass(MessageCreator.class); - - verify(jmsTemplate, times(1)).send(anyString(), messageCreatorArgumentCaptor.capture()); - - final MessageCreator creator = messageCreatorArgumentCaptor.getValue(); - - Assertions.assertThatCode(() -> creator.createMessage(session)).doesNotThrowAnyException(); - } - -} diff --git a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/kafka/KafkaMetadataTests.java b/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/kafka/KafkaMetadataTests.java deleted file mode 100644 index 727b7c98d5..0000000000 --- a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/kafka/KafkaMetadataTests.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2020-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.kafka; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.dataformat.yaml.YAMLMapper; -import org.assertj.core.api.BDDAssertions; -import org.junit.jupiter.api.Test; - -class KafkaMetadataTests { - - YAMLMapper mapper = new YAMLMapper(); - - @Test - void should_parse_the_metadata_entry() throws JsonProcessingException { - // @formatter:off - String yamlEntry = "kafka:\n" - + " input:\n" - + " connectToBroker:\n" - + " additionalOptions: foo\n" - + " outputMessage:\n" - + " connectToBroker:\n" - + " additionalOptions: bar"; - // @formatter:on - - KafkaMetadata metadata = KafkaMetadata - .fromMetadata(this.mapper.readerForMapOf(Object.class).readValue(yamlEntry)); - - String serialized = this.mapper.writer().forType(KafkaMetadata.class).writeValueAsString(metadata); - BDDAssertions.then(serialized).isEqualToNormalizingPunctuationAndWhitespace(yamlEntry.replace("kafka:\n", "")); - } - -} diff --git a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/noop/NoOpContractVerifierAutoConfigurationTests.java b/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/noop/NoOpContractVerifierAutoConfigurationTests.java deleted file mode 100644 index 9983d55e35..0000000000 --- a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/noop/NoOpContractVerifierAutoConfigurationTests.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2020-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.noop; - -import org.junit.Test; - -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Tim Ysewyn - */ -public class NoOpContractVerifierAutoConfigurationTests { - - private ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(NoOpContractVerifierAutoConfiguration.class)); - - @Test - public void shouldCreateBeansByDefault() { - this.contextRunner.run((context) -> { - assertThat(context.getBeansOfType(NoOpStubMessages.class)).hasSize(1); - }); - } - -} diff --git a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/stream/ContractVerifierStreamAutoConfigurationTests.java b/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/stream/ContractVerifierStreamAutoConfigurationTests.java deleted file mode 100644 index a7a90d68e0..0000000000 --- a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/stream/ContractVerifierStreamAutoConfigurationTests.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2020-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.messaging.stream; - -import org.junit.Test; - -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Tim Ysewyn - */ -public class ContractVerifierStreamAutoConfigurationTests { - - private ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(ContractVerifierStreamAutoConfiguration.class)); - - @Test - public void shouldCreateBeansByDefault() { - this.contextRunner.run((context) -> { - assertThat(context.getBeansOfType(ContractVerifierHelper.class)).hasSize(1); - assertThat(context.getBeansOfType(StreamStubMessages.class)).hasSize(1); - }); - } - - @Test - public void shouldNotCreateBeansWhenDisabled() { - this.contextRunner.withPropertyValues("stubrunner.stream.enabled=false").run((context) -> { - assertThat(context.getBeansOfType(ContractVerifierHelper.class)).hasSize(0); - assertThat(context.getBeansOfType(StreamStubMessages.class)).hasSize(0); - }); - } - - @Test - public void shouldCreateBeansWhenExplicitlyEnabled() { - this.contextRunner.withPropertyValues("stubrunner.stream.enabled=true").run((context) -> { - assertThat(context.getBeansOfType(ContractVerifierHelper.class)).hasSize(1); - assertThat(context.getBeansOfType(StreamStubMessages.class)).hasSize(1); - }); - } - -} diff --git a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/util/ContractVerifierUtilTest.java b/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/util/ContractVerifierUtilTest.java deleted file mode 100644 index 70f454a1fc..0000000000 --- a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/util/ContractVerifierUtilTest.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright 2020-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.util; - -import java.io.IOException; -import java.io.StringReader; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -import org.junit.Test; -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Chris Bono - * @since 2.1.0 - */ -public class ContractVerifierUtilTest { - - private final String unnamedXml = "\n" + "customer@test.com\n" + ""; - - private final String namedComplexXml = "\n" - + "customer@test.com\n" + "\n" - + "Krombopulous" + "
" + "" + "51" + "50" - + "" + "
" + "
\n" + "
"; - - @Test - public void shouldGetValueFromXPath() { - // Given - Document parsedXml = parsedXml(unnamedXml); - // When - String value = ContractVerifierUtil.valueFromXPath(parsedXml, "/customer/email/text()"); - // Then - assertThat(value).isEqualTo("customer@test.com"); - } - - @Test(expected = IllegalArgumentException.class) - public void shouldThrowExceptionOnIllegalValueFromXPath() { - // Given - Document parsedXml = parsedXml(unnamedXml); - // When - ContractVerifierUtil.valueFromXPath(parsedXml, "/ns1:customer/email/text()"); - } - - @Test - public void shouldGetEmptyValueFromXPathWithNamespace() { - // Given - Document parsedXml = parsedXml(namedComplexXml); - // When - String value = ContractVerifierUtil.valueFromXPath(parsedXml, "/customer/email/text()"); - // Then - assertThat(value).isEqualTo(""); - } - - @Test - public void shouldGetValueFromXPathWithNamespace() { - // Given - Document parsedXml = parsedXml(namedComplexXml); - // When - String value = ContractVerifierUtil.valueFromXPath(parsedXml, "/ns1:customer/email/text()"); - // Then - assertThat(value).isEqualTo("customer@test.com"); - } - - @Test - public void shouldGetNamespaceValueFromXPathWithNamespace() { - // Given - Document parsedXml = parsedXml(namedComplexXml); - // When - String value = ContractVerifierUtil.valueFromXPath(parsedXml, "/ns1:customer/namespace::ns1"); - // Then - assertThat(value).isEqualTo("http://demo.com/customer"); - } - - @Test - public void shouldGetValueFromXPathWithDefaultNamespace() { - // Given - Document parsedXml = parsedXml(namedComplexXml); - // When - String value = ContractVerifierUtil.valueFromXPath(parsedXml, - "/ns1:customer/*[local-name()='contact-info' and namespace-uri()='http://demo.com/contact-info']/*[local-name()='name']/text()"); - // Then - assertThat(value).isEqualTo("Krombopulous"); - } - - @Test - public void shouldGetValueFromXPathWithNestedNamespaces1() { - // Given - Document parsedXml = parsedXml(namedComplexXml); - // When - String value = ContractVerifierUtil.valueFromXPath(parsedXml, - "/ns1:customer/*[local-name()='contact-info' and namespace-uri()='http://demo.com/contact-info']/*[local-name()='address']/addr:gps/*[local-name()='lat']/text()"); - // Then - assertThat(value).isEqualTo("51"); - } - - @Test - public void shouldGetValueFromXPathWithNestedNamespaces2() { - // Given - Document parsedXml = parsedXml(namedComplexXml); - // When - String value = ContractVerifierUtil.valueFromXPath(parsedXml, - "/ns1:customer/*[local-name()='contact-info' and namespace-uri()='http://demo.com/contact-info']/*[local-name()='address']/addr:gps/addr:lon/text()"); - // Then - assertThat(value).isEqualTo("50"); - } - - @Test - public void shouldGetEmptyValueFromXPathWithDefaultNamespace() { - // Given - Document parsedXml = parsedXml(namedComplexXml); - // When - String value = ContractVerifierUtil.valueFromXPath(parsedXml, "/ns1:customer/contact-info/name/text()"); - // Then - assertThat(value).isEqualTo(""); - } - - @Test - public void shouldGetEmptyValueFromXPathWithNestedDefaultNamespace() { - // Given - Document parsedXml = parsedXml(namedComplexXml); - // When - String value = ContractVerifierUtil.valueFromXPath(parsedXml, - "/ns1:customer/*[local-name()='contact-info' and namespace-uri()='http://demo.com/contact-info']/name/text()"); - // Then - assertThat(value).isEqualTo(""); - } - - @Test - public void shouldGetNodeFromXPath() { - // Given - Document parsedXml = parsedXml(unnamedXml); - // When - Node node = ContractVerifierUtil.nodeFromXPath(parsedXml, "/customer/email/text()"); - // Then - assertThat(node.getTextContent()).isEqualTo("customer@test.com"); - } - - @Test(expected = IllegalArgumentException.class) - public void shouldThrowExceptionOnIllegalNodeFromXPath() { - // Given - Document parsedXml = parsedXml(unnamedXml); - // When - ContractVerifierUtil.nodeFromXPath(parsedXml, "/ns1:customer/email/text()"); - } - - @Test - public void shouldGetNodeFromXPathWithNamespace() { - // Given - Document parsedXml = parsedXml(namedComplexXml); - // When - Node node = ContractVerifierUtil.nodeFromXPath(parsedXml, "/ns1:customer/email/text()"); - // Then - assertThat(node.getTextContent()).isEqualTo("customer@test.com"); - } - - @Test - public void shouldGetNamespaceNodeFromXPathWithNamespace() { - // Given - Document parsedXml = parsedXml(namedComplexXml); - // When - Node node = ContractVerifierUtil.nodeFromXPath(parsedXml, "/ns1:customer/namespace::ns1"); - // Then - assertThat(node.getTextContent()).isEqualTo("http://demo.com/customer"); - } - - @Test - public void shouldGetEmptyNodeFromXPathWithNamespace() { - // Given - Document parsedXml = parsedXml(namedComplexXml); - // When - Node node = ContractVerifierUtil.nodeFromXPath(parsedXml, "/customer/email/text()"); - // Then - assertThat(node).isNull(); - } - - @Test - public void shouldSetPathWithoutPrefixAndWithSuffix() { - assertThat(ContractVerifierUtil.fromRelativePath("validate_foo()")).isEqualTo("foo.yml"); - assertThat(ContractVerifierUtil.fromRelativePath("validate_foo")).isEqualTo("foo.yml"); - assertThat(ContractVerifierUtil.fromRelativePath("foo")).isEqualTo("foo.yml"); - assertThat(ContractVerifierUtil.fromRelativePath("foo.yml")).isEqualTo("foo.yml"); - } - - private Document parsedXml(String inputXml) { - DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); - builderFactory.setNamespaceAware(true); - try { - DocumentBuilder documentBuilder = builderFactory.newDocumentBuilder(); - return documentBuilder.parse(new InputSource(new StringReader(inputXml))); - } - catch (ParserConfigurationException | IOException | SAXException e) { - throw new RuntimeException(e); - } - } - -} diff --git a/spring-cloud-contract-verifier/src/test/resources/META-INF/spring.factories b/spring-cloud-contract-verifier/src/test/resources/META-INF/spring.factories deleted file mode 100644 index 4ec198834e..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/META-INF/spring.factories +++ /dev/null @@ -1,4 +0,0 @@ -# tag::extension[] -org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockExtensions=\ -org.springframework.cloud.contract.verifier.dsl.wiremock.TestWireMockExtensions -# end::extension[] diff --git a/spring-cloud-contract-verifier/src/test/resources/application.properties b/spring-cloud-contract-verifier/src/test/resources/application.properties deleted file mode 100644 index 24edc25897..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ -logging.level.wiremock.com.github.jknack.handlebars.internal=INFO diff --git a/spring-cloud-contract-verifier/src/test/resources/body_builder/request.pdf b/spring-cloud-contract-verifier/src/test/resources/body_builder/request.pdf deleted file mode 100644 index 69503635d87cbdfa660d5cd8be66d3e74b3b20e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14631 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
-a~gh80YfUd6$}odJqFHl#jbC) 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 diff --git a/spring-cloud-contract-verifier/src/test/resources/body_builder/response.pdf b/spring-cloud-contract-verifier/src/test/resources/body_builder/response.pdf deleted file mode 100644 index c3b233056b758d1cc9bf3176e99a95add89ba607..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15767 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 - - Jozo - 123 - \ No newline at end of file diff --git a/spring-cloud-contract-verifier/src/test/resources/classpath/response.json b/spring-cloud-contract-verifier/src/test/resources/classpath/response.json deleted file mode 100644 index cb55e0cb2f..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/classpath/response.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "status": "RESPONSE" -} diff --git a/spring-cloud-contract-verifier/src/test/resources/contract.groovy b/spring-cloud-contract-verifier/src/test/resources/contract.groovy deleted file mode 100644 index 8bc2f26a97..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/contract.groovy +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - request { - method('PUT') - headers { - contentType(applicationJson()) - } - body(""" { "status" : "OK" } """) - url("/1") - } - response { - status OK() - body(""" { "status" : "OK" } """) - headers { - contentType(textPlain()) - } - } -} diff --git a/spring-cloud-contract-verifier/src/test/resources/contract.yml b/spring-cloud-contract-verifier/src/test/resources/contract.yml deleted file mode 100644 index 72e9e23295..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/contract.yml +++ /dev/null @@ -1,45 +0,0 @@ -description: Some description -name: some name -priority: 8 -ignored: true -request: - url: /foo - queryParameters: - a: b - b: c - method: PUT - headers: - foo: bar - fooReq: baz - body: - foo: bar - matchers: - body: - - path: $.foo - type: by_regex - value: bar - headers: - - key: foo - regex: bar -response: - status: 200 - headers: - foo2: bar - foo3: foo33 - fooRes: baz - body: - foo2: bar - foo3: baz - matchers: - body: - - path: $.foo2 - type: by_regex - value: bar - - path: $.foo3 - type: by_command - value: executeMe($it) - headers: - - key: foo2 - regex: bar - - key: foo3 - command: andMeToo($it) diff --git a/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract.java b/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract.java deleted file mode 100644 index d8e1af9aac..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package example; - -import java.util.Collection; -import java.util.Collections; -import java.util.function.Supplier; - -import org.springframework.cloud.contract.spec.Contract; - -class contract implements Supplier> { - - @Override - public Collection get() { - return Collections.singletonList(Contract.make(c -> { - c.request(r -> { - r.method(r.PUT()); - r.headers(h -> { - h.contentType(h.applicationJson()); - }); - r.body(" { \"status\" : \"OK\" } "); - r.url("/1"); - }); - c.response(r -> { - r.status(r.OK()); - r.body(" { \"status\" : \"OK\" } "); - r.headers(h -> { - h.contentType(h.textPlain()); - }); - }); - })); - } - -} diff --git a/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_docs_examples.java b/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_docs_examples.java deleted file mode 100644 index 86c7f805bb..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_docs_examples.java +++ /dev/null @@ -1,342 +0,0 @@ - -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import java.util.Collection; -import java.util.Collections; -import java.util.function.Supplier; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.verifier.util.ContractVerifierUtil; - -// tag::class[] -class contract_docs_examples implements Supplier> { - - org.springframework.cloud.contract.spec.Contract httpDsl = - // tag::http_dsl[] - org.springframework.cloud.contract.spec.Contract.make(c -> { - // Definition of HTTP request part of the contract - // (this can be a valid request or invalid depending - // on type of contract being specified). - c.request(r -> { - r.method(r.GET()); - r.url("/foo"); - // ... - }); - - // Definition of HTTP response part of the contract - // (a service implementing this contract should respond - // with following response after receiving request - // specified in "request" part above). - c.response(r -> { - r.status(200); - // ... - }); - - // Contract priority, which can be used for overriding - // contracts (1 is highest). Priority is optional. - c.priority(1); - }); - - // end::http_dsl[] - - org.springframework.cloud.contract.spec.Contract methodDsl = org.springframework.cloud.contract.spec.Contract - .make(c -> { - c.request(r -> { - // tag::method[] - r.method(r.GET()); - // end::method[] - r.url("/foo"); - }); - - c.response(r -> { - r.status(200); - }); - - c.priority(1); - }); - - org.springframework.cloud.contract.spec.Contract request = - // tag::request[] - org.springframework.cloud.contract.spec.Contract.make(c -> { - c.request(r -> { - // HTTP request method (GET/POST/PUT/DELETE). - r.method("GET"); - - // Path component of request URL is specified as follows. - r.urlPath("/users"); - }); - - c.response(r -> { - // ... - r.status(200); - }); - }); - - // end::request[] - - org.springframework.cloud.contract.spec.Contract url = - // tag::url[] - org.springframework.cloud.contract.spec.Contract.make(c -> { - c.request(r -> { - r.method("GET"); - - // Specifying `url` and `urlPath` in one contract is illegal. - r.url("http://localhost:8888/users"); - }); - - c.response(r -> { - // ... - r.status(200); - }); - }); - - // end::url[] - - org.springframework.cloud.contract.spec.Contract urlPaths = - // tag::urlpath[] - org.springframework.cloud.contract.spec.Contract.make(c -> { - c.request(r -> { - // ... - r.method(r.GET()); - - r.urlPath("/users", u -> { - - // Each parameter is specified in form - // `'paramName' : paramValue` where parameter value - // may be a simple literal or one of matcher functions, - // all of which are used in this example. - u.queryParameters(q -> { - - // If a simple literal is used as value - // default matcher function is used (equalTo) - q.parameter("limit", 100); - - // `equalTo` function simply compares passed value - // using identity operator (==). - q.parameter("filter", r.equalTo("email")); - - // `containing` function matches strings - // that contains passed substring. - q.parameter("gender", r.value(r.consumer(r.containing("[mf]")), r.producer("mf"))); - - // `matching` function tests parameter - // against passed regular expression. - q.parameter("offset", r.value(r.consumer(r.matching("[0-9]+")), r.producer(123))); - - // `notMatching` functions tests if parameter - // does not match passed regular expression. - q.parameter("loginStartsWith", r.value(r.consumer(r.notMatching(".{0,2}")), r.producer(3))); - }); - }); - - // ... - }); - - c.response(r -> { - // ... - r.status(200); - }); - }); - - // end::urlpath[] - - org.springframework.cloud.contract.spec.Contract headers = - // tag::headers[] - org.springframework.cloud.contract.spec.Contract.make(c -> { - c.request(r -> { - // ... - r.method(r.GET()); - r.url("/foo"); - - // Each header is added in form `'Header-Name' : 'Header-Value'`. - // there are also some helper methods - r.headers(h -> { - h.header("key", "value"); - h.contentType(h.applicationJson()); - }); - - // ... - }); - - c.response(r -> { - // ... - r.status(200); - }); - }); - - // end::headers[] - - org.springframework.cloud.contract.spec.Contract cookies = - // tag::cookies[] - org.springframework.cloud.contract.spec.Contract.make(c -> { - c.request(r -> { - // ... - r.method(r.GET()); - r.url("/foo"); - - // Each Cookies is added in form `'Cookie-Key' : 'Cookie-Value'`. - // there are also some helper methods - r.cookies(ck -> { - ck.cookie("key", "value"); - ck.cookie("another_key", "another_value"); - }); - - // ... - }); - - c.response(r -> { - // ... - r.status(200); - }); - }); - - // end::cookies[] - - org.springframework.cloud.contract.spec.Contract body = - // tag::body[] - org.springframework.cloud.contract.spec.Contract.make(c -> { - c.request(r -> { - // ... - r.method(r.GET()); - r.url("/foo"); - - // Currently only JSON format of request body is supported. - // Format will be determined from a header or body's content. - r.body("{ \"login\" : \"john\", \"name\": \"John The Contract\" }"); - }); - - c.response(r -> { - // ... - r.status(200); - }); - }); - - // end::body[] - - org.springframework.cloud.contract.spec.Contract bodyAsXml = - // tag::bodyAsXml[] - org.springframework.cloud.contract.spec.Contract.make(c -> { - c.request(r -> { - // ... - r.method(r.GET()); - r.url("/foo"); - - // In this case body will be formatted as XML. - r.body(r.equalToXml("johnJohn The Contract")); - }); - - c.response(r -> { - // ... - r.status(200); - }); - }); - - // end::bodyAsXml[] - - org.springframework.cloud.contract.spec.Contract response = - // tag::response[] - org.springframework.cloud.contract.spec.Contract.make(c -> { - c.request(r -> { - // ... - r.method(r.GET()); - r.url("/foo"); - }); - c.response(r -> { - // Status code sent by the server - // in response to request specified above. - r.status(r.OK()); - }); - }); - - // end::response[] - - org.springframework.cloud.contract.spec.Contract regex = - // tag::regex[] - org.springframework.cloud.contract.spec.Contract.make(c -> { - c.request(r -> { - r.method("GET"); - r.url(r.$(r.consumer(r.regex("\\/[0-9]{2}")), r.producer("/12"))); - }); - c.response(r -> { - r.status(r.OK()); - r.body(ContractVerifierUtil.map().entry("id", r.$(r.anyNumber())).entry("surname", - r.$(r.consumer("Kowalsky"), r.producer(r.regex("[a-zA-Z]+"))))); - r.headers(h -> { - h.header("Content-Type", "text/plain"); - }); - }); - }); - - // end::regex[] - - org.springframework.cloud.contract.spec.Contract optionals = - // tag::optionals[] - org.springframework.cloud.contract.spec.Contract.make(c -> { - c.priority(1); - c.name("optionals"); - c.request(r -> { - r.method("POST"); - r.url("/users/password"); - r.headers(h -> { - h.contentType(h.applicationJson()); - }); - r.body(ContractVerifierUtil.map() - .entry("email", r.$(r.consumer(r.optional(r.regex(r.email()))), r.producer("abc@abc.com"))) - .entry("callback_url", - r.$(r.consumer(r.regex(r.hostname())), r.producer("https://partners.com")))); - }); - c.response(r -> { - r.status(404); - r.headers(h -> { - h.header("Content-Type", "application/json"); - }); - r.body(ContractVerifierUtil.map().entry("code", - r.value(r.consumer("123123"), r.producer(r.optional("123123"))))); - }); - }); - - // end::optionals[] - - org.springframework.cloud.contract.spec.Contract method = - // tag::methodBuilder[] - org.springframework.cloud.contract.spec.Contract.make(c -> { - c.request(r -> { - r.method("PUT"); - r.url(r.$(r.consumer(r.regex("^/api/[0-9]{2}$")), r.producer("/api/12"))); - r.headers(h -> { - h.header("Content-Type", "application/json"); - }); - r.body("[{\"text\": \"Gonna see you at Warsaw\" }]"); - }); - c.response(r -> { - r.body(ContractVerifierUtil.map() - .entry("path", r.$(r.consumer("/api/12"), r.producer(r.regex("^/api/[0-9]{2}$")))) - .entry("correlationId", - r.$(r.consumer("1223456"), r.producer(r.execute("isProperCorrelationId($it)"))))); - r.status(r.OK()); - }); - }); - - // end::methodBuilder[] - - @Override - public Collection get() { - return Collections.singletonList(method); - } - -} -// end::class[] \ No newline at end of file diff --git a/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_multipart.java b/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_multipart.java deleted file mode 100644 index 668027be27..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_multipart.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// tag::class[] -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Supplier; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.internal.DslProperty; -import org.springframework.cloud.contract.spec.internal.Request; -import org.springframework.cloud.contract.verifier.util.ContractVerifierUtil; - -class contract_multipart implements Supplier> { - - private static Map namedProps(Request r) { - Map map = new HashMap<>(); - // name of the file - map.put("name", r.$(r.c(r.regex(r.nonEmpty())), r.p("filename.csv"))); - // content of the file - map.put("content", r.$(r.c(r.regex(r.nonEmpty())), r.p("file content"))); - // content type for the part - map.put("contentType", r.$(r.c(r.regex(r.nonEmpty())), r.p("application/json"))); - return map; - } - - @Override - public Collection get() { - return Collections.singletonList(Contract.make(c -> { - c.request(r -> { - r.method("PUT"); - r.url("/multipart"); - r.headers(h -> { - h.contentType("multipart/form-data;boundary=AaB03x"); - }); - r.multipart(ContractVerifierUtil.map() - // key (parameter name), value (parameter value) pair - .entry("formParameter", r.$(r.c(r.regex("\".+\"")), r.p("\"formParameterValue\""))) - .entry("someBooleanParameter", r.$(r.c(r.regex(r.anyBoolean())), r.p("true"))) - // a named parameter (e.g. with `file` name) that represents file - // with - // `name` and `content`. You can also call `named("fileName", - // "fileContent")` - .entry("file", r.named(namedProps(r)))); - }); - c.response(r -> { - r.status(r.OK()); - }); - })); - } - -} -// end::class[] diff --git a/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_rest.java b/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_rest.java deleted file mode 100644 index 58e941dc3d..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_rest.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// tag::class[] -import java.util.Collection; -import java.util.Collections; -import java.util.function.Supplier; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.verifier.util.ContractVerifierUtil; - -class contract_rest implements Supplier> { - - @Override - public Collection get() { - return Collections.singletonList(Contract.make(c -> { - c.description("Some description"); - c.name("some name"); - c.priority(8); - c.ignored(); - c.request(r -> { - r.url("/foo", u -> { - u.queryParameters(q -> { - q.parameter("a", "b"); - q.parameter("b", "c"); - }); - }); - r.method(r.PUT()); - r.headers(h -> { - h.header("foo", r.value(r.client(r.regex("bar")), r.server("bar"))); - h.header("fooReq", "baz"); - }); - r.body(ContractVerifierUtil.map().entry("foo", "bar")); - r.bodyMatchers(m -> { - m.jsonPath("$.foo", m.byRegex("bar")); - }); - }); - c.response(r -> { - r.fixedDelayMilliseconds(1000); - r.status(r.OK()); - r.headers(h -> { - h.header("foo2", r.value(r.server(r.regex("bar")), r.client("bar"))); - h.header("foo3", r.value(r.server(r.execute("andMeToo($it)")), r.client("foo33"))); - h.header("fooRes", "baz"); - }); - r.body(ContractVerifierUtil.map().entry("foo2", "bar").entry("foo3", "baz").entry("nullValue", null)); - r.bodyMatchers(m -> { - m.jsonPath("$.foo2", m.byRegex("bar")); - m.jsonPath("$.foo3", m.byCommand("executeMe($it)")); - m.jsonPath("$.nullValue", m.byNull()); - }); - }); - })); - } - -} -// end::class[] diff --git a/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_rest_from_file.java b/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_rest_from_file.java deleted file mode 100644 index c224d4423e..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_rest_from_file.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// tag::class[] -import java.util.Collection; -import java.util.Collections; -import java.util.function.Supplier; - -import org.springframework.cloud.contract.spec.Contract; - -class contract_rest_from_file implements Supplier> { - - @Override - public Collection get() { - return Collections.singletonList(Contract.make(c -> { - c.request(r -> { - r.url("/foo"); - r.method(r.GET()); - r.body(r.file("request.json")); - }); - c.response(r -> { - r.status(r.OK()); - r.body(r.file("response.json")); - }); - })); - } - -} -// end::class[] diff --git a/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_rest_from_pdf.java b/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_rest_from_pdf.java deleted file mode 100644 index 88bbc645fe..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_rest_from_pdf.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// tag::class[] -import java.util.Collection; -import java.util.Collections; -import java.util.function.Supplier; - -import org.springframework.cloud.contract.spec.Contract; - -class contract_rest_from_pdf implements Supplier> { - - @Override - public Collection get() { - return Collections.singletonList(Contract.make(c -> { - c.request(r -> { - r.url("/1"); - r.method(r.PUT()); - r.body(r.fileAsBytes("request.pdf")); - r.headers(h -> { - h.contentType(h.applicationOctetStream()); - }); - }); - c.response(r -> { - r.status(r.OK()); - r.body(r.fileAsBytes("response.pdf")); - r.headers(h -> { - h.contentType(h.applicationOctetStream()); - }); - }); - })); - } - -} -// end::class[] diff --git a/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_rest_with_tags.java b/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_rest_with_tags.java deleted file mode 100644 index 743d24cf2a..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_rest_with_tags.java +++ /dev/null @@ -1,116 +0,0 @@ - -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// tag::class[] - -import java.util.Collection; -import java.util.Collections; -import java.util.function.Supplier; - -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.verifier.util.ContractVerifierUtil; -import org.springframework.cloud.contract.verifier.util.MetadataUtil; - -// tag::class[] -class contract_rest_with_tags implements Supplier> { - - static Object description = Collections.singletonList( - // tag::description[] - Contract.make(c -> { - c.description("Some description"); - })); - - // end::description[] - - static Object name = Collections.singletonList( - // tag::name[] - Contract.make(c -> { - c.name("some name"); - })); - - // end::name[] - - static Object ignored = Collections.singletonList( - // tag::ignored[] - Contract.make(c -> { - c.ignored(); - })); - - // end::ignored[] - - static Object in_progress = Collections.singletonList( - // tag::in_progress[] - Contract.make(c -> { - c.inProgress(); - })); - - // end::in_progress[] - - static Object metadata = Collections.singletonList( - // tag::metadata[] - Contract.make(c -> { - c.metadata(MetadataUtil.map().entry("wiremock", ContractVerifierUtil.map().entry("stubMapping", - "{ \"response\" : { \"fixedDelayMilliseconds\" : 2000 } }"))); - })); - - // end::metadata[] - - @Override - public Collection get() { - return Collections.singletonList(Contract.make(c -> { - c.description("Some description"); - c.name("some name"); - c.priority(8); - c.ignored(); - c.inProgress(); - c.request(r -> { - r.url("/foo", u -> { - u.queryParameters(q -> { - q.parameter("a", "b"); - q.parameter("b", "c"); - }); - }); - r.method(r.PUT()); - r.headers(h -> { - h.header("foo", r.value(r.client(r.regex("bar")), r.server("bar"))); - h.header("fooReq", "baz"); - }); - r.body(ContractVerifierUtil.map().entry("foo", "bar")); - r.bodyMatchers(m -> { - m.jsonPath("$.foo", m.byRegex("bar")); - }); - }); - c.response(r -> { - r.fixedDelayMilliseconds(1000); - r.status(r.OK()); - r.headers(h -> { - h.header("foo2", r.value(r.server(r.regex("bar")), r.client("bar"))); - h.header("foo3", r.value(r.server(r.execute("andMeToo($it)")), r.client("foo33"))); - h.header("fooRes", "baz"); - }); - r.body(ContractVerifierUtil.map().entry("foo2", "bar").entry("foo3", "baz").entry("nullValue", null)); - r.bodyMatchers(m -> { - m.jsonPath("$.foo2", m.byRegex("bar")); - m.jsonPath("$.foo3", m.byCommand("executeMe($it)")); - m.jsonPath("$.nullValue", m.byNull()); - }); - }); - })); - } - -} -// end::class[] diff --git a/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_xml.java b/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_xml.java deleted file mode 100644 index 58a4c566d0..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/contract_xml.java +++ /dev/null @@ -1,65 +0,0 @@ - -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// tag::class[] -import java.util.function.Supplier; - -import org.springframework.cloud.contract.spec.Contract; - -class contract_xml implements Supplier { - - @Override - public Contract get() { - return Contract.make(c -> { - c.request(r -> { - r.method(r.GET()); - r.urlPath("/get"); - r.headers(h -> { - h.contentType(h.applicationXml()); - }); - }); - c.response(r -> { - r.status(r.OK()); - r.headers(h -> { - h.contentType(h.applicationXml()); - }); - r.body("\n" + "123\n" + "abc\n" + "\n" - + "abc\n" + "def\n" + "ghi\n" + "\n" - + "123\n" + "true\n" + "2017-01-01\n" - + "2017-01-01T01:23:45\n" + "\n" - + "foo\n" + "foo\n" - + ""); - r.bodyMatchers(m -> { - m.xPath("/test/duck/text()", m.byRegex("[0-9]{3}")); - m.xPath("/test/duck/text()", m.byCommand("equals($it)")); - m.xPath("/test/duck/xxx", m.byNull()); - m.xPath("/test/duck/text()", m.byEquality()); - m.xPath("/test/alpha/text()", m.byRegex(r.onlyAlphaUnicode())); - m.xPath("/test/alpha/text()", m.byEquality()); - m.xPath("/test/number/text()", m.byRegex(r.number())); - m.xPath("/test/date/text()", m.byDate()); - m.xPath("/test/dateTime/text()", m.byTimestamp()); - m.xPath("/test/time/text()", m.byTime()); - m.xPath("/test/*/complex/text()", m.byEquality()); - m.xPath("/test/duck/@type", m.byEquality()); - }); - }); - }); - }; - -} -// end::class[] diff --git a/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/package_contract.java b/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/package_contract.java deleted file mode 100644 index 9fce68310d..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/package_contract.java +++ /dev/null @@ -1,32 +0,0 @@ -package example; - -import java.util.Collection; -import java.util.Collections; -import java.util.function.Supplier; - -import org.springframework.cloud.contract.spec.Contract; - -class package_contract implements Supplier> { - - @Override - public Collection get() { - return Collections.singletonList(Contract.make(c -> { - c.request(r -> { - r.method(r.PUT()); - r.headers(h -> { - h.contentType(h.applicationJson()); - }); - r.body(" { \"status\" : \"OK\" } "); - r.url("/1"); - }); - c.response(r -> { - r.status(r.OK()); - r.body(" { \"status\" : \"OK\" } "); - r.headers(h -> { - h.contentType(h.textPlain()); - }); - }); - })); - } - -} diff --git a/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/request.json b/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/request.json deleted file mode 100644 index 55f5fd83a8..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/request.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "hello": "request" -} diff --git a/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/request.pdf b/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/request.pdf deleted file mode 100644 index 69503635d87cbdfa660d5cd8be66d3e74b3b20e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14631 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 diff --git a/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/response.json b/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/response.json deleted file mode 100644 index b52d1df636..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/response.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "hello": "response" -} diff --git a/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/response.pdf b/spring-cloud-contract-verifier/src/test/resources/contractsToCompile/response.pdf deleted file mode 100644 index c3b233056b758d1cc9bf3176e99a95add89ba607..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15767 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 - priority = 1 - name = "optionals" - request { - method = POST - url = url("/users/password") - headers { - contentType = APPLICATION_JSON - } - body = body(mapOf( - "email" to v(consumer(optional(regex(email))), producer("abc@abc.com")), - "callback_url" to v(consumer(regex(hostname)), producer("https://partners.com")) - )) - } - response { - status = NOT_FOUND - headers { - header("Content-Type", "application/json") - } - body(mapOf( - "code" to value(consumer("123123"), producer(optional("123123"))) - )) - } - } - // end::optionals[] - -var methodDsl: org.springframework.cloud.contract.spec.Contract = - contract { c -> - request { - // tag::method[] - method = GET - // end::method[] - url = url("/foo") - } - response { - status = NOT_FOUND - } - priority = 1 - } - -var method: org.springframework.cloud.contract.spec.Contract = - // tag::methodBuilder[] - contract { - request { - method = PUT - url = url(v(consumer(regex("^/api/[0-9]{2}$")), producer("/api/12"))) - headers { - header("Content-Type", "application/json") - } - body = body("[{\"text\": \"Gonna see you at Warsaw\" }]") - } - response { - status = OK - body = body(mapOf( - "path" to v(consumer("/api/12"), producer(regex("^/api/[0-9]{2}$"))), - "correlationId" to v(consumer("1223456"), producer(execute("isProperCorrelationId(\$it)"))) - )) - } - } - // end::methodBuilder[] diff --git a/spring-cloud-contract-verifier/src/test/resources/kotlin/contract_rest.kts b/spring-cloud-contract-verifier/src/test/resources/kotlin/contract_rest.kts deleted file mode 100644 index 0215ed3ea4..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/kotlin/contract_rest.kts +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// tag::class[] -import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract -import org.springframework.cloud.contract.spec.withQueryParameters - -contract { - name = "some name" - description = "Some description" - priority = 8 - ignored = true - request { - url = url("/foo") withQueryParameters { - parameter("a", "b") - parameter("b", "c") - } - method = PUT - headers { - header("foo", value(client(regex("bar")), server("bar"))) - header("fooReq", "baz") - } - body = body(mapOf("foo" to "bar")) - bodyMatchers { - jsonPath("$.foo", byRegex("bar")) - } - } - response { - delay = fixedMilliseconds(1000) - status = OK - headers { - header("foo2", value(server(regex("bar")), client("bar"))) - header("foo3", value(server(execute("andMeToo(\$it)")), client("foo33"))) - header("fooRes", "baz") - } - body = body(mapOf( - "foo" to "bar", - "foo3" to "baz", - "nullValue" to null - )) - bodyMatchers { - jsonPath("$.foo2", byRegex("bar")) - jsonPath("$.foo3", byCommand("executeMe(\$it)")) - jsonPath("$.nullValue", byNull) - } - } -} -// end::class[] diff --git a/spring-cloud-contract-verifier/src/test/resources/kotlin/contract_xml.kts b/spring-cloud-contract-verifier/src/test/resources/kotlin/contract_xml.kts deleted file mode 100644 index 2ec6df2edc..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/kotlin/contract_xml.kts +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts - -// tag::class[] -import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract - -contract { - request { - method = GET - urlPath = path("/get") - headers { - contentType = APPLICATION_XML - } - } - response { - status = OK - headers { - contentType =APPLICATION_XML - } - body = body("\n" + "123\n" - + "abc\n" + "\n" + "abc\n" - + "def\n" + "ghi\n" + "\n" - + "123\n" + "true\n" - + "2017-01-01\n" - + "2017-01-01T01:23:45\n" - + "\n" - + "foo\n" - + "foo\n" + "") - bodyMatchers { - xPath("/test/duck/text()", byRegex("[0-9]{3}")) - xPath("/test/duck/text()", byCommand("equals(\$it)")) - xPath("/test/duck/xxx", byNull) - xPath("/test/duck/text()", byEquality) - xPath("/test/alpha/text()", byRegex(onlyAlphaUnicode)) - xPath("/test/alpha/text()", byEquality) - xPath("/test/number/text()", byRegex(number)) - xPath("/test/date/text()", byDate) - xPath("/test/dateTime/text()", byTimestamp) - xPath("/test/time/text()", byTime) - xPath("/test/*/complex/text()", byEquality) - xPath("/test/duck/@type", byEquality) - } - } -} -// end::class[] diff --git a/spring-cloud-contract-verifier/src/test/resources/kotlin/multipart.kts b/spring-cloud-contract-verifier/src/test/resources/kotlin/multipart.kts deleted file mode 100644 index 9274ff8181..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/kotlin/multipart.kts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package contracts - -// tag::class[] -import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract - -contract { - request { - method = PUT - url = url("/multipart") - multipart { - field("formParameter", value(consumer(regex("\".+\"")), producer("\"formParameterValue\""))) - field("someBooleanParameter", value(consumer(anyBoolean), producer("true"))) - field("file", - named( - // name of the file - value(consumer(regex(nonEmpty)), producer("filename.csv")), - // content of the file - value(consumer(regex(nonEmpty)), producer("file content")), - // content type for the part - value(consumer(regex(nonEmpty)), producer("application/json")) - ) - ) - } - headers { - contentType = "multipart/form-data;boundary=AaB03x" - } - } - response { - status = OK - } -} -// end::class[] diff --git a/spring-cloud-contract-verifier/src/test/resources/kotlin/readFromFile.kts b/spring-cloud-contract-verifier/src/test/resources/kotlin/readFromFile.kts deleted file mode 100644 index 126250b998..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/kotlin/readFromFile.kts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// tag::class[] -import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract - -contract { - request { - url = url("/1") - method = PUT - headers { - contentType = APPLICATION_JSON - } - body = bodyFromFile("request.json") - } - response { - status = OK - body = bodyFromFile("response.json") - headers { - contentType = APPLICATION_JSON - } - } -} -// end::class[] diff --git a/spring-cloud-contract-verifier/src/test/resources/kotlin/request.json b/spring-cloud-contract-verifier/src/test/resources/kotlin/request.json deleted file mode 100644 index 26c2b2f565..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/kotlin/request.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "status": "REQUEST" -} diff --git a/spring-cloud-contract-verifier/src/test/resources/kotlin/request.pdf b/spring-cloud-contract-verifier/src/test/resources/kotlin/request.pdf deleted file mode 100644 index 69503635d87cbdfa660d5cd8be66d3e74b3b20e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14631 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 diff --git a/spring-cloud-contract-verifier/src/test/resources/kotlin/response.json b/spring-cloud-contract-verifier/src/test/resources/kotlin/response.json deleted file mode 100644 index cb55e0cb2f..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/kotlin/response.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "status": "RESPONSE" -} diff --git a/spring-cloud-contract-verifier/src/test/resources/kotlin/response.pdf b/spring-cloud-contract-verifier/src/test/resources/kotlin/response.pdf deleted file mode 100644 index c3b233056b758d1cc9bf3176e99a95add89ba607..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15767 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 - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - - - - - - \ No newline at end of file diff --git a/spring-cloud-contract-verifier/src/test/resources/main.json b/spring-cloud-contract-verifier/src/test/resources/main.json deleted file mode 100644 index 03dc238c22..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/main.json +++ /dev/null @@ -1,17 +0,0 @@ -// -// Copyright 2013-2020 the original author or authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - - diff --git a/spring-cloud-contract-verifier/src/test/resources/messageResponse.json b/spring-cloud-contract-verifier/src/test/resources/messageResponse.json deleted file mode 100644 index f9504caa62..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/messageResponse.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "payload": "{\"propsA\":\"valueA\",\"propsB\":\"valueB\"}" -} diff --git a/spring-cloud-contract-verifier/src/test/resources/multiple_contracts.groovy b/spring-cloud-contract-verifier/src/test/resources/multiple_contracts.groovy deleted file mode 100644 index 7f2a98359b..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/multiple_contracts.groovy +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.springframework.cloud.contract.spec.Contract - -(1..2).collect { int index -> - Contract.make { - request { - method('PUT') - headers { - contentType(applicationJson()) - } - body(""" { "status" : "OK" } """) - url("/${index}") - } - response { - status OK() - body(""" { "status" : "OK" } """) - headers { - contentType(textPlain()) - } - } - } -} diff --git a/spring-cloud-contract-verifier/src/test/resources/prependFolderName/META-INF/1.0.0.SNAPSHOT/01_login.groovy b/spring-cloud-contract-verifier/src/test/resources/prependFolderName/META-INF/1.0.0.SNAPSHOT/01_login.groovy deleted file mode 100644 index 81b89235c1..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/prependFolderName/META-INF/1.0.0.SNAPSHOT/01_login.groovy +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - diff --git a/spring-cloud-contract-verifier/src/test/resources/prependFolderName/META-INF/1.0.0.SNAPSHOT/3.0.0.SNAPSHOT/01_login.groovy b/spring-cloud-contract-verifier/src/test/resources/prependFolderName/META-INF/1.0.0.SNAPSHOT/3.0.0.SNAPSHOT/01_login.groovy deleted file mode 100644 index 81b89235c1..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/prependFolderName/META-INF/1.0.0.SNAPSHOT/3.0.0.SNAPSHOT/01_login.groovy +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - diff --git a/spring-cloud-contract-verifier/src/test/resources/prependFolderName/META-INF/1.0.0.SNAPSHOT/3.0.0.SNAPSHOT/normal/01_login.groovy b/spring-cloud-contract-verifier/src/test/resources/prependFolderName/META-INF/1.0.0.SNAPSHOT/3.0.0.SNAPSHOT/normal/01_login.groovy deleted file mode 100644 index 81b89235c1..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/prependFolderName/META-INF/1.0.0.SNAPSHOT/3.0.0.SNAPSHOT/normal/01_login.groovy +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - diff --git a/spring-cloud-contract-verifier/src/test/resources/prependFolderName/META-INF/1.0.0.SNAPSHOT/normal/01_login.groovy b/spring-cloud-contract-verifier/src/test/resources/prependFolderName/META-INF/1.0.0.SNAPSHOT/normal/01_login.groovy deleted file mode 100644 index 1a794cfd80..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/prependFolderName/META-INF/1.0.0.SNAPSHOT/normal/01_login.groovy +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - - diff --git a/spring-cloud-contract-verifier/src/test/resources/prependFolderName/META-INF/2.0.0.SNAPSHOT/01_login.groovy b/spring-cloud-contract-verifier/src/test/resources/prependFolderName/META-INF/2.0.0.SNAPSHOT/01_login.groovy deleted file mode 100644 index 81b89235c1..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/prependFolderName/META-INF/2.0.0.SNAPSHOT/01_login.groovy +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - diff --git a/spring-cloud-contract-verifier/src/test/resources/strange_[3.3.3]_directory/02_login.groovy b/spring-cloud-contract-verifier/src/test/resources/strange_[3.3.3]_directory/02_login.groovy deleted file mode 100644 index ef5cba91ab..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/strange_[3.3.3]_directory/02_login.groovy +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - request { - method(GET()) - url("/foo10") - } - response { - status(200) - } -} diff --git a/spring-cloud-contract-verifier/src/test/resources/strange_[3.3.3]_directory/bar/03_login.groovy b/spring-cloud-contract-verifier/src/test/resources/strange_[3.3.3]_directory/bar/03_login.groovy deleted file mode 100644 index a4b4493b55..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/strange_[3.3.3]_directory/bar/03_login.groovy +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - request { - method(GET()) - url("/foo13") - } - response { - status(200) - } -} diff --git a/spring-cloud-contract-verifier/src/test/resources/strange_[3.3.3]_directory/foo/01_login.groovy b/spring-cloud-contract-verifier/src/test/resources/strange_[3.3.3]_directory/foo/01_login.groovy deleted file mode 100644 index 07978817b9..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/strange_[3.3.3]_directory/foo/01_login.groovy +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - request { - method(GET()) - url("/foo11") - } - response { - status(200) - } -} diff --git a/spring-cloud-contract-verifier/src/test/resources/stubs/wiremocks/other/sample.json b/spring-cloud-contract-verifier/src/test/resources/stubs/wiremocks/other/sample.json deleted file mode 100644 index b3c6ca2e5c..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/stubs/wiremocks/other/sample.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "request": { - "method": "PUT", - "url": "/loanApplication", - "headers": { - "Content-Type": { - "equalTo": "application/vnd.loanapplicationservice.v1+json" - } - }, - "bodyPatterns": [ - { - "matches": "{\"client\":{\"pesel\":\"1234567890\"},\"loanApplicationId\":123123123,\"amount\":123.123}" - } - ] - }, - "response": { - "status": 200, - "body": "{\"loanApplicationStatus\":\"LOAN_APPLIED\",\"loanApplicationId\":\"${123123123:$anyInt($it)}\"}", - "headers": { - "Content-Type": "application/vnd.loanapplicationservice.v1+json" - } - } -} diff --git a/spring-cloud-contract-verifier/src/test/resources/stubs/wiremocks/sample.json b/spring-cloud-contract-verifier/src/test/resources/stubs/wiremocks/sample.json deleted file mode 100644 index a9356b249c..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/stubs/wiremocks/sample.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "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" - } - } -} diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/contract.yml b/spring-cloud-contract-verifier/src/test/resources/yml/contract.yml deleted file mode 100644 index f7f47657c1..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/yml/contract.yml +++ /dev/null @@ -1,87 +0,0 @@ -#tag::description[] -description: Some description -#end::description[] -#tag::name[] -name: some name -#end::name[] -#tag::priority[] -priority: 8 -#end::priority[] -#tag::ignored[] -ignored: true -#end::ignored[] -#tag::in_progress[] -inProgress: true -#end::in_progress[] -#tag::request[] -request: - #end::request[] - #tag::request_obligatory[] - method: PUT - url: /foo - #end::request_obligatory[] - #tag::query_params[] - queryParameters: - a: b - b: c - #end::query_params[] - #tag::headers[] - headers: - foo: bar - fooReq: baz - #end::headers[] - #tag::cookies[] - cookies: - foo: bar - fooReq: baz - #end::cookies[] - #tag::body[] - body: - foo: bar - #end::body[] - #tag::request_matcher[] - matchers: - body: - - path: $.foo - type: by_regex - value: bar - headers: - - key: foo - regex: bar -#end::request_matcher[] -#tag::response[] -response: - #end::response[] - #tag::response_obligatory[] - status: 200 - #end::response_obligatory[] - fixedDelayMilliseconds: 1000 - headers: - foo2: bar - foo3: foo33 - fooRes: baz - body: - foo2: bar - foo3: baz - nullValue: null - matchers: - body: - - path: $.foo2 - type: by_regex - value: bar - - path: $.foo3 - type: by_command - value: executeMe($it) - - path: $.nullValue - type: by_null - value: null - headers: - - key: foo2 - regex: bar - - key: foo3 - command: andMeToo($it) - cookies: - - key: foo2 - regex: bar - - key: foo3 - predefined: diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/contract_broken_request_headers.yml b/spring-cloud-contract-verifier/src/test/resources/yml/contract_broken_request_headers.yml deleted file mode 100644 index f4f9318a9e..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/yml/contract_broken_request_headers.yml +++ /dev/null @@ -1,46 +0,0 @@ -request: - url: /foo - queryParameters: - a: b - b: c - method: PUT - headers: - foo: bar - fooReq: baz - body: - foo: bar - matchers: - body: - - path: $.foo - type: by_regex - value: bar - headers: - - key: foo - regex: barrrr -response: - status: 200 - headers: - foo2: bar - fooRes: baz - body: - foo2: bar - cookies: - foo: baz - fooRegex: 123 - source: ip_address - fooPredefinedRegex: true - matchers: - body: - - path: $.foo2 - type: by_regex - value: bar - headers: - - key: foo2 - regex: bar - cookies: - - key: fooRegex - regex: "[0-9]+" - - key: source - regex: ip_address - - key: fooPredefinedRegex - predefined: any_boolean diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/contract_broken_response_headers.yml b/spring-cloud-contract-verifier/src/test/resources/yml/contract_broken_response_headers.yml deleted file mode 100644 index a547611e2b..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/yml/contract_broken_response_headers.yml +++ /dev/null @@ -1,12 +0,0 @@ -request: - url: /foo - method: PUT -response: - status: 200 - headers: - foo2: bar - fooRes: baz - matchers: - headers: - - key: foo2 - regex: barrrr diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/contract_cookies.yml b/spring-cloud-contract-verifier/src/test/resources/yml/contract_cookies.yml deleted file mode 100644 index 2136d7df78..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/yml/contract_cookies.yml +++ /dev/null @@ -1,34 +0,0 @@ -description: Contract with cookies -name: cookies-contract -priority: 1 -ignored: true -request: - method: PUT - url: /foo - cookies: - foo: bar - fooRegex: reg - fooPredefinedRegex: true - matchers: - cookies: - - key: fooRegex - regex: reg - - key: fooPredefinedRegex - predefined: any_boolean -response: - status: 200 - cookies: - foo: baz - fooRegex: 123 - source: ip_address - fooPredefinedRegex: true - body: - status: OK - matchers: - cookies: - - key: fooRegex - regex: "[0-9]+" - - key: source - regex: ip_address - - key: fooPredefinedRegex - predefined: any_boolean diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/contract_from_file.yml b/spring-cloud-contract-verifier/src/test/resources/yml/contract_from_file.yml deleted file mode 100644 index 3af1157667..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/yml/contract_from_file.yml +++ /dev/null @@ -1,7 +0,0 @@ -request: - method: GET - url: /foo - bodyFromFile: request.json -response: - status: 200 - bodyFromFile: response.json diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/contract_matchers.yml b/spring-cloud-contract-verifier/src/test/resources/yml/contract_matchers.yml deleted file mode 100644 index a89c01cf1b..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/yml/contract_matchers.yml +++ /dev/null @@ -1,206 +0,0 @@ -request: - method: GET - urlPath: /get/1 - headers: - Content-Type: application/json - cookies: - foo: 2 - bar: 3 - queryParameters: - limit: 10 - offset: 20 - filter: 'email' - sort: name - search: 55 - age: 99 - name: John.Doe - email: 'bob@email.com' - body: - duck: 123 - alpha: "abc" - number: 123 - aBoolean: true - date: "2017-01-01" - dateTime: "2017-01-01T01:23:45" - time: "01:02:34" - valueWithoutAMatcher: "foo" - valueWithTypeMatch: "string" - key: - "complex.key": 'foo' - nullValue: null - valueWithMin: - - 1 - - 2 - - 3 - valueWithMax: - - 1 - - 2 - - 3 - valueWithMinMax: - - 1 - - 2 - - 3 - valueWithMinEmpty: [] - valueWithMaxEmpty: [] - matchers: - url: - regex: /get/[0-9] - # predefined: - # execute a method - #command: 'equals($it)' - queryParameters: - - key: limit - type: equal_to - value: 20 - - key: offset - type: containing - value: 20 - - key: sort - type: equal_to - value: name - - key: search - type: not_matching - value: '^[0-9]{2}$' - - key: age - type: not_matching - value: '^\\w*$' - - key: name - type: matching - value: 'John.*' - - key: hello - type: absent - cookies: - - key: foo - regex: '[0-9]' - - key: bar - command: 'equals($it)' - headers: - - key: Content-Type - regex: "application/json.*" - body: - - path: $.duck - type: by_regex - value: "[0-9]{3}" - - path: $.duck - type: by_equality - - path: $.alpha - type: by_regex - predefined: only_alpha_unicode - - path: $.alpha - type: by_equality - - path: $.number - type: by_regex - predefined: number - - path: $.aBoolean - type: by_regex - predefined: any_boolean - - path: $.date - type: by_date - - path: $.dateTime - type: by_timestamp - - path: $.time - type: by_time - - path: "$.['key'].['complex.key']" - type: by_equality - - path: $.nullvalue - type: by_null - - path: $.valueWithMin - type: by_type - minOccurrence: 1 - - path: $.valueWithMax - type: by_type - maxOccurrence: 3 - - path: $.valueWithMinMax - type: by_type - minOccurrence: 1 - maxOccurrence: 3 -response: - status: 200 - cookies: - foo: 1 - bar: 2 - body: - duck: 123 - alpha: "abc" - number: 123 - aBoolean: true - date: "2017-01-01" - dateTime: "2017-01-01T01:23:45" - time: "01:02:34" - valueWithoutAMatcher: "foo" - valueWithTypeMatch: "string" - valueWithMin: - - 1 - - 2 - - 3 - valueWithMax: - - 1 - - 2 - - 3 - valueWithMinMax: - - 1 - - 2 - - 3 - valueWithMinEmpty: [] - valueWithMaxEmpty: [] - key: - 'complex.key': 'foo' - nulValue: null - matchers: - headers: - - key: Content-Type - regex: "application/json.*" - cookies: - - key: foo - regex: '[0-9]' - - key: bar - command: 'equals($it)' - body: - - path: $.duck - type: by_regex - value: "[0-9]{3}" - - path: $.duck - type: by_equality - - path: $.alpha - type: by_regex - predefined: only_alpha_unicode - - path: $.alpha - type: by_equality - - path: $.number - type: by_regex - predefined: number - - path: $.aBoolean - type: by_regex - predefined: any_boolean - - path: $.date - type: by_date - - path: $.dateTime - type: by_timestamp - - path: $.time - type: by_time - - path: $.valueWithTypeMatch - type: by_type - - path: $.valueWithMin - type: by_type - minOccurrence: 1 - - path: $.valueWithMax - type: by_type - maxOccurrence: 3 - - path: $.valueWithMinMax - type: by_type - minOccurrence: 1 - maxOccurrence: 3 - - path: $.valueWithMinEmpty - type: by_type - minOccurrence: 0 - - path: $.valueWithMaxEmpty - type: by_type - maxOccurrence: 0 - - path: $.duck - type: by_command - value: assertThatValueIsANumber($it) - - path: $.nullValue - type: by_null - value: null - headers: - Content-Type: application/json diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/contract_matchers_url.yml b/spring-cloud-contract-verifier/src/test/resources/yml/contract_matchers_url.yml deleted file mode 100644 index c36bdbb7fb..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/yml/contract_matchers_url.yml +++ /dev/null @@ -1,8 +0,0 @@ -request: - method: GET - urlPath: /get/1 - matchers: - url: - regex: /get/[0-9] -response: - status: 200 \ No newline at end of file diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/contract_message.yml b/spring-cloud-contract-verifier/src/test/resources/yml/contract_message.yml deleted file mode 100644 index 10687ca89c..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/yml/contract_message.yml +++ /dev/null @@ -1,30 +0,0 @@ -description: Some description -label: some_label -name: some name -ignored: true -input: - triggeredBy: foo() - assertThat: bar() -outputMessage: - sentTo: bar - headers: - foo2: bar - foo3: bar3 - fooRes: baz - body: - foo2: bar - foo3: baz - assertThat: baz() - matchers: - body: - - path: $.foo2 - type: by_regex - value: bar - - path: $.foo3 - type: by_command - value: executeMe($it) - headers: - - key: foo2 - regex: bar - - key: foo3 - command: andMeToo($it) diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/contract_message_matchers.yml b/spring-cloud-contract-verifier/src/test/resources/yml/contract_message_matchers.yml deleted file mode 100644 index 936355a5b4..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/yml/contract_message_matchers.yml +++ /dev/null @@ -1,81 +0,0 @@ -label: card_rejected -input: - triggeredBy: "foo()" -outputMessage: - sentTo: channel - body: - duck: 123 - alpha: "abc" - number: 123 - aBoolean: true - date: "2017-01-01" - dateTime: "2017-01-01T01:23:45" - time: "01:02:34" - valueWithoutAMatcher: "foo" - valueWithTypeMatch: "string" - valueWithMin: - - 1 - - 2 - - 3 - valueWithMax: - - 1 - - 2 - - 3 - valueWithMinMax: - - 1 - - 2 - - 3 - valueWithMinEmpty: [] - valueWithMaxEmpty: [] - key: - 'complex.key': 'foo' - matchers: - headers: - - key: Content-Type - regex: "application/json.*" - body: - - path: $.duck - type: by_regex - value: "[0-9]{3}" - - path: $.duck - type: by_equality - - path: $.alpha - type: by_regex - predefined: only_alpha_unicode - - path: $.alpha - type: by_equality - - path: $.number - type: by_regex - predefined: number - - path: $.aBoolean - type: by_regex - predefined: any_boolean - - path: $.date - type: by_date - - path: $.dateTime - type: by_timestamp - - path: $.time - type: by_time - - path: $.valueWithTypeMatch - type: by_type - - path: $.valueWithMin - type: by_type - minOccurrence: 1 - - path: $.valueWithMax - type: by_type - maxOccurrence: 3 - - path: $.valueWithMinMax - type: by_type - minOccurrence: 1 - maxOccurrence: 3 - - path: $.valueWithMinEmpty - type: by_type - minOccurrence: 0 - - path: $.valueWithMaxEmpty - type: by_type - maxOccurrence: 0 - - path: $.duck - type: by_command - value: assertThatValueIsANumber($it) - headers: - contentType: application/json diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/contract_message_method.yml b/spring-cloud-contract-verifier/src/test/resources/yml/contract_message_method.yml deleted file mode 100644 index 31de49419e..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/yml/contract_message_method.yml +++ /dev/null @@ -1,17 +0,0 @@ -# Human readable description -description: Some description -# Label by means of which the output message can be triggered -label: some_label -input: - # the contract will be triggered by a method - triggeredBy: bookReturnedTriggered() -# output message of the contract -outputMessage: - # destination to which the output message will be sent - sentTo: output - # the body of the output message - body: - bookName: foo - # the headers of the output message - headers: - BOOK-NAME: foo diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/contract_message_scenario1.yml b/spring-cloud-contract-verifier/src/test/resources/yml/contract_message_scenario1.yml deleted file mode 100644 index 8c1cea9f7d..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/yml/contract_message_scenario1.yml +++ /dev/null @@ -1,10 +0,0 @@ -label: some_label -input: - triggeredBy: bookReturnedTriggered -outputMessage: - sentTo: activemq:output - body: - bookName: foo - headers: - BOOK-NAME: foo - contentType: application/json diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/contract_messaging_pdf.yml b/spring-cloud-contract-verifier/src/test/resources/yml/contract_messaging_pdf.yml deleted file mode 100644 index d402fed175..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/yml/contract_messaging_pdf.yml +++ /dev/null @@ -1,8 +0,0 @@ -label: some_label -input: - triggeredBy: foo() -outputMessage: - sentTo: jms:output - bodyFromFileAsBytes: response.pdf - headers: - contentType: application/octet-stream diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/contract_multipart.yml b/spring-cloud-contract-verifier/src/test/resources/yml/contract_multipart.yml deleted file mode 100644 index 122c44bfa8..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/yml/contract_multipart.yml +++ /dev/null @@ -1,29 +0,0 @@ -request: - method: PUT - url: /multipart - headers: - Content-Type: multipart/form-data;boundary=AaB03x - multipart: - params: - # key (parameter name), value (parameter value) pair - formParameter: '"formParameterValue"' - someBooleanParameter: true - named: - - paramName: file - fileName: filename.csv - fileContent: file content - matchers: - multipart: - params: - - key: formParameter - regex: ".+" - - key: someBooleanParameter - predefined: any_boolean - named: - - paramName: file - fileName: - predefined: non_empty - fileContent: - predefined: non_empty -response: - status: 200 diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/contract_pdf.yml b/spring-cloud-contract-verifier/src/test/resources/yml/contract_pdf.yml deleted file mode 100644 index e5f9c4b12f..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/yml/contract_pdf.yml +++ /dev/null @@ -1,11 +0,0 @@ -request: - url: /1 - method: PUT - headers: - Content-Type: application/octet-stream - bodyFromFileAsBytes: request.pdf -response: - status: 200 - bodyFromFileAsBytes: response.pdf - headers: - Content-Type: application/octet-stream diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/contract_reference_request.yml b/spring-cloud-contract-verifier/src/test/resources/yml/contract_reference_request.yml deleted file mode 100644 index 8d94b325d4..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/yml/contract_reference_request.yml +++ /dev/null @@ -1,30 +0,0 @@ -request: - method: GET - url: /api/v1/xxxx - queryParameters: - foo: - - bar - - bar2 - headers: - Authorization: - - secret - - secret2 - body: - foo: bar - baz: 5 -response: - status: 200 - headers: - Authorization: "foo {{{ request.headers.Authorization.0 }}} bar" - body: - url: "{{{ request.url }}}" - path: "{{{ request.path }}}" - pathIndex: "{{{ request.path.1 }}}" - param: "{{{ request.query.foo }}}" - paramIndex: "{{{ request.query.foo.1 }}}" - authorization: "{{{ request.headers.Authorization.0 }}}" - authorization2: "{{{ request.headers.Authorization.1 }}" - fullBody: "{{{ request.body }}}" - responseFoo: "{{{ jsonpath this '$.foo' }}}" - responseBaz: "{{{ jsonpath this '$.baz' }}}" - responseBaz2: "Bla bla {{{ jsonpath this '$.foo' }}} bla bla" diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/contract_rest.yml b/spring-cloud-contract-verifier/src/test/resources/yml/contract_rest.yml deleted file mode 100644 index 2acb1700fe..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/yml/contract_rest.yml +++ /dev/null @@ -1,49 +0,0 @@ -description: Some description -name: some name -priority: 8 -ignored: true -request: - url: /foo - queryParameters: - a: b - b: c - method: PUT - headers: - foo: bar - fooReq: baz - body: - foo: bar - matchers: - body: - - path: $.foo - type: by_regex - value: bar - headers: - - key: foo - regex: bar -response: - status: 200 - headers: - foo2: bar - foo3: foo33 - fooRes: baz - body: - foo2: bar - foo3: baz - nullValue: null - matchers: - body: - - path: $.foo2 - type: by_regex - value: bar - - path: $.foo3 - type: by_command - value: executeMe($it) - - path: $.nullValue - type: by_null - value: null - headers: - - key: foo2 - regex: bar - - key: foo3 - command: andMeToo($it) diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/contract_rest_named_xml.yml b/spring-cloud-contract-verifier/src/test/resources/yml/contract_rest_named_xml.yml deleted file mode 100644 index 959bda6c86..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/yml/contract_rest_named_xml.yml +++ /dev/null @@ -1,17 +0,0 @@ -request: - method: GET - url: /getymlResponse - headers: - Content-Type: application/xml - body: | - - customer@test.com - -response: - status: 200 - headers: - Content-Type: application/xml - body: | - - customer@test.com - \ No newline at end of file diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/contract_rest_with_path.yml b/spring-cloud-contract-verifier/src/test/resources/yml/contract_rest_with_path.yml deleted file mode 100644 index f7ad611c1b..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/yml/contract_rest_with_path.yml +++ /dev/null @@ -1,51 +0,0 @@ -description: Some description -name: some name -priority: 8 -ignored: true -#tag::url_path[] -request: - method: PUT - urlPath: /foo - #end::url_path[] - queryParameters: - a: b - b: c - headers: - foo: bar - fooReq: baz - body: - foo: bar - matchers: - body: - - path: $.foo - type: by_regex - value: bar - headers: - - key: foo - regex: bar -response: - status: 200 - headers: - foo2: bar - foo3: foo33 - fooRes: baz - body: - foo2: bar - foo3: baz - nullValue: null - matchers: - body: - - path: $.foo2 - type: by_regex - value: bar - - path: $.foo3 - type: by_command - value: executeMe($it) - - path: $.nullValue - type: by_null - value: null - headers: - - key: foo2 - regex: bar - - key: foo3 - command: andMeToo($it) diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/contract_rest_xml.yml b/spring-cloud-contract-verifier/src/test/resources/yml/contract_rest_xml.yml deleted file mode 100644 index b8fd07f464..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/yml/contract_rest_xml.yml +++ /dev/null @@ -1,68 +0,0 @@ -request: - method: GET - url: /getymlResponse - headers: - Content-Type: application/xml - body: | - - 123 - abc - - abc - def - ghi - - 123 - true - 2017-01-01 - 2017-01-01T01:23:45 - - foo - string - foo - - matchers: - body: - - path: /test/duck/text() - type: by_regex - value: "[0-9]{10}" - - path: /test/duck/text() - type: by_equality - - path: /test/time/text() - type: by_time -response: - status: 200 - headers: - Content-Type: application/xml - body: | - - 123 - abc - - abc - def - ghi - - 123 - true - 2017-01-01 - 2017-01-01T01:23:45 - - foo - string - foo - - matchers: - body: - - path: /test/duck/text() - type: by_regex - value: "[0-9]{10}" - - path: /test/duck/text() - type: by_command - value: "test($it)" - - path: /test/duck/xxx - type: by_null - - path: /test/duck/text() - type: by_equality - - path: /test/time/text() - type: by_time diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/issue1038.yml b/spring-cloud-contract-verifier/src/test/resources/yml/issue1038.yml deleted file mode 100644 index ea749fd479..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/yml/issue1038.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: get-all-users -request: - url: /users - method: GET -response: - status: 200 - headers: - content-type: application/json; charset=UTF-8 - body: - - id: 001 - name: alice - country: US - - id: 002 - name: bob - country: 日本 \ No newline at end of file diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/issue1052.yml b/spring-cloud-contract-verifier/src/test/resources/yml/issue1052.yml deleted file mode 100644 index 38c1634b07..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/yml/issue1052.yml +++ /dev/null @@ -1,22 +0,0 @@ -request: - url: /numbers - queryParameters: - page: 0 - size: 2 - method: GET - headers: - Content-Type: application/json - -response: - status: 200 - headers: - Content-Type: application/json;charset=UTF-8 - body: - - number: 1541609556000 - - number: 1541609316000 - matchers: - body: - - path: $.[0].number - type: by_equality - - path: $.[1].number - type: by_equality \ No newline at end of file diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/multiple_contracts.yml b/spring-cloud-contract-verifier/src/test/resources/yml/multiple_contracts.yml deleted file mode 100644 index d1ee1a3c01..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/yml/multiple_contracts.yml +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: should post a user -request: - method: POST - url: /users/1 -response: - status: 200 ---- -request: - method: POST - url: /users/2 -response: - status: 200 ---- -request: - method: POST - url: /users/3 -response: - status: 200 - - diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/oa3/openapi_petstore.yml b/spring-cloud-contract-verifier/src/test/resources/yml/oa3/openapi_petstore.yml deleted file mode 100644 index ede29d2fe9..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/yml/oa3/openapi_petstore.yml +++ /dev/null @@ -1,157 +0,0 @@ -openapi: "3.0.0" -info: - version: 1.0.0 - title: Swagger Petstore - license: - name: MIT -servers: - - url: http://petstore.swagger.io/v1 -paths: - /pets: - get: - summary: List all pets - operationId: listPets - tags: - - pets - # Define Contracts - x-contracts: - - contractId: 1 - name: Test List All Pets, No Limit - requestHeaders: - - Content-type: application/json - serviceName: serviceA - - contractId: 2 - name: Test List All Pets, Limit 5 - requestHeaders: - - Content-type: application/json - serviceName: serviceB - parameters: - - name: limit - in: query - description: How many items to return at one time (max 100) - required: false - schema: - type: integer - format: int32 - # Define Parameters for Contracts - x-contracts: - - contractId: 1 - value: null - - contractId: 2 - value: 5 - responses: - '200': - description: An paged array of pets - headers: - x-next: - description: A link to the next page of responses - schema: - type: string - content: - application/json: - schema: - $ref: "#/components/schemas/Pets" - #Define Expectations for Contracts (expecting 200, application/json response and below conditions) - x-contracts: - - contractId: 1 - matchers: - path: $.* - maxOccurance: 25 - - contractId: 2 - matchers: - path: $.* - maxOccurance: 25 - default: - description: unexpected error - content: - application/json: - schema: - $ref: "#/components/schemas/Error" - post: - description: Creates a new pet in the store. Duplicates are allowed - operationId: addPet - # Define Contracts - x-contracts: - - contractId: 1 - name: Test Create Pet - serviceName: serviceC - requestHeaders: - - Content-type: application/json - requestBody: - description: Pet to add to the store - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/NewPet' - x-contracts: - - contractId: 1 - body: - name: Jake - responses: - '200': - description: pet response - content: - application/json: - schema: - $ref: '#/components/schemas/Pet' - default: - description: unexpected error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - /pets/{petId}: - get: - summary: Info for a specific pet - operationId: showPetById - tags: - - pets - parameters: - - name: petId - in: path - required: true - description: The id of the pet to retrieve - schema: - type: string - responses: - '200': - description: Expected response to a valid request - content: - application/json: - schema: - $ref: "#/components/schemas/Pets" - default: - description: unexpected error - content: - application/json: - schema: - $ref: "#/components/schemas/Error" -components: - schemas: - Pet: - required: - - id - - name - properties: - id: - type: integer - format: int64 - name: - type: string - tag: - type: string - Pets: - type: array - items: - $ref: "#/components/schemas/Pet" - Error: - required: - - code - - message - properties: - code: - type: integer - format: int32 - message: - type: string \ No newline at end of file diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/request.json b/spring-cloud-contract-verifier/src/test/resources/yml/request.json deleted file mode 100644 index 55f5fd83a8..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/yml/request.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "hello": "request" -} diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/request.pdf b/spring-cloud-contract-verifier/src/test/resources/yml/request.pdf deleted file mode 100644 index 69503635d87cbdfa660d5cd8be66d3e74b3b20e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14631 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 diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/response.json b/spring-cloud-contract-verifier/src/test/resources/yml/response.json deleted file mode 100644 index b52d1df636..0000000000 --- a/spring-cloud-contract-verifier/src/test/resources/yml/response.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "hello": "response" -} diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/response.pdf b/spring-cloud-contract-verifier/src/test/resources/yml/response.pdf deleted file mode 100644 index c3b233056b758d1cc9bf3176e99a95add89ba607..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15767 zcmch;W0WS%+NND*m+iZ3+g)~5mu=g&ZQJUyZJS+Pw!3WC)bs59&f0tSJ8S00H{YF+ zh`1vo<2tT$<&Ri-lKv1DrDddJg(2;EEck$70x$q<4J=@IcmVX$<~GLq4(1-lMgYdI z8i0|NosAtpFAmTIuyL>h7@61r+5mbv02_c_|b4#{;n|s`1oLqZH)dJ z4)Fi?4~F?)0#S0eGX~JBDHxl4g<))C>SP9BWdP8Nnp-&;JA9q3^qq`_jSX#$zIy%R z{6pWt+7a*<1R+~1XKNcr01JTrhl8<^xuKJ-!&m5Eu>t5+zeq3wn7;Ne4iYv-#%^B? zUscwB)J<#wjErB?Pyo;?*xEXM4e|H2;ulc>;}^)U@m&7N?SI8XFCh%jOqhV8@>u4e~Vg%0z$TgVE8M2|GfGCMIvGTBJy8q z`=M`Y?D!Yizajl2WkUK+`c}54{~{#Tf4Sqo&7UHG`Ad)g%rXn-zlX1+E3o73^R75^-}9Q*`o11?0_(4t z{TJT<7S=y8F)?%e8>j5}ElDB9Z^M_bsBP#eq~;5a0G)5^)yV+}c{U7b+g`p5rKV@c zBG+=Dq*FET-Hpb8ShQCqg`guvHv~ly%ZC6xWy9cGOSg7^c2hG+^`8>_kKPBNSS4=j zeOXxu`d!2vUQRL<&}pQy4zIqdopm}yb;c+%IgYzIndnQJAhKyqFBG#6{;8SBjf!^J zXbq+Gc2Xpn+-4)aL8rgjd?TnSvz1sDq$SX6&+`Bkf7G6_gwtg(QIJqpl7F0$5Mrq= zfD6An>N3WD$Mx6OjTd_mN|n-mJa^p!D9BgYy}jV19@#}h#>xSiMl}A1!a4r$pfLiN z8Q9pr-gy6H$jHpd`R{5w_l9;-8oF_H-pV0;B{3p~9?OUlvINoxkw9D_{2n08 zBpqS|z)26n%oTJy)3-l@CITrS3WJZtv;(#mu8Am1kdgM zyve@JzKpwet!VG~+J3gT+X@mP0zvtC#O0-SO{%DO+MZ{%&X;|j!($-XX`SSJV znE_eXtRxQ^H)-cSf#-Qb`weSrX|S((pH^uDwS5B3daLc$qTx-ndSS#o@f7$%s{|zn zUwr>C6;_Z?zpol;Zm$F~0(^fuoQLUvquDA3QL`PqX=YlhO7^(~+l)NtAQ(MpW*U(y za)auP8UU&jNLG#+zjU2?1p&aVz1M*J&hCDU?V;iB@i7^V)4i+n*w)qTIa>`}Ftu5} zeMv5@LC1kO8PS_VI0#4VEwwS5;K0=Pqn2yAWBjJ@$6GhUrc-nQj$oh{9y?FZj|CIH z7sOr%x=iIx zGi4Za7-3j>7-o|VO@Bz*C}uAZU7+`pxoa<|S`X6NxmpXfIetnDfFJbrUcsGz1N(TAQZVvF`RG;8OEZ;oB@uz9WVj~$+f+2v-~M4ad+Fr@}F&EV5`|1}07 z+fLe6m>WfaRu(^+Il)76SiW)CFOJ_LHQBA!wVhD!T+l}rhujdaa-vbfJ&VMWZG0TQ z*e#ro-07NIV$j>G?$S4Wo%}JzDtmU8)WKC04G`xZ=#)ajc6gnL_9Y-| zIs^7x#EoHeVM>FlVO3#mVFF>MNE>!Gz3!w)HJHpiY$9HIR%S5;aPsU(4dd8s(7sfj zCXrm|xg%xX$cH}}ZWy0^b{Heu&mLl?9#Lbl=+UluQ%888<7*N}l45r^4Yvlws{@w< zF*S9@AMs8n9|yR&z*PVne)gSdBQ(Efq}sIIDxovCbAFt}v00vzK0qlz_ZAJm7|`FZ z_KQjB;l!wyWe0N_Gp~>S+z~yoNgJXQNLj>FVC|}f{~cIw^TI1VPY}X)JaMh2v*pj% zo6jw9Xa>K>(E zc_o7%p6I8rUd~9D-@PKs(RN%Tgi1Y1j+_MV;sQ#oGzKtRJG>+Ivh-Uw0KkN=cc^9&XDmSJ*HSJqHzo`4}at>up^5>I&w`8b@!7O zD85MhI8H9!u9HpZ)3-CsRJ?KyO@`3|2P0{56b&V(b*9MjGlJoC&CI48(q z#+d=z0Vii&@}I5H&ToPnuW6xkTMIn+)-gx+=X^6Rl#>nGnK5tVP|-*BT8~xT%&apD z1v#Y~U8dy<2*8_;N(+$Vi(bt#`6 zWnDAqHk8~jlV%xZ)Yf5=C%m2R0{H0$@{z*K9Gik^*zKPRN{o7^Ld1h+kJi-C@q z_`O+SHeyw|7|t}B<&1%3jP~?nY$GTQk7(ngA^zcG_-npDsZg^EU1eW8EB0g}$0b#z zX25F;#>GbRGQYsonxA9MpvR^wX3xYGH^>$}7q!#;Qluvk6y6gr_)%(iFzvidEyx~+ zqA&ldK4sCiy8y$(E>ag-*bN9;1zH$apkTN>Q!idYH$tbJt2i)b%iA~JUUdINnP8`K zb|;hkxc<$7t`{60ir`*pmv8t+(X|<=>g2~{ZT9c4S2kmRVh6x<(`aY=h zvZlaN8*vOTg|18+=6)~BHK6a2K)-$l?fnGk_B)wVT~ry5ejd6fOoVejxR==1;t-15 zS%T(QVBk5G6wcYO=gZ0KPPZ&zINzU~{JM6%L;176XTVQ4fDh(ndX*)ZhPKKSU+teA zHg(60Nf;f>RgZ@F+xVP3{`oq= z(VrQc@18^q=$E^*bU`QW&&NI0Y6P){E);t_Cudk`x27*|SflpGq*i6Ut1i(xzJTaA z1iPPb$(+hFA)oO+pLlt`7(_5Z-oAcNtRVqoVsT+kRP*HuaO>m#2dFehp63!*=c;<# z>(r;-ABv}pDp$$KHpgmPb?b9AzA7c2J9Euf!~XR67yhKUR+!_&Tq*aqy~yzA70VB& zO~wyTxq4i8acof8-v`w~>s@$q(xEbf+K0pVDmc9k_F7Ysv{dd80$6bkE{Tr$>>Qp} zU-dsk8|y56ZB(-q8$I9m?xn;&^L$hu;0?HP&@R8z7bV71HqU*er>XOFpUID8y=`-E#{BMJh9~KuXMGXSU3EMEyFg{ z_|P|PapJfKVJE>L{ZD7yH$I0c&*M+7_xH!x&!pY#p%@Rct4nvnuC6`qL0{>vk2jRn zYwdwQpZtZ^-KMktR4%=)CG=ODM>ek)w_=wZIuRdM=CEu-j%b%j{%`nGm-TNSG#9Z{ zXqUFT_>s3DL7tR7+_$gPe;?*)#Z}E%1#>Cicys@N?}{UZq2PeLk?BKoe)8z~ygxtc zJ+}zx184xSW7+%o^}(%Ul)L%QcNE@%K6FSD32!8cjo&TeRHQVET-5+LGbXj^XF3n; z4~U*Y=f*R2aw{zvpc$#GTjoAX5Eh0_(5nKg602>iOy@l3Am>cypsUua!kb!Yf3j<6ZlFHvsoA9;N97>iyswwrBfiiNfLKF-&u57LBO#VXZyd z;n(Oj6!QW$MiNFEMj}QsM#4Hz1Bcz{@MhuA@QiO{g;NG+$VQ5_@tR~iNS+<0I znU9gX7CXY(#$?_zLs;Of$F0UKu(y)7oWvG>mb_;2Of^))cf2S{HI%OG?QG?TO!Yft zjxFq4JAl(ZVryKWKzpTV2Bc_G^Y%l*nxL%Ep3ybOSnFx7C|1UM_jk{=vd)-q{?byQ zHC@zb3huFNle)gY&OG?umWWF_Vb+Fk*5<@1)U=Mk#Ob;;44$B@}cpO1dOG>%f}Eg(=STrhWC{ zWEQitDT2?+?b#~x+Ds*P*Tvn^LIsd4|L|*0I2Z3Fi^<_am#n7TBWJb~)sfOeIbkW2 z>^=XlBc&R}4LQ=B2wpUwh^)7r{YUa1&gWla^lmkYHQ78)H$#aW6Jx4!d>%I^i7Vux zxsyEUPE6ND*G68GJ89I6N8jjoWiCZF4BJDUaGViN*^Za~;LmpDuNAKqcw)}f*ft5V zKDkh>Ja3Y|uYG0(d}s@F+>lbvYo*xeJxaXpl>g5eau_*4D{eD-|T{QJDe2_X+BL2^!< zi)2SpY4OH9^E~hg_zCHW@(J9D^?Jpn1bLBM@l3Jfyy|?*Jorh$9r1hohw!I_Z%NPW z#GUF3{R>W)V5V8aK0Ua&zgs(^)*{;jg=ZA+baMmwGJJC)@0iO@`3;L>!-f??&gAPd zvlYK5`b;|L86an2rU7F)@(huCQpZ4SdEyN1fyy%)&$y<6eVOrr%rmlUYEyq?rQ?kE zf$!DNdsMbIc6r22(tDiGkbH&mfs=b`y0+mA_cg$KY`URld28kO8O{UkYmE2IM;~1+ z!Lo=;`1`1j!KV>_gYIbRK2OJ_kMXBLPaSn7w95eg>i3s^=2`-s;g-U#S_B>co_?uX zT*o;#^8^-w3<{a}63K-k9`pJn*q*qW6a8kOoX~qaVAsP!I|M8U*92*%-1X?Ap{^oy z?6LEGkZ1oXLuD%@M~UZorxO$N5T)LfT5Oexl=^2YtO~=46`1A()>>sN){f+jk)_(E zGg+SaOLWtlKr7-+bGDtSL*V9|jXr#n%oTK=a)S65iT7e($u~TC*zI=##{8!|ym@#w zN$J90C+}~dAb|lw-}3dd`-zDP3%ExHhn>Ua;-bS#NE(VQTP}DLJWGm7?oYEfOKp2T zKp{-NVe{;VdA`poHK(5tswJx3(NRjAacdmd@KZaH3h zKi0gif&O9VX}!*uL9pGdzmK<$<$HK~Aa^-S%2~f(T)5cqe7Nv5`D}=Wgy(yFgQdsk zdYg|=)pfsbDy-?TKbvaV^f`L!xY~Rr@N(NNjOBm6Ye+2R#RSgTtnSK0?4(Fz{MCou*PQq>}Ei37xZ#fMfu~DI;zsHC`~$40|!qDYRTyf zfVnbB6`zDbTxf4xQjSBjgiBAhaRScRUAX&b%^1_c#06{s0rgV{7(r0yTo~T|*>M8R ziVVzwmFx6dLdaP^4X%x=-zU@pRH(0{-10erpB0e91%={)4KiyIREVfC!m5k_L6Bsd zp|twS#dHZxwZA5l=~~1(3fZBt=@54GGbQhaQP2j<1YF6^MVt{K2=O3`%{f$ytTZwA zvxQ!AXUEY_$ggOKH03m0H6yC}sZmF%W-mT5Gp6axgP8VnFDFYRNCcetmQHKS%EdUm z^Cb7WeEqhwO&-P?>xy{(+gtl@XHrv~!El@$_ZBR>$74*>qN#^RZDR^q3WwA?6$(p7 z492$^{hak{Gc4;$^9-ek+9(U#Arj8Ryo`)Xpg9eQiL~tdhv`ul`gJ8UJSKsW{Fw8Lo#X}~15fhxc&ua&rSxcQ1upofwb)TJHRU;|w>8z#1q+c}L@||^A?aL%0OtVt zB&@r?jmhw5BT-o-wzEf+q`c5RZcF}^=t26WEz3t}Ha2gn8@+%=N4Z5iBxwshf{m(8 zsg7P?5DYUcUN(1EeqWC^PDlpR4n?xwppZ?DJpN7yWh?X4lWyVB)%Tb;wH7oPwg6bY zH%euTx@^75@uNMA*y*Gk&a`7}YzJuvSt0$vsyRje2@)J>ILKopkD`30j#(Uz=$ya` zgALA#+c_0dqaTtb(1Jx2tzlOH67gPBYy%zxvR&E10jR3DJyx`^;4q;use&OYk@L3F z*e0YgDuIV-N*N51Ooc3YK!j)M0kzYaaIi_V!XN~tLDwtQukr!3)uvLxfytBmtQW{) zg6XKiiq{S(nB*stJ2WUlFl4<3RA3vh0BMIN9xIv&AP~<*K^MIpT;Rmqb z64Mt&gf1xkxbMDs7)j_J`nGmvF9Yf9bM)KhgM>lCJ-suW9`NY%4XvPpSDfFj8FmqO zId+KzrDk@IzWK;5EKuBY77>OJnh@cO;tFaBA0Hn*vCJxZ@rRQig%VQm2Fro+hEH&X z&mg{FIpogG{AfaW_%o;!(s%M4=WQki+_b`i_OEg$1q^-kDfKijjf##TRy_vr5zNTh1D04{(gMY z;c1s4>fse@>?UYJ;vI?~Ou=%xcIPaxRZs){LguYJ%N{pO%qyz9hLQ`E4!jJ%JmRfp%0xi`NIQhD$#F-WsqUeZBTkJ8;X`!808U_G-wAf)5pl0w~zm%GCQJI zfnVu}T$zG|X~^WO2C?CX%ZHyr(EOvqc*BF{Ce-+xcl0{cc+6t|X~1EP=y zJjk5{#MX=FxxYk0njgm%xAj*ZPRj`h*dzbYP%+Zcw{*u#L zzD#QrTWs1dfIR7WF84%x;nm+_AC0l|(A0Ayg6{a3PA-&xSk1AQyeL*?2EVqL`Gl4;*uOP;A z-#mwSYLIw?GkZ5Auw}&L@MT3i5Z3hXXjZ)4>&xSx_JDsf!jWIp&M|PgwtDK_9E)a~ zCU}0oF>A5upK|YjR?m!WvS}}f-#+;*&eLgOPSf)fA4pIzwL1Kuac!RU`56(9(^u`T zwl+T>i&MSlmO?3atV(z8{E629F@!+m1Im5)-c{hP0wr4`PwNG-*SC8L&(V!y8>^| znV&qr=TolvQ#jRR=pvt2=aNozoIjt!1{B++bOkA94rJRp7`2_3(6~QtWA!ZX1hONr z8J~w>t+cs!n5yBadqQYJnr2$5KYNPF9&_hyXiRceUZp(N!QPI&*1)u!B)~T>!=(yvt!4BOI1?ED)Yk>t z><7J$ri1FsRA5qMa!0wK+(ez!eON3x1`mv`gB){d8uR;=U$PUYrM>sl|JcejBd_TnillfK!txX-uU8 zznh$}kFxJ9}&CTv$ z4@8?Jy|vR2s!3qSzvg%3DR#2r`Hw1vVhk61_oh=|xP+;GzNVKzXP`cNV*$~2-0P4N*Ql8>tkn9* zJ}hd!1Se-Jkmj}EGj+6AY~!+l;C6^a5{*ZiYEV+e2(`ZzpaO(PgP?x^TaIGN!A<%x zTQPp~WBdW1T(p^Zr2eOEqyY{;7=v`$ zkou|o4PjXToB}X$j=>DtVlPxv8E9bL6&t5?qP-KOmrTLf`8*Wv0aEPREsW%l0B}+- z1c&%beEecr`VQ6~cN`-77)|@d`&!6{y;39{zZvno!vxdJBV?zL90r)*4G5crp~Wc` zks2ZPLWRlgLJ-YLy^(gPo1|nn$W^mo7W1qsQ`R{Mgt#69sEZHwXV0!T)Y^Wz!Sj|h zBh0t~b9AnbmID=bF@td|OgYlU8|L5}B+CByrf1Q)M0N#T1if=|hKpyV{&%f+P-|lu zjoKR19szU2=x&Jk0jc7M)kx*C&j~Sk%qM|&uqS*EV4k|B1Ik+<#L$2(<5n@Xcj8xeHIda-$+h) z()M`F^G@gy4G$14e)ud0QF8;0>?pov`O}AmfW_&(U0uG&68iSdfYgUrp=||jhBkCc zbpy6`q3>YL3*2fIXrm9djE7>wRd#}J_}b&~M`k+i2=3S^B_)#*ihbr0DRqB-uS$_} z-8sTK!Hv`(Nrybos#Y&`S8LF2P;?CXPvNC~;B0aKreFvFyVJw2gk{r%6Hc8+#!f!*PZ40sj#KLUk63rAQ z^O0f59|5q*on(vOkL|ed`CEQKW{0}gcpme;AaxO)6ai5RN5pxE6BmPw5h_bL&vT8@ zc9DA1c@t`JHGgk1UNv47J&$z@$NHI> zmsv(VyHUPY^ZG+~v?mf~rnkY`cTr$kGP20(1WQfowRZYx_y&IXR+=JVSRqQOJ-af` zHO`ww!m+}I0Z)3kkJPKFC$?LZpd|G~&zuHJhHL=$BlG8*6wdUMtq+1e{Q&p_PxUz- z?z4(DK>a(t1*kp(QV+X~PO?Xx(TU8HG?$Q*6>OH#2T6ohUaS-f1B{NI5Uaah5?jCG zJdXn;k5B{fTjpH_W6VfAUK)mj1lM!wexK$gM^pjud}=M`;k?{7$i*Jo6}!SQ!)wR`Je%01%UOePEoEP9IokyorVW; z6TfV3!f?G*hC~sVYcF2yw?lVyfo!taF1ZK+BE`PRX#lAn)e6)MVHgYja z;eU8RQFvoLk;C|t+$8mRco1SwS@af2D^QX?_+uuj02SQZNgyvMenCmJig|d`pUr*F zS|k74^2QG@If$Ue@}_(LNAHPGa@x{4+NrAv#cbIf`px-_$A8+R>X0Wnr?jgtwvxOY zG25z@Xa6+LJ|s6Zs*4LOgwWP(SnN_~_=jN`76BM0%f$SS3H7Jg0~7b8?@|w%-*s*x zc<bHe0!dNX8&OGhE~~!)ONRPosg~Q!WVon3QWq8F+I>h;d(hb zF-@!YlH-}SYB4+<-HsVJ#MDML5<*l9=Ke4Yk{?n@S?rXMwBaM9ox@%K#dJ27lBcbe zXx(}$oG&p34An2u;SzB?QRK$|IrVY*qUZ}(4D8V*O8>`cHQ)t+EDVZD+8TgF5xF`l zAPk>@sD!D6H3)GeMvgJbtR+jgT|&`1$to}v0yjn>j^aW%<}E1C7zCZW7BfpN7Nhmc z0$#^EO139K=urnRGO$MI_3nEW%j^iYIK^opaMvW1Wl^kVptF(!Ts|I8py&6=`$v!= z5U&ldgFi8|kF1b2Z;lu+HiOD!+ipHr8yB@e)gJsx+H#~4OD6-)T)e*|5;kMyPfHh= zC6+8$!5x6&LCL^SA(S8%AhWnZvcx7(~|@)4!Lw z|K4};ta00RCgUa&@&_wyZY%jfMw61xVpVYT|!t(xarJ;z}9UuFT)# zj*hJ#-Z#H_E5RxWnm%LUwJ^C`Of#>mC|FVyI&zbMiA1=HtR3Ylh%CPpY!6avt>PM4 zF{MD_e(2|jf+1lz>#v11%M5V;@#6$~&(!CoRs^Tk@nmicoUKC$tBJ~3@<4%b5cbNcVGI}A-9Yfjmh zgyk-h?ah>$r%QvIEzb6c4}<`-G?ViqsB9crF&xp*Evr_}EO4;lP%ua#C6+CpJcNd0 z!+p$v&mm#Ra{Hw=*6CraLo}_!Q_q$Rs8bM%-ZZJ$h|*S&LPpf*kM|dib`9xanZ{RM zL#fNL&-{bv6tsQ%8CxpM1y6|y$*I0=hLMl@BaLbuZv~ zEJHYGSST|6_q`JG$)!}%+FH>W49@|B7ox64_BzY0A37KFO*I0=gj7Qhat|(b6z3GS zKPYWm+T$1@w@_UZc{ue%wbZqex2pP_38mgugWhP5!{dhIYy*1W8NnbS#`6hx^79Gv z3H^Qa>lQIlPHNy_S;4?93f|v{3JthM#6#C`n>B7Cg8C?-7~IE2HP%wBv&v&l1S%%7x?(;xQ(nCffKv408QuTZ z6k-zm7AQCXas5PgJJ=HmHEfN%z)6hCu7F9jjGd}4{!NSo;Kfax+d8&7$#pb%9!6HhDkJNk8vn6`@ra->J6 z<+_mWu*ja3_E!9ov;q?1xOz$48)7kr8SK;5_>*!9Jqj(`1B&qJ{i-@&MWrRl2`sVWnx4Z&>1eZhxGZO;>L0E=c>8|TM zvQs3Kq$VZ8)j~%kt;Vx4hcJi;hrSyz`J*OCI$+Eti0(FLDDLhNlgfBS=vI;*lJUbj zk#88zN2f3tKu@4~Hn(W=8V~36=(Pf3(qZ|jUzhBfwt04semG&j&?K4i7Ip{dZRYDG?6$rseLV*ZuKB!@JpKZ!Bs^=#YPy(_v2`+pQm8WKumeP$3);Il22l; zD{#%JcW#%y;y+ubAL@-(ldo$sK_tlCp4w_I-ObLW_*Rn>;Eey4#<>_Dr(+XYNr2?p zEpsa$eO@ZqR<^|0;OUmjZQFq0XYM&{t$5MonRP6(&wDGz@k76NeP}Ix8~c%5ide}B zx7ics7NN68(gy;eFo6+la)eV~qm1qT)q zt>8{OzNVxD+0ZYkq=S&na8A`pU?fIX-pSt-+*x`9Jj*>_e&at&?hrT*DX}mRQ|`r3 zB-%ao8GxAhqosG0tS_=B3Lg#NMq3jbfz~Oz=!({Q!`A z86EY{tB6=so$L61YCZ+GAu*Vmr+?`-=>Ey}2M*B^i}IuYfcj8j_-tO3EFUhHWd9Pw3!#sn=n1v&^02cz`s0Po z5xlt^;jWq#<1`N$mjTC0PmF2+B}|I~=}oQ7&q26}igW;qMwxIXm#xwj1{%v!vd)*v zLA_w}fghK0sxX387c#<(b6H(x#j&O6kGEA-5?vFaG(0qkPa zbjC)uS2E7~9x-mt%HlG=!Xn?7+ZB{C=%05dH=#DMeCM^s-!x;hHBZY zq0c6HGncfg(!r(tN2QF~9_ATa-s1kJl(1F#?8T#De}|)1chglf6Qj-_Ol6K4EoIG2 z3*U|~bMt>S7XfSw_lN+OLO6lv3ta_C1rPF6aMoMHHTTN5B65|H`5`x{_4jW;;V7oNPeGw zRFK=UaVVEx%7{%`V%kB%Stom;*0{AlFKA+&Pg;o#YN8sVE5EJk=VrgurCzn}M^-+? z^+KRjsYHM8!uAxaL1k1Tb0|}7S+u-4&2!P&d#+X+awqZwd z5lB@>kmSACHKk_ASgk1~7tT?m@aUb6>0LcD^0|>!^Hi)h6$H=P({xB_yh!PWKgu9* zm)b{kh!Z(;&GBf3)TR@8z3c>SnOas@+|Q9TF|ww2<;7z4(LfmF{n>)T%| zZs_SXhiB^DigM`~d|n-MCoE`ETE_A>-JdV$kyBin zIjerIuD5!;6jiJaTK~b@iKQKCqDI;C-1}Lu;nvju=@`tuW`bgiZ{GA2PhOxz=%300XPf1oj4Q8)b%$Gv6rr{Bax(7?%qprQ{hN=8bu;gD9kCGi% z7VeM)O3t;ee@4B$(THv_%H5s2TLXUyu4%64dTw#&)RW_#Y8SqTpW$6<@KY^WbYZOx zrTxAztQoPwv*La2DYC9euF1}S?<(jLg}-msiY6~|1@jpUXtN@-67kPmk&PAUnx@amG4^F z_UxS#-M)7?1~{r4xGufy3UY#HTQnbV$sl8Ca0-o-KUTurL(DvuIwYusqnBRw8hJJ6 z;PCu>%0%lSfBStWi*oZuk5#fnagDD4E`CKvt^Jlwu+*rY?#VjSVY-aB)Mu;U7k)gWmWNjMziT$E@=Kq z?`A(@9$RNGK`hy@XA=vnOW`U$hsrc1Wjrx!i1Zhod&0m$S;i#=w!FN~ImKR}(yuW( z9G8BNBdf0kcL(&;$0X*8tY(Fk7zH+RwiIP0&i#Z8Ce5}5W!g0(D@eg)DE2`^OqzA)Y^I#>=Vi^0 zN>L#jky+K_3YvJi0grU9i|tg_$z|9PsQD4UWHAWRB2`tCla#~e6uRoT#MM_x#O!6t zt1M=f&PEE^c%Ajy*R3lTbd>wN7q!Ksr_hW#vNVIc=^K=%4yZp0M@O1a4H3B*Hif10 zkCVo3z%-kz;vGlE_e^JG(IPk{wPRM1QKj(M`COHz%aGFB3WsA8M~+4fMWaXY**P_* zaXBfuJ*^&E*8!h^&vj&{;NSD>v|f5zxYg|%ZhfT)7o8EiRGP*T*=eDW{4EQWTy50_ zA&-r>P$K6RDY0 zLvhWnz+Yrjg?3>Z8nUf+E7M;*L>Po3BI)n^3B4E$%T-p47Anj@YlU5-DXW;MK!xa; zLG7OA5j=Qqp2uFJiIU8OE&OSHspKx%7Iw>ZNo6PV)6q_9*+{i`;3Dh1QMbbZt4fWI zDCw~Y4UMxcmeJv-@b2kYMMaRci0E;iQhCGV7)DScRNHFA&o(;JT9I#&;}IHB=^5(9 zvZ~OzkRu9{+97?>FNGCUe~d`Cm0_E5#h1U97MF&uqu6VPcaRtKsvEg~j{ibaD))fZ zSCtTvF-ICc^(rk?k+A{o~DR`(O`tf?PQo^MZ- z50=0O>91eOf%EegmX?YWoiQz{NlhCl@SGLnDihZJnuy8$@np)A{dipPjw;|}PdQ$R zDxBxCnLI0G4#{R3X`DLrVaz_zbO_UikpL_X$}32fpW#TZ3GVW9H@ zCu3}eD}zJ5ntbHLE{&NJb2coD_>rbvD`sp78-6q2lA6O+2Z`>v6a?3eBEfbeMtYzX zNvlo0zWIHES{KQ?{D;kl^Z(A~17KqNcW;z-{De&~05Rl|XNX1)gWSz}x<4&zHD^$S zzWf{%5S3B{BB1s3AX3Xl2^|-k{uzp8w!qgc$(3iTatn|5O#wQxL5D`{*gh$u2n%X# zLstI)g*nK>zGWJ|R0S?W2@S~mac*S=O;$DEvy=Gl7fho+SB1e)LN(r$Q4#E1G=@JJ-~rnKDgN1XcE7m;Zs3@h{)ofBDV+VMvoRuuyce z{+}i(mM@t9z3o!=FBhq(xr3tg){LTG*O_b1Oovx9br*Ye+XE6ziH zKe>QER=k`L()Ua|``{4DRk1W{OzZdJ>wo;1h1mYy)9&Dx8%K1`+zGNlz#X|!Qa@1a z(gyx={5rh&9X3!V)s=a;XGmn}ZwV751hX^rzZYBNMQS)iO32j!!d~Lhm z{sG9z)eW}L2-U>x`Lb$25cYZ5jg95>P505KVHGb_FH`1qLWt&NDYZG)A~A9m^|+yG z9r1-&8ok)JVS!@HxyiZ~H@_3tgtZH5 zA8+p=M_F4Wc2t0A1XQ+oc(u%r0HwKif#4M?lU5ci1h`7@96sb=P z@0oce - - 4.0.0 - - org.springframework.cloud - spring-cloud-contract-parent - 4.1.0-SNAPSHOT - .. - - spring-cloud-contract-wiremock - jar - spring-cloud-contract-wiremock - Spring Cloud Contract Wiremock - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - - - org.springframework.boot - spring-boot-starter - - - org.springframework.boot - spring-boot-autoconfigure-processor - true - - - org.springframework.boot - spring-boot-starter-tomcat - test - - - org.springframework.boot - spring-boot-starter-webflux - test - - - jakarta.servlet - jakarta.servlet-api - - - org.springframework - spring-web - - - org.springframework.restdocs - spring-restdocs-mockmvc - true - - - org.springframework.restdocs - spring-restdocs-webtestclient - true - - - org.springframework.restdocs - spring-restdocs-restassured - true - - - org.springframework.boot - spring-boot-starter-test - true - - - org.junit.vintage - junit-vintage-engine - - - - - com.github.tomakehurst - wiremock-jre8-standalone - - - io.rest-assured - rest-assured - true - - - org.apache.httpcomponents.client5 - httpclient5 - - - org.assertj - assertj-core - compile - - - org.springframework.boot - spring-boot-configuration-processor - true - - - org.springframework.cloud - spring-cloud-test-support - - - org.springframework.cloud - spring-cloud-contract-verifier - test - - - com.example.github - github-webhook - stubs - 1.0.0.M1-190120_193303-VERSION - test - - - * - * - - - - - com.example.github - github-analytics - stubs - 1.0.0.M1-190120_105104-VERSION - test - - - * - * - - - - - org.junit.vintage - junit-vintage-engine - test - - - diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/AutoConfigureHttpClient.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/AutoConfigureHttpClient.java deleted file mode 100644 index 4367fb8af0..0000000000 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/AutoConfigureHttpClient.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.boot.test.autoconfigure.properties.PropertyMapping; -import org.springframework.context.annotation.Import; - -/** - * Annotation for test classes that want to install a RestTemplateCustomizer that sets up - * a Spring Boot app to ignore SSL errors. Use only in tests! - * - * @author Dave Syer - * - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Import(WireMockRestTemplateConfiguration.class) -@PropertyMapping("wiremock.server") -public @interface AutoConfigureHttpClient { - -} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMock.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMock.java deleted file mode 100644 index 3e667e4c19..0000000000 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMock.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.boot.test.autoconfigure.properties.PropertyMapping; -import org.springframework.boot.test.autoconfigure.properties.SkipPropertyMapping; -import org.springframework.context.annotation.Import; - -/** - * Annotation for test classes that want to start a WireMock server as part of the Spring - * Application Context. The port, https port and stub locations (if any) can all be - * controlled directly here. For more fine-grained control of the server instance add a - * bean of type {@link com.github.tomakehurst.wiremock.core.Options} to the application - * context. - * - * @author Dave Syer - * - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Import(WireMockConfiguration.class) -@PropertyMapping(value = "wiremock.server", skip = SkipPropertyMapping.ON_DEFAULT_VALUE) -@AutoConfigureHttpClient -@Inherited -public @interface AutoConfigureWireMock { - - /** - * Configures WireMock instance to listen on specified port. - *

- * Set this value to 0 for WireMock to listen to a random port. - *

- * @return port to which WireMock instance should listen to - */ - int port() default 8080; - - /** - * If specified, configures WireMock instance to enable HTTPS on specified - * port. - *

- * Set this value to 0 for WireMock to listen to a random port. - *

- * @return port to which WireMock instance should listen to - */ - int httpsPort() default -1; - - /** - * The resource locations to use for loading WireMock mappings. - *

- * When none specified, src/test/resources/mappings is used as default - * location. - *

- *

- * To customize the location, this attribute must be set to the directory where - * mappings are stored. - *

- * @return locations to read WireMock mappings from - */ - String[] stubs() default { "" }; - - /** - * The resource locations to use for loading WireMock response bodies. - *

- * When none specified, src/test/resources/__files is used as default. - *

- *

- * To customize the location, this attribute must be set to the parent directory of - * __files directory. - *

- * @return locations to read WireMock response bodies from - */ - String[] files() default { "" }; - -} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockApplicationListener.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockApplicationListener.java deleted file mode 100644 index aca984c794..0000000000 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockApplicationListener.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.boot.context.event.ApplicationPreparedEvent; -import org.springframework.cloud.test.TestSocketUtils; -import org.springframework.context.ApplicationListener; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.env.MapPropertySource; -import org.springframework.core.env.MutablePropertySources; -import org.springframework.core.env.PropertySource; - -/** - * Listener that prepares the environment so that WireMock will work when it is - * initialized. For example, by finding free ports for the server to listen on. - * - * @author Dave Syer - * @author Matt Garner - * - */ -@Order(Ordered.LOWEST_PRECEDENCE) -public class WireMockApplicationListener implements ApplicationListener { - - private static final Log log = LogFactory.getLog(WireMockApplicationListener.class); - - @Override - public void onApplicationEvent(ApplicationPreparedEvent event) { - registerPort(event.getApplicationContext().getEnvironment()); - } - - private void registerPort(ConfigurableEnvironment environment) { - Integer httpPortProperty = environment.getProperty("wiremock.server.port", Integer.class); - // If the httpPortProperty is not found it means the AutoConfigureWireMock hasn't - // been initialised or the default was used - if (httpPortProperty != null && isHttpDynamic(httpPortProperty)) { - registerPropertySourceForDynamicEntries(environment, "wiremock.server.port", 10000, 12500, - "wiremock.server.port-dynamic"); - if (log.isDebugEnabled()) { - log.debug("Registered property source for dynamic http port"); - } - } - else { - Map source = getWireMockSource(environment); - source.put("wiremock.server.port", 8080); - if (log.isDebugEnabled()) { - log.debug("Registered WireMock server port property to the default <8080> value"); - } - } - int httpsPortProperty = environment.getProperty("wiremock.server.https-port", Integer.class, 0); - if (isHttpsDynamic(httpsPortProperty)) { - registerPropertySourceForDynamicEntries(environment, "wiremock.server.https-port", 12500, 15000, - "wiremock.server.https-port-dynamic"); - if (log.isDebugEnabled()) { - log.debug("Registered property source for dynamic https port"); - } - } - else if (httpsPortProperty == -1) { - Map source = getWireMockSource(environment); - source.put("wiremock.server.https-port-dynamic", true); - if (log.isDebugEnabled()) { - log.debug("Registered property source for dynamic https with https port property set to -1"); - } - } - - } - - private Map getWireMockSource(ConfigurableEnvironment environment) { - MutablePropertySources propertySources = environment.getPropertySources(); - addPropertySource(propertySources); - Map source = ((MapPropertySource) propertySources.get("wiremock")).getSource(); - return source; - } - - private boolean isHttpsDynamic(int httpsPortProperty) { - return httpsPortProperty == 0; - } - - private boolean isHttpDynamic(Integer httpPortProperty) { - return httpPortProperty.equals(0); - } - - private void registerPropertySourceForDynamicEntries(ConfigurableEnvironment environment, String portProperty, - int minPort, int maxPort, String dynamicPortProperty) { - Map source = getWireMockSource(environment); - int port = TestSocketUtils.findAvailableTcpPort(minPort, maxPort); - source.put(portProperty, port); - if (log.isDebugEnabled()) { - log.debug("Registered property source for property [" + portProperty + "] with value [" + port + "]"); - } - source.put(dynamicPortProperty, true); - } - - private void addPropertySource(MutablePropertySources propertySources) { - if (!propertySources.contains("wiremock")) { - propertySources.addFirst(new MapPropertySource("wiremock", new HashMap())); - } - else { - // Move it up into first place - PropertySource wiremock = propertySources.remove("wiremock"); - propertySources.addFirst(wiremock); - } - } - -} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockConfiguration.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockConfiguration.java deleted file mode 100644 index e2549c30aa..0000000000 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockConfiguration.java +++ /dev/null @@ -1,482 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import com.github.tomakehurst.wiremock.common.Notifier; -import com.github.tomakehurst.wiremock.core.Options; -import com.github.tomakehurst.wiremock.extension.responsetemplating.ResponseTemplateTransformer; -import com.github.tomakehurst.wiremock.stubbing.StubMapping; -import jakarta.annotation.PostConstruct; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.contract.wiremock.file.ResourcesFileSource; -import org.springframework.context.SmartLifecycle; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; -import org.springframework.core.io.support.PathMatchingResourcePatternResolver; -import org.springframework.util.StreamUtils; -import org.springframework.util.StringUtils; - -/** - * Configuration and lifecycle for a Spring Application context that wants to run a - * WireMock server. Can be used by adding - * {@link AutoConfigureWireMock @AutoConfigureWireMock} to a Spring Boot JUnit test. To - * configure the properties of the wiremock server you can use the AutoConfigureWireMock - * annotation, or add a bean of type {@link Options} (via - * {@link WireMockSpring#options()}) to your test context. - * - * @author Dave Syer - * @author Matt Garner - * @author Waldemar Panas - * - */ -@Configuration(proxyBeanMethods = false) -@EnableConfigurationProperties(WireMockProperties.class) -public class WireMockConfiguration implements SmartLifecycle { - - static final String WIREMOCK_SERVER_BEAN_NAME = "wireMockServer"; - - private static final Log log = LogFactory.getLog(WireMockConfiguration.class); - - @Autowired - WireMockProperties wireMock; - - private volatile boolean running; - - private WireMockServer server; - - @Autowired(required = false) - private Options options; - - @Autowired(required = false) - private ObjectProvider customizers; - - @Autowired - private DefaultListableBeanFactory beanFactory; - - @Autowired - private ResourceLoader resourceLoader; - - @PostConstruct - public void init() throws IOException { - if (log.isDebugEnabled()) { - log.debug("Running initialization of the WireMock configuration"); - } - if (this.options == null) { - com.github.tomakehurst.wiremock.core.WireMockConfiguration factory = WireMockSpring.options(); - if (this.wireMock.getServer().getPort() != 8080) { - factory.port(this.wireMock.getServer().getPort()); - } - if (this.wireMock.getServer().getHttpsPort() != -1) { - factory.httpsPort(this.wireMock.getServer().getHttpsPort()); - } - registerFiles(factory); - factory.notifier(new Slf4jNotifier(true)); - if (this.wireMock.getPlaceholders().isEnabled()) { - factory.extensions(new ResponseTemplateTransformer(false)); - } - this.options = factory; - if (this.customizers != null) { - this.customizers.orderedStream().forEach(customizer -> customizer.customize(factory)); - } - } - reRegisterServerWithResetMappings(); - reRegisterBeans(); - updateCurrentServer(); - } - - void initIfNotRunning() throws IOException { - if (!this.running) { - init(); - } - } - - private void reRegisterBeans() { - if (!this.beanFactory.containsBean(WIREMOCK_SERVER_BEAN_NAME)) { - if (log.isDebugEnabled()) { - printRegistrationLog(); - } - this.beanFactory.registerSingleton(WIREMOCK_SERVER_BEAN_NAME, this.server); - } - else { - if (log.isDebugEnabled()) { - log.debug("Destroying WireMock [" + this.beanFactory.getBean(WIREMOCK_SERVER_BEAN_NAME) + "] instance"); - } - this.beanFactory.destroySingleton(WIREMOCK_SERVER_BEAN_NAME); - if (log.isDebugEnabled()) { - printRegistrationLog(); - } - this.beanFactory.registerSingleton(WIREMOCK_SERVER_BEAN_NAME, this.server); - } - } - - private void printRegistrationLog() { - log.debug("Registering WireMock [" + this.server + "] at http port [" + httpPort() + "] and https port [" - + httpsPort() + "]"); - } - - private void reRegisterServer() { - if (log.isTraceEnabled()) { - log.trace("Creating a new server at http port [" + this.wireMock.getServer().getPort() + "] and " - + "https port [" + this.wireMock.getServer().getHttpsPort() + "]"); - } - if (this.isRunning()) { - if (log.isDebugEnabled()) { - log.debug("Stopping server [" + this.server + "] at port [" + port(this.server) + "]"); - } - stop(); - } - else if (this.server == null) { - this.server = new WireMockServer(this.options); - if (log.isDebugEnabled()) { - log.debug("Created new server [" + this.server + "] at http port [" + httpPort() + "] and https port [" - + httpsPort() + "]"); - } - } - start(); - if (log.isDebugEnabled()) { - log.debug("Started server [" + this.server + "] at http port [" + httpPort() + "] and https port [" - + httpsPort() + "]"); - } - logRegisteredMappings(); - } - - private void logRegisteredMappings() { - if (log.isDebugEnabled()) { - log.debug("WireMock server has [" + this.server.getStubMappings().size() + "] stubs registered"); - } - } - - void reRegisterServerWithResetMappings() { - reRegisterServer(); - resetMappings(); - if (this.server.isRunning()) { - updateCurrentServer(); - } - } - - void resetMappings() { - if (this.server.isRunning()) { - this.server.resetAll(); - this.server.resetRequests(); - this.server.resetScenarios(); - WireMock.reset(); - WireMock.resetAllRequests(); - WireMock.resetAllScenarios(); - registerStubs(); - logRegisteredMappings(); - } - } - - private void registerStubs() { - if (log.isDebugEnabled()) { - log.debug("Will register [" + this.wireMock.getServer().getStubs().length + "] stub locations"); - } - for (String stubs : this.wireMock.getServer().getStubs()) { - if (StringUtils.hasText(stubs)) { - PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver( - this.resourceLoader); - StringBuilder pattern = new StringBuilder(stubs); - if (!stubs.contains("*")) { - if (!stubs.endsWith("/")) { - pattern.append("/"); - } - pattern.append("**/*.json"); - } - try { - for (Resource resource : resolver.getResources(pattern.toString())) { - try (InputStream inputStream = resource.getInputStream()) { - StubMapping stubMapping = WireMockStubMapping - .buildFrom(StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8)); - this.server.addStubMapping(stubMapping); - } - } - } - catch (IOException ex) { - throw new IllegalStateException(ex); - } - } - } - } - - private void registerFiles(com.github.tomakehurst.wiremock.core.WireMockConfiguration factory) throws IOException { - List resources = new ArrayList<>(); - for (String files : this.wireMock.getServer().getFiles()) { - if (StringUtils.hasText(files)) { - PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver( - this.resourceLoader); - for (Resource resource : resolver.getResources(files)) { - if (resource.exists()) { - resources.add(resource); - } - } - } - } - if (!resources.isEmpty()) { - ResourcesFileSource fileSource = new ResourcesFileSource(resources.toArray(new Resource[0])); - factory.fileSource(fileSource); - } - } - - @Override - public void start() { - if (isRunning()) { - if (log.isDebugEnabled()) { - log.debug("Server [" + this.server + "] is already running at http port [" + httpPort() - + "] / https port [" + httpsPort() + "]"); - } - updateCurrentServer(); - return; - } - this.server.start(); - updateCurrentServer(); - } - - private int httpPort() { - return this.server.isRunning() ? this.server.port() : -1; - } - - private void updateCurrentServer() { - WireMock.configureFor(new WireMock(this.server)); - this.running = true; - if (log.isDebugEnabled() && this.server.isRunning()) { - log.debug("Server [" + this.server + "] is already running at http port [" + httpPort() + "] / https port [" - + httpsPort() + "]. It has [" + this.server.getStubMappings().size() + "] mappings registered"); - } - } - - private int httpsPort() { - return this.server.isRunning() && this.server.getOptions().httpsSettings().enabled() ? this.server.httpsPort() - : -1; - } - - @Override - public void stop() { - if (this.running) { - WireMockServer server = this.server; - int port = port(server); - this.server.stop(); - this.running = false; - if (log.isDebugEnabled()) { - log.debug("Stopped WireMock [" + server + "] instance port [" + port + "]"); - } - } - else if (log.isDebugEnabled()) { - log.debug("Server already stopped"); - } - } - - private int port(WireMockServer server) { - return server.isRunning() ? (server.getOptions().httpsSettings().enabled() ? server.httpsPort() : server.port()) - : -1; - } - - @Override - public boolean isRunning() { - return this.running; - } - - @Override - public int getPhase() { - return 0; - } - - @Override - public boolean isAutoStartup() { - return true; - } - - @Override - public void stop(Runnable callback) { - stop(); - callback.run(); - } - - static class Slf4jNotifier implements Notifier { - - private static final Logger log = LoggerFactory.getLogger("WireMock"); - - private final boolean verbose; - - Slf4jNotifier(boolean verbose) { - this.verbose = verbose; - } - - @Override - public void info(String message) { - if (verbose) { - log.info(message); - } - } - - @Override - public void error(String message) { - log.error(message); - } - - @Override - public void error(String message, Throwable t) { - log.error(message, t); - } - - } - -} - -@ConfigurationProperties("wiremock") -class WireMockProperties { - - private Server server = new Server(); - - private Placeholders placeholders = new Placeholders(); - - private boolean restTemplateSslEnabled; - - private boolean resetMappingsAfterEachTest; - - public boolean isRestTemplateSslEnabled() { - return this.restTemplateSslEnabled; - } - - public void setRestTemplateSslEnabled(boolean restTemplateSslEnabled) { - this.restTemplateSslEnabled = restTemplateSslEnabled; - } - - public boolean isResetMappingsAfterEachTest() { - return this.resetMappingsAfterEachTest; - } - - public void setResetMappingsAfterEachTest(boolean resetMappingsAfterEachTest) { - this.resetMappingsAfterEachTest = resetMappingsAfterEachTest; - } - - public Server getServer() { - return this.server; - } - - public void setServer(Server server) { - this.server = server; - } - - public Placeholders getPlaceholders() { - return this.placeholders; - } - - public void setPlaceholders(Placeholders placeholders) { - this.placeholders = placeholders; - } - - public class Placeholders { - - /** - * Flag to indicate that http URLs in generated wiremock stubs should be filtered - * to add or resolve a placeholder for a dynamic port. - */ - private boolean enabled = true; - - public boolean isEnabled() { - return this.enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - } - - public static class Server { - - private int port = 8080; - - private int httpsPort = -1; - - private String[] stubs = new String[0]; - - private String[] files = new String[0]; - - private boolean portDynamic = false; - - private boolean httpsPortDynamic = false; - - public int getPort() { - return this.port; - } - - public void setPort(int port) { - this.port = port; - } - - public int getHttpsPort() { - return this.httpsPort; - } - - public void setHttpsPort(int httpsPort) { - this.httpsPort = httpsPort; - } - - public String[] getStubs() { - return this.stubs; - } - - public void setStubs(String[] stubs) { - this.stubs = stubs; - } - - public String[] getFiles() { - return this.files; - } - - public void setFiles(String[] files) { - this.files = files; - } - - public boolean isPortDynamic() { - return this.portDynamic; - } - - public void setPortDynamic(boolean portDynamic) { - this.portDynamic = portDynamic; - } - - public boolean isHttpsPortDynamic() { - return this.httpsPortDynamic; - } - - public void setHttpsPortDynamic(boolean httpsPortDynamic) { - this.httpsPortDynamic = httpsPortDynamic; - } - - } - -} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockConfigurationCustomizer.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockConfigurationCustomizer.java deleted file mode 100644 index 0d36453618..0000000000 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockConfigurationCustomizer.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -/** - * Allows customization of - * {@link com.github.tomakehurst.wiremock.core.WireMockConfiguration}. - * - * @author Marcin Grzejszczak - * @since 1.2.2 - */ -public interface WireMockConfigurationCustomizer { - - void customize(com.github.tomakehurst.wiremock.core.WireMockConfiguration config); - -} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockRestServiceServer.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockRestServiceServer.java deleted file mode 100644 index e56cfb481f..0000000000 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockRestServiceServer.java +++ /dev/null @@ -1,456 +0,0 @@ -/* - * Copyright 2015-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.regex.Pattern; - -import javax.xml.xpath.XPathExpressionException; - -import com.github.tomakehurst.wiremock.common.Json; -import com.github.tomakehurst.wiremock.http.HttpHeader; -import com.github.tomakehurst.wiremock.http.MultiValue; -import com.github.tomakehurst.wiremock.http.ResponseDefinition; -import com.github.tomakehurst.wiremock.matching.ContentPattern; -import com.github.tomakehurst.wiremock.matching.MatchResult; -import com.github.tomakehurst.wiremock.matching.MatchesJsonPathPattern; -import com.github.tomakehurst.wiremock.matching.MatchesXPathPattern; -import com.github.tomakehurst.wiremock.matching.MultiValuePattern; -import com.github.tomakehurst.wiremock.matching.RequestPattern; -import com.github.tomakehurst.wiremock.stubbing.StubMapping; -import org.hamcrest.BaseMatcher; -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.MatcherAssert; -import org.hamcrest.TypeSafeMatcher; - -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.PathMatchingResourcePatternResolver; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.client.ClientHttpRequest; -import org.springframework.mock.http.client.MockClientHttpRequest; -import org.springframework.test.web.client.MockRestServiceServer; -import org.springframework.test.web.client.MockRestServiceServer.MockRestServiceServerBuilder; -import org.springframework.test.web.client.RequestMatcher; -import org.springframework.test.web.client.ResponseActions; -import org.springframework.test.web.client.match.MockRestRequestMatchers; -import org.springframework.test.web.client.response.DefaultResponseCreator; -import org.springframework.util.StreamUtils; -import org.springframework.util.StringUtils; -import org.springframework.web.client.RestTemplate; - -import static org.springframework.test.web.client.match.MockRestRequestMatchers.header; -import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; -import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; -import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus; - -/** - * Convenience class for loading WireMock stubs into a {@link MockRestServiceServer}. In - * this way using a {@link RestTemplate} can mock the responses from a server using - * WireMock JSON DSL instead of the native Java DSL. - * - * @author Dave Syer - * - */ -public final class WireMockRestServiceServer { - - private final PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); - - private String suffix = ".json"; - - private String baseUrl = ""; - - private boolean bufferContent = false; - - private MockRestServiceServerBuilder builder; - - private List locations = new ArrayList(); - - private List files = new ArrayList(); - - private boolean ignoreExpectOrder = true; - - private WireMockRestServiceServer(RestTemplate restTemplate) { - this.builder = MockRestServiceServer.bindTo(restTemplate); - } - - /** - * Public factory method for wrapping a rest template into a MockRestServiceServer. - * @param restTemplate the rest template to wrap - * @return a WireMockRestServiceServer - */ - public static WireMockRestServiceServer with(RestTemplate restTemplate) { - return new WireMockRestServiceServer(restTemplate); - } - - /** - * Flag to tell the MockRestServiceServer to ignore the order of calls when matching - * requests. The default is true because there is an implied ordering in the stubs (by - * url path and with more specific request matchers first). - * @param ignoreExpectOrder flag value (default true) - * @return this - */ - public WireMockRestServiceServer ignoreExpectOrder(boolean ignoreExpectOrder) { - this.ignoreExpectOrder = ignoreExpectOrder; - return this; - } - - /** - * Flag to tell the server to buffer the contents of the response. - * @return this - */ - public WireMockRestServiceServer bufferContent() { - this.bufferContent = true; - return this; - } - - /** - * If stub locations are given as a directory, then we search recursively in that - * directory for files with this suffix. Default is ".json". - * @param suffix the suffix to use when creating a resource pattern - * @return this - */ - public WireMockRestServiceServer suffix(String suffix) { - this.suffix = suffix; - return this; - } - - /** - * Add a base url to all requests. Most WireMock JSON stubs have a path, but no - * protocol or host in the request matcher, so this is useful when your rest template - * is calling to a specific host. - * @param baseUrl a base url to apply - * @return this - */ - public WireMockRestServiceServer baseUrl(String baseUrl) { - this.baseUrl = baseUrl; - return this; - } - - /** - * Add some resource locations for stubs. Each location can be a resource path (to a - * single JSON file), or a pattern with ant-style wildcards to load all stubs that - * match, or a plain directory name (which will have - * **/*.json appended, where ".json" is the value of the - * {@link #suffix(String) suffix}). Examples: - * - *
-	 * classpath:/mappings/foo.json
-	 * classpath:/mappings/*.json
-	 * classpath:META-INF/com.example/stubs/1.0.0/mappings/**/*.json
-	 * file:src/test/resources/stubs
-	 * 
- * @param locations a set of resource locations - * @return this - */ - public WireMockRestServiceServer stubs(String... locations) { - this.locations.addAll(Arrays.asList(locations)); - return this; - } - - /** - * Add some resource locations for files that represent response bodies. Wiremock - * defaults to "file:src/test/resources/__files". - * @param locations locations with files - * @return this - */ - public WireMockRestServiceServer files(String... locations) { - this.files.addAll(Arrays.asList(locations)); - return this; - } - - /** - * Build a MockRestServiceServer from the configured stubs. The server can later be - * verified (optionally), if you need to check that all expected requests were made. - * @return a MockRestServiceServer - */ - public MockRestServiceServer build() { - if (this.ignoreExpectOrder) { - this.builder.ignoreExpectOrder(true); // default is false - } - if (this.bufferContent) { - this.builder.bufferContent(); - } - MockRestServiceServer server = this.builder.build(); - List mappings = new ArrayList<>(); - for (String location : this.locations) { - try { - for (Resource resource : this.resolver.getResources(pattern(location))) { - StubMapping mapping = mapping(resource); - mappings.add(mapping); - } - } - catch (IOException e) { - throw new IllegalStateException("Cannot load resources for: " + location, e); - } - } - if (this.ignoreExpectOrder) { - Collections.sort(mappings, new StubMappingComparator()); - } - for (StubMapping mapping : mappings) { - ResponseActions expect = responseActions(server, mapping); - expect.andExpect(method(HttpMethod.valueOf(mapping.getRequest().getMethod().getName()))); - mapping.getRequest().getBodyPatterns(); - bodyPatterns(expect, mapping.getRequest()); - requestHeaders(expect, mapping.getRequest()); - expect.andRespond(response(mapping.getResponse())); - } - return server; - } - - private ResponseActions responseActions(MockRestServiceServer server, StubMapping mapping) { - if (StringUtils.hasText(mapping.getRequest().getUrl()) - || StringUtils.hasText(mapping.getRequest().getUrlPath())) { - return server.expect(requestTo(request(mapping.getRequest()))); - } - return server.expect(requestTo(requestMatcher(mapping.getRequest()))); - } - - private void bodyPatterns(ResponseActions expect, RequestPattern request) { - if (request.getBodyPatterns() == null) { - return; - } - for (final ContentPattern pattern : request.getBodyPatterns()) { - if (pattern instanceof MatchesJsonPathPattern) { - expect.andExpect(MockRestRequestMatchers - .jsonPath(((MatchesJsonPathPattern) pattern).getMatchesJsonPath()).exists()); - } - else if (pattern instanceof MatchesXPathPattern) { - expect.andExpect(xpath((MatchesXPathPattern) pattern)); - } - expect.andExpect(matchContents(pattern)); - } - } - - private RequestMatcher matchContents(@SuppressWarnings("rawtypes") final ContentPattern pattern) { - return new RequestMatcher() { - @Override - public void match(ClientHttpRequest request) throws IOException, AssertionError { - MockClientHttpRequest mockRequest = (MockClientHttpRequest) request; - @SuppressWarnings("unchecked") - MatchResult result = pattern.match(mockRequest.getBodyAsString()); - MatcherAssert.assertThat("Request as string [" + mockRequest.getBodyAsString() + "]", - result.isExactMatch()); - } - }; - } - - private RequestMatcher xpath(MatchesXPathPattern pattern) { - try { - return MockRestRequestMatchers.xpath(pattern.getMatchesXPath()).exists(); - } - catch (XPathExpressionException e) { - throw new IllegalStateException(e); - } - } - - private String request(RequestPattern request) { - return this.baseUrl + (request.getUrlPath() == null ? (request.getUrl() == null ? "/" : request.getUrl()) - : request.getUrlPath()); - } - - private String withoutBaseUrl(String url) { - int indexOfBaseUrl = url.indexOf(this.baseUrl); - if (indexOfBaseUrl == -1) { - return url; - } - return url.substring(indexOfBaseUrl + this.baseUrl.length()); - } - - private Matcher requestMatcher(RequestPattern request) { - return new TypeSafeMatcher() { - @Override - protected boolean matchesSafely(String item) { - if (request.getUrlPathPattern() != null) { - return Pattern.compile(request.getUrlPathPattern()).matcher(withoutBaseUrl(item)).matches(); - } - else if (request.getUrlMatcher() != null) { - return request.getUrlMatcher().match(item).isExactMatch(); - } - else if (request.getUrlPattern() != null) { - return Pattern.compile(request.getUrlPattern()).matcher(item).matches(); - } - return false; - } - - @Override - public void describeTo(Description description) { - - } - }; - } - - private String pattern(String location) { - if (!StringUtils.getFilename(location).contains(".") && !location.contains("*")) { - if (!location.endsWith("/")) { - location = location + "/"; - } - location = location + "**/*" + this.suffix; - } - return location; - } - - private StubMapping mapping(Resource resource) throws IOException { - return Json.read(StreamUtils.copyToString(resource.getInputStream(), Charset.defaultCharset()), - StubMapping.class); - } - - private DefaultResponseCreator response(ResponseDefinition response) { - return withStatus(HttpStatus.valueOf(response.getStatus())).body(body(response)) - .contentType(contentType(response)).headers(responseHeaders(response)); - } - - private byte[] body(ResponseDefinition response) { - if (response.getByteBody() != null) { - return response.getByteBody(); - } - String file = response.getBodyFileName(); - if (file != null) { - List locations = this.files.isEmpty() ? Arrays.asList("classpath:/__files/") : this.files; - for (String location : locations) { - try { - if (!location.endsWith("/")) { - location = location + "/"; - } - for (Resource files : this.resolver.getResources(location)) { - if (files.exists()) { - try { - Resource resource = files.createRelative(file); - if (resource.exists()) { - return StreamUtils.copyToByteArray(resource.getInputStream()); - } - } - catch (IOException e) { - throw new IllegalStateException("Cannot locate body file: " + file, e); - } - } - } - } - catch (IOException e) { - // Ignore - } - } - } - return new byte[0]; - } - - private void requestHeaders(ResponseActions expect, RequestPattern request) { - if (request.getHeaders() != null) { - for (final String header : request.getHeaders().keySet()) { - final MultiValuePattern pattern = request.getHeaders().get(header); - expect.andExpect(header(header, new BaseMatcher() { - - @Override - public boolean matches(Object item) { - return pattern.match(new MultiValue(header, Arrays.asList((String) item))).isExactMatch(); - } - - @Override - public void describeTo(Description description) { - description.appendText("should match header: " + header + " with ") - .appendText(pattern.getExpected()); - } - })); - } - } - } - - private HttpHeaders responseHeaders(ResponseDefinition response) { - HttpHeaders headers = new HttpHeaders(); - if (response.getHeaders() != null) { - for (HttpHeader header : response.getHeaders().all()) { - if (!header.keyEquals("Content-Type")) { - for (String value : header.values()) { - headers.add(header.key(), value); - } - } - } - } - return headers; - } - - private MediaType contentType(ResponseDefinition response) { - String value = null; - if (response.getHeaders() != null) { - HttpHeader header = response.getHeaders().getHeader("Content-Type"); - if (header != null && header.isPresent()) { - value = header.firstValue(); - } - } - return value == null ? MediaType.TEXT_PLAIN : MediaType.valueOf(value); - } - - private static class StubMappingComparator implements Comparator { - - @Override - public int compare(StubMapping one, StubMapping two) { - if (one == two) { - return 0; - } - int value = request(one.getRequest()).compareTo(request(two.getRequest())); - if (value == 0) { - - if (one.getPriority() != null) { - if (two.getPriority() != null) { - return one.getPriority().compareTo(two.getPriority()); - } - else { - return -one.getPriority(); - } - } - if (two.getPriority() != null) { - return -two.getPriority(); - } - - // Every mapping has a url pattern, and zero or more header patterns - int twos = 0; - if (two.getRequest().getHeaders() != null) { - twos = two.getRequest().getHeaders().size(); - } - int ones = 0; - if (one.getRequest().getHeaders() != null) { - ones = one.getRequest().getHeaders().size(); - } - value = twos - ones; - if (value == 0) { - // Same number of header matchers - if (two.getPriority() != null) { - return one.getPriority() != null ? one.getPriority() - two.getPriority() : 1; - } - value = (int) (one.getInsertionIndex() - two.getInsertionIndex()); - } - } - return value; - } - - private String request(RequestPattern request) { - return (request.getUrlPath() == null ? (request.getUrl() == null ? "/" : request.getUrl()) - : request.getUrlPath()); - } - - } - -} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockRestTemplateConfiguration.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockRestTemplateConfiguration.java deleted file mode 100644 index d0fcd12cd1..0000000000 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockRestTemplateConfiguration.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2016-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import java.lang.reflect.Field; - -import org.apache.hc.client5.http.classic.HttpClient; -import org.apache.hc.client5.http.impl.classic.HttpClients; -import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; -import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; -import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder; -import org.apache.http.conn.ssl.TrustSelfSignedStrategy; -import org.apache.http.ssl.SSLContextBuilder; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.web.client.RestTemplateCustomizer; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.client.ClientHttpRequestFactory; -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; -import org.springframework.http.client.InterceptingClientHttpRequestFactory; -import org.springframework.util.ReflectionUtils; -import org.springframework.web.client.RestTemplate; - -import static org.apache.hc.client5.http.ssl.NoopHostnameVerifier.INSTANCE; - -/** - * @author Dave Syer - * @author Nikola Kološnjaji - * - */ -@Configuration(proxyBeanMethods = false) -public class WireMockRestTemplateConfiguration { - - @Bean - @ConditionalOnClass(SSLContextBuilder.class) - @ConditionalOnProperty(value = "wiremock.rest-template-ssl-enabled", matchIfMissing = true) - public RestTemplateCustomizer wiremockRestTemplateCustomizer() { - return new RestTemplateCustomizer() { - @Override - public void customize(RestTemplate restTemplate) { - if (restTemplate.getRequestFactory() instanceof HttpComponentsClientHttpRequestFactory factory) { - factory.setHttpClient(createSslHttpClient()); - } - else if (restTemplate.getRequestFactory() instanceof InterceptingClientHttpRequestFactory) { - Field requestFactoryField = ReflectionUtils.findField(RestTemplate.class, "requestFactory"); - if (requestFactoryField != null) { - requestFactoryField.setAccessible(true); - ClientHttpRequestFactory requestFactory = (ClientHttpRequestFactory) ReflectionUtils - .getField(requestFactoryField, restTemplate); - if (requestFactory instanceof HttpComponentsClientHttpRequestFactory factory) { - factory.setHttpClient(createSslHttpClient()); - } - } - } - } - - private HttpClient createSslHttpClient() { - try { - - SSLConnectionSocketFactoryBuilder sslConnectionSocketFactoryBuilder = SSLConnectionSocketFactoryBuilder - .create(); - sslConnectionSocketFactoryBuilder - .setSslContext(new SSLContextBuilder() - .loadTrustMaterial(null, TrustSelfSignedStrategy.INSTANCE).build()) - .setHostnameVerifier(INSTANCE); - PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder - .create().setSSLSocketFactory(sslConnectionSocketFactoryBuilder.build()).build(); - return HttpClients.custom().setConnectionManager(connectionManager).build(); - } - catch (Exception ex) { - throw new IllegalStateException("Unable to create SSL HttpClient", ex); - } - } - }; - } - -} 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 deleted file mode 100644 index 692aee10d4..0000000000 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockSpring.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2015-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import javax.net.ssl.HttpsURLConnection; - -import com.github.tomakehurst.wiremock.core.WireMockConfiguration; -import org.apache.http.conn.ssl.NoopHostnameVerifier; -import org.apache.http.conn.ssl.TrustSelfSignedStrategy; -import org.apache.http.ssl.SSLContexts; - -import org.springframework.util.ClassUtils; - -/** - * Convenience factory class for a {@link WireMockConfiguration} that knows how to use - * Spring Boot to create a stub server. Use, for example, in a JUnit rule: - * - *
- * @ClassRule
- * public static WireMockClassRule wiremock = new WireMockClassRule(
- * 		WireMockSpring.options());
- * 
- * - * and then use {@link com.github.tomakehurst.wiremock.client.WireMock} as normal in your - * test methods. - * - * @author Dave Syer - * - */ -public abstract class WireMockSpring { - - private static boolean initialized = false; - - public static WireMockConfiguration options() { - if (!initialized) { - if (ClassUtils.isPresent("org.apache.http.conn.ssl.NoopHostnameVerifier", null)) { - HttpsURLConnection.setDefaultHostnameVerifier(NoopHostnameVerifier.INSTANCE); - try { - HttpsURLConnection.setDefaultSSLSocketFactory(SSLContexts.custom() - .loadTrustMaterial(null, TrustSelfSignedStrategy.INSTANCE).build().getSocketFactory()); - } - catch (Exception e) { - throw new AssertionError("Cannot install custom socket factory: [" + e.getMessage() + "]"); - } - } - initialized = true; - } - return new WireMockConfiguration(); - } - -} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockStubMapping.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockStubMapping.java deleted file mode 100644 index 9727b794e3..0000000000 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockStubMapping.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import com.github.tomakehurst.wiremock.stubbing.StubMapping; - -/** - * @author Marcin Grzejszczak - */ -public final class WireMockStubMapping { - - private WireMockStubMapping() { - throw new IllegalStateException("Can't instantiate a utility class"); - } - - public static StubMapping buildFrom(String mappingDefinition) { - return StubMapping.buildFrom(mappingDefinition); - } - -} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockTestExecutionListener.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockTestExecutionListener.java deleted file mode 100644 index c463b8133a..0000000000 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockTestExecutionListener.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.context.ApplicationContext; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.TestContext; -import org.springframework.test.context.TestContextAnnotationUtils; -import org.springframework.test.context.support.AbstractTestExecutionListener; - -/** - * Dirties the test context if WireMock was running on a fixed port. - * - * @author Marcin Grzejszczak - * @author Matt Garner - * @author Waldemar Panas - * @author Fabian Winter - * @since 1.2.6 - */ -public final class WireMockTestExecutionListener extends AbstractTestExecutionListener { - - private static final Log log = LogFactory.getLog(WireMockTestExecutionListener.class); - - @Override - public void beforeTestClass(TestContext testContext) throws Exception { - if (applicationContextBroken(testContext) || wireMockConfigurationMissing(testContext) - || annotationMissing(testContext)) { - return; - } - if (!portIsFixed(testContext)) { - if (log.isDebugEnabled()) { - log.debug("Re-registering default mappings"); - } - wireMockConfig(testContext).initIfNotRunning(); - wireMockConfig(testContext).start(); - } - } - - @Override - public void afterTestClass(TestContext testContext) { - if (applicationContextBroken(testContext) || wireMockConfigurationMissing(testContext) - || annotationMissing(testContext)) { - return; - } - if (portIsFixed(testContext)) { - if (log.isWarnEnabled()) { - log.warn("You've used fixed ports for WireMock setup - " - + "will mark context as dirty. Please use random ports, as much " - + "as possible. Your tests will be faster and more reliable and this " - + "warning will go away"); - } - testContext.markApplicationContextDirty(DirtiesContext.HierarchyMode.EXHAUSTIVE); - } - else { - if (log.isDebugEnabled()) { - log.debug("Resetting mappings for the next test to restart them. That's necessary when" - + " reusing the same context with new servers running on random ports"); - } - wireMockConfig(testContext).reRegisterServerWithResetMappings(); - } - } - - @Override - public void afterTestMethod(TestContext testContext) throws Exception { - if (applicationContextBroken(testContext) || wireMockConfigurationMissing(testContext) - || annotationMissing(testContext)) { - return; - } - WireMockConfiguration wireMockConfiguration = wireMockConfig(testContext); - if (wireMockConfiguration.wireMock.isResetMappingsAfterEachTest()) { - if (log.isDebugEnabled()) { - log.debug("Resetting mappings for the next test."); - } - wireMockConfiguration.resetMappings(); - } - } - - private boolean annotationMissing(TestContext testContext) { - if (!TestContextAnnotationUtils.hasAnnotation(testContext.getTestClass(), AutoConfigureWireMock.class)) { - if (log.isDebugEnabled()) { - log.debug( - "No @AutoConfigureWireMock annotation found on [" + testContext.getTestClass() + "]. Skipping"); - } - return true; - } - return false; - } - - private boolean wireMockConfigurationMissing(TestContext testContext) { - boolean missing = !testContext(testContext).containsBean(WireMockConfiguration.class.getName()); - if (log.isDebugEnabled()) { - log.debug("WireMockConfiguration is missing [" + missing + "]"); - } - return missing; - } - - private ApplicationContext testContext(TestContext testContext) { - return testContext.getApplicationContext(); - } - - private boolean applicationContextBroken(TestContext testContext) { - try { - testContext.getApplicationContext(); - return false; - } - catch (Exception ex) { - if (log.isDebugEnabled()) { - log.debug("Application context is broken due to", ex); - } - return true; - } - } - - private WireMockConfiguration wireMockConfig(TestContext testContext) { - return testContext(testContext).getBean(WireMockConfiguration.class); - } - - private boolean portIsFixed(TestContext testContext) { - WireMockConfiguration wireMockProperties = wireMockConfig(testContext); - boolean httpPortDynamic = wireMockProperties.wireMock.getServer().isPortDynamic(); - boolean httpsPortDynamic = wireMockProperties.wireMock.getServer().isHttpsPortDynamic(); - if (log.isDebugEnabled()) { - int httpPort = wireMockProperties.wireMock.getServer().getPort(); - int httpsPort = wireMockProperties.wireMock.getServer().getHttpsPort(); - log.debug("Http port [" + httpPort + "] dynamic [" + httpPortDynamic + "]" + " https port [" + httpsPort - + "] dynamic [" + httpsPortDynamic + "]"); - } - return !httpPortDynamic || !httpsPortDynamic; - } - -} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/file/ResourcesFileSource.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/file/ResourcesFileSource.java deleted file mode 100644 index 0bfe15bd4c..0000000000 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/file/ResourcesFileSource.java +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright 2015-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.file; - -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.util.ArrayList; -import java.util.List; - -import com.github.tomakehurst.wiremock.common.BinaryFile; -import com.github.tomakehurst.wiremock.common.ClasspathFileSource; -import com.github.tomakehurst.wiremock.common.FileSource; -import com.github.tomakehurst.wiremock.common.SingleRootFileSource; -import com.github.tomakehurst.wiremock.common.TextFile; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.Resource; -import org.springframework.core.io.UrlResource; - -import static java.util.Arrays.asList; - -/** - * @author Dave Syer - * @author Pei-Tang Huang - * @author Hunhee Jung - */ -public class ResourcesFileSource implements FileSource { - - private static final Log log = LogFactory.getLog(ResourcesFileSource.class); - - private final FileSource[] sources; - - public ResourcesFileSource(Resource... resources) { - this(toSources(resources)); - } - - protected ResourcesFileSource(FileSource... sources) { - this.sources = sources; - } - - private static FileSource[] toSources(Resource[] resources) { - FileSource[] sources = new FileSource[resources.length]; - for (int i = 0; i < resources.length; i++) { - Resource resource = resources[i]; - if (resource instanceof ClassPathResource) { - ClassPathResource classes = (ClassPathResource) resource; - sources[i] = new ClasspathFileSource(classes.getPath()); - } - else if (resource instanceof FileSystemResource) { - FileSystemResource files = (FileSystemResource) resource; - sources[i] = new SingleRootFileSource(files.getFile()); - } - else if (resource instanceof UrlResource) { - sources[i] = fileOrFallbackToClasspath(resource); - } - else { - throw new IllegalArgumentException("Unsupported resource type for file source: " + resource.getClass()); - } - } - return sources; - } - - private static FileSource fileOrFallbackToClasspath(Resource resource) { - UrlResource file = (UrlResource) resource; - try { - URI uri = file.getURI(); - if (compressedResource(uri)) { - return new ClasspathFileSource(pathFromCompressed(uri)); - } - return new SingleRootFileSource(getFile(file)); - } - catch (IOException e) { - throw new IllegalStateException(e); - } - } - - private static String pathFromCompressed(URI pathUri) { - String path = pathUri.getSchemeSpecificPart().split("!")[1]; - return path.startsWith("/") ? path.substring(1) : path; - } - - private static boolean compressedResource(URI pathUri) { - return asList("jar", "war", "ear", "zip").contains(pathUri.getScheme()); - } - - private static File getFile(UrlResource file) { - try { - return file.getFile(); - } - catch (IOException e) { - throw new IllegalStateException(e); - } - } - - @Override - public BinaryFile getBinaryFileNamed(String name) { - for (FileSource resource : this.sources) { - if (log.isDebugEnabled()) { - log.debug("Trying FileSource with path " + resource.getPath()); - } - try { - if (resource instanceof ClasspathFileSource) { - ClasspathFileSource classpathFileSource = (ClasspathFileSource) resource; - if (classpathFileSource.exists() && compressedResource(classpathFileSource.getUri())) { - return classpathFileSource.getBinaryFileNamed(name); - } - } - UrlResource uri = new UrlResource(resource.getUri()); - if (uri.exists()) { - Resource relativeResource = new UrlResource(uri.getURI() + "/" + name); - if (relativeResource.exists()) { - return resource.getBinaryFileNamed(name); - } - } - } - catch (RuntimeException e) { - if (log.isDebugEnabled()) { - log.debug("Caught exception while trying to create file handle for file " + name - + ", trying next FileSource", e); - } - } - catch (IOException e) { - if (log.isDebugEnabled()) { - log.debug("Caught exception while trying to create file handle for file " + name - + ", trying next FileSource", e); - } - } - } - throw new IllegalStateException("Cannot create file handler for " + name); - } - - @Override - public TextFile getTextFileNamed(String name) { - for (FileSource resource : this.sources) { - if (log.isDebugEnabled()) { - log.debug("Trying FileSource with path " + resource.getPath()); - } - TextFile file = resource.getTextFileNamed(name); - try { - file.readContentsAsString(); - return file; - } - catch (RuntimeException e) { - if (log.isDebugEnabled()) { - log.debug("Caught exception while trying to create file handler for " + name, e); - } - } - } - return null; - } - - @Override - public void createIfNecessary() { - throw new UnsupportedOperationException("Resource file sources are read-only"); - } - - @Override - public FileSource child(String subDirectoryName) { - List childSources = new ArrayList<>(); - for (FileSource resource : this.sources) { - if (log.isDebugEnabled()) { - log.debug("Trying FileSource with path " + resource.getPath()); - } - try { - UrlResource uri = new UrlResource(resource.child(subDirectoryName).getUri()); - if (uri.exists()) { - FileSource child = resource.child(subDirectoryName); - childSources.add(child); - } - } - catch (IOException e) { - if (log.isDebugEnabled()) { - log.debug("Caught exception while trying to create file source for " + subDirectoryName - + ", continuing with next source", e); - } - } - } - if (!childSources.isEmpty()) { - return new ResourcesFileSource(childSources.toArray(new FileSource[0])); - } - return this.sources[0].child(subDirectoryName); - } - - @Override - public String getPath() { - for (FileSource resource : this.sources) { - if (log.isDebugEnabled()) { - log.debug("Trying FileSource with path " + resource.getPath()); - } - try { - UrlResource uri = new UrlResource(resource.getUri()); - if (uri.exists()) { - return resource.getPath(); - } - } - catch (IOException e) { - if (log.isDebugEnabled()) { - log.debug("Caught exception while trying to create URL file handler for " + resource.getPath() - + ", continuing with next source", e); - } - } - } - return this.sources[0].getPath(); - } - - @Override - public URI getUri() { - for (FileSource resource : this.sources) { - if (log.isDebugEnabled()) { - log.debug("Trying FileSource with path " + resource.getPath()); - } - try { - UrlResource uri = new UrlResource(resource.getUri()); - if (uri.exists()) { - return resource.getUri(); - } - } - catch (IOException e) { - if (log.isDebugEnabled()) { - log.debug("Caught exception while trying to create URL file handler for " + resource.getPath() - + ", continuing with next source", e); - } - } - } - return this.sources[0].getUri(); - } - - @Override - public List listFilesRecursively() { - List files = new ArrayList<>(); - for (FileSource resource : this.sources) { - files.addAll(resource.listFilesRecursively()); - } - return files; - } - - @Override - public void writeTextFile(String name, String contents) { - throw new UnsupportedOperationException("Resource file sources are read-only"); - } - - @Override - public void writeBinaryFile(String name, byte[] contents) { - throw new UnsupportedOperationException("Resource file sources are read-only"); - } - - @Override - public boolean exists() { - for (FileSource resource : this.sources) { - if (resource.exists()) { - return true; - } - } - return false; - } - - @Override - public void deleteFile(String name) { - - } - -} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/BasicMappingBuilder.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/BasicMappingBuilder.java deleted file mode 100644 index 0f9944b9a9..0000000000 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/BasicMappingBuilder.java +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.restdocs; - -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.UUID; - -import com.github.tomakehurst.wiremock.client.BasicCredentials; -import com.github.tomakehurst.wiremock.client.MappingBuilder; -import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.client.ScenarioMappingBuilder; -import com.github.tomakehurst.wiremock.common.Metadata; -import com.github.tomakehurst.wiremock.extension.Parameters; -import com.github.tomakehurst.wiremock.http.Request; -import com.github.tomakehurst.wiremock.http.RequestMethod; -import com.github.tomakehurst.wiremock.http.ResponseDefinition; -import com.github.tomakehurst.wiremock.matching.ContentPattern; -import com.github.tomakehurst.wiremock.matching.MultipartValuePatternBuilder; -import com.github.tomakehurst.wiremock.matching.RequestPattern; -import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder; -import com.github.tomakehurst.wiremock.matching.StringValuePattern; -import com.github.tomakehurst.wiremock.matching.UrlPattern; -import com.github.tomakehurst.wiremock.matching.ValueMatcher; -import com.github.tomakehurst.wiremock.stubbing.StubMapping; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; - -class BasicMappingBuilder implements ScenarioMappingBuilder { - - private RequestPatternBuilder requestPatternBuilder; - - private ResponseDefinitionBuilder responseDefBuilder; - - private Integer priority; - - private String scenarioName; - - private String requiredScenarioState; - - private String newScenarioState; - - private UUID id = UUID.randomUUID(); - - private String name; - - private boolean isPersistent = false; - - private Map postServeActions = new LinkedHashMap<>(); - - private Metadata metadata = new Metadata(); - - BasicMappingBuilder(RequestMethod method, UrlPattern urlPattern) { - this.requestPatternBuilder = new RequestPatternBuilder(method, urlPattern); - } - - BasicMappingBuilder(ValueMatcher requestMatcher) { - this.requestPatternBuilder = new RequestPatternBuilder(requestMatcher); - } - - BasicMappingBuilder(String customRequestMatcherName, Parameters parameters) { - this.requestPatternBuilder = new RequestPatternBuilder(customRequestMatcherName, parameters); - } - - @Override - public BasicMappingBuilder willReturn(ResponseDefinitionBuilder responseDefBuilder) { - this.responseDefBuilder = responseDefBuilder; - return this; - } - - @Override - public BasicMappingBuilder withScheme(String scheme) { - this.requestPatternBuilder.withScheme(scheme); - return this; - } - - @Override - public BasicMappingBuilder withHost(StringValuePattern hostPattern) { - this.requestPatternBuilder.withHost(hostPattern); - return this; - } - - @Override - public BasicMappingBuilder withPort(int port) { - this.requestPatternBuilder.withPort(port); - return this; - } - - @Override - public BasicMappingBuilder atPriority(Integer priority) { - this.priority = priority; - return this; - } - - @Override - public BasicMappingBuilder withHeader(String key, StringValuePattern headerPattern) { - this.requestPatternBuilder.withHeader(key, headerPattern); - return this; - } - - @Override - public BasicMappingBuilder withCookie(String name, StringValuePattern cookieValuePattern) { - this.requestPatternBuilder.withCookie(name, cookieValuePattern); - return this; - } - - @Override - public BasicMappingBuilder withQueryParam(String key, StringValuePattern queryParamPattern) { - this.requestPatternBuilder.withQueryParam(key, queryParamPattern); - return this; - } - - @Override - public ScenarioMappingBuilder withQueryParams(Map queryParams) { - for (Map.Entry entry : queryParams.entrySet()) { - this.requestPatternBuilder.withQueryParam(entry.getKey(), entry.getValue()); - } - return this; - } - - @Override - public ScenarioMappingBuilder withRequestBody(ContentPattern bodyPattern) { - this.requestPatternBuilder.withRequestBody(bodyPattern); - return this; - } - - @Override - public ScenarioMappingBuilder withMultipartRequestBody(MultipartValuePatternBuilder multipartPatternBuilder) { - this.requestPatternBuilder.withRequestBodyPart(multipartPatternBuilder.build()); - return this; - } - - @Override - public BasicMappingBuilder inScenario(String scenarioName) { - this.scenarioName = scenarioName; - return this; - } - - @Override - public BasicMappingBuilder whenScenarioStateIs(String stateName) { - this.requiredScenarioState = stateName; - return this; - } - - @Override - public BasicMappingBuilder willSetStateTo(String stateName) { - this.newScenarioState = stateName; - return this; - } - - @Override - public BasicMappingBuilder withId(UUID id) { - this.id = id; - return this; - } - - @Override - public BasicMappingBuilder withName(String name) { - this.name = name; - return this; - } - - @Override - public ScenarioMappingBuilder persistent() { - this.isPersistent = true; - return this; - } - - @Override - public ScenarioMappingBuilder persistent(boolean b) { - this.isPersistent = b; - return this; - } - - @Override - public BasicMappingBuilder withBasicAuth(String username, String password) { - this.requestPatternBuilder.withBasicAuth(new BasicCredentials(username, password)); - return this; - } - - @Override - public

BasicMappingBuilder withPostServeAction(String extensionName, P parameters) { - Parameters params = parameters instanceof Parameters ? (Parameters) parameters : Parameters.of(parameters); - this.postServeActions.put(extensionName, params); - return this; - } - - @Override - public ScenarioMappingBuilder withMetadata(Map map) { - this.metadata = new Metadata(map); - return this; - } - - @Override - public ScenarioMappingBuilder withMetadata(Metadata metadata) { - this.metadata = metadata; - return this; - } - - @Override - public ScenarioMappingBuilder withMetadata(Metadata.Builder builder) { - this.metadata = builder.build(); - return this; - } - - @Override - public ScenarioMappingBuilder andMatching(ValueMatcher requestMatcher) { - this.requestPatternBuilder.andMatching(requestMatcher); - return this; - } - - @Override - public MappingBuilder andMatching(String customRequestMatcherName) { - this.requestPatternBuilder.andMatching(customRequestMatcherName); - return this; - } - - @Override - public MappingBuilder andMatching(String customRequestMatcherName, Parameters parameters) { - this.requestPatternBuilder.andMatching(customRequestMatcherName, parameters); - return this; - } - - @Override - public StubMapping build() { - if (this.scenarioName == null && (this.requiredScenarioState != null || this.newScenarioState != null)) { - throw new IllegalStateException("Scenario name must be specified to require or set a new scenario state"); - } - RequestPattern requestPattern = this.requestPatternBuilder.build(); - ResponseDefinition response = (this.responseDefBuilder != null ? this.responseDefBuilder : aResponse()).build(); - StubMapping mapping = new StubMapping(requestPattern, response); - mapping.setPriority(this.priority); - mapping.setScenarioName(this.scenarioName); - mapping.setRequiredScenarioState(this.requiredScenarioState); - mapping.setNewScenarioState(this.newScenarioState); - mapping.setUuid(this.id); - mapping.setName(this.name); - mapping.setPersistent(this.isPersistent); - mapping.setPostServeActions(this.postServeActions.isEmpty() ? null : this.postServeActions); - mapping.setMetadata(this.metadata); - return mapping; - } - -} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/ContractDslSnippet.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/ContractDslSnippet.java deleted file mode 100644 index 92f3cbf062..0000000000 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/ContractDslSnippet.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.restdocs; - -import java.io.File; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.net.URI; -import java.nio.file.Files; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.springframework.http.HttpHeaders; -import org.springframework.restdocs.RestDocumentationContext; -import org.springframework.restdocs.operation.Operation; -import org.springframework.restdocs.operation.OperationRequest; -import org.springframework.restdocs.operation.OperationResponse; -import org.springframework.restdocs.operation.QueryParameters; -import org.springframework.restdocs.snippet.RestDocumentationContextPlaceholderResolver; -import org.springframework.restdocs.snippet.TemplatedSnippet; -import org.springframework.restdocs.templates.TemplateEngine; -import org.springframework.util.PropertyPlaceholderHelper; -import org.springframework.util.StringUtils; - -/** - * A {@link org.springframework.restdocs.snippet.Snippet} that documents the Spring Cloud - * Contract Groovy DSL. - * - * @author Marcin Grzejszczak - * @since 1.0.4 - */ -public class ContractDslSnippet extends TemplatedSnippet { - - private static final String CONTRACTS_FOLDER = "contracts"; - - private static final String SNIPPET_NAME = "dsl-contract"; - - private static final Set IGNORED_HEADERS = new HashSet<>( - Arrays.asList(HttpHeaders.HOST, HttpHeaders.CONTENT_LENGTH)); - - private final PropertyPlaceholderHelper propertyPlaceholderHelper = new PropertyPlaceholderHelper("{", "}"); - - private Map model = new HashMap<>(); - - /** - * Creates a new {@code ContractDslSnippet} with no additional attributes. - */ - protected ContractDslSnippet() { - this(null); - } - - /** - * Creates a new {@code ContractDslSnippet} with the given additional - * {@code attributes} that will be included in the model during template rendering. - * @param attributes The additional attributes - */ - protected ContractDslSnippet(Map attributes) { - super(SNIPPET_NAME, attributes); - } - - @Override - protected Map createModel(Operation operation) { - return this.model; - } - - @Override - public void document(Operation operation) throws IOException { - TemplateEngine templateEngine = (TemplateEngine) operation.getAttributes().get(TemplateEngine.class.getName()); - String renderedContract = templateEngine.compileTemplate(getTemplate()) - .render(createModelForContract(operation)); - this.model.put("contract", renderedContract); - storeDslContract(operation, renderedContract); - super.document(operation); - } - - protected String getTemplate() { - return "default-dsl-contract-only"; - } - - private void insertResponseModel(Operation operation, Map model) { - OperationResponse response = operation.getResponse(); - model.put("response_status", response.getStatus().value()); - model.put("response_body_present", response.getContent().length > 0); - model.put("response_body", response.getContentAsString()); - Map headers = new HashMap<>(response.getHeaders().toSingleValueMap()); - filterHeaders(headers); - model.put("response_headers_present", !headers.isEmpty()); - model.put("response_headers", headers.entrySet()); - } - - private Set jsonPaths(Set jsonPaths) { - Set paths = new HashSet<>(); - if (jsonPaths == null) { - return paths; - } - for (String s : jsonPaths) { - paths.add(new JsonPaths(s)); - } - return paths; - } - - private void insertRequestModel(Operation operation, Map model) { - OperationRequest request = operation.getRequest(); - model.put("request_method", request.getMethod()); - model.put("request_url", prepareRequestUrl(request.getUri())); - String rawQuery = request.getUri().getRawQuery(); - boolean urlPathPresent = StringUtils.hasText(rawQuery); - model.put("request_urlpath_present", urlPathPresent); - if (urlPathPresent) { - // TODO: Add support for multiple values - model.put("request_queryparams", QueryParameters.from(request).toSingleValueMap().entrySet()); - } - model.put("request_body_present", request.getContent().length > 0); - model.put("request_body", request.getContentAsString()); - Map headers = new HashMap<>(request.getHeaders().toSingleValueMap()); - filterHeaders(headers); - model.put("request_headers_present", !headers.isEmpty()); - model.put("request_headers", headers.entrySet()); - @SuppressWarnings("unchecked") - Set jsonPaths = (Set) operation.getAttributes().get("contract.jsonPaths"); - model.put("request_json_paths_present", jsonPaths != null && !jsonPaths.isEmpty()); - model.put("request_json_paths", jsonPaths(jsonPaths)); - } - - private void filterHeaders(Map headers) { - for (String header : IGNORED_HEADERS) { - if (headers.containsKey(header)) { - headers.remove(header); - } - } - } - - private String prepareRequestUrl(URI uri) { - return uri.getRawPath(); - } - - private Map createModelForContract(Operation operation) { - Map modelForContract = new HashMap<>(); - insertRequestModel(operation, modelForContract); - insertResponseModel(operation, modelForContract); - insertAdditionalModel(operation, modelForContract); - return modelForContract; - } - - protected void insertAdditionalModel(Operation operation, Map modelForContract) { - boolean hasPriority = getAttributes().containsKey("priority"); - modelForContract.put("priority_present", hasPriority); - if (hasPriority) { - modelForContract.put("priority", getAttributes().get("priority")); - } - } - - private void storeDslContract(Operation operation, String content) throws IOException { - RestDocumentationContext context = (RestDocumentationContext) operation.getAttributes() - .get(RestDocumentationContext.class.getName()); - RestDocumentationContextPlaceholderResolver resolver = new RestDocumentationContextPlaceholderResolver(context); - String resolvedName = replacePlaceholders(resolver, operation.getName()); - File output = new File(context.getOutputDirectory(), CONTRACTS_FOLDER + "/" + resolvedName + ".groovy"); - output.getParentFile().mkdirs(); - try (Writer writer = new OutputStreamWriter(Files.newOutputStream(output.toPath()))) { - writer.append(content); - } - } - - private String replacePlaceholders(PropertyPlaceholderHelper.PlaceholderResolver resolver, String input) { - return this.propertyPlaceholderHelper.replacePlaceholders(input, resolver); - } - -} - -class JsonPaths { - - private final String jsonPath; - - JsonPaths(String jsonPath) { - this.jsonPath = jsonPath; - } - - public String getJsonPath() { - return this.jsonPath; - } - -} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/ContractExchangeHandler.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/ContractExchangeHandler.java deleted file mode 100644 index 1df697b466..0000000000 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/ContractExchangeHandler.java +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Copyright 2016-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.restdocs; - -import java.io.IOException; -import java.lang.reflect.Field; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Consumer; -import java.util.stream.Collectors; - -import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.http.Body; -import com.github.tomakehurst.wiremock.http.ContentTypeHeader; -import com.github.tomakehurst.wiremock.http.Cookie; -import com.github.tomakehurst.wiremock.http.HttpHeader; -import com.github.tomakehurst.wiremock.http.QueryParameter; -import com.github.tomakehurst.wiremock.http.Request; -import com.github.tomakehurst.wiremock.http.RequestMethod; -import org.apache.commons.codec.binary.Base64; -import wiremock.com.google.common.base.Optional; - -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockServletContext; -import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentationConfigurer; -import org.springframework.test.web.reactive.server.EntityExchangeResult; -import org.springframework.test.web.reactive.server.WebTestClient; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.util.ReflectionUtils; -import org.springframework.util.StringUtils; -import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest; - -/** - * @author Dave Syer - * - */ -public class ContractExchangeHandler extends WireMockVerifyHelper, ContractExchangeHandler> - implements Consumer> { - - @Override - public void accept(EntityExchangeResult result) { - configure(result); - } - - @Override - protected ResponseDefinitionBuilder getResponseDefinition(EntityExchangeResult result) { - ResponseDefinitionBuilder definition = ResponseDefinitionBuilder.responseDefinition() - .withBody(result.getResponseBodyContent()).withStatus(result.getStatus().value()); - addResponseHeaders(definition, result.getResponseHeaders()); - return definition; - } - - private void addResponseHeaders(ResponseDefinitionBuilder definition, HttpHeaders httpHeaders) { - for (String name : httpHeaders.keySet()) { - definition.withHeader(name, httpHeaders.get(name).toArray(new String[0])); - } - } - - @Override - protected Map getConfiguration(EntityExchangeResult result) { - Field field = ReflectionUtils.findField(WebTestClientRestDocumentationConfigurer.class, "configurations"); - ReflectionUtils.makeAccessible(field); - String index = result.getRequestHeaders().getFirst(WebTestClient.WEBTESTCLIENT_REQUEST_ID); - @SuppressWarnings("unchecked") - Map map = (((Map>) ReflectionUtils.getField(field, null)) - .get(index)); - if (map == null) { - return new HashMap<>(); - } - return map; - } - - @Override - protected Request getWireMockRequest(EntityExchangeResult result) { - return new WireMockHttpRequestAdapter(result); - } - - @Override - protected MediaType getContentType(EntityExchangeResult result) { - return result.getRequestHeaders().getContentType(); - } - - @Override - protected byte[] getRequestBodyContent(EntityExchangeResult result) { - return result.getRequestBodyContent(); - } - -} - -class WireMockHttpRequestAdapter implements Request { - - private EntityExchangeResult result; - - WireMockHttpRequestAdapter(EntityExchangeResult result) { - this.result = result; - } - - @Override - public String getUrl() { - return this.result.getUrl().getRawPath(); - } - - @Override - public String getAbsoluteUrl() { - return this.result.getUrl().toString(); - } - - @Override - public RequestMethod getMethod() { - return new RequestMethod(this.result.getMethod().name()); - } - - @Override - public String getScheme() { - return this.result.getUrl().getScheme(); - } - - @Override - public String getHost() { - return this.result.getUrl().getHost(); - } - - @Override - public int getPort() { - return this.result.getUrl().getPort(); - } - - @Override - public String getClientIp() { - return "127.0.0.1"; - } - - @Override - public String getHeader(String key) { - HttpHeaders headers = this.result.getRequestHeaders(); - return headers.containsKey(key) ? headers.getFirst(key) : null; - } - - @Override - public HttpHeader header(String key) { - HttpHeaders headers = this.result.getRequestHeaders(); - return headers.containsKey(key) ? new HttpHeader(key, headers.getValuesAsList(key)) : null; - } - - @Override - public ContentTypeHeader contentTypeHeader() { - MediaType contentType = this.result.getRequestHeaders().getContentType(); - if (contentType == null) { - return null; - } - return new ContentTypeHeader(contentType.toString()); - } - - @Override - public com.github.tomakehurst.wiremock.http.HttpHeaders getHeaders() { - com.github.tomakehurst.wiremock.http.HttpHeaders target = new com.github.tomakehurst.wiremock.http.HttpHeaders(); - HttpHeaders headers = this.result.getRequestHeaders(); - for (String key : headers.keySet()) { - target = target.plus(new HttpHeader(key, headers.getValuesAsList(key))); - } - return target; - } - - @Override - public boolean containsHeader(String key) { - return this.result.getRequestHeaders().containsKey(key); - } - - @Override - public Set getAllHeaderKeys() { - return this.result.getRequestHeaders().keySet(); - } - - @Override - public Map getCookies() { - return new LinkedHashMap<>(); - } - - @Override - public QueryParameter queryParameter(String key) { - String query = this.result.getUrl().getRawQuery(); - if (query == null) { - return null; - } - List values = new ArrayList<>(); - String[] strings = StringUtils.split(query, "&"); - if (strings == null) { - return null; - } - for (String name : strings) { - if (name.equals(key)) { - values.add(""); - } - else if (name.startsWith(key + "=")) { - values.add(name.substring(name.indexOf("=") + 1)); - } - } - if (values.isEmpty()) { - return null; - } - return new QueryParameter(key, values); - } - - @Override - public byte[] getBody() { - return this.result.getRequestBodyContent(); - } - - @Override - public String getBodyAsString() { - return new String(this.result.getRequestBodyContent(), Charset.forName("UTF-8")); - } - - @Override - public String getBodyAsBase64() { - return Base64.encodeBase64String(this.result.getRequestBodyContent()); - } - - @Override - public boolean isMultipart() { - return MediaType.MULTIPART_FORM_DATA.isCompatibleWith(this.result.getRequestHeaders().getContentType()); - } - - @Override - public Collection getParts() { - try { - return getWireMockParts(); - } - catch (Exception e) { - throw new IllegalStateException(e); - } - } - - // TODO: Consider caching this - private Collection getWireMockParts() { - MockHttpServletRequest request = MockMvcRequestBuilders - .request(this.result.getMethod(), this.result.getUriTemplate()) - .contentType(this.result.getRequestHeaders().getContentType()) - .content(this.result.getRequestBodyContent()).buildRequest(new MockServletContext()); - try { - return new StandardMultipartHttpServletRequest(request).getParts().stream() - .map(part -> partFromServletPart(part)).collect(Collectors.toList()); - } - catch (Exception e) { - throw new IllegalStateException(e); - } - } - - private Part partFromServletPart(jakarta.servlet.http.Part part) { - return new Part() { - - @Override - public String getName() { - return part.getName(); - } - - @Override - public HttpHeader getHeader(String name) { - return new HttpHeader(name, part.getHeader(name)); - } - - @Override - public com.github.tomakehurst.wiremock.http.HttpHeaders getHeaders() { - com.github.tomakehurst.wiremock.http.HttpHeaders headers = new com.github.tomakehurst.wiremock.http.HttpHeaders(); - for (String s : part.getHeaderNames()) { - headers.plus(new HttpHeader(s, part.getHeader(s))); - } - return headers; - } - - @Override - public Body getBody() { - try { - byte[] targetArray = new byte[part.getInputStream().available()]; - return new Body(targetArray); - } - catch (IOException e) { - throw new IllegalStateException(e); - } - } - }; - } - - // TODO: Consider caching this - @Override - public Part getPart(String name) { - return getWireMockParts().stream().filter(part -> name.equals(part.getName())).findFirst().get(); - } - - @Override - public boolean isBrowserProxyRequest() { - return false; - } - - @Override - public Optional getOriginalRequest() { - return Optional.absent(); - } - - @Override - public String getProtocol() { - return this.result.getUrl().getScheme(); - } - -} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/ContractResultHandler.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/ContractResultHandler.java deleted file mode 100644 index b8b5b5bfa1..0000000000 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/ContractResultHandler.java +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.restdocs; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.http.Body; -import com.github.tomakehurst.wiremock.http.ContentTypeHeader; -import com.github.tomakehurst.wiremock.http.Cookie; -import com.github.tomakehurst.wiremock.http.HttpHeader; -import com.github.tomakehurst.wiremock.http.HttpHeaders; -import com.github.tomakehurst.wiremock.http.QueryParameter; -import com.github.tomakehurst.wiremock.http.Request; -import com.github.tomakehurst.wiremock.http.RequestMethod; -import wiremock.com.google.common.base.Optional; -import wiremock.org.apache.commons.io.IOUtils; - -import org.springframework.http.MediaType; -import org.springframework.mock.web.MockHttpServletResponse; -import org.springframework.test.web.servlet.MvcResult; -import org.springframework.test.web.servlet.ResultHandler; -import org.springframework.util.Base64Utils; -import org.springframework.util.StringUtils; - -/** - * Converts a {@link MvcResult} to a WireMock response. - * - * @author Dave Syer - */ -public class ContractResultHandler extends WireMockVerifyHelper - implements ResultHandler { - - static final String ATTRIBUTE_NAME_CONFIGURATION = "org.springframework.restdocs.configuration"; - - @Override - public void handle(MvcResult result) throws Exception { - configure(result); - } - - @Override - protected ResponseDefinitionBuilder getResponseDefinition(MvcResult result) { - MockHttpServletResponse response = result.getResponse(); - ResponseDefinitionBuilder definition; - try { - definition = ResponseDefinitionBuilder.responseDefinition().withBody(response.getContentAsString()) - .withStatus(response.getStatus()); - addResponseHeaders(definition, response); - return definition; - } - catch (UnsupportedEncodingException e) { - throw new IllegalStateException("Cannot create response body", e); - } - } - - private void addResponseHeaders(ResponseDefinitionBuilder definition, MockHttpServletResponse input) { - for (String name : input.getHeaderNames()) { - definition.withHeader(name, input.getHeader(name)); - } - } - - @Override - protected Map getConfiguration(MvcResult result) { - @SuppressWarnings("unchecked") - Map map = (Map) result.getRequest().getAttribute(ATTRIBUTE_NAME_CONFIGURATION); - if (map == null) { - map = new HashMap<>(); - result.getRequest().setAttribute(ATTRIBUTE_NAME_CONFIGURATION, map); - } - return map; - } - - @Override - protected Request getWireMockRequest(MvcResult result) { - return new Request() { - @Override - public String getUrl() { - return result.getRequest().getRequestURI(); - } - - @Override - public String getAbsoluteUrl() { - return result.getRequest().getRequestURI(); - } - - @Override - public RequestMethod getMethod() { - return RequestMethod.fromString(result.getRequest().getMethod()); - } - - @Override - public String getScheme() { - return result.getRequest().getScheme(); - } - - @Override - public String getHost() { - return result.getRequest().getRemoteHost(); - } - - @Override - public int getPort() { - return result.getRequest().getServerPort(); - } - - @Override - public String getClientIp() { - return ""; - } - - @Override - public String getHeader(String key) { - return result.getRequest().getHeader(key); - } - - @Override - public HttpHeader header(String key) { - return new HttpHeader(key, getHeader(key)); - } - - @Override - public ContentTypeHeader contentTypeHeader() { - return new ContentTypeHeader(result.getRequest().getContentType()); - } - - @Override - public HttpHeaders getHeaders() { - List headers = new ArrayList<>(); - Enumeration headerNames = result.getRequest().getHeaderNames(); - while (headerNames.hasMoreElements()) { - String key = headerNames.nextElement(); - String value = getHeader(key); - headers.add(new HttpHeader(key, value)); - } - return new HttpHeaders(headers); - } - - @Override - public boolean containsHeader(String key) { - Enumeration headerNames = result.getRequest().getHeaderNames(); - while (headerNames.hasMoreElements()) { - String name = headerNames.nextElement(); - if (name.equals(key)) { - return true; - } - } - return false; - } - - @Override - public Set getAllHeaderKeys() { - return getHeaders().keys(); - } - - @Override - public Map getCookies() { - Map nameToCookie = new HashMap<>(); - if (result.getRequest().getCookies() == null) { - return nameToCookie; - } - for (jakarta.servlet.http.Cookie cookie : result.getRequest().getCookies()) { - nameToCookie.put(cookie.getName(), new Cookie(cookie.getValue())); - } - return nameToCookie; - } - - @Override - public QueryParameter queryParameter(String key) { - return new QueryParameter(key, Collections.singletonList(result.getRequest().getParameter(key))); - } - - @Override - public byte[] getBody() { - return result.getRequest().getContentAsByteArray(); - } - - @Override - public String getBodyAsString() { - try { - return result.getRequest().getContentAsString(); - } - catch (Exception ex) { - return new String(result.getRequest().getContentAsByteArray()); - } - } - - @Override - public String getBodyAsBase64() { - return Base64Utils.encodeToString(result.getRequest().getContentAsByteArray()); - } - - @Override - public boolean isMultipart() { - return StringUtils.hasText(result.getRequest().getHeader("multipart/form-data")); - } - - @Override - public Collection getParts() { - try { - return result.getRequest().getParts().stream().map(part -> new Part() { - @Override - public String getName() { - return part.getName(); - } - - @Override - public HttpHeader getHeader(String name) { - String header = part.getHeader(name); - return new HttpHeader(name, header); - } - - @Override - public HttpHeaders getHeaders() { - List headers = new ArrayList<>(); - for (String headerName : part.getHeaderNames()) { - headers.add(new HttpHeader(headerName, getHeader(headerName).values())); - } - return new HttpHeaders(headers); - } - - @Override - public Body getBody() { - try { - return new Body(IOUtils.toByteArray(part.getInputStream())); - } - catch (IOException ex) { - throw new IllegalStateException(ex); - } - } - }).collect(Collectors.toList()); - } - catch (Exception ex) { - throw new IllegalStateException(ex); - } - } - - @Override - public Part getPart(String name) { - return getParts().stream().filter(part -> part.getName().equals(name)).findFirst().orElse(null); - } - - @Override - public boolean isBrowserProxyRequest() { - return false; - } - - @Override - public Optional getOriginalRequest() { - return Optional.absent(); - } - - @Override - public String getProtocol() { - return result.getRequest().getProtocol(); - } - }; - } - - @Override - protected MediaType getContentType(MvcResult result) { - return MediaType.valueOf(result.getRequest().getContentType()); - } - - @Override - protected byte[] getRequestBodyContent(MvcResult result) { - byte[] body = getWireMockRequest(result).getBody(); - return body != null ? body : new byte[0]; - } - -} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/DynamicPortPlaceholderInserterPreprocessor.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/DynamicPortPlaceholderInserterPreprocessor.java deleted file mode 100644 index a13788d1df..0000000000 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/DynamicPortPlaceholderInserterPreprocessor.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2019-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.restdocs; - -import org.springframework.restdocs.operation.OperationRequest; -import org.springframework.restdocs.operation.OperationResponse; -import org.springframework.restdocs.operation.OperationResponseFactory; -import org.springframework.restdocs.operation.preprocess.OperationPreprocessor; - -class DynamicPortPlaceholderInserterPreprocessor implements OperationPreprocessor { - - private final OperationResponseFactory responseFactory = new OperationResponseFactory(); - - @Override - public OperationRequest preprocess(OperationRequest request) { - return request; - } - - @Override - public OperationResponse preprocess(OperationResponse response) { - String content = response.getContentAsString(); - if (content.contains("localhost:8080")) { - content = content.replace("localhost:8080", "localhost:{{request.requestLine.port}}"); - response = this.responseFactory.createFrom(response, content.getBytes()); - } - return response; - } - -} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/JsonPathValue.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/JsonPathValue.java deleted file mode 100644 index 0da02e8e37..0000000000 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/JsonPathValue.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2016-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.restdocs; - -import com.jayway.jsonpath.JsonPath; - -import org.springframework.util.ObjectUtils; -import org.springframework.util.StringUtils; - -class JsonPathValue { - - private final JsonPath jsonPath; - - private final String expression; - - private final CharSequence actual; - - JsonPathValue(JsonPath jsonPath, CharSequence actual) { - this.jsonPath = jsonPath; - this.actual = actual; - this.expression = jsonPath.getPath(); - } - - public void assertHasValue(Class type, String expectedDescription) { - Object value = getValue(true); - if (value == null || isIndefiniteAndEmpty()) { - throw new AssertionError(getNoValueMessage()); - } - if (type != null && !type.isInstance(value)) { - throw new AssertionError(getExpectedValueMessage(expectedDescription)); - } - } - - private boolean isIndefiniteAndEmpty() { - return !isDefinite() && isEmpty(); - } - - private boolean isDefinite() { - return this.jsonPath.isDefinite(); - } - - private boolean isEmpty() { - return ObjectUtils.isEmpty(getValue(false)); - } - - public Object getValue(boolean required) { - try { - CharSequence json = this.actual; - return this.jsonPath.read(json == null ? null : json.toString()); - } - catch (Exception ex) { - if (!required) { - return null; - } - throw new AssertionError(getNoValueMessage() + ". " + ex.getMessage()); - } - } - - private String getNoValueMessage() { - return "No value at JSON path \"" + this.expression + "\""; - } - - private String getExpectedValueMessage(String expectedDescription) { - return String.format("Expected %s at JSON path \"%s\" but found: %s", expectedDescription, this.expression, - ObjectUtils.nullSafeToString(StringUtils.quoteIfString(getValue(false)))); - } - -} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/SpringCloudContractRestDocs.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/SpringCloudContractRestDocs.java deleted file mode 100644 index 4a3b595fa6..0000000000 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/SpringCloudContractRestDocs.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.restdocs; - -import java.util.Map; - -import org.springframework.restdocs.snippet.Snippet; - -/** - * Convenience class for setting up RestDocs to generate a - * {@link org.springframework.restdocs.snippet.Snippet} with Spring Cloud Contract DSL. - * Example usage: - * - *

- * @RunWith(SpringRunner.class)
- * @SpringBootTest
- * @AutoConfigureRestDocs(outputDir = "target/snippets")
- * @AutoConfigureMockMvc
- * public class ContractRestDocsApplicationTests {
- *
- * 	@Autowired
- * 	private MockMvc mockMvc;
- *
- * 	@Test
- * 	public void contextLoads() throws Exception {
- *     this.mockMvc.perform(post("/foo")
- *          .accept(MediaType.APPLICATION_PDF)
- *          .accept(MediaType.APPLICATION_JSON)
- *          .contentType(MediaType.APPLICATION_JSON)
- *          .content("{\"foo\": 23 }"))
- *     .andExpect(status().isOk())
- *     .andExpect(content().string("bar"))
- *     // first WireMock
- *     .andDo(WireMockRestDocs.verify()
- *          .jsonPath("$[?(@.foo >= 20)]")
- *          .contentType(MediaType.valueOf("application/json")))
- *     // then Contract DSL documentation
- *     .andDo(document("index", SpringCloudContractRestDocs.dslContract()));
- * 	}
- * 
- * - * which creates a file "target/snippets/contracts/index.groovy" and a standard - * documentation entitled `dsl-contract.adoc` containing that contract. - * - * @author Marcin Grzejszczak - * @since 1.0.4 - */ -public final class SpringCloudContractRestDocs { - - private SpringCloudContractRestDocs() { - - } - - /** - * Returns a new {@code Snippet} that will document Spring Cloud Contract DSL for the - * API operation. - * @return the snippet that will document the Spring Cloud Contract DSL - */ - public static Snippet dslContract() { - return new ContractDslSnippet(); - } - - /** - * Returns a new {@code Snippet} that will document the Spring Cloud Contract DSL for - * the API operation. The given {@code attributes} will be available during snippet - * generation. - * @param attributes the attributes - * @return the snippet that will document the Spring Cloud Contract DSL - */ - public static Snippet dslContract(Map attributes) { - return new ContractDslSnippet(attributes); - } - -} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockRestAssuredConfiguration.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockRestAssuredConfiguration.java deleted file mode 100644 index f82b6ec024..0000000000 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockRestAssuredConfiguration.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.restdocs; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.test.autoconfigure.restdocs.RestDocsRestAssuredConfigurationCustomizer; -import org.springframework.context.annotation.Configuration; -import org.springframework.restdocs.restassured.RestAssuredRestDocumentationConfigurer; - -/** - * Custom configuration for Spring RestDocs that adds a WireMock snippet (for generating - * JSON stubs). Applied automatically if you use - * {@link org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs @AutoConfigureRestDocs} - * in your test case and this class is available. JSON stubs are generated and added to - * the restdocs path under "stubs". - * - * @author Eddú Meléndez - * @author Olga Maciaszek-Sharma - * @see WireMockRestDocs for a convenient entry point for customizing and asserting the - * stub behaviour - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnClass(RestAssuredRestDocumentationConfigurer.class) -public class WireMockRestAssuredConfiguration implements RestDocsRestAssuredConfigurationCustomizer { - - @Override - public void customize(RestAssuredRestDocumentationConfigurer configurer) { - configurer.snippets().withAdditionalDefaults(new WireMockSnippet()); - } - -} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockRestDocs.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockRestDocs.java deleted file mode 100644 index e5df0a3529..0000000000 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockRestDocs.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.restdocs; - -/** - * Convenience class for setting up RestDocs to record WireMock stubs. Example usage: - * - *
- * @RunWith(SpringRunner.class)
- * @SpringBootTest
- * @AutoConfigureRestDocs(outputDir = "target/snippets")
- * @AutoConfigureMockMvc
- * public class WiremockServerRestDocsApplicationTests {
- *
- * 	@Autowired
- * 	private MockMvc mockMvc;
- *
- * 	@Test
- * 	public void contextLoads() throws Exception {
- * 		mockMvc.perform(get("/resource"))
- * 				.andExpect(content().string("Hello World"))
- * 				.andDo(verify())
- * 				.andDo(document("resource"));
- * 	}
- * 
which creates a file "target/snippets/stubs/resource.json" matching any GET - * request to "/resource". To match POST and PUT, you can also specify the content type - * using verify().contentType(...) and JSON content of the body using - * verify().jsonPath(...). - * - * @author Dave Syer - */ -public final class WireMockRestDocs { - - private WireMockRestDocs() { - throw new IllegalStateException("Can't instantiate a utility class"); - } - - public static ContractResultHandler verify() { - return new ContractResultHandler(); - } - -} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockRestDocsConfiguration.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockRestDocsConfiguration.java deleted file mode 100644 index bc970224fb..0000000000 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockRestDocsConfiguration.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.restdocs; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.test.autoconfigure.restdocs.RestDocsMockMvcConfigurationCustomizer; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; -import org.springframework.restdocs.mockmvc.MockMvcRestDocumentationConfigurer; - -/** - * Custom configuration for Spring RestDocs that adds a WireMock snippet (for generating - * JSON stubs). Applied automatically if you use - * {@link org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs @AutoConfigureRestDocs} - * in your test case and this class is available. JSON stubs are generated and added to - * the restdocs path under "stubs". - * - * @author Dave Syer - * @see WireMockRestDocs for a convenient entry point for customizing and asserting the - * stub behaviour - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnClass(MockMvcRestDocumentationConfigurer.class) -public class WireMockRestDocsConfiguration implements RestDocsMockMvcConfigurationCustomizer { - - private final Environment environment; - - public WireMockRestDocsConfiguration(Environment environment) { - this.environment = environment; - } - - @Override - public void customize(MockMvcRestDocumentationConfigurer configurer) { - if (this.environment.getProperty("wiremock.placeholders.enabled", "true").equals("true")) { - configurer.operationPreprocessors().withResponseDefaults(new DynamicPortPlaceholderInserterPreprocessor()); - } - configurer.snippets().withAdditionalDefaults(new WireMockSnippet()); - } - -} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockSnippet.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockSnippet.java deleted file mode 100644 index 8140d691f7..0000000000 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockSnippet.java +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.restdocs; - -import java.io.IOException; -import java.io.Writer; -import java.util.Arrays; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.Set; -import java.util.regex.Pattern; - -import com.github.tomakehurst.wiremock.client.MappingBuilder; -import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.client.WireMock; -import com.github.tomakehurst.wiremock.common.Json; -import com.github.tomakehurst.wiremock.http.HttpHeader; -import com.github.tomakehurst.wiremock.http.HttpHeaders; -import com.github.tomakehurst.wiremock.matching.UrlPattern; -import com.github.tomakehurst.wiremock.stubbing.StubMapping; - -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.restdocs.RestDocumentationContext; -import org.springframework.restdocs.operation.Operation; -import org.springframework.restdocs.snippet.RestDocumentationContextPlaceholderResolverFactory; -import org.springframework.restdocs.snippet.Snippet; -import org.springframework.restdocs.snippet.StandardWriterResolver; -import org.springframework.restdocs.snippet.WriterResolver; -import org.springframework.restdocs.templates.TemplateFormat; -import org.springframework.util.StringUtils; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.delete; -import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; -import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; -import static com.github.tomakehurst.wiremock.client.WireMock.equalToXml; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.head; -import static com.github.tomakehurst.wiremock.client.WireMock.matching; -import static com.github.tomakehurst.wiremock.client.WireMock.matchingJsonPath; -import static com.github.tomakehurst.wiremock.client.WireMock.options; -import static com.github.tomakehurst.wiremock.client.WireMock.patch; -import static com.github.tomakehurst.wiremock.client.WireMock.post; -import static com.github.tomakehurst.wiremock.client.WireMock.put; -import static com.github.tomakehurst.wiremock.client.WireMock.trace; -import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; - -/** - * Represents a snippet for a WireMock stub. - * - * @author Dave Syer - */ -public class WireMockSnippet implements Snippet { - - private static final TemplateFormat TEMPLATE_FORMAT = new TemplateFormat() { - - @Override - public String getId() { - return "json"; - } - - @Override - public String getFileExtension() { - return "json"; - } - }; - - private String snippetName = "stubs"; - - private Set headerBlackList = new HashSet<>(Arrays.asList("host", "content-length")); - - private Set jsonPaths = new LinkedHashSet<>(); - - private MediaType contentType; - - private StubMapping stubMapping; - - private boolean hasJsonBodyRequestToMatch = false; - - private boolean hasXmlBodyRequestToMatch = false; - - @Override - public void document(Operation operation) throws IOException { - extractMatchers(operation); - if (this.stubMapping == null) { - this.stubMapping = request(operation).willReturn(response(operation)).build(); - } - String json = Json.write(this.stubMapping); - RestDocumentationContext context; - context = (RestDocumentationContext) operation.getAttributes().get(RestDocumentationContext.class.getName()); - RestDocumentationContextPlaceholderResolverFactory placeholders; - placeholders = new RestDocumentationContextPlaceholderResolverFactory(); - WriterResolver writerResolver = new StandardWriterResolver(placeholders, "UTF-8", TEMPLATE_FORMAT); - try (Writer writer = writerResolver.resolve(this.snippetName, operation.getName(), context)) { - writer.append(json); - } - } - - private void extractMatchers(Operation operation) { - this.stubMapping = (StubMapping) operation.getAttributes().get("contract.stubMapping"); - if (this.stubMapping != null) { - return; - } - @SuppressWarnings("unchecked") - Set jsonPaths = (Set) operation.getAttributes().get("contract.jsonPaths"); - this.jsonPaths = jsonPaths; - this.contentType = (MediaType) operation.getAttributes().get("contract.contentType"); - if (this.contentType == null) { - this.hasJsonBodyRequestToMatch = hasJsonContentType(operation); - this.hasXmlBodyRequestToMatch = hasXmlContentType(operation); - } - } - - private boolean hasJsonContentType(Operation operation) { - return hasContentType(operation, MediaType.APPLICATION_JSON); - } - - private boolean hasXmlContentType(Operation operation) { - return hasContentType(operation, MediaType.APPLICATION_XML); - } - - private boolean hasContentType(Operation operation, MediaType mediaType) { - return operation.getRequest().getHeaders().getContentType() != null - && (operation.getRequest().getHeaders().getContentType().isCompatibleWith(mediaType)); - } - - private ResponseDefinitionBuilder response(Operation operation) { - String content = operation.getResponse().getContentAsString(); - ResponseDefinitionBuilder response = aResponse().withHeaders(responseHeaders(operation)).withBody(content); - if (content != null && content.contains("localhost:{{request.requestLine.port}}")) { - response = response.withTransformers("response-template"); - } - return response.withStatus(operation.getResponse().getStatus().value()); - } - - private MappingBuilder request(Operation operation) { - return queryParams(requestHeaders(requestBuilder(operation), operation), operation); - } - - private MappingBuilder queryParams(MappingBuilder request, Operation operation) { - String rawQuery = operation.getRequest().getUri().getRawQuery(); - if (!StringUtils.hasText(rawQuery)) { - return request; - } - for (String queryPair : rawQuery.split("&")) { - String[] splitQueryPair = queryPair.split("="); - String value = splitQueryPair.length > 1 ? splitQueryPair[1] : ""; - request = request.withQueryParam(splitQueryPair[0], WireMock.equalTo(value)); - } - return request; - } - - private MappingBuilder requestHeaders(MappingBuilder request, Operation operation) { - org.springframework.http.HttpHeaders headers = operation.getRequest().getHeaders(); - // TODO: whitelist headers - for (String name : headers.keySet()) { - if (!this.headerBlackList.contains(name.toLowerCase())) { - if ("content-type".equalsIgnoreCase(name) && this.contentType != null) { - continue; - } - request = request.withHeader(name, equalTo(headers.getFirst(name))); - } - } - if (this.contentType != null) { - request = request.withHeader("Content-Type", matching(Pattern.quote(this.contentType.toString()) + ".*")); - } - return request; - } - - private MappingBuilder requestBuilder(Operation operation) { - HttpMethod method = operation.getRequest().getMethod(); - if (method.equals(HttpMethod.DELETE)) { - return delete(requestPattern(operation)); - } - else if (method.equals(HttpMethod.POST)) { - return bodyPattern(post(requestPattern(operation)), operation.getRequest().getContentAsString()); - } - else if (method.equals(HttpMethod.PUT)) { - return bodyPattern(put(requestPattern(operation)), operation.getRequest().getContentAsString()); - } - else if (method.equals(HttpMethod.PATCH)) { - return bodyPattern(patch(requestPattern(operation)), operation.getRequest().getContentAsString()); - } - else if (method.equals(HttpMethod.GET)) { - return get(requestPattern(operation)); - } - else if (method.equals(HttpMethod.HEAD)) { - return head(requestPattern(operation)); - } - else if (method.equals(HttpMethod.OPTIONS)) { - return options(requestPattern(operation)); - } - else if (method.equals(HttpMethod.TRACE)) { - return trace(requestPattern(operation)); - } - throw new UnsupportedOperationException("Unsupported method type: " + method); - } - - private MappingBuilder bodyPattern(MappingBuilder builder, String content) { - if (this.jsonPaths != null && !this.jsonPaths.isEmpty()) { - for (String jsonPath : this.jsonPaths) { - builder.withRequestBody(matchingJsonPath(jsonPath)); - } - } - else if (!!StringUtils.hasText(content)) { - if (this.hasJsonBodyRequestToMatch) { - builder.withRequestBody(equalToJson(content)); - } - else if (this.hasXmlBodyRequestToMatch) { - builder.withRequestBody(equalToXml(content)); - } - else { - builder.withRequestBody(equalTo(content)); - } - } - return builder; - } - - private UrlPattern requestPattern(Operation operation) { - return urlPathEqualTo(operation.getRequest().getUri().getPath()); - } - - private HttpHeaders responseHeaders(Operation operation) { - org.springframework.http.HttpHeaders headers = operation.getResponse().getHeaders(); - HttpHeaders result = new HttpHeaders(); - for (String name : headers.keySet()) { - if (!this.headerBlackList.contains(name.toLowerCase())) { - result = result.plus(new HttpHeader(name, headers.get(name))); - } - } - return result; - } - -} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockVerifyHelper.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockVerifyHelper.java deleted file mode 100644 index bb06044349..0000000000 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockVerifyHelper.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2016-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.restdocs; - -import java.nio.charset.Charset; -import java.util.LinkedHashMap; -import java.util.Map; - -import com.github.tomakehurst.wiremock.client.MappingBuilder; -import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.http.Request; -import com.github.tomakehurst.wiremock.matching.MatchResult; -import com.github.tomakehurst.wiremock.stubbing.StubMapping; -import com.jayway.jsonpath.JsonPath; - -import org.springframework.http.MediaType; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @param result type - * @param stub type - * @author Dave Syer - */ -public abstract class WireMockVerifyHelper> { - - private Map jsonPaths = new LinkedHashMap<>(); - - private MediaType contentType; - - private MappingBuilder builder; - - public void configure(T result) { - Map configuration = getConfiguration(result); - byte[] requestBodyContent = getRequestBodyContent(result); - if (requestBodyContent != null) { - String actual = new String(requestBodyContent, Charset.forName("UTF-8")); - for (JsonPath jsonPath : this.jsonPaths.values()) { - new JsonPathValue(jsonPath, actual).assertHasValue(Object.class, "an object"); - } - } - configuration.put("contract.jsonPaths", this.jsonPaths.keySet()); - if (this.contentType != null) { - configuration.put("contract.contentType", this.contentType); - MediaType resultType = getContentType(result); - assertThat(resultType).isNotNull().as("no content type"); - assertThat(this.contentType.includes(resultType)).isTrue().as("content type did not match"); - } - if (this.builder != null) { - this.builder.willReturn(getResponseDefinition(result)); - StubMapping stubMapping = this.builder.build(); - Request request = getWireMockRequest(result); - MatchResult match = stubMapping.getRequest().match(request); - assertThat(match.isExactMatch()).as("wiremock did not match request").isTrue(); - configuration.put("contract.stubMapping", stubMapping); - } - } - - protected abstract Request getWireMockRequest(T result); - - protected abstract MediaType getContentType(T result); - - protected abstract byte[] getRequestBodyContent(T result); - - protected abstract ResponseDefinitionBuilder getResponseDefinition(T result); - - protected abstract Map getConfiguration(T result); - - @SuppressWarnings("unchecked") - public S wiremock(MappingBuilder builder) { - this.builder = builder; - return (S) this; - } - - @SuppressWarnings("unchecked") - public S jsonPath(String expression, Object... args) { - compile(expression, args); - return (S) this; - } - - @SuppressWarnings("unchecked") - public S contentType(MediaType contentType) { - this.contentType = contentType; - return (S) this; - } - - private void compile(String expression, Object... args) { - org.springframework.util.Assert.hasText((expression == null ? null : expression), - "expression must not be null or empty"); - expression = String.format(expression, args); - this.jsonPaths.put(expression, JsonPath.compile(expression)); - } - -} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockWebTestClient.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockWebTestClient.java deleted file mode 100644 index 36c21e2a45..0000000000 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockWebTestClient.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.restdocs; - -/** - * Convenience class for setting up RestDocs to record WireMock stubs. Example usage: - * - *
- * @RunWith(SpringRunner.class)
- * @SpringBootTest
- * @AutoConfigureRestDocs(outputDir = "target/snippets")
- * @AutoConfigureWebTestClient
- * public class WiremockServerRestDocsApplicationTests {
- *
- * 	@Autowired
- * 	private WebTestClient client;
- *
- * 	@Test
- * 	public void contextLoads() throws Exception {
- * 		client.get().uri("/resource").exchange()
- * 				.expectBody(String.class).isEqualTo("Hello World")
- * 				.consumeWith(verify().stub("resource"));
- * 	}
- * 
- * - * which creates a file "target/snippets/stubs/resource.json" matching any GET request to - * "/resource". To match POST and PUT, you can also specify the content type using - * verify().contentType(...) and JSON content of the body using - * verify().jsonPath(...). - * - * @author Dave Syer - */ -public final class WireMockWebTestClient { - - private WireMockWebTestClient() { - throw new IllegalStateException("Can't instantiate a utility class"); - } - - public static ContractExchangeHandler verify() { - return new ContractExchangeHandler(); - } - -} diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockWebTestClientConfiguration.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockWebTestClientConfiguration.java deleted file mode 100644 index b5f06b91ee..0000000000 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockWebTestClientConfiguration.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.restdocs; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.test.autoconfigure.restdocs.RestDocsWebTestClientConfigurationCustomizer; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; -import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentationConfigurer; - -/** - * Custom configuration for Spring RestDocs that adds a WireMock snippet (for generating - * JSON stubs). Applied automatically if you use - * {@link org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs @AutoConfigureRestDocs} - * in your test case and this class is available. JSON stubs are generated and added to - * the restdocs path under "stubs". - * - * @author Dave Syer - * @see WireMockRestDocs for a convenient entry point for customizing and asserting the - * stub behaviour - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnClass(WebTestClientRestDocumentationConfigurer.class) -public class WireMockWebTestClientConfiguration implements RestDocsWebTestClientConfigurationCustomizer { - - private final Environment environment; - - public WireMockWebTestClientConfiguration(Environment environment) { - this.environment = environment; - } - - @Override - public void customize(WebTestClientRestDocumentationConfigurer configurer) { - if (this.environment.getProperty("wiremock.placeholders.enabled", "true").equals("true")) { - configurer.operationPreprocessors().withResponseDefaults(new DynamicPortPlaceholderInserterPreprocessor()); - } - configurer.snippets().withAdditionalDefaults(new WireMockSnippet()); - } - -} diff --git a/spring-cloud-contract-wiremock/src/main/resources/META-INF/spring.factories b/spring-cloud-contract-wiremock/src/main/resources/META-INF/spring.factories deleted file mode 100644 index a55333b024..0000000000 --- a/spring-cloud-contract-wiremock/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,6 +0,0 @@ -# Application Listeners -org.springframework.context.ApplicationListener=\ -org.springframework.cloud.contract.wiremock.WireMockApplicationListener -# Test Execution Listeners -org.springframework.test.context.TestExecutionListener=\ -org.springframework.cloud.contract.wiremock.WireMockTestExecutionListener diff --git a/spring-cloud-contract-wiremock/src/main/resources/META-INF/spring/org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs.imports b/spring-cloud-contract-wiremock/src/main/resources/META-INF/spring/org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs.imports deleted file mode 100644 index c0d7a1e9c7..0000000000 --- a/spring-cloud-contract-wiremock/src/main/resources/META-INF/spring/org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs.imports +++ /dev/null @@ -1,3 +0,0 @@ -org.springframework.cloud.contract.wiremock.restdocs.WireMockRestDocsConfiguration -org.springframework.cloud.contract.wiremock.restdocs.WireMockWebTestClientConfiguration -org.springframework.cloud.contract.wiremock.restdocs.WireMockRestAssuredConfiguration diff --git a/spring-cloud-contract-wiremock/src/main/resources/org/springframework/restdocs/templates/asciidoctor/default-dsl-contract.snippet b/spring-cloud-contract-wiremock/src/main/resources/org/springframework/restdocs/templates/asciidoctor/default-dsl-contract.snippet deleted file mode 100644 index 4069a24a50..0000000000 --- a/spring-cloud-contract-wiremock/src/main/resources/org/springframework/restdocs/templates/asciidoctor/default-dsl-contract.snippet +++ /dev/null @@ -1,4 +0,0 @@ -[source,groovy] ----- -{{contract}} ----- diff --git a/spring-cloud-contract-wiremock/src/main/resources/org/springframework/restdocs/templates/default-dsl-contract-only.snippet b/spring-cloud-contract-wiremock/src/main/resources/org/springframework/restdocs/templates/default-dsl-contract-only.snippet deleted file mode 100644 index e5cada93ae..0000000000 --- a/spring-cloud-contract-wiremock/src/main/resources/org/springframework/restdocs/templates/default-dsl-contract-only.snippet +++ /dev/null @@ -1,47 +0,0 @@ -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - request { - method '{{request_method}}' - urlPath('{{request_url}}') {{#request_urlpath_present}} { - queryParameters { - {{#request_queryparams}} - parameter('''{{key}}''', '''{{value}}''') - {{/request_queryparams}} - } - } {{/request_urlpath_present}} - {{#request_body_present}} - body('''{{request_body}}''') - {{/request_body_present}} - {{#request_headers_present}} - headers { - {{#request_headers}} - header('''{{key}}''', '''{{value}}''') - {{/request_headers}} - } - {{/request_headers_present}} - {{#request_json_paths_present}} - bodyMatchers { - {{#request_json_paths}} - jsonPath('''{{jsonPath}}''', byEquality()) - {{/request_json_paths}} - } - {{/request_json_paths_present}} - } - response { - status {{response_status}} - {{#response_body_present}} - body('''{{response_body}}''') - {{/response_body_present}} - {{#response_headers_present}} - headers { - {{#response_headers}} - header('''{{key}}''', '''{{value}}''') - {{/response_headers}} - } - {{/response_headers_present}} - } - {{#priority_present}} - priority {{priority}} - {{/priority_present}} -} diff --git a/spring-cloud-contract-wiremock/src/main/resources/org/springframework/restdocs/templates/markdown/default-dsl-contract.snippet b/spring-cloud-contract-wiremock/src/main/resources/org/springframework/restdocs/templates/markdown/default-dsl-contract.snippet deleted file mode 100644 index 47818012ec..0000000000 --- a/spring-cloud-contract-wiremock/src/main/resources/org/springframework/restdocs/templates/markdown/default-dsl-contract.snippet +++ /dev/null @@ -1,3 +0,0 @@ -```groovy -{{contract}} -``` diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockAdditionalImportTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockAdditionalImportTests.java deleted file mode 100644 index ce091bc9d4..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockAdditionalImportTests.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import java.util.Collections; -import java.util.List; - -import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.client.WireMock; -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Mono; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.core.ParameterizedTypeReference; -import org.springframework.stereotype.Component; -import org.springframework.test.web.reactive.server.WebTestClient; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.reactive.function.client.WebClient; - -// issue 1541 -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = TestConfiguration.class, - properties = "base-url=http://localhost:${wiremock.server.port}") -@AutoConfigureWireMock(port = 0) -@Import(ExtraConfig.class) -public class AutoConfigureWireMockAdditionalImportTests { - - @AfterEach - public void resetWiremock() { - WireMock.reset(); - } - - @Nested - @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = TestConfiguration.class, - properties = "base-url=http://localhost:${wiremock.server.port}") - @AutoConfigureWireMock(port = 0) - class SecondControllerTest { - - @Test - void test(@Autowired WebTestClient webTestClient) { - // arrange - WireMock.stubFor(WireMock.get(WireMock.urlMatching("/find-all")).willReturn( - ResponseDefinitionBuilder.okForJson(Collections.singletonList(new TestItem("my-name"))))); - - // act - List responseBody = webTestClient.get().uri("find-all").exchange().expectStatus() - .is2xxSuccessful().expectBody(new ParameterizedTypeReference>() { - }).returnResult().getResponseBody(); - - // assert - Assertions.assertThat(responseBody.get(0).getName()).isEqualTo("my-name"); - } - - } - -} - -@Component -class ExtraConfig { - -} - -@Configuration(proxyBeanMethods = false) -@EnableAutoConfiguration -class TestConfiguration { - - @Bean - WebClient webClient(WebClient.Builder builder) { - return builder.build(); - } - - @Bean - TestController testController(WebClient webClient, @Value("${base-url}") String baseUrl) { - return new TestController(webClient, baseUrl); - } - -} - -@RestController -class TestController { - - private final WebClient webClient; - - private final String baseUrl; - - TestController(WebClient webClient, String baseUrl) { - this.webClient = webClient; - this.baseUrl = baseUrl; - System.out.println("Creating with URL [" + this.baseUrl + "] HASH [" + this.hashCode() + "]"); - } - - @GetMapping("find-all") - public Mono> findAll() { - System.out.println("Will send a request to [" + this.baseUrl + "] HASH [" + this.hashCode() + "]"); - return webClient.get().uri(baseUrl + "/find-all").retrieve() - .bodyToMono(new ParameterizedTypeReference>() { - }); - } - -} - -class TestItem { - - private String name; - - TestItem() { - } - - TestItem(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockApplicationTests.java deleted file mode 100644 index d1282d6fdf..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockApplicationTests.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.system.OutputCaptureRule; -import org.springframework.test.context.junit4.SpringRunner; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = WiremockTestsApplication.class, - properties = "app.baseUrl=http://localhost:${wiremock.server.port}", webEnvironment = WebEnvironment.NONE) -@AutoConfigureWireMock(port = 26384) -public class AutoConfigureWireMockApplicationTests { - - @Rule - public OutputCaptureRule output = new OutputCaptureRule(); - - @Autowired - private Service service; - - @Autowired - private WireMockProperties wireMockProperties; - - @Test - public void contextLoads() throws Exception { - stubFor(get(urlEqualTo("/test")) - .willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!"))); - assertThat(this.service.go()).isEqualTo("Hello World!"); - assertThat(this.output.getOut()).as("Must contain debug logging for WireMock") - .contains("Matched response definition:"); - } - - @Test - public void portsAreFixed() { - boolean httpPortDynamic = this.wireMockProperties.getServer().isPortDynamic(); - boolean httpsPortDynamic = this.wireMockProperties.getServer().isHttpsPortDynamic(); - assertThat(!httpPortDynamic || !httpsPortDynamic).isTrue(); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockAutoStubsApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockAutoStubsApplicationTests.java deleted file mode 100644 index 2c47f33a50..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockAutoStubsApplicationTests.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.junit4.SpringRunner; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = WiremockTestsApplication.class, - properties = "app.baseUrl=http://localhost:${wiremock.server.port}", webEnvironment = WebEnvironment.NONE) -@AutoConfigureWireMock(port = 0) -// Default stubs work at classpath:/mappings -public class AutoConfigureWireMockAutoStubsApplicationTests { - - @Autowired - private Service service; - - @Autowired - private WireMockProperties wireMockProperties; - - @Test - public void contextLoads() throws Exception { - assertThat(this.service.go()).isEqualTo("Hello World"); - } - - @Test - public void portsAreNotFixed() { - boolean httpPortDynamic = this.wireMockProperties.getServer().isPortDynamic(); - boolean httpsPortDynamic = this.wireMockProperties.getServer().isHttpsPortDynamic(); - assertThat(!httpPortDynamic || !httpsPortDynamic).isFalse(); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockConfigurationCustomizerTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockConfigurationCustomizerTests.java deleted file mode 100644 index 8331457417..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockConfigurationCustomizerTests.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import com.github.tomakehurst.wiremock.core.WireMockConfiguration; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.test.context.junit4.SpringRunner; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@SpringBootTest( - classes = { WiremockTestsApplication.class, AutoConfigureWireMockConfigurationCustomizerTests.Config.class }, - properties = "app.baseUrl=http://localhost:${wiremock.server.port}", webEnvironment = WebEnvironment.NONE) -@AutoConfigureWireMock(port = 0, stubs = "file:src/test/resources/io.stubs/mappings") -public class AutoConfigureWireMockConfigurationCustomizerTests { - - @Autowired - private Service service; - - @Autowired - private Config config; - - @Test - public void contextLoads() throws Exception { - assertThat(this.service.go()).isEqualTo("Hello World"); - assertThat(this.config.isExecuted()).isTrue(); - } - - @Configuration - protected static class Config { - - boolean executed = false; - - // tag::customizer_1[] - @Bean - WireMockConfigurationCustomizer optionsCustomizer() { - return new WireMockConfigurationCustomizer() { - @Override - public void customize(WireMockConfiguration options) { - // end::customizer_1[] - assertThat(options.portNumber()).isGreaterThan(0); - Config.this.executed = true; - // tag::customizer_2[] - } - }; - } - // end::customizer_2[] - - public boolean isExecuted() { - return this.executed; - } - - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockConfigurationInYamlTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockConfigurationInYamlTests.java deleted file mode 100644 index ce12aa17c8..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockConfigurationInYamlTests.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = WiremockTestsApplication.class, - properties = "app.baseUrl=http://localhost:${wiremock.server.port}", webEnvironment = WebEnvironment.NONE) -@AutoConfigureWireMock -@ActiveProfiles("customfoo") -public class AutoConfigureWireMockConfigurationInYamlTests { - - @Autowired - private Service service; - - @Autowired - private WireMockProperties wireMockProperties; - - @Test - public void contextLoadsWithWiremockConfigFromYaml() { - assertThat(this.service.go()).isEqualToIgnoringWhitespace("{\"message\":\"Hello Custom One\"}"); - assertThat(this.wireMockProperties.getServer().isPortDynamic()).isTrue(); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockConfigurationMultipleCustomizerTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockConfigurationMultipleCustomizerTests.java deleted file mode 100644 index caa3d1c433..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockConfigurationMultipleCustomizerTests.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import com.github.tomakehurst.wiremock.core.WireMockConfiguration; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.test.context.junit4.SpringRunner; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@SpringBootTest( - classes = { WiremockTestsApplication.class, - AutoConfigureWireMockConfigurationMultipleCustomizerTests.Config.class }, - webEnvironment = WebEnvironment.NONE) -@AutoConfigureWireMock(port = 0) -public class AutoConfigureWireMockConfigurationMultipleCustomizerTests { - - @Autowired - private Config config; - - @Test - public void bothCustomizersHaveBeenExecuted() throws Exception { - assertThat(this.config.isExecuted()).isTrue(); - } - - @Configuration - protected static class Config { - - boolean executedCustomizer1 = false; - - boolean executedCustomizer2 = false; - - @Bean - WireMockConfigurationCustomizer optionsCustomizer1() { - return new WireMockConfigurationCustomizer() { - @Override - public void customize(WireMockConfiguration options) { - Config.this.executedCustomizer1 = true; - } - }; - } - - @Bean - WireMockConfigurationCustomizer optionsCustomizer2() { - return new WireMockConfigurationCustomizer() { - @Override - public void customize(WireMockConfiguration options) { - Config.this.executedCustomizer2 = true; - } - }; - } - - public boolean isExecuted() { - return this.executedCustomizer1 && this.executedCustomizer2; - } - - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockDefaultSetupTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockDefaultSetupTests.java deleted file mode 100644 index 03c638ad54..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockDefaultSetupTests.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.junit4.SpringRunner; - -import static org.assertj.core.api.BDDAssertions.then; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = WiremockTestsApplication.class, - properties = "app.baseUrl=http://localhost:${wiremock.server.port}", webEnvironment = WebEnvironment.NONE) -@AutoConfigureWireMock -public class AutoConfigureWireMockDefaultSetupTests { - - @Value("${app.baseUrl}") - String url; - - @Test - public void contextLoads() throws Exception { - then(url).isEqualTo("http://localhost:8080"); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockFilesApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockFilesApplicationTests.java deleted file mode 100644 index 82d2156612..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockFilesApplicationTests.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.junit4.SpringRunner; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = WiremockTestsApplication.class, - properties = "app.baseUrl=http://localhost:${wiremock.server.port}", webEnvironment = WebEnvironment.NONE) -@AutoConfigureWireMock(port = 0, files = "classpath:/root/") -public class AutoConfigureWireMockFilesApplicationTests { - - @Autowired - private Service service; - - @Test - public void contextLoads() throws Exception { - assertThat(this.service.go()).isEqualToIgnoringWhitespace("{\"message\":\"Hello Root\"}"); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockFilesApplicationWithUrlResourceTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockFilesApplicationWithUrlResourceTests.java deleted file mode 100644 index 451e4fb564..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockFilesApplicationWithUrlResourceTests.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import org.assertj.core.api.BDDAssertions; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Configuration; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.web.client.RestTemplate; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = AutoConfigureWireMockFilesApplicationWithUrlResourceTests.Config.class, - properties = "app.baseUrl=http://localhost:${wiremock.server.port}", - webEnvironment = SpringBootTest.WebEnvironment.NONE) -// tag::load_all_stubs[] -@AutoConfigureWireMock(port = 0, stubs = "classpath*:/META-INF/**/mappings/**/*.json") -// end::load_all_stubs[] -public class AutoConfigureWireMockFilesApplicationWithUrlResourceTests { - - @Value("${wiremock.server.port}") - int wiremockPort; - - @Test - public void should_work_for_analytics() throws Exception { - String count = new RestTemplate().getForObject("http://localhost:" + this.wiremockPort + "/issues/count", - String.class); - - BDDAssertions.then(count).isEqualTo("5"); - } - - @Test - public void should_work_for_webhook() throws Exception { - String response = new RestTemplate().getForObject("http://localhost:" + this.wiremockPort + "/", String.class); - - BDDAssertions.then(response).contains("spring-cloud/spring-cloud-netflix"); - } - - @Configuration - @EnableAutoConfiguration - static class Config { - - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockFilesApplicationWithoutSlashTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockFilesApplicationWithoutSlashTests.java deleted file mode 100644 index eca41e0fec..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockFilesApplicationWithoutSlashTests.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.junit4.SpringRunner; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = WiremockTestsApplication.class, - properties = "app.baseUrl=http://localhost:${wiremock.server.port}", webEnvironment = WebEnvironment.NONE) -@AutoConfigureWireMock(port = 0, files = "classpath:root") -public class AutoConfigureWireMockFilesApplicationWithoutSlashTests { - - @Autowired - private Service service; - - @Test - public void contextLoads() throws Exception { - assertThat(this.service.go()).isEqualToIgnoringWhitespace("{\"message\":\"Hello Root\"}"); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockHttpsPortApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockHttpsPortApplicationTests.java deleted file mode 100644 index 65c14a4654..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockHttpsPortApplicationTests.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.junit4.SpringRunner; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Dave Syer - * @author Nikola Kološnjaji - * - */ -@RunWith(SpringRunner.class) -@SpringBootTest(classes = WiremockTestsApplication.class, - properties = "app.baseUrl=https://localhost:${wiremock.server.https-port}", - webEnvironment = WebEnvironment.NONE) -@AutoConfigureWireMock(httpsPort = 9999, port = 0) -public class AutoConfigureWireMockHttpsPortApplicationTests { - - @Autowired - private Service service; - - @Autowired - private WireMockProperties wireMockProperties; - - @Test - public void contextLoads() throws Exception { - stubFor(get(urlEqualTo("/test")) - .willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!"))); - assertThat(this.service.go()).isEqualTo("Hello World!"); - } - - @Test - public void contextLoadsWithApacheClient() throws Exception { - stubFor(get(urlEqualTo("/test")) - .willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!"))); - assertThat(this.service.goWithApacheClient()).isEqualTo("Hello World!"); - } - - @Test - public void contextLoadsWithApacheClientAndAdditonalInterceptor() throws Exception { - stubFor(get(urlEqualTo("/test")) - .willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!"))); - assertThat(this.service.goWithApacheClientAndAdditonalInterceptor()).isEqualTo("Hello World!"); - } - - @Test - public void portsAreFixed() { - boolean httpPortDynamic = this.wireMockProperties.getServer().isPortDynamic(); - boolean httpsPortDynamic = this.wireMockProperties.getServer().isHttpsPortDynamic(); - assertThat(!httpPortDynamic || !httpsPortDynamic).isTrue(); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockOnlyHttpsPortApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockOnlyHttpsPortApplicationTests.java deleted file mode 100644 index 2e26c2630f..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockOnlyHttpsPortApplicationTests.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.junit4.SpringRunner; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = WiremockTestsApplication.class, - properties = "app.baseUrl=https://localhost:${wiremock.server.https-port}", - webEnvironment = WebEnvironment.NONE) -@AutoConfigureWireMock(httpsPort = 9999) -public class AutoConfigureWireMockOnlyHttpsPortApplicationTests { - - @Autowired - private Service service; - - @Autowired - private WireMockProperties wireMockProperties; - - @Test - public void contextLoads() throws Exception { - stubFor(get(urlEqualTo("/test")) - .willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!"))); - assertThat(this.service.go()).isEqualTo("Hello World!"); - } - - @Test - public void portsAreFixed() { - boolean httpsPortDynamic = this.wireMockProperties.getServer().isHttpsPortDynamic(); - assertThat(httpsPortDynamic).isFalse(); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockOnlyRandomPortHttpsApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockOnlyRandomPortHttpsApplicationTests.java deleted file mode 100644 index 59bc6e52e5..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockOnlyRandomPortHttpsApplicationTests.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.junit4.SpringRunner; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = WiremockTestsApplication.class, - properties = "app.baseUrl=https://localhost:${wiremock.server.https-port}", - webEnvironment = WebEnvironment.NONE) -@AutoConfigureWireMock(httpsPort = 0) -public class AutoConfigureWireMockOnlyRandomPortHttpsApplicationTests { - - @Autowired - private Service service; - - @Autowired - private WireMockProperties wireMockProperties; - - @Test - public void contextLoads() throws Exception { - stubFor(get(urlEqualTo("/test")) - .willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!"))); - assertThat(this.service.go()).isEqualTo("Hello World!"); - } - - @Test - public void portsAreNotFixed() { - boolean httpsPortDynamic = this.wireMockProperties.getServer().isHttpsPortDynamic(); - assertThat(httpsPortDynamic).isTrue(); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockPortApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockPortApplicationTests.java deleted file mode 100644 index b186e6f104..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockPortApplicationTests.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.junit4.SpringRunner; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = WiremockTestsApplication.class, - properties = "app.baseUrl=http://localhost:${wiremock.server.port}", webEnvironment = WebEnvironment.NONE) -@AutoConfigureWireMock(port = 9999) -public class AutoConfigureWireMockPortApplicationTests { - - @Autowired - private Service service; - - @Test - public void contextLoads() throws Exception { - stubFor(get(urlEqualTo("/test")) - .willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!"))); - assertThat(this.service.go()).isEqualTo("Hello World!"); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockRandomPortApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockRandomPortApplicationTests.java deleted file mode 100644 index 199de62ea7..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockRandomPortApplicationTests.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.junit4.SpringRunner; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static org.assertj.core.api.Assertions.assertThat; - -@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) -@RunWith(SpringRunner.class) -@SpringBootTest(classes = WiremockTestsApplication.class, - properties = "app.baseUrl=http://localhost:${wiremock.server.port}", webEnvironment = WebEnvironment.NONE) -@AutoConfigureWireMock(port = 0) -public class AutoConfigureWireMockRandomPortApplicationTests { - - @Autowired - private WireMockServer wireMockServer; - - @Autowired - private Service service; - - @Test - public void contextLoads() throws Exception { - wireMockServer.verify(0, RequestPatternBuilder.allRequests()); - WireMock.verify(0, RequestPatternBuilder.allRequests()); - - stubFor(get(urlEqualTo("/test")) - .willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!"))); - assertThat(this.service.go()).isEqualTo("Hello World!"); - - wireMockServer.verify(1, RequestPatternBuilder.allRequests()); - WireMock.verify(1, RequestPatternBuilder.allRequests()); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockRandomPortHttpsApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockRandomPortHttpsApplicationTests.java deleted file mode 100644 index ca5d0193fd..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockRandomPortHttpsApplicationTests.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.junit4.SpringRunner; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = WiremockTestsApplication.class, - properties = "app.baseUrl=https://localhost:${wiremock.server.https-port}", - webEnvironment = WebEnvironment.NONE) -@AutoConfigureWireMock(port = 0, httpsPort = 0) -public class AutoConfigureWireMockRandomPortHttpsApplicationTests { - - @Autowired - private Service service; - - @Autowired - private WireMockProperties wireMockProperties; - - @Test - public void contextLoads() throws Exception { - stubFor(get(urlEqualTo("/test")) - .willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!"))); - assertThat(this.service.go()).isEqualTo("Hello World!"); - } - - @Test - public void portsAreNotFixed() { - boolean httpPortDynamic = this.wireMockProperties.getServer().isPortDynamic(); - boolean httpsPortDynamic = this.wireMockProperties.getServer().isHttpsPortDynamic(); - assertThat(httpPortDynamic).isTrue(); - assertThat(httpsPortDynamic).isTrue(); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockRandomPortInheretedApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockRandomPortInheretedApplicationTests.java deleted file mode 100644 index 01e98b3a27..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockRandomPortInheretedApplicationTests.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -public class AutoConfigureWireMockRandomPortInheretedApplicationTests - extends AutoConfigureWireMockRandomPortApplicationTests { - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockSamePortApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockSamePortApplicationTests.java deleted file mode 100644 index 74f6469e22..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockSamePortApplicationTests.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.junit4.SpringRunner; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = WiremockTestsApplication.class, - properties = "app.baseUrl=http://localhost:${wiremock.server.port}", webEnvironment = WebEnvironment.NONE) -@AutoConfigureWireMock(port = 9999) -// Should manage to register -public class AutoConfigureWireMockSamePortApplicationTests { - - @Autowired - private Service service; - - @Test - public void contextLoads() throws Exception { - stubFor(get(urlEqualTo("/test2")) - .willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World2!"))); - assertThat(this.service.go2()).isEqualTo("Hello World2!"); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockStubsAndFilesApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockStubsAndFilesApplicationTests.java deleted file mode 100644 index 04ff8198bf..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockStubsAndFilesApplicationTests.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.junit4.SpringRunner; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = WiremockTestsApplication.class, - properties = "app.baseUrl=http://localhost:${wiremock.server.port}", webEnvironment = WebEnvironment.NONE) -@AutoConfigureWireMock(port = 0, files = "classpath:/root/", stubs = "file:src/test/resources/io.stubs/mappings") -public class AutoConfigureWireMockStubsAndFilesApplicationTests { - - @Autowired - private Service service; - - @Test - public void contextLoads() throws Exception { - assertThat(this.service.go()).isEqualToIgnoringWhitespace("{\"message\":\"Hello Root\"}"); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockStubsAndMultipleFilesApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockStubsAndMultipleFilesApplicationTests.java deleted file mode 100644 index 969c408922..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockStubsAndMultipleFilesApplicationTests.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.junit4.SpringRunner; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = WiremockTestsApplication.class, - properties = "app.baseUrl=http://localhost:${wiremock.server.port}", webEnvironment = WebEnvironment.NONE) -@AutoConfigureWireMock(port = 0, files = { "classpath:/", "classpath:/root/", "classpath:/nonexistent/" }, - stubs = "file:src/test/resources/io.stubs/mappings") -public class AutoConfigureWireMockStubsAndMultipleFilesApplicationTests { - - @Autowired - private Service service; - - @Test - public void contextLoads() throws Exception { - assertThat(this.service.go()).isEqualToIgnoringWhitespace("{\"message\":\"Hello Root\"}"); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockStubsApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockStubsApplicationTests.java deleted file mode 100644 index 249c48f060..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockStubsApplicationTests.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.junit4.SpringRunner; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = WiremockTestsApplication.class, - properties = "app.baseUrl=http://localhost:${wiremock.server.port}", webEnvironment = WebEnvironment.NONE) -@AutoConfigureWireMock(port = 0, stubs = "file:src/test/resources/io.stubs/mappings") -public class AutoConfigureWireMockStubsApplicationTests { - - @Autowired - private Service service; - - @Value("localhost:${wiremock.server.port}") - private String hostname; - - @Test - public void contextLoads() throws Exception { - assertThat(this.service.go()).isEqualTo("Hello World"); - } - - @Test - public void link() throws Exception { - assertThat(this.service.link()).contains("http://" + this.hostname); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockStubsApplicationWithSlashTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockStubsApplicationWithSlashTests.java deleted file mode 100644 index 072c12c219..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockStubsApplicationWithSlashTests.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.junit4.SpringRunner; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = WiremockTestsApplication.class, - properties = "app.baseUrl=http://localhost:${wiremock.server.port}", webEnvironment = WebEnvironment.NONE) -@AutoConfigureWireMock(port = 0, stubs = "file:src/test/resources/io.stubs/mappings/") -public class AutoConfigureWireMockStubsApplicationWithSlashTests { - - @Autowired - private Service service; - - @Test - public void contextLoads() throws Exception { - assertThat(this.service.go()).isEqualTo("Hello World"); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockWithResetAfterEachTestApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockWithResetAfterEachTestApplicationTests.java deleted file mode 100644 index 455a47b556..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockWithResetAfterEachTestApplicationTests.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import org.junit.FixMethodOrder; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.web.client.RestTemplate; - -import static org.assertj.core.api.BDDAssertions.then; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = WiremockTestsApplication.class, - properties = { "app.baseUrl=http://localhost:${wiremock.server.port}", - "wiremock.reset-mappings-after-each-test=true" }, - webEnvironment = WebEnvironment.NONE) -@AutoConfigureWireMock(port = 0) -@FixMethodOrder -public class AutoConfigureWireMockWithResetAfterEachTestApplicationTests { - - @Autowired - private WireMockServer wireMockServer; - - @Value("localhost:${wiremock.server.port}") - private String hostname; - - @Test - public void _01_test() throws Exception { - this.wireMockServer - .givenThat(WireMock.get("/should_register_mapping").willReturn(WireMock.aResponse().withBody("bar"))); - - String result = new RestTemplate().getForObject("http://" + this.hostname + "/should_register_mapping", - String.class); - - then(result).isEqualTo("bar"); - } - - @Test - public void _02_test() throws Exception { - String result = new RestTemplate().getForObject("http://" + this.hostname + "/should_register_mapping", - String.class); - - // taken from test/resources/mappings/resource-without-content-type.json - then(result).isEqualTo("Hello World"); - } - - @Test - public void _03_test() throws Exception { - WireMock.givenThat(WireMock.get("/should_register_mapping").willReturn(WireMock.aResponse().withBody("bar"))); - - String result = new RestTemplate().getForObject("http://" + this.hostname + "/should_register_mapping", - String.class); - - then(result).isEqualTo("bar"); - } - - @Test - public void _04_test() throws Exception { - String result = new RestTemplate().getForObject("http://" + this.hostname + "/should_register_mapping", - String.class); - - // taken from test/resources/mappings/resource-without-content-type.json - then(result).isEqualTo("Hello World"); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockWithResetAfterEachTestNestedApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockWithResetAfterEachTestNestedApplicationTests.java deleted file mode 100644 index affb0e853d..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockWithResetAfterEachTestNestedApplicationTests.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.web.client.RestTemplate; - -import static org.assertj.core.api.BDDAssertions.then; - -@SpringBootTest(classes = WiremockTestsApplication.class, - properties = { "app.baseUrl=http://localhost:${wiremock.server.port}", - "wiremock.reset-mappings-after-each-test=true" }, - webEnvironment = WebEnvironment.NONE) -@AutoConfigureWireMock(port = 0) -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) -class AutoConfigureWireMockWithResetAfterEachTestNestedApplicationTests { - - @Autowired - private WireMockServer wireMockServer; - - @Value("localhost:${wiremock.server.port}") - private String hostname; - - @Test - @Order(1) - void outerTest() { - this.wireMockServer - .givenThat(WireMock.get("/should_register_mapping").willReturn(WireMock.aResponse().withBody("bar"))); - - String result = new RestTemplate().getForObject("http://" + this.hostname + "/should_register_mapping", - String.class); - - then(result).isEqualTo("bar"); - } - - @Nested - class NestedTests { - - @Test - @Order(2) - void innerOne() { - String result = new RestTemplate().getForObject("http://" + hostname + "/should_register_mapping", - String.class); - - // taken from test/resources/mappings/resource-without-content-type.json - then(result).isEqualTo("Hello World"); - } - - @Test - @Order(3) - void innerTwo() { - WireMock.givenThat( - WireMock.get("/should_register_mapping").willReturn(WireMock.aResponse().withBody("bar"))); - - String result = new RestTemplate().getForObject("http://" + hostname + "/should_register_mapping", - String.class); - - then(result).isEqualTo("bar"); - } - - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/MetaAnnotationWithResetAfterEachTestApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/MetaAnnotationWithResetAfterEachTestApplicationTests.java deleted file mode 100644 index 8ed90b9463..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/MetaAnnotationWithResetAfterEachTestApplicationTests.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; -import org.junit.FixMethodOrder; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.web.client.RestTemplate; - -import static org.assertj.core.api.BDDAssertions.then; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = WiremockTestsApplication.class, - properties = { "app.baseUrl=http://localhost:${wiremock.server.port}", - "wiremock.reset-mappings-after-each-test=true" }, - webEnvironment = WebEnvironment.NONE) -@ComponentTestAnnotation -@FixMethodOrder -@DirtiesContext -public class MetaAnnotationWithResetAfterEachTestApplicationTests { - - @Autowired - private WireMockServer wireMockServer; - - @Value("localhost:${wiremock.server.port}") - private String hostname; - - @Test - public void _01_test() throws Exception { - this.wireMockServer - .givenThat(WireMock.get("/should_register_mapping").willReturn(WireMock.aResponse().withBody("bar"))); - - String result = new RestTemplate().getForObject("http://" + this.hostname + "/should_register_mapping", - String.class); - - then(result).isEqualTo("bar"); - } - - @Test - public void _02_test() throws Exception { - String result = new RestTemplate().getForObject("http://" + this.hostname + "/should_register_mapping", - String.class); - - // taken from test/resources/mappings/resource-without-content-type.json - then(result).isEqualTo("Hello World"); - } - - @Test - public void _03_test() throws Exception { - WireMock.givenThat(WireMock.get("/should_register_mapping").willReturn(WireMock.aResponse().withBody("bar"))); - - String result = new RestTemplate().getForObject("http://" + this.hostname + "/should_register_mapping", - String.class); - - then(result).isEqualTo("bar"); - } - - @Test - public void _04_test() throws Exception { - String result = new RestTemplate().getForObject("http://" + this.hostname + "/should_register_mapping", - String.class); - - // taken from test/resources/mappings/resource-without-content-type.json - then(result).isEqualTo("Hello World"); - } - -} - -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -@Inherited -@SpringBootTest -@AutoConfigureWireMock(port = 0) -@interface ComponentTestAnnotation { - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WireMockStubMappingTest.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WireMockStubMappingTest.java deleted file mode 100644 index 9e96c3df72..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WireMockStubMappingTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import org.json.JSONException; -import org.junit.Test; - -/** - * @author Marcin Grzejszczak - */ -public class WireMockStubMappingTest { - - private static final String stub_2_1_7 = "{\"request\" : { \"method\" : \"GET\" }, " - + "\"response\" : { \"status\" : 200 }}"; - - private static final String stub_2_5_1 = "{\"id\" : \"77514bd4-a102-4478-a3c0-0fda8b905591\", " - + "\"request\" : { \"method\" : \"GET\" }, \"response\" :" - + " { \"status\" : 200 }, \"uuid\" : \"77514bd4-a102-4478-a3c0-0fda8b905591\"}"; - - @Test - public void should_successfully_parse_a_WireMock_2_1_7_stub() throws JSONException { - // when: - WireMockStubMapping.buildFrom(stub_2_1_7); - } - - @Test - public void should_successfully_parse_a_WireMock_2_5_1_stub() throws JSONException { - // when: - WireMockStubMapping.buildFrom(stub_2_5_1); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockHttpsServerApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockHttpsServerApplicationTests.java deleted file mode 100644 index 1a7b4d6a5d..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockHttpsServerApplicationTests.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import com.github.tomakehurst.wiremock.junit.WireMockClassRule; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = WiremockTestsApplication.class, properties = "app.baseUrl=https://localhost:8443") -public class WiremockHttpsServerApplicationTests { - - @ClassRule - public static WireMockClassRule wiremock = new WireMockClassRule( - WireMockSpring.options().port(5433).httpsPort(8443)); - - @Autowired - private Service service; - - @Test - public void contextLoads() throws Exception { - stubFor(get(urlEqualTo("/test")) - .willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!"))); - assertThat(this.service.go()).isEqualTo("Hello World!"); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockMockServerApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockMockServerApplicationTests.java deleted file mode 100644 index 0acb663193..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockMockServerApplicationTests.java +++ /dev/null @@ -1,464 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import java.net.URI; -import java.util.Collections; -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonCreator; -import org.junit.Test; - -import org.springframework.http.MediaType; -import org.springframework.http.RequestEntity; -import org.springframework.http.ResponseEntity; -import org.springframework.test.web.client.MockRestServiceServer; -import org.springframework.web.client.RestTemplate; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; - -public class WiremockMockServerApplicationTests { - - private RestTemplate restTemplate = new RestTemplate(); - - @Test - public void simpleGet() throws Exception { - MockRestServiceServer server = WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // - .stubs("classpath:/mappings/resource.json").build(); - assertThat(this.restTemplate.getForObject("https://example.org/resource", String.class)) - .isEqualTo("Hello World"); - server.verify(); - } - - @Test - public void simplePutShouldFail() throws Exception { - MockRestServiceServer server = WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // - .stubs("classpath:/mappings/resource.json").build(); - RequestEntity postRequest = RequestEntity.post(URI.create("https://example.org/resource")) - .accept(MediaType.TEXT_PLAIN).build(); - ResponseEntity response; - try { - response = this.restTemplate.exchange(postRequest, String.class); - } - catch (AssertionError e) { - response = null; - } - if (null != response) { - fail("There was a response for POST request: " + postRequest + "\n\tresponse: " + response); - } - } - - @Test - public void simpleGetWithBodyFile() throws Exception { - MockRestServiceServer server = WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // - .stubs("classpath:/mappings/resource-with-body-file.json").build(); - assertThat(this.restTemplate.getForObject("https://example.org/resource", String.class)) - .isEqualToIgnoringWhitespace("{\"message\":\"Hello World\"}"); - server.verify(); - } - - @Test - public void simpleGetWithJsonBody() throws Exception { - MockRestServiceServer server = WireMockRestServiceServer.with(this.restTemplate).baseUrl("https://example.org") - .stubs("classpath:/mappings/resource-with-json-body.json").build(); - - String response = this.restTemplate.getForObject("https://example.org/resource", String.class); - - assertThat(response).isEqualToIgnoringWhitespace("{\"message\":\"Hello World\"}"); - server.verify(); - } - - @Test - public void simpleGetWithBase64Body() throws Exception { - MockRestServiceServer server = WireMockRestServiceServer.with(this.restTemplate).baseUrl("https://example.org") - .stubs("classpath:/mappings/resource-with-base64-body.json").build(); - - String response = this.restTemplate.getForObject("https://example.org/resource", String.class); - - assertThat(response).isEqualToIgnoringWhitespace("Hello World"); - server.verify(); - } - - @Test - public void simpleGetWithBodyFileCustomLocation() throws Exception { - MockRestServiceServer server = WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // - .stubs("classpath:/mappings/resource-with-body-file.json").files("classpath:/custom/").build(); - assertThat(this.restTemplate.getForObject("https://example.org/resource", String.class)) - .isEqualToIgnoringWhitespace("{\"message\":\"Hello Custom\"}"); - server.verify(); - } - - @Test - public void simpleGetWithBodyFileCustomLocationDirectory() throws Exception { - MockRestServiceServer server = WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // - .stubs("classpath:/mappings/resource-with-body-file.json").files("file:src/test/resources/custom") - .build(); - assertThat(this.restTemplate.getForObject("https://example.org/resource", String.class)) - .isEqualToIgnoringWhitespace("{\"message\":\"Hello Custom\"}"); - server.verify(); - } - - @Test - public void simpleGetWithEmptyPath() throws Exception { - MockRestServiceServer server = WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // - .stubs("classpath:/mappings/resource-with-empty-path.json").build(); - assertThat(this.restTemplate.getForObject("https://example.org/", String.class)).isEqualTo("Hello World"); - server.verify(); - } - - @Test - public void simpleGetWithContentType() throws Exception { - MockRestServiceServer server = WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // - .stubs("classpath:/mappings/resource-with-content-type.json").build(); - assertThat(this.restTemplate.getForObject("https://example.org/resource", String.class)) - .isEqualTo("Hello World"); - server.verify(); - } - - @Test - public void simpleGetWithoutContentType() throws Exception { - MockRestServiceServer server = WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // - .stubs("classpath:/mappings/resource-without-content-type.json").build(); - assertThat(this.restTemplate.getForObject("https://example.org/resource", String.class)) - .isEqualTo("Hello World"); - server.verify(); - } - - @Test - public void simplePost() throws Exception { - MockRestServiceServer server = WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // - .stubs("classpath:/mappings/poster.json").build(); - assertThat(this.restTemplate.postForObject("https://example.org/poster", "greeting", String.class)) - .isEqualTo("Hello World"); - server.verify(); - } - - @Test - public void postWithHeader() throws Exception { - WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // order determined by content... - .stubs("classpath:/mappings/poster.json", "classpath:/mappings/accept.json").build(); - assertThat(this.restTemplate.exchange( - RequestEntity.post(new URI("https://example.org/poster")).accept(MediaType.TEXT_PLAIN).build(), - String.class).getBody()).isEqualTo("Accepted World"); - } - - @Test - public void postWithHeaderContains() throws Exception { - WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // order determined by content... - .stubs("classpath:/mappings/poster.json", "classpath:/mappings/header-contains.json").build(); - assertThat(this.restTemplate.exchange(RequestEntity.post(new URI("https://example.org/poster")) - .accept(MediaType.valueOf("application/v.foo")).build(), String.class).getBody()) - .isEqualTo("Foo World"); - } - - @Test - public void postWithHeaderMatches() throws Exception { - WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // order determined by content... - .stubs("classpath:/mappings/poster.json", "classpath:/mappings/header-matches.json").build(); - assertThat(this.restTemplate.exchange(RequestEntity.post(new URI("https://example.org/poster")) - .accept(MediaType.valueOf("application/v.bar")).build(), String.class).getBody()) - .isEqualTo("Bar World"); - } - - @Test - public void postWithMoreExactHeaderMatch() throws Exception { - WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // order determined by content... - .stubs("classpath:/mappings/header-matches.json", "classpath:/mappings/header-matches-precise.json") - .build(); - assertThat( - this.restTemplate.exchange( - RequestEntity.post(new URI("https://example.org/poster")) - .accept(MediaType.valueOf("application/v.bar")).header("X-Precise", "true").build(), - String.class).getBody()).isEqualTo("Precise World"); - } - - @Test - public void postWithMoreExactHeaderMatchButOrdered() throws Exception { - WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // order matters... - .stubs("classpath:/mappings/header-matches.json", "classpath:/mappings/header-matches-precise.json") - .ignoreExpectOrder(false).build(); - assertThat( - this.restTemplate.exchange( - RequestEntity.post(new URI("https://example.org/poster")) - .accept(MediaType.valueOf("application/v.bar")).header("X-Precise", "true").build(), - String.class).getBody()).isEqualTo("Bar World"); - // The first one matches, not the most precise! - } - - @Test - public void getWithPriortyOrder() throws Exception { - WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // - .stubs("classpath:/mappings/resource-with-low-priority.json", - "classpath:/mappings/resource-with-high-priority.json") - .build(); - assertThat(this.restTemplate.getForObject("https://example.org/resource", String.class)) - .isEqualTo("Hello High"); - } - - @Test - public void simpleGetWithAllStubs() throws Exception { - WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // - .stubs("classpath:/mappings").build(); - assertThat(this.restTemplate.getForObject("https://example.org/resource", String.class)) - .isEqualTo("Hello World"); - } - - @Test - public void simpleGetWithAllStubsInDirectoryWithPeriod() throws Exception { - WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // - .stubs("classpath:/io.stubs/mappings").build(); - assertThat(this.restTemplate.getForObject("https://example.org/resource", String.class)) - .isEqualTo("Hello World"); - } - - // Issue #135 - @Test - public void postWithBodyMatchingJsonPaths() throws Exception { - WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // - .stubs("classpath:/mappings/body-matches-jsonpath.json").build(); - - assertThat(this.restTemplate.postForObject("https://example.org/body", - new Things(Collections.singletonList(new Thing("RequiredThing"))), String.class)) - .isEqualTo("Hello Body"); - } - - @Test - public void postWithRequestThatHasNonMatchingJsonPaths() throws Exception { - WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // - .stubs("classpath:/mappings/body-matches-jsonpath.json").build(); - - String response; - try { - response = this.restTemplate.postForObject("https://example.org/body", - new Things(Collections.singletonList(new Thing("AbsentThing"))), String.class); - } - catch (AssertionError e) { - response = null; - } - if (null != response) { - fail("There was a response for a request that shouldn't be matched : " + response); - } - } - - @Test - public void postWithBodyMatchingXPath() throws Exception { - WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // - .stubs("classpath:/mappings/body-matches-xpath.json").build(); - - assertThat(this.restTemplate.exchange( - RequestEntity.post(URI.create("https://example.org/body")).contentType(MediaType.APPLICATION_XML) - .body("RequiredThing"), - String.class).getBody()).isEqualTo("Hello Body"); - } - - @Test - public void postWithRequestThatHasNonMatchingXPaths() throws Exception { - WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // - .stubs("classpath:/mappings/body-matches-xpath.json").build(); - - ResponseEntity response; - try { - response = this.restTemplate.exchange(RequestEntity.post(URI.create("https://example.org/body")) - .contentType(MediaType.APPLICATION_XML).body(""), String.class); - } - catch (AssertionError e) { - response = null; - } - if (null != response) { - fail("There was a response for a request that shouldn't be matched : " + response); - } - } - - @Test - public void postWithBodyMatchingJson() throws Exception { - WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // - .stubs("classpath:/mappings/body-matches-equaltojson.json").build(); - - assertThat(this.restTemplate.postForObject("https://example.org/body", - new Things(Collections.singletonList(new Thing("RequiredThing"))), String.class)) - .isEqualTo("Hello Body"); - } - - @Test - public void postWithRequestThatHasNonMatchingJson() throws Exception { - WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // - .stubs("classpath:/mappings/body-matches-equaltojson.json").build(); - - String response; - try { - response = this.restTemplate.postForObject("https://example.org/body", - new Things(Collections.singletonList(new Thing("AbsentThing"))), String.class); - } - catch (AssertionError e) { - response = null; - } - if (null != response) { - fail("There was a response for a request that shouldn't be matched : " + response); - } - } - - @Test - public void postWithBodyMatchingXml() throws Exception { - WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // - .stubs("classpath:/mappings/body-matches-equaltoxml.json").build(); - - assertThat(this.restTemplate.exchange( - RequestEntity.post(URI.create("https://example.org/body")).contentType(MediaType.APPLICATION_XML) - .body("RequiredThing"), - String.class).getBody()).isEqualTo("Hello Body"); - } - - @Test - public void postWithRequestThatHasNonMatchingXml() throws Exception { - WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // - .stubs("classpath:/mappings/body-matches-equaltoxml.json").build(); - - ResponseEntity response; - try { - response = this.restTemplate.exchange( - RequestEntity.post(URI.create("https://example.org/body")).contentType(MediaType.APPLICATION_XML) - .body("AbsentThing"), - String.class); - } - catch (AssertionError e) { - response = null; - } - if (null != response) { - fail("There was a response for a request that shouldn't be matched : " + response); - } - } - - @Test - public void postWithBodyMatchingRegex() throws Exception { - WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // - .stubs("classpath:/mappings/body-matches-regex.json").build(); - - assertThat(this.restTemplate.exchange( - RequestEntity.post(URI.create("https://example.org/body")).contentType(MediaType.APPLICATION_XML) - .body("RequiredThing"), - String.class).getBody()).isEqualTo("Hello Body"); - } - - @Test - public void postWithRequestThatHasNonMatchingRegex() throws Exception { - WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // - .stubs("classpath:/mappings/body-matches-regex.json").build(); - - ResponseEntity response; - try { - response = this.restTemplate.exchange( - RequestEntity.post(URI.create("https://example.org/body")).contentType(MediaType.APPLICATION_XML) - .body("AbsentThing"), - String.class); - } - catch (AssertionError e) { - response = null; - } - if (null != response) { - fail("There was a response for a request that shouldn't be matched : " + response); - } - } - - @Test - public void getWithUrlPathMatching() throws Exception { - MockRestServiceServer server = WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // - .stubs("classpath:/mappings/url-path-pattern.json").build(); - assertThat(this.restTemplate.getForObject("https://example.org/123/url-path-pattern/", String.class)) - .isEqualTo("Hello Url Path Matcher"); - server.verify(); - } - - @Test - public void getWithSimpleUrlPathMatchingWithTrailingSlashInBaseUrl() throws Exception { - MockRestServiceServer server = WireMockRestServiceServer.with(this.restTemplate).baseUrl("https://example.org/") - .stubs("classpath:/mappings/url-simple-path-pattern-without-leading-slash.json").build(); - assertThat(this.restTemplate.getForObject("https://example.org/my/api", String.class)) - .isEqualTo("Hello Url Path Matcher"); - server.verify(); - } - - @Test - public void getWithSimpleUrlPathMatchingWithLeadingSlashInPattern() throws Exception { - MockRestServiceServer server = WireMockRestServiceServer.with(this.restTemplate).baseUrl("https://example.org") - .stubs("classpath:/mappings/url-simple-path-pattern-with-leading-slash.json").build(); - assertThat(this.restTemplate.getForObject("https://example.org/my/api", String.class)) - .isEqualTo("Hello Url Path Matcher"); - server.verify(); - } - - @Test - public void getWithUrlMatching() throws Exception { - MockRestServiceServer server = WireMockRestServiceServer.with(this.restTemplate) // - .baseUrl("https://example.org") // - .stubs("classpath:/mappings/url-matches.json").build(); - assertThat(this.restTemplate.getForObject("https://example.org/123/hello-url-matcher/", String.class)) - .isEqualTo("Hello Url Matcher"); - server.verify(); - } - - public static class Things { - - public List things; - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - public Things(List things) { - this.things = things; - } - - } - - public static class Thing { - - public String name; - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - public Thing(String name) { - this.name = name; - } - - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerApplicationTests.java deleted file mode 100644 index 06bfbf1291..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerApplicationTests.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import com.github.tomakehurst.wiremock.junit.WireMockClassRule; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.junit4.SpringRunner; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = WiremockTestsApplication.class, properties = "app.baseUrl=http://localhost:5435", - webEnvironment = WebEnvironment.NONE) -public class WiremockServerApplicationTests { - - @ClassRule - public static WireMockClassRule wiremock = new WireMockClassRule(WireMockSpring.options().port(5435)); - - @Autowired - private Service service; - - @Test - public void hello() throws Exception { - stubFor(get(urlEqualTo("/test")) - .willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!"))); - assertThat(this.service.go()).isEqualTo("Hello World!"); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerRestAssuredApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerRestAssuredApplicationTests.java deleted file mode 100644 index b97d095eaa..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerRestAssuredApplicationTests.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import io.restassured.specification.RequestSpecification; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import wiremock.org.eclipse.jetty.http.HttpStatus; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.ImportAutoConfiguration; -import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration; -import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; -//import static org.springframework.restdocs.restassured3.RestAssuredRestDocumentation.document; - -@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -@AutoConfigureRestDocs(outputDir = "target/snippets") -@Disabled("jakarta") -public class WiremockServerRestAssuredApplicationTests { - - @Autowired - private RequestSpecification documentationSpec; - - @Value("${local.server.port}") - private int port; - - /* - * @Test public void contextLoads() throws Exception { - * given().port(this.port).when().get("/resource").then().assertThat().statusCode(is( - * 200)) .body(equalTo("Hello World")); } - * - * @Test public void statusIsMaintained() throws Exception { - * given(this.documentationSpec.port(this.port)).filter(document("status")).when().get - * ("/status").then() .assertThat().statusCode(is(202)).body(equalTo("Hello World")); - * } - */ - - @Test - void foo() { - - } - - @Configuration - @EnableWebMvc - @RestController - @ImportAutoConfiguration(DispatcherServletAutoConfiguration.class) - protected static class TestConfiguration { - - @ResponseBody - @RequestMapping("/resource") - public String resource() { - return "Hello World"; - } - - @ResponseBody - @RequestMapping("/status") - public ResponseEntity status() { - return ResponseEntity.status(HttpStatus.ACCEPTED_202).body("Hello World"); - } - - @Bean - TomcatServletWebServerFactory tomcatServletWebServerFactory() { - return new TomcatServletWebServerFactory(0); - } - - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerRestDocsApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerRestDocsApplicationTests.java deleted file mode 100644 index b27169e9b6..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerRestDocsApplicationTests.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import java.io.File; -import java.nio.file.Files; -import java.util.Map; - -import com.github.tomakehurst.wiremock.client.WireMock; -import com.github.tomakehurst.wiremock.matching.MultiValuePattern; -import com.github.tomakehurst.wiremock.stubbing.StubMapping; -import jakarta.servlet.http.HttpServletRequest; -import org.assertj.core.api.BDDAssertions; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import wiremock.org.eclipse.jetty.http.HttpStatus; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.contract.wiremock.WiremockServerRestDocsApplicationTests.TestConfiguration; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.ResponseEntity; -import org.springframework.http.server.ServletServerHttpRequest; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.util.UriComponents; -import org.springframework.web.util.UriComponentsBuilder; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@SpringBootTest(classes = TestConfiguration.class) -@AutoConfigureRestDocs(outputDir = "target/snippets") -@AutoConfigureMockMvc -@Disabled("jakarta") -public class WiremockServerRestDocsApplicationTests { - - @Autowired - private MockMvc mockMvc; - - @Test - public void contextLoads() throws Exception { - this.mockMvc.perform(MockMvcRequestBuilders.get("/resource")).andExpect(content().string("Hello World")) - .andDo(document("resource")); - } - - @Test - public void statusIsMaintained() throws Exception { - this.mockMvc.perform(MockMvcRequestBuilders.get("/status")).andExpect(content().string("Hello World")) - .andExpect(status().is(HttpStatus.ACCEPTED_202)).andDo(document("status")); - } - - @Test - public void queryParamsAreFetchedFromStubs() throws Exception { - this.mockMvc - .perform(MockMvcRequestBuilders - .get("/project_metadata/spring-framework?callback=a_function_name&foo=foo&bar=bar")) - .andExpect(status().isOk()).andExpect(content().string("spring-framework a_function_name foo bar")) - .andDo(document("query")); - - File file = new File("target/snippets/stubs", "query.json"); - BDDAssertions.then(file).exists(); - StubMapping stubMapping = StubMapping.buildFrom(new String(Files.readAllBytes(file.toPath()))); - Map queryParameters = stubMapping.getRequest().getQueryParameters(); - BDDAssertions.then(queryParameters.get("callback").getValuePattern()) - .isEqualTo(WireMock.equalTo("a_function_name")); - BDDAssertions.then(queryParameters.get("foo").getValuePattern()).isEqualTo(WireMock.equalTo("foo")); - BDDAssertions.then(queryParameters.get("bar").getValuePattern()).isEqualTo(WireMock.equalTo("bar")); - } - - @Test - public void stubsRenderLinksWithPlaceholder() throws Exception { - this.mockMvc.perform(MockMvcRequestBuilders.get("/link")).andExpect(status().isOk()) - .andExpect(content().string(containsString("link:"))).andDo(document("link")); - - File file = new File("target/snippets/stubs", "link.json"); - BDDAssertions.then(file).exists(); - StubMapping stubMapping = StubMapping.buildFrom(new String(Files.readAllBytes(file.toPath()))); - String body = stubMapping.getResponse().getBody(); - BDDAssertions.then(body).contains("http://localhost:{{request.requestLine.port}}/link"); - BDDAssertions.then(stubMapping.getResponse().getTransformers()).contains("response-template"); - } - - @Configuration - @RestController - protected static class TestConfiguration { - - @ResponseBody - @RequestMapping("/resource") - public String resource() { - return "Hello World"; - } - - @ResponseBody - @RequestMapping("/link") - public String link(HttpServletRequest request) { - UriComponents uriComponents = UriComponentsBuilder.fromHttpRequest(new ServletServerHttpRequest(request)) - .build(); - return "link: " + uriComponents.toUriString(); - } - - @ResponseBody - @RequestMapping("/status") - public ResponseEntity status() { - return ResponseEntity.status(HttpStatus.ACCEPTED_202).body("Hello World"); - } - - @ResponseBody - @RequestMapping("/project_metadata/{projectId}") - public ResponseEntity query(@PathVariable("projectId") String projectId, - @RequestParam("callback") String callback, @RequestParam("foo") String foo, - @RequestParam("bar") String bar) { - return ResponseEntity.ok().body(projectId + " " + callback + " " + foo + " " + bar); - } - - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerRestDocsHypermediaApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerRestDocsHypermediaApplicationTests.java deleted file mode 100644 index 31f88a262d..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerRestDocsHypermediaApplicationTests.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import java.io.File; -import java.nio.file.Files; - -import com.github.tomakehurst.wiremock.stubbing.StubMapping; -import jakarta.servlet.http.HttpServletRequest; -import org.assertj.core.api.BDDAssertions; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.contract.wiremock.WiremockServerRestDocsHypermediaApplicationTests.TestConfiguration; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.server.ServletServerHttpRequest; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.util.UriComponents; -import org.springframework.web.util.UriComponentsBuilder; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@SpringBootTest(classes = TestConfiguration.class, properties = "wiremock.placeholders.enabled=false") -@AutoConfigureRestDocs(outputDir = "target/snippets") -@AutoConfigureMockMvc -@Disabled("jakarta") -public class WiremockServerRestDocsHypermediaApplicationTests { - - @Autowired - private MockMvc mockMvc; - - @Test - public void stubsRenderLinksWithoutPlaceholder() throws Exception { - this.mockMvc.perform(MockMvcRequestBuilders.get("/link")).andExpect(status().isOk()) - .andExpect(content().string(containsString("link:"))).andDo(document("link")); - - File file = new File("target/snippets/stubs", "link.json"); - BDDAssertions.then(file).exists(); - StubMapping stubMapping = StubMapping.buildFrom(new String(Files.readAllBytes(file.toPath()))); - String body = stubMapping.getResponse().getBody(); - BDDAssertions.then(body).contains("http://localhost:8080/link"); - } - - @Configuration - @RestController - protected static class TestConfiguration { - - @ResponseBody - @RequestMapping("/link") - public String resource(HttpServletRequest request) { - UriComponents uriComponents = UriComponentsBuilder.fromHttpRequest(new ServletServerHttpRequest(request)) - .build(); - return "link: " + uriComponents.toUriString(); - } - - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerRestDocsMatcherApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerRestDocsMatcherApplicationTests.java deleted file mode 100644 index 43694659fc..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerRestDocsMatcherApplicationTests.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import java.io.File; - -import com.github.tomakehurst.wiremock.client.WireMock; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.contract.wiremock.WiremockServerRestDocsMatcherApplicationTests.TestConfiguration; -import org.springframework.cloud.contract.wiremock.restdocs.WireMockRestDocs; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.MediaType; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.result.MockMvcResultMatchers; -import org.springframework.util.FileSystemUtils; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = TestConfiguration.class) -@AutoConfigureRestDocs(outputDir = "target/snippets") -@AutoConfigureMockMvc -public class WiremockServerRestDocsMatcherApplicationTests { - - @Rule - public ExpectedException expected = ExpectedException.none(); - - @Autowired - private MockMvc mockMvc; - - @Test - public void matchesRequest() throws Exception { - FileSystemUtils.deleteRecursively(new File("target/snippets/stubs/posted.json")); - this.mockMvc - .perform(MockMvcRequestBuilders.post("/resource").content("greeting").contentType(MediaType.TEXT_PLAIN)) - .andExpect(MockMvcResultMatchers.content().string("Hello World")) - .andDo(WireMockRestDocs.verify().wiremock(WireMock.post(WireMock.urlPathEqualTo("/resource")) - .withRequestBody(WireMock.matching("greeting.*")))) - .andDo(document("posted")); - assertThat(new File("target/snippets/stubs/posted.json")).exists(); - } - - @Test - public void doesNotMatch() throws Exception { - this.expected.expect(AssertionError.class); - this.expected.expectMessage("wiremock did not match"); - this.mockMvc - .perform(MockMvcRequestBuilders.post("/resource").content("greeting").contentType(MediaType.TEXT_PLAIN)) - .andExpect(MockMvcResultMatchers.content().string("Hello World")) - .andDo(WireMockRestDocs.verify().wiremock(WireMock.post(WireMock.urlPathEqualTo("/resource")) - .withRequestBody(WireMock.matching("garbage.*")))) - .andDo(document("posted")); - } - - @Configuration - @RestController - protected static class TestConfiguration { - - @ResponseBody - @RequestMapping(value = "/resource", method = RequestMethod.POST) - public String resource(@RequestBody String body) { - return "Hello World"; - } - - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerWebTestClientApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerWebTestClientApplicationTests.java deleted file mode 100644 index 7b2f6af413..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockServerWebTestClientApplicationTests.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import java.io.File; -import java.nio.file.Files; - -import com.github.tomakehurst.wiremock.stubbing.StubMapping; -import org.assertj.core.api.BDDAssertions; -import org.junit.Test; -import org.junit.runner.RunWith; -import wiremock.org.eclipse.jetty.http.HttpStatus; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; -import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; -import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; -import org.springframework.cloud.contract.wiremock.WiremockServerWebTestClientApplicationTests.TestConfiguration; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.ResponseEntity; -import org.springframework.http.server.reactive.ServerHttpRequest; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.reactive.server.WebTestClient; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.util.UriComponents; -import org.springframework.web.util.UriComponentsBuilder; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document; - -@RunWith(SpringRunner.class) -@WebFluxTest -@ContextConfiguration(classes = TestConfiguration.class) -@AutoConfigureRestDocs(outputDir = "target/snippets/webtestclient") -@AutoConfigureWebTestClient -public class WiremockServerWebTestClientApplicationTests { - - @Autowired - private WebTestClient client; - - @Test - public void contextLoads() throws Exception { - this.client.get().uri("/resource").exchange().expectBody(String.class).isEqualTo("Hello World") - .consumeWith(document("resource")); - } - - @Test - public void statusIsMaintained() throws Exception { - this.client.get().uri("/status").exchange().expectStatus().isAccepted().expectBody(String.class) - .isEqualTo("Hello World").consumeWith(document("status")); - } - - @Test - public void stubsRenderLinksWithPlaceholder() throws Exception { - this.client.get().uri("/link").exchange().expectBody(String.class).value(containsString("link:")) - .consumeWith(document("link")); - - File file = new File("target/snippets/webtestclient/stubs", "link.json"); - BDDAssertions.then(file).exists(); - StubMapping stubMapping = StubMapping.buildFrom(new String(Files.readAllBytes(file.toPath()))); - String body = stubMapping.getResponse().getBody(); - BDDAssertions.then(body).contains("http://localhost:{{request.requestLine.port}}/link"); - BDDAssertions.then(stubMapping.getResponse().getTransformers()).contains("response-template"); - } - - @Configuration - @RestController - protected static class TestConfiguration { - - @RequestMapping("/resource") - public String resource() { - return "Hello World"; - } - - @ResponseBody - @RequestMapping("/link") - public String link(ServerHttpRequest request) { - UriComponents uriComponents = UriComponentsBuilder.fromHttpRequest(request).build(); - return "link: " + uriComponents.toUriString(); - } - - @RequestMapping("/status") - public ResponseEntity status() { - return ResponseEntity.status(HttpStatus.ACCEPTED_202).body("Hello World"); - } - - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockTestsApplication.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockTestsApplication.java deleted file mode 100644 index 759673f113..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockTestsApplication.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock; - -import java.net.URI; -import java.util.stream.Stream; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.context.annotation.Primary; -import org.springframework.http.MediaType; -import org.springframework.http.RequestEntity; -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; -import org.springframework.http.client.support.BasicAuthenticationInterceptor; -import org.springframework.stereotype.Component; -import org.springframework.web.client.RestTemplate; - -/** - * @author Dave Syer - * @author Nikola Kološnjaji - * - */ -@Configuration -@EnableAutoConfiguration -@Import(Service.class) -public class WiremockTestsApplication { - - public static void main(String[] args) { - SpringApplication.run(WiremockTestsApplication.class, args); - } - - @Bean - @Primary - public RestTemplate restTemplate() { - return new RestTemplate(); - } - - @Bean - public RestTemplate apacheHttpClient(RestTemplateBuilder builder) { - return builder.requestFactory(() -> new HttpComponentsClientHttpRequestFactory()).build(); - } - - @Bean - public RestTemplate apacheHttpClientWithInterceptor(RestTemplateBuilder builder) { - return builder.requestFactory(() -> new HttpComponentsClientHttpRequestFactory()) - .additionalInterceptors(new BasicAuthenticationInterceptor("u", "p")).build(); - } - -} - -@Component -class Service { - - private static final Log log = LogFactory.getLog(Service.class); - - @Value("${app.baseUrl:https://example.org}") - String base; - - private RestTemplate restTemplate; - - private RestTemplate apacheHttpClient; - - private RestTemplate apacheHttpClientWithInterceptor; - - Service(RestTemplate restTemplate, @Qualifier("apacheHttpClient") RestTemplate apacheHttpClient, - @Qualifier("apacheHttpClientWithInterceptor") RestTemplate apacheHttpClientWithInterceptor) { - this.restTemplate = restTemplate; - this.apacheHttpClient = apacheHttpClient; - this.apacheHttpClientWithInterceptor = apacheHttpClientWithInterceptor; - } - - public String go() { - String requestUrl = this.base + "/test"; - log.info("Will send a request to [" + requestUrl + "]"); - return this.restTemplate.getForEntity(requestUrl, String.class).getBody(); - } - - public String goWithApacheClient() { - String requestUrl = this.base + "/test"; - log.info("Will send a request to [" + requestUrl + "]"); - return this.apacheHttpClient.getForEntity(requestUrl, String.class).getBody(); - } - - public String goWithApacheClientAndAdditonalInterceptor() { - String requestUrl = this.base + "/test"; - log.info("Will send a request to [" + requestUrl + "]"); - return this.apacheHttpClientWithInterceptor.getForEntity(requestUrl, String.class).getBody(); - } - - public String link() { - String requestUrl = this.base + "/link"; - log.info("Will send a request to [" + requestUrl + "]"); - return this.restTemplate.getForEntity(requestUrl, String.class).getBody(); - } - - public String pom() { - String requestUrl = this.base + "/pom.xml"; - log.info("Will send a request to [" + requestUrl + "]"); - return this.restTemplate - .exchange(RequestEntity.get(URI.create(requestUrl)).accept(mediaTypes()).build(), String.class) - .getBody(); - } - - private MediaType[] mediaTypes() { - return Stream.of("text/plain", "text/plain", "application/json", "application/json", "application/*+json", - "application/*+json", "*/*", "*/*").map(MediaType::valueOf).toArray(MediaType[]::new); - } - - public String go2() { - String requestUrl = this.base + "/test2"; - log.info("Will send a request to [" + requestUrl + "]"); - return this.restTemplate.getForEntity(requestUrl, String.class).getBody(); - } - - public void setBase(String base) { - this.base = base; - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/file/ResourcesFileSourceTest.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/file/ResourcesFileSourceTest.java deleted file mode 100644 index 8b9c063802..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/file/ResourcesFileSourceTest.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.file; - -import java.io.File; -import java.net.URI; -import java.net.URISyntaxException; - -import com.github.tomakehurst.wiremock.common.BinaryFile; -import com.github.tomakehurst.wiremock.common.ClasspathFileSource; -import com.github.tomakehurst.wiremock.common.FileSource; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -class ResourcesFileSourceTest { - - @DisplayName("find all files in the multiple files directories.") - @Test - void child() { - // given - Resource resource1 = new ClassPathResource("src/test/resources/files_banner"); - Resource resource2 = new ClassPathResource("src/test/resources/files_notice"); - ResourcesFileSource resourcesFileSource = new ResourcesFileSource(resource1, resource2); - - // when - String filesDirName = "__files"; - FileSource fileSource = resourcesFileSource.child(filesDirName); - - // then - assertThat(fileSource).isInstanceOf(ResourcesFileSource.class); - assertThat(fileSource.listFilesRecursively()).hasSize(4); - } - - @DisplayName("find a mapped response file in multiple directories.") - @Test - void getBinaryFileNamed() { - // given - Resource resource1 = new ClassPathResource("src/test/resources/files_banner/__files"); - Resource resource2 = new ClassPathResource("src/test/resources/files_notice/__files"); - ResourcesFileSource resourcesFileSource = new ResourcesFileSource(resource1, resource2); - - // when & then - assertThat(resourcesFileSource.getBinaryFileNamed("response-bannerList-success.json").getStream()).isNotEmpty(); - assertThat(resourcesFileSource.getBinaryFileNamed("response-noticeList-success.json").getStream()).isNotEmpty(); - } - - @DisplayName("find a stub file in jar") - @Test - void find_stub_file_in_jar() throws URISyntaxException { - - // given - ClassLoader classLoader = getClass().getClassLoader(); - File file = new File(classLoader.getResource("jarfiles/module-banner-test-fixtures.jar").getFile()); - - String bannerStubPathInJar = "jar:file:" + file.getAbsolutePath() + "!/wiremock/banner/__files"; - String bannerStubFilename = "response-bannerList-success.json"; - ClasspathFileSource classpathFileSource1 = mock(ClasspathFileSource.class); - when(classpathFileSource1.getUri()).thenReturn(new URI(bannerStubPathInJar)); - when(classpathFileSource1.exists()).thenReturn(true); - when(classpathFileSource1.getBinaryFileNamed(bannerStubFilename)) - .thenReturn(new BinaryFile(new URI(bannerStubPathInJar + "/response-bannerList-success.json"))); - ResourcesFileSource resourcesFileSource = new ResourcesFileSource(classpathFileSource1); - - // when & then - assertThat(resourcesFileSource.getBinaryFileNamed(bannerStubFilename).getStream()).isNotEmpty(); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/issue399/NotOrderedCustomizerTest.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/issue399/NotOrderedCustomizerTest.java deleted file mode 100644 index 1bb5d3edc3..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/issue399/NotOrderedCustomizerTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.issues.issue399; - -import org.assertj.core.api.BDDAssertions; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock; -import org.springframework.test.context.junit4.SpringRunner; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; - -@RunWith(SpringRunner.class) -@SpringBootTest -@AutoConfigureWireMock(port = 0) -public class NotOrderedCustomizerTest { - - @Value("${wiremock.server.port}") - Integer port; - - @Autowired - RestTemplateBuilder restTemplateBuilder; - - @Test - public void should_not_fail_when_ordered_customizer_added_interceptor_to_rest_template() { - stubFor(get(urlEqualTo("/some-url")).willReturn(aResponse().withStatus(200).withBody("Yeah!"))); - RestTemplateClient client = new RestTemplateClient( - this.restTemplateBuilder.rootUri("http://localhost:" + this.port)); - - String body = client.get(); - - BDDAssertions.then(body).isEqualTo("Yeah!"); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/issue399/OrderedCustomizerTest.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/issue399/OrderedCustomizerTest.java deleted file mode 100644 index 14d2e6a260..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/issue399/OrderedCustomizerTest.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.issues.issue399; - -import org.assertj.core.api.BDDAssertions; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; - -@RunWith(SpringRunner.class) -@SpringBootTest -@AutoConfigureWireMock(port = 0) -@ActiveProfiles("bug") -public class OrderedCustomizerTest { - - @Value("${wiremock.server.port}") - Integer port; - - @Autowired - RestTemplateBuilder restTemplateBuilder; - - @Test - public void should_not_fail_when_ordered_customizer_added_interceptor_to_rest_template() { - stubFor(get(urlEqualTo("/some-url")).willReturn(aResponse().withStatus(200).withBody("Yeah!"))); - RestTemplateClient client = new RestTemplateClient( - this.restTemplateBuilder.rootUri("http://localhost:" + this.port)); - - String body = client.get(); - - BDDAssertions.then(body).isEqualTo("Yeah!"); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/issue399/SpringContractWiremockIssueDemoApplication.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/issue399/SpringContractWiremockIssueDemoApplication.java deleted file mode 100644 index 6af0252fee..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/issue399/SpringContractWiremockIssueDemoApplication.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.issues.issue399; - -import java.io.IOException; - -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.boot.web.client.RestTemplateCustomizer; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Profile; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; -import org.springframework.http.HttpRequest; -import org.springframework.http.client.ClientHttpRequestExecution; -import org.springframework.http.client.ClientHttpRequestInterceptor; -import org.springframework.http.client.ClientHttpResponse; -import org.springframework.web.client.RestTemplate; - -@SpringBootApplication -public class SpringContractWiremockIssueDemoApplication { - - private static final int SOME_NOT_LOWEST_PRECEDENCE = Ordered.LOWEST_PRECEDENCE - 1; - - @Bean - @Order(SOME_NOT_LOWEST_PRECEDENCE) - @Profile("bug") - public RestTemplateCustomizer someOrderedInterceptorCustomizer() { - return new RestTemplateCustomizer() { - @Override - public void customize(RestTemplate restTemplate) { - ClientHttpRequestInterceptor emptyInterceptor = new ClientHttpRequestInterceptor() { - @Override - public ClientHttpResponse intercept(HttpRequest request, byte[] body, - ClientHttpRequestExecution execution) throws IOException { - return execution.execute(request, body); - } - }; - restTemplate.getInterceptors().add(emptyInterceptor); - } - }; - } - - @Bean - public RestTemplateCustomizer someNotOrderedInterceptorCustomizer() { - return new RestTemplateCustomizer() { - @Override - public void customize(RestTemplate restTemplate) { - ClientHttpRequestInterceptor emptyInterceptor = new ClientHttpRequestInterceptor() { - @Override - public ClientHttpResponse intercept(HttpRequest request, byte[] body, - ClientHttpRequestExecution execution) throws IOException { - return execution.execute(request, body); - } - }; - restTemplate.getInterceptors().add(emptyInterceptor); - } - }; - } - - @Bean - @Order - public RestTemplateCustomizer someLowestPrecedenceOrderedInterceptorCustomizer() { - return new RestTemplateCustomizer() { - @Override - public void customize(RestTemplate restTemplate) { - ClientHttpRequestInterceptor emptyInterceptor = new ClientHttpRequestInterceptor() { - @Override - public ClientHttpResponse intercept(HttpRequest request, byte[] body, - ClientHttpRequestExecution execution) throws IOException { - return execution.execute(request, body); - } - }; - restTemplate.getInterceptors().add(emptyInterceptor); - } - }; - } - -} - -class RestTemplateClient { - - private final RestTemplate restTemplate; - - RestTemplateClient(RestTemplateBuilder restTemplateBuilder) { - this.restTemplate = restTemplateBuilder.build(); - } - - public String get() { - return this.restTemplate.getForObject("/some-url", String.class); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/Client.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/Client.java deleted file mode 100644 index fcd3153f93..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/Client.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.issues.sameConfigsDifferentTests; - -public class Client { - - private String pesel; - - public Client() { - } - - public Client(String pesel) { - this.pesel = pesel; - } - - public String getPesel() { - return pesel; - } - - public void setPesel(String pesel) { - this.pesel = pesel; - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/FirstTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/FirstTests.java deleted file mode 100644 index b5ad43e760..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/FirstTests.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.issues.sameConfigsDifferentTests; - -import java.nio.charset.Charset; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.stubbing.StubMapping; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.io.Resource; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.util.StreamUtils; -import org.springframework.web.client.RestTemplate; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@SpringBootTest(properties = "service.port=${wiremock.server.port}", classes = FirstTests.Config.class) -@AutoConfigureWireMock(port = 0) -public class FirstTests { - - @Value("classpath:example-mappings/shouldMarkClientAsFraud.json") - private Resource markClientAsFraud; - - @Autowired - private WireMockServer server; - - @Test - public void shouldBeRejectedDueToAbnormalLoanAmount() throws Exception { - server.addStubMapping(StubMapping - .buildFrom(StreamUtils.copyToString(markClientAsFraud.getInputStream(), Charset.forName("UTF-8")))); - // given: - LoanApplication loanApplication = new LoanApplication(new Client("1234567890"), 99999); - - // when: - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.add(HttpHeaders.CONTENT_TYPE, "application/vnd.fraud.v1+json"); - - ResponseEntity response = new RestTemplate().exchange( - "http://localhost:" + server.port() + "/fraudcheck", HttpMethod.PUT, - new HttpEntity<>(new FraudServiceRequest(loanApplication), httpHeaders), FraudServiceResponse.class); - // then: - assertThat(response.getBody().getFraudCheckStatus()).isEqualTo(FraudCheckStatus.FRAUD); - assertThat(response.getBody().getRejectionReason()).isEqualTo("Amount too high"); - } - - @EnableAutoConfiguration - @Configuration - static class Config { - - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/FraudCheckStatus.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/FraudCheckStatus.java deleted file mode 100644 index 302377eab7..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/FraudCheckStatus.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.issues.sameConfigsDifferentTests; - -public enum FraudCheckStatus { - - OK, FRAUD - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/FraudServiceRequest.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/FraudServiceRequest.java deleted file mode 100644 index aadc29c4fb..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/FraudServiceRequest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.issues.sameConfigsDifferentTests; - -import java.math.BigDecimal; - -public class FraudServiceRequest { - - private String clientId; - - private BigDecimal loanAmount; - - public FraudServiceRequest() { - } - - public FraudServiceRequest(LoanApplication loanApplication) { - this.clientId = loanApplication.getClient().getPesel(); - this.loanAmount = loanApplication.getAmount(); - } - - public String getClientId() { - return clientId; - } - - public void setClientId(String clientId) { - this.clientId = clientId; - } - - public BigDecimal getLoanAmount() { - return loanAmount; - } - - public void setLoanAmount(BigDecimal loanAmount) { - this.loanAmount = loanAmount; - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/FraudServiceResponse.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/FraudServiceResponse.java deleted file mode 100644 index faa8a1e99f..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/FraudServiceResponse.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.issues.sameConfigsDifferentTests; - -public class FraudServiceResponse { - - private FraudCheckStatus fraudCheckStatus; - - private String rejectionReason; - - public FraudServiceResponse() { - } - - public FraudCheckStatus getFraudCheckStatus() { - return fraudCheckStatus; - } - - public void setFraudCheckStatus(FraudCheckStatus fraudCheckStatus) { - this.fraudCheckStatus = fraudCheckStatus; - } - - public String getRejectionReason() { - return rejectionReason; - } - - public void setRejectionReason(String rejectionReason) { - this.rejectionReason = rejectionReason; - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/LoanApplication.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/LoanApplication.java deleted file mode 100644 index c9a9c54d3a..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/LoanApplication.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.issues.sameConfigsDifferentTests; - -import java.math.BigDecimal; - -public class LoanApplication { - - private Client client; - - private BigDecimal amount; - - private String loanApplicationId; - - public LoanApplication() { - } - - public LoanApplication(Client client, double amount) { - this.client = client; - this.amount = BigDecimal.valueOf(amount); - } - - public Client getClient() { - return client; - } - - public void setClient(Client client) { - this.client = client; - } - - public BigDecimal getAmount() { - return amount; - } - - public void setAmount(BigDecimal amount) { - this.amount = amount; - } - - public String getLoanApplicationId() { - return loanApplicationId; - } - - public void setLoanApplicationId(String loanApplicationId) { - this.loanApplicationId = loanApplicationId; - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/SecondTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/SecondTests.java deleted file mode 100644 index a1ca63cb60..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/sameConfigsDifferentTests/SecondTests.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.issues.sameConfigsDifferentTests; - -import java.nio.charset.Charset; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.stubbing.StubMapping; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.io.Resource; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.util.StreamUtils; -import org.springframework.web.client.RestTemplate; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@SpringBootTest(properties = "service.port=${wiremock.server.port}", classes = SecondTests.Config.class) -@AutoConfigureWireMock(port = 0) -public class SecondTests { - - @Value("classpath:example-mappings/shouldMarkClientAsNotFraud.json") - private Resource markClientAsNotFraud; - - @Autowired - private WireMockServer server; - - @Test - public void shouldBeRejectedDueToAbnormalLoanAmount() throws Exception { - server.addStubMapping(StubMapping - .buildFrom(StreamUtils.copyToString(markClientAsNotFraud.getInputStream(), Charset.forName("UTF-8")))); - // given: - LoanApplication loanApplication = new LoanApplication(new Client("1234567890"), 123.123); - - // when: - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.add(HttpHeaders.CONTENT_TYPE, "application/vnd.fraud.v1+json"); - - ResponseEntity response = new RestTemplate().exchange( - "http://localhost:" + server.port() + "/fraudcheck", HttpMethod.PUT, - new HttpEntity<>(new FraudServiceRequest(loanApplication), httpHeaders), FraudServiceResponse.class); - // then: - assertThat(response.getBody().getFraudCheckStatus()).isEqualTo(FraudCheckStatus.OK); - } - - @EnableAutoConfiguration - @Configuration - static class Config { - - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/staticInit/ClientProperties.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/staticInit/ClientProperties.java deleted file mode 100644 index 7087b03937..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/staticInit/ClientProperties.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.issues.staticInit; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties(prefix = "my-client") -public class ClientProperties { - - private String url; - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/staticInit/RestTemplateConfiguration.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/staticInit/RestTemplateConfiguration.java deleted file mode 100644 index cb5da0733d..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/staticInit/RestTemplateConfiguration.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.issues.staticInit; - -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.client.RestTemplate; - -@Configuration -@EnableConfigurationProperties(ClientProperties.class) -public class RestTemplateConfiguration { - - @Bean - public RestTemplate restTemplate() { - return new RestTemplate(); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/staticInit/TimeoutApplication.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/staticInit/TimeoutApplication.java deleted file mode 100644 index daa800c24e..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/staticInit/TimeoutApplication.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.issues.staticInit; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class TimeoutApplication { - - public static void main(String[] args) { - SpringApplication.run(TimeoutApplication.class, args); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/staticInit/WebClient.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/staticInit/WebClient.java deleted file mode 100644 index 9604bb6ec1..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/staticInit/WebClient.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.issues.staticInit; - -import java.net.URI; - -import org.springframework.stereotype.Component; -import org.springframework.web.client.RestTemplate; - -@Component -public class WebClient { - - private final RestTemplate restTemplate; - - private final ClientProperties clientProperties; - - public WebClient(RestTemplate restTemplate, ClientProperties clientProperties) { - this.restTemplate = restTemplate; - this.clientProperties = clientProperties; - } - - public String get() { - URI url = URI.create(clientProperties.getUrl()); - return restTemplate.getForObject(url, String.class); - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/staticInit/WebClientTest.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/staticInit/WebClientTest.java deleted file mode 100644 index b60c22a059..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/issues/staticInit/WebClientTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.issues.staticInit; - -import com.github.tomakehurst.wiremock.WireMockServer; -import org.assertj.core.api.BDDAssertions; -import org.junit.jupiter.api.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock; -import org.springframework.context.annotation.Bean; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; - -@SpringBootTest(properties = "my-client.url=http://localhost:${wiremock.server.port}/resources") -@AutoConfigureWireMock(port = 0, httpsPort = 0, files = "src/test/resources/__files") -class WebClientTest { - - private static Logger log = LoggerFactory.getLogger(WebClientTest.class); - - @Autowired - WebClient underTest; - - @Autowired - Stubber stubber; - - @Test - void shouldRespondForGetJustFine() { - String actual = underTest.get(); - - BDDAssertions.then(actual).isEqualTo("Everything seems fine!"); - } - - @TestConfiguration - static class WebClientTestConfiguration { - - @Bean - Stubber stubberWithoutDeps() { - return new Stubber(); - } - - } - - static class Stubber { - - Stubber() { - log.info("Setting up GET"); - stubFor(get(urlEqualTo("/resources")).willReturn(aResponse().withBody("Everything seems fine!"))); - } - - Stubber(WireMockServer wireMockServer) { - log.info("Setting up GET"); - wireMockServer - .stubFor(get(urlEqualTo("/resources")).willReturn(aResponse().withBody("Everything seems fine!"))); - } - - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/restdocs/ContractDslSnippetTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/restdocs/ContractDslSnippetTests.java deleted file mode 100644 index 9867468d88..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/restdocs/ContractDslSnippetTests.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.restdocs; - -import java.io.File; -import java.net.URISyntaxException; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.apache.groovy.util.Maps; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.contract.spec.Contract; -import org.springframework.cloud.contract.spec.internal.Header; -import org.springframework.cloud.contract.spec.internal.QueryParameter; -import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; -import org.springframework.restdocs.JUnitRestDocumentation; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.context.WebApplicationContext; - -import static org.assertj.core.api.BDDAssertions.then; -import static org.springframework.cloud.contract.wiremock.restdocs.SpringCloudContractRestDocs.dslContract; -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -/** - * @author Marcin Grzejszczak - */ -@RunWith(SpringRunner.class) -@SpringBootTest(classes = ContractDslSnippetTests.Config.class) -public class ContractDslSnippetTests { - - private static final String OUTPUT = "target/generated-snippets"; - - @Rule - public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation(OUTPUT); - - MockMvc mockMvc; - - @Autowired - WebApplicationContext context; - - @Before - public void setUp() { - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context) - .apply(documentationConfiguration(this.restDocumentation).snippets() - .withAdditionalDefaults(new WireMockSnippet())) - .build(); - } - - @Test - public void should_create_contract_template_and_doc() throws Exception { - // tag::contract_snippet[] - this.mockMvc - .perform(post("/foo").accept(MediaType.APPLICATION_PDF).accept(MediaType.APPLICATION_JSON) - .contentType(MediaType.APPLICATION_JSON).content("{\"foo\": 23, \"bar\" : \"baz\" }")) - .andExpect(status().isOk()).andExpect(content().string("bar")) - // first WireMock - .andDo(WireMockRestDocs.verify().jsonPath("$[?(@.foo >= 20)]") - .jsonPath("$[?(@.bar in ['baz','bazz','bazzz'])]") - .contentType(MediaType.valueOf("application/json"))) - // then Contract DSL documentation - .andDo(document("index", SpringCloudContractRestDocs.dslContract(Maps.of("priority", 1)))); - // end::contract_snippet[] - - then(file("/contracts/index.groovy")).exists(); - then(file("/stubs/index.json")).exists(); - then(file("/index/dsl-contract.adoc")).exists(); - Collection parsedContracts = ContractVerifierDslConverter.convertAsCollection(new File("/"), - file("/contracts/index.groovy")); - Contract parsedContract = parsedContracts.iterator().next(); - then(parsedContract.getRequest().getHeaders().getEntries()).isNotNull(); - then(headerNames(parsedContract.getRequest().getHeaders().getEntries())).doesNotContain(HttpHeaders.HOST, - HttpHeaders.CONTENT_LENGTH); - then(headerNames(parsedContract.getResponse().getHeaders().getEntries())).doesNotContain(HttpHeaders.HOST, - HttpHeaders.CONTENT_LENGTH); - then(parsedContract.getRequest().getMethod().getClientValue()).isNotNull(); - then(parsedContract.getRequest().getUrlPath().getClientValue()).isNotNull(); - then(parsedContract.getRequest().getUrlPath().getClientValue().toString()).startsWith("/"); - then(parsedContract.getRequest().getBody().getClientValue()).isNotNull(); - then(parsedContract.getRequest().getBodyMatchers().hasMatchers()).isTrue(); - then(parsedContract.getResponse().getStatus().getClientValue()).isNotNull(); - then(parsedContract.getResponse().getHeaders().getEntries()).isNotEmpty(); - then(parsedContract.getResponse().getBody().getClientValue()).isNotNull(); - then(parsedContract.getPriority().intValue()).isEqualTo(1); - } - - @Test - public void should_create_contract_template_and_doc_with_placeholder_names() throws Exception { - this.mockMvc - .perform(post("/foo").accept(MediaType.APPLICATION_PDF).accept(MediaType.APPLICATION_JSON) - .contentType(MediaType.APPLICATION_JSON).content("{\"foo\": 23, \"bar\" : \"baz\" }")) - .andExpect(status().isOk()).andExpect(content().string("bar")) - // first WireMock - .andDo(WireMockRestDocs.verify().jsonPath("$[?(@.foo >= 20)]") - .jsonPath("$[?(@.bar in ['baz','bazz','bazzz'])]") - .contentType(MediaType.valueOf("application/json"))) - // then Contract DSL documentation - .andDo(document("{methodName}", SpringCloudContractRestDocs.dslContract())); - - then(file("/contracts/should_create_contract_template_and_doc_with_placeholder_names.groovy")).exists(); - then(file("/stubs/should_create_contract_template_and_doc_with_placeholder_names.json")).exists(); - then(file("/should_create_contract_template_and_doc_with_placeholder_names/dsl-contract.adoc")).exists(); - Collection parsedContracts = ContractVerifierDslConverter.convertAsCollection(new File("/"), - file("/contracts/should_create_contract_template_and_doc_with_placeholder_names.groovy")); - Contract parsedContract = parsedContracts.iterator().next(); - then(parsedContract.getRequest().getHeaders().getEntries()).isNotNull(); - then(headerNames(parsedContract.getRequest().getHeaders().getEntries())).doesNotContain(HttpHeaders.HOST, - HttpHeaders.CONTENT_LENGTH); - then(headerNames(parsedContract.getResponse().getHeaders().getEntries())).doesNotContain(HttpHeaders.HOST, - HttpHeaders.CONTENT_LENGTH); - then(parsedContract.getRequest().getMethod().getClientValue()).isNotNull(); - then(parsedContract.getRequest().getUrlPath().getClientValue()).isNotNull(); - then(parsedContract.getRequest().getUrlPath().getClientValue().toString()).startsWith("/"); - then(parsedContract.getRequest().getBody().getClientValue()).isNotNull(); - then(parsedContract.getRequest().getBodyMatchers().hasMatchers()).isTrue(); - then(parsedContract.getResponse().getStatus().getClientValue()).isNotNull(); - then(parsedContract.getResponse().getHeaders().getEntries()).isNotEmpty(); - then(parsedContract.getResponse().getBody().getClientValue()).isNotNull(); - } - - @Test - public void should_create_contract_template_and_doc_without_body_and_headers() throws Exception { - this.mockMvc.perform(MockMvcRequestBuilders.get("/foo").param("one", "newValueOne").param("two", "newValueTwo")) - .andExpect(status().isOk()).andDo(document("empty", dslContract())); - - then(file("/contracts/empty.groovy")).exists(); - then(file("/empty/dsl-contract.adoc")).exists(); - Collection parsedContracts = ContractVerifierDslConverter.convertAsCollection(new File("/"), - file("/contracts/empty.groovy")); - Contract parsedContract = parsedContracts.iterator().next(); - then(parsedContract.getRequest().getHeaders()).isNull(); - then(parsedContract.getRequest().getMethod().getClientValue()).isNotNull(); - then(parsedContract.getRequest().getUrlPath().getClientValue()).isNotNull(); - then(parsedContract.getRequest().getUrlPath().getClientValue().toString()).startsWith("/"); - List parameters = parsedContract.getRequest().getUrlPath().getQueryParameters().getParameters(); - QueryParameter one = parameter(parameters, "one"); - QueryParameter two = parameter(parameters, "two"); - then(one.getClientValue()).isEqualTo("newValueOne"); - then(two.getClientValue()).isEqualTo("newValueTwo"); - then(parsedContract.getRequest().getBody()).isNull(); - then(parsedContract.getResponse().getStatus().getClientValue()).isNotNull(); - then(parsedContract.getResponse().getHeaders()).isNull(); - then(parsedContract.getResponse().getBody()).isNull(); - then(parsedContract.getResponse().getBodyMatchers()).isNull(); - } - - private QueryParameter parameter(List parameters, String name) { - return parameters.stream().filter(queryParameter -> queryParameter.getName().equals(name)).findFirst() - .orElseThrow(() -> new AssertionError("Missing entry")); - } - - private Set headerNames(Set
headers) { - Set names = new HashSet<>(); - for (Header header : headers) { - names.add(header.getName()); - } - return names; - } - - private File file(String name) throws URISyntaxException { - return new File(OUTPUT, name); - } - - @Configuration - @EnableAutoConfiguration - @RestController - static class Config { - - @PostMapping("/foo") - String foo() { - return "bar"; - } - - @GetMapping("/foo") - void getFoo(@RequestParam(name = "one", defaultValue = "valueOne") String one, - @RequestParam(name = "two", defaultValue = "valueTwo") String two) { - } - - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockSnippetTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockSnippetTests.java deleted file mode 100644 index 67e7619d63..0000000000 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/restdocs/WireMockSnippetTests.java +++ /dev/null @@ -1,489 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.wiremock.restdocs; - -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import com.github.tomakehurst.wiremock.matching.EqualToJsonPattern; -import com.github.tomakehurst.wiremock.matching.EqualToXmlPattern; -import com.github.tomakehurst.wiremock.matching.MultiValuePattern; -import com.github.tomakehurst.wiremock.stubbing.StubMapping; -import org.assertj.core.api.Assertions; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -import org.springframework.cloud.contract.wiremock.WireMockStubMapping; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.restdocs.ManualRestDocumentation; -import org.springframework.restdocs.RestDocumentationContext; -import org.springframework.restdocs.operation.Operation; -import org.springframework.restdocs.operation.OperationRequest; -import org.springframework.restdocs.operation.OperationRequestPart; -import org.springframework.restdocs.operation.OperationResponse; -import org.springframework.restdocs.operation.RequestCookie; -import org.springframework.restdocs.operation.ResponseCookie; - -import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Marcin Grzejszczak - */ -public class WireMockSnippetTests { - - @Rule - public TemporaryFolder tmp = new TemporaryFolder(); - - Operation operation; - - RestDocumentationContext context; - - private File outputFolder; - - @Before - public void setup() throws IOException { - this.outputFolder = this.tmp.newFolder(); - ManualRestDocumentation restDocumentation = new ManualRestDocumentation(this.outputFolder.getAbsolutePath()); - restDocumentation.beforeTest(this.getClass(), "method"); - this.context = restDocumentation.beforeOperation(); - this.operation = operation(request(), response(), this.context); - } - - @Test - public void should_maintain_the_response_status_when_generating_stub() throws Exception { - WireMockSnippet snippet = new WireMockSnippet(); - - snippet.document(this.operation); - - File stub = new File(this.outputFolder, "stubs/foo.json"); - assertThat(stub).exists(); - StubMapping stubMapping = WireMockStubMapping.buildFrom(new String(Files.readAllBytes(stub.toPath()))); - assertThat(stubMapping.getResponse().getStatus()).isEqualTo(HttpStatus.ACCEPTED.value()); - } - - @Test - public void should_use_placeholders_in_stub_file_name() throws Exception { - this.operation = operation("{method-name}/{step}", request(), response(), this.context); - WireMockSnippet snippet = new WireMockSnippet(); - - snippet.document(this.operation); - - File stub = new File(this.outputFolder, "stubs/method/1.json"); - assertThat(stub).exists(); - StubMapping stubMapping = WireMockStubMapping.buildFrom(new String(Files.readAllBytes(stub.toPath()))); - assertThat(stubMapping.getResponse().getStatus()).isEqualTo(HttpStatus.ACCEPTED.value()); - } - - @Test - public void should_use_equal_to_json_pattern_for_body_when_request_content_type_is_json_when_generating_stub() - throws Exception { - this.operation = operation(requestPostWithJsonContentType(), response(), this.context); - WireMockSnippet snippet = new WireMockSnippet(); - - snippet.document(this.operation); - - File stub = new File(this.outputFolder, "stubs/foo.json"); - assertThat(stub).exists(); - StubMapping stubMapping = WireMockStubMapping.buildFrom(new String(Files.readAllBytes(stub.toPath()))); - assertThat(stubMapping.getRequest().getBodyPatterns().get(0)).isInstanceOf(EqualToJsonPattern.class); - assertThat(stubMapping.getRequest().getBodyPatterns().get(0).getValue()).isEqualTo("{\"name\": \"12\"}"); - } - - @Test - public void should_use_equal_to_xml_pattern_for_body_when_request_content_type_is_xml_when_generating_stub() - throws Exception { - this.operation = operation(requestPostWithXmlContentType(), response(), this.context); - WireMockSnippet snippet = new WireMockSnippet(); - - snippet.document(this.operation); - - File stub = new File(this.outputFolder, "stubs/foo.json"); - assertThat(stub).exists(); - StubMapping stubMapping = WireMockStubMapping.buildFrom(new String(Files.readAllBytes(stub.toPath()))); - assertThat(stubMapping.getRequest().getBodyPatterns().get(0)).isInstanceOf(EqualToXmlPattern.class); - assertThat(stubMapping.getRequest().getBodyPatterns().get(0).getValue()).isEqualTo("foo"); - } - - @Test - public void should_handle_empty_request_body() throws IOException { - this.operation = operation(requestPostWithEmptyBody(), response(), this.context); - WireMockSnippet snippet = new WireMockSnippet(); - - snippet.document(this.operation); - - File stub = new File(this.outputFolder, "stubs/foo.json"); - assertThat(stub).exists(); - StubMapping stubMapping = WireMockStubMapping.buildFrom(new String(Files.readAllBytes(stub.toPath()))); - assertThat(stubMapping.getRequest().getBodyPatterns()).isNullOrEmpty(); - assertThat(stubMapping.getResponse().getStatus()).isEqualTo(HttpStatus.ACCEPTED.value()); - } - - @Test - public void should_accept_empty_value_for_query_params() throws IOException { - this.operation = operation(requestPostWithEmptyQueryParamValue(), response(), this.context); - WireMockSnippet snippet = new WireMockSnippet(); - - snippet.document(this.operation); - - File stub = new File(this.outputFolder, "stubs/foo.json"); - assertThat(stub).exists(); - WireMockStubMapping.buildFrom(new String(Files.readAllBytes(stub.toPath()))); - } - - @Test - public void should_accept_query_params() throws IOException { - this.operation = operation(requestGetWithQueryParam(), response(), this.context); - WireMockSnippet snippet = new WireMockSnippet(); - - snippet.document(this.operation); - - File stub = new File(this.outputFolder, "stubs/foo.json"); - assertThat(stub).exists(); - StubMapping stubMapping = WireMockStubMapping.buildFrom(new String(Files.readAllBytes(stub.toPath()))); - assertThat(stubMapping.getRequest().getUrlPath()).isEqualTo("/bar"); - assertThat(stubMapping.getRequest().getQueryParameters()) - .containsOnly(Assertions.entry("myParam", MultiValuePattern.of(equalTo(("myValue"))))); - } - - private Operation operation(OperationRequest request, OperationResponse response, - RestDocumentationContext context) { - return operation("foo", request, response, context); - } - - private Operation operation(String name, OperationRequest request, OperationResponse response, - RestDocumentationContext context) { - return new Operation() { - - Map map = new HashMap<>(); - - @Override - public Map getAttributes() { - this.map.put(RestDocumentationContext.class.getName(), context); - return this.map; - } - - @Override - public String getName() { - return name; - } - - @Override - public OperationRequest getRequest() { - return request; - } - - @Override - public OperationResponse getResponse() { - return response; - } - }; - } - - private OperationResponse response() { - return new OperationResponse() { - - @Override - public HttpStatus getStatus() { - return HttpStatus.ACCEPTED; - } - - @Override - public HttpHeaders getHeaders() { - return new HttpHeaders(); - } - - @Override - public byte[] getContent() { - return new byte[0]; - } - - @Override - public String getContentAsString() { - return null; - } - - @Override - public Collection getCookies() { - return Collections.emptySet(); - } - - }; - } - - private OperationRequest request() { - return new OperationRequest() { - - @Override - public byte[] getContent() { - return new byte[0]; - } - - @Override - public String getContentAsString() { - return null; - } - - @Override - public HttpHeaders getHeaders() { - return new HttpHeaders(); - } - - @Override - public HttpMethod getMethod() { - return HttpMethod.GET; - } - - @Override - public Collection getParts() { - return null; - } - - @Override - public URI getUri() { - return URI.create("https://foo/bar"); - } - - @Override - public Collection getCookies() { - return Collections.emptySet(); - } - }; - } - - private OperationRequest requestPostWithJsonContentType() { - return new OperationRequest() { - - @Override - public byte[] getContent() { - String content = "{\"name\": \"12\"}"; - return content.getBytes(Charset.forName("UTF-8")); - } - - @Override - public String getContentAsString() { - return "{\"name\": \"12\"}"; - } - - @Override - public HttpHeaders getHeaders() { - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.add("Content-Type", MediaType.APPLICATION_JSON_VALUE); - return httpHeaders; - } - - @Override - public HttpMethod getMethod() { - return HttpMethod.POST; - } - - @Override - public Collection getParts() { - return null; - } - - @Override - public URI getUri() { - return URI.create("https://foo/bar"); - } - - @Override - public Collection getCookies() { - return Collections.emptySet(); - } - }; - } - - private OperationRequest requestPostWithXmlContentType() { - return new OperationRequest() { - - @Override - public byte[] getContent() { - String content = "foo"; - return content.getBytes(Charset.forName("UTF-8")); - } - - @Override - public String getContentAsString() { - return "foo"; - } - - @Override - public HttpHeaders getHeaders() { - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.add("Content-Type", MediaType.APPLICATION_XML_VALUE); - return httpHeaders; - } - - @Override - public HttpMethod getMethod() { - return HttpMethod.POST; - } - - @Override - public Collection getParts() { - return null; - } - - @Override - public URI getUri() { - return URI.create("https://foo/bar"); - } - - @Override - public Collection getCookies() { - return Collections.emptySet(); - } - }; - } - - private OperationRequest requestPostWithEmptyBody() { - return new OperationRequest() { - @Override - public byte[] getContent() { - return new byte[0]; - } - - @Override - public String getContentAsString() { - return ""; - } - - @Override - public HttpHeaders getHeaders() { - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); - return httpHeaders; - } - - @Override - public HttpMethod getMethod() { - return HttpMethod.POST; - } - - @Override - public Collection getParts() { - return null; - } - - @Override - public URI getUri() { - return URI.create("https://foo/bar"); - } - - @Override - public Collection getCookies() { - return Collections.emptySet(); - } - }; - } - - private OperationRequest requestPostWithEmptyQueryParamValue() { - return new OperationRequest() { - @Override - public byte[] getContent() { - return new byte[0]; - } - - @Override - public String getContentAsString() { - return ""; - } - - @Override - public HttpHeaders getHeaders() { - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); - return httpHeaders; - } - - @Override - public HttpMethod getMethod() { - return HttpMethod.POST; - } - - @Override - public Collection getParts() { - return null; - } - - @Override - public URI getUri() { - return URI.create("https://foo/bar?myParam="); - } - - @Override - public Collection getCookies() { - return Collections.emptySet(); - } - }; - } - - private OperationRequest requestGetWithQueryParam() { - return new OperationRequest() { - @Override - public byte[] getContent() { - return new byte[0]; - } - - @Override - public String getContentAsString() { - return ""; - } - - @Override - public HttpHeaders getHeaders() { - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); - return httpHeaders; - } - - @Override - public HttpMethod getMethod() { - return HttpMethod.GET; - } - - @Override - public Collection getParts() { - return null; - } - - @Override - public URI getUri() { - return URI.create("https://foo/bar?myParam=myValue"); - } - - @Override - public Collection getCookies() { - return Collections.emptySet(); - } - }; - } - -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/__files/hello.json b/spring-cloud-contract-wiremock/src/test/resources/__files/hello.json deleted file mode 100644 index 5ea152e675..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/__files/hello.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "message": "Hello World" -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/application-customfoo.yml b/spring-cloud-contract-wiremock/src/test/resources/application-customfoo.yml deleted file mode 100644 index 4a0c45e0e1..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/application-customfoo.yml +++ /dev/null @@ -1,7 +0,0 @@ -wiremock: - server: - port: 0 - stubs: - - "file:src/test/resources/custom-from-yml/mappings" - files: - - "file:src/test/resources/custom-from-yml" diff --git a/spring-cloud-contract-wiremock/src/test/resources/application.yml b/spring-cloud-contract-wiremock/src/test/resources/application.yml deleted file mode 100644 index caca78953a..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/application.yml +++ /dev/null @@ -1,4 +0,0 @@ -logging: - level: - org.springframework.cloud.contract: debug - com.github.tomakehurst.wiremock: trace diff --git a/spring-cloud-contract-wiremock/src/test/resources/custom-from-yml/__files/hello-custom.json b/spring-cloud-contract-wiremock/src/test/resources/custom-from-yml/__files/hello-custom.json deleted file mode 100644 index 4839848bd9..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/custom-from-yml/__files/hello-custom.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "message": "Hello Custom One" -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/custom-from-yml/mappings/custom-test-endpoint.json b/spring-cloud-contract-wiremock/src/test/resources/custom-from-yml/mappings/custom-test-endpoint.json deleted file mode 100644 index b47092fb84..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/custom-from-yml/mappings/custom-test-endpoint.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "request": { - "urlPath": "/test", - "method": "GET" - }, - "response": { - "status": 200, - "bodyFileName": "hello-custom.json" - } -} - diff --git a/spring-cloud-contract-wiremock/src/test/resources/custom/hello.json b/spring-cloud-contract-wiremock/src/test/resources/custom/hello.json deleted file mode 100644 index 4d8edd619f..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/custom/hello.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "message": "Hello Custom" -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/example-mappings/shouldMarkClientAsFraud.json b/spring-cloud-contract-wiremock/src/test/resources/example-mappings/shouldMarkClientAsFraud.json deleted file mode 100644 index 2453086652..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/example-mappings/shouldMarkClientAsFraud.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "id" : "6655794c-a651-4b71-a2b9-b7dc7e1c273f", - "request" : { - "url" : "/fraudcheck", - "method" : "PUT", - "headers" : { - "Content-Type" : { - "matches" : "application/vnd\\.fraud\\.v1\\+json.*" - } - }, - "bodyPatterns" : [ { - "matchesJsonPath" : "$[?(@.['clientId'] =~ /[0-9]{10}/)]" - }, { - "matchesJsonPath" : "$[?(@.['loanAmount'] == 99999)]" - } ] - }, - "response" : { - "status" : 200, - "body" : "{\"fraudCheckStatus\":\"FRAUD\",\"rejectionReason\":\"Amount too high\"}", - "headers" : { - "Content-Type" : "application/vnd.fraud.v1+json" - }, - "transformers" : [ "response-template" ] - }, - "uuid" : "6655794c-a651-4b71-a2b9-b7dc7e1c273f" -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/example-mappings/shouldMarkClientAsNotFraud.json b/spring-cloud-contract-wiremock/src/test/resources/example-mappings/shouldMarkClientAsNotFraud.json deleted file mode 100644 index 90e351fa0a..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/example-mappings/shouldMarkClientAsNotFraud.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "id" : "de2f8246-ae1a-4bdf-8d4c-a44af6df7a83", - "request" : { - "url" : "/fraudcheck", - "method" : "PUT", - "headers" : { - "Content-Type" : { - "matches" : "application/vnd\\.fraud\\.v1\\+json.*" - } - }, - "bodyPatterns" : [ { - "matchesJsonPath" : "$[?(@.['clientId'] =~ /[0-9]{10}/)]" - }, { - "matchesJsonPath" : "$[?(@.['loanAmount'] == 123.123)]" - } ] - }, - "response" : { - "status" : 200, - "body" : "{\"fraudCheckStatus\":\"OK\",\"rejectionReason\":null}", - "headers" : { - "Content-Type" : "application/vnd.fraud.v1+json" - }, - "transformers" : [ "response-template" ] - }, - "uuid" : "de2f8246-ae1a-4bdf-8d4c-a44af6df7a83" -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/files/__files/hello.json b/spring-cloud-contract-wiremock/src/test/resources/files/__files/hello.json deleted file mode 100644 index 672c1b5bcd..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/files/__files/hello.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "message": "Hello Root" -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/files_banner/__files/response-bannerList-error.json b/spring-cloud-contract-wiremock/src/test/resources/files_banner/__files/response-bannerList-error.json deleted file mode 100644 index 0cf2bbf8f8..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/files_banner/__files/response-bannerList-error.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "successful": false, - "message": "INVALID_PARAMETER", - "result": null -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/files_banner/__files/response-bannerList-success.json b/spring-cloud-contract-wiremock/src/test/resources/files_banner/__files/response-bannerList-success.json deleted file mode 100644 index 2e4173a1ec..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/files_banner/__files/response-bannerList-success.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "results": [ - { - "seq": 1, - "title": "1111111111111111111111111", - "content": "1111111111111111111111111111111", - "regDate": "2022/06/17" - }, - { - "seq": 2, - "title": "22222222222222222222222222", - "content": "2222222222222222222222222222222", - "regDate": "2022/06/18" - } - ] -} - diff --git a/spring-cloud-contract-wiremock/src/test/resources/files_notice/__files/response-noticeList-error.json b/spring-cloud-contract-wiremock/src/test/resources/files_notice/__files/response-noticeList-error.json deleted file mode 100644 index 0cf2bbf8f8..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/files_notice/__files/response-noticeList-error.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "successful": false, - "message": "INVALID_PARAMETER", - "result": null -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/files_notice/__files/response-noticeList-success.json b/spring-cloud-contract-wiremock/src/test/resources/files_notice/__files/response-noticeList-success.json deleted file mode 100644 index 5fe55eb27a..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/files_notice/__files/response-noticeList-success.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "results": [ - { - "seq": 1, - "title": "[AAA] BBBBBBBBBBBBBBB", - "content": "CCCCCCCCCCCCCCCCCCCCCCCCC", - "regDate": "2022/06/17" - }, - { - "seq": 2, - "title": "[BBB] CCCCCCCCCCCCCCCCCCCCCCC", - "content": "DDDDDDDDDDDDDDDDDDD", - "regDate": "2022/06/18" - } - ] -} - diff --git a/spring-cloud-contract-wiremock/src/test/resources/io.stubs/mappings/link.json b/spring-cloud-contract-wiremock/src/test/resources/io.stubs/mappings/link.json deleted file mode 100644 index 2ee9a34e51..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/io.stubs/mappings/link.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "priority": 1, - "request": { - "urlPath": "/link", - "method": "GET" - }, - "response": { - "status": 200, - "body": "{\"_links\": {\"markup\":{\"href\":\"http://localhost:{{request.requestLine.port}}/documents\"}}}", - "transformers": ["response-template"] - } -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/io.stubs/mappings/resource.json b/spring-cloud-contract-wiremock/src/test/resources/io.stubs/mappings/resource.json deleted file mode 100644 index 5c73d668eb..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/io.stubs/mappings/resource.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "request": { - "urlPath": "/resource", - "method": "GET" - }, - "response": { - "status": 200, - "body": "Hello World" - } -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/jarfiles/module-banner-test-fixtures.jar b/spring-cloud-contract-wiremock/src/test/resources/jarfiles/module-banner-test-fixtures.jar deleted file mode 100644 index 95a8bedd0a38da5562eb44ca122d29a3e12e0320..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1146 zcmWIWW@h1HVBp|j(3MvVWdH&u5CH_7KE;?7qUY=O+4sz8A8%c~i@e^tTIbH3-yCFc#rVO~M^Bm13O$=I$t*6>O)VlD{HdL@Xut~|QbQq_UAa;c?d%+?sRuyXy)Et3aw8Y2UP z1&K~8E=^8OEiOiKoR_ZNSxwEbO+g)OMWQ0B4ypt!ve+u1k+FjL@${5wPnIybPT?tJ zRNZmw$)7!wuIv%ov+Ckkk)_Lat4wRiH83(Tx@2x}+1wGZW%3B|JnmtF2DU|N%R zc&&^tzuERkhr4Vl$vd-l?g09Mkx7IZcRB-l1PBBe-a3M4c&bC!hMwv`ia}sWqb87q zYePzd=q7+vBPVbWA7XJCkcOuxeA++>4+22$oeyNfwLz01KHZ>X2mv77=YdRg-LOQ7 yZVGy$gqgFXksX*8aG8QXiK5$qp1KfrEF#ekRequiredThing" - } - ] - }, - "response": { - "status": 200, - "body": "Hello Body" - } -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/mappings/body-matches-jsonpath.json b/spring-cloud-contract-wiremock/src/test/resources/mappings/body-matches-jsonpath.json deleted file mode 100644 index ad5ecfe753..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/mappings/body-matches-jsonpath.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "request": { - "urlPath": "/body", - "method": "POST", - "bodyPatterns": [ - { - "matchesJsonPath": "$.things[?(@.name == 'RequiredThing')]" - } - ] - }, - "response": { - "status": 200, - "body": "Hello Body" - } -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/mappings/body-matches-regex.json b/spring-cloud-contract-wiremock/src/test/resources/mappings/body-matches-regex.json deleted file mode 100644 index efbfc701b9..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/mappings/body-matches-regex.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "request": { - "urlPath": "/body", - "method": "POST", - "bodyPatterns": [ - { - "matches": ".*RequiredThing.*" - } - ] - }, - "response": { - "status": 200, - "body": "Hello Body" - } -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/mappings/body-matches-xpath.json b/spring-cloud-contract-wiremock/src/test/resources/mappings/body-matches-xpath.json deleted file mode 100644 index bd1f1d3759..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/mappings/body-matches-xpath.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "request": { - "urlPath": "/body", - "method": "POST", - "bodyPatterns": [ - { - "matchesXPath": "//things" - } - ] - }, - "response": { - "status": 200, - "body": "Hello Body" - } -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/mappings/header-contains.json b/spring-cloud-contract-wiremock/src/test/resources/mappings/header-contains.json deleted file mode 100644 index 070b85c706..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/mappings/header-contains.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "request": { - "urlPath": "/poster", - "method": "POST", - "headers": { - "Accept": { - "contains": "v.foo" - } - } - }, - "response": { - "status": 200, - "body": "Foo World" - } -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/mappings/header-matches-precise.json b/spring-cloud-contract-wiremock/src/test/resources/mappings/header-matches-precise.json deleted file mode 100644 index 5634986b02..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/mappings/header-matches-precise.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "request": { - "urlPath": "/poster", - "method": "POST", - "headers": { - "Accept": { - "matches": ".*/v.bar" - }, - "X-Precise": { - "equalTo": "true" - } - } - }, - "response": { - "status": 200, - "body": "Precise World" - } -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/mappings/header-matches.json b/spring-cloud-contract-wiremock/src/test/resources/mappings/header-matches.json deleted file mode 100644 index 145d5388d8..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/mappings/header-matches.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "request": { - "urlPath": "/poster", - "method": "POST", - "headers": { - "Accept": { - "matches": ".*/v.bar" - } - } - }, - "response": { - "status": 200, - "body": "Bar World" - } -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/mappings/poster.json b/spring-cloud-contract-wiremock/src/test/resources/mappings/poster.json deleted file mode 100644 index 00a3df6744..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/mappings/poster.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "request": { - "urlPath": "/poster", - "method": "POST" - }, - "response": { - "status": 200, - "body": "Hello World" - } -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-base64-body.json b/spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-base64-body.json deleted file mode 100644 index 779883bdef..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-base64-body.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "priority": 100, - "request": { - "urlPath": "/resource", - "method": "GET" - }, - "response": { - "status": 200, - "base64Body": "SGVsbG8gV29ybGQ=" - } -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-body-file.json b/spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-body-file.json deleted file mode 100644 index 2d4a2602cb..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-body-file.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "priority": 100, - "request": { - "urlPath": "/resource", - "method": "GET" - }, - "response": { - "status": 200, - "bodyFileName": "hello.json" - } -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-content-type.json b/spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-content-type.json deleted file mode 100644 index 4555c33050..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-content-type.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "request": { - "urlPath": "/resource", - "method": "GET" - }, - "response": { - "status": 200, - "body": "Hello World", - "headers": { - "ETag": "\"356b53e9c9e124a7772d88f087a58838\"", - "Content-Type": "application/json", - "Cache-Control": "max-age=604800" - } - } -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-empty-path.json b/spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-empty-path.json deleted file mode 100644 index 0ec8bd7f0b..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-empty-path.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "request": { - "method": "GET" - }, - "response": { - "status": 200, - "body": "Hello World", - "headers": { - "ETag": "\"356b53e9c9e124a7772d88f087a58838\"", - "Content-Type": "application/json", - "Cache-Control": "max-age=604800" - } - } -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-high-priority.json b/spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-high-priority.json deleted file mode 100644 index 9cd5bfa599..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-high-priority.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "priority": 500, - "request": { - "urlPath": "/resource", - "method": "GET" - }, - "response": { - "status": 200, - "body": "Hello High" - } -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-json-body.json b/spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-json-body.json deleted file mode 100644 index d404db1207..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-json-body.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "priority": 100, - "request": { - "urlPath": "/resource", - "method": "GET" - }, - "response": { - "status": 200, - "jsonBody": { - "message": "Hello World" - } - } -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-low-priority.json b/spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-low-priority.json deleted file mode 100644 index 01d89bc62d..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/mappings/resource-with-low-priority.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "priority": 1000, - "request": { - "urlPath": "/resource", - "method": "GET" - }, - "response": { - "status": 200, - "body": "Hello Low" - } -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/mappings/resource-without-content-type.json b/spring-cloud-contract-wiremock/src/test/resources/mappings/resource-without-content-type.json deleted file mode 100644 index b3b665e231..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/mappings/resource-without-content-type.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "request": { - "urlPath": "/resource", - "method": "GET" - }, - "response": { - "status": 200, - "body": "Hello World", - "headers": { - "ETag": "\"356b53e9c9e124a7772d88f087a58838\"", - "Cache-Control": "max-age=604800" - } - } -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/mappings/resource.json b/spring-cloud-contract-wiremock/src/test/resources/mappings/resource.json deleted file mode 100644 index 57383e4549..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/mappings/resource.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "priority": 1, - "request": { - "urlPath": "/resource", - "method": "GET" - }, - "response": { - "status": 200, - "body": "Hello World" - } -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/mappings/url-matches.json b/spring-cloud-contract-wiremock/src/test/resources/mappings/url-matches.json deleted file mode 100644 index f328fe113c..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/mappings/url-matches.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "request": { - "method": "GET", - "urlPattern": "^.*[0-9]{3}/hello-url-matcher/" - }, - "response": { - "status": 200, - "body": "Hello Url Matcher" - } -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/mappings/url-path-pattern.json b/spring-cloud-contract-wiremock/src/test/resources/mappings/url-path-pattern.json deleted file mode 100644 index 26fccb5a45..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/mappings/url-path-pattern.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "request": { - "method": "GET", - "urlPathPattern": "/([0-9]+)/url-path-pattern/" - }, - "response": { - "status": 200, - "body": "Hello Url Path Matcher" - } -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/mappings/url-simple-path-pattern-with-leading-slash.json b/spring-cloud-contract-wiremock/src/test/resources/mappings/url-simple-path-pattern-with-leading-slash.json deleted file mode 100644 index ce37ae8b9f..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/mappings/url-simple-path-pattern-with-leading-slash.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "request": { - "method": "GET", - "urlPathPattern": "/my/api" - }, - "response": { - "status": 200, - "body": "Hello Url Path Matcher" - } -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/mappings/url-simple-path-pattern-without-leading-slash.json b/spring-cloud-contract-wiremock/src/test/resources/mappings/url-simple-path-pattern-without-leading-slash.json deleted file mode 100644 index db22373c33..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/mappings/url-simple-path-pattern-without-leading-slash.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "request": { - "method": "GET", - "urlPathPattern": "my/api" - }, - "response": { - "status": 200, - "body": "Hello Url Path Matcher" - } -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/root/__files/hello.json b/spring-cloud-contract-wiremock/src/test/resources/root/__files/hello.json deleted file mode 100644 index 672c1b5bcd..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/root/__files/hello.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "message": "Hello Root" -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/root/mappings/accept.json b/spring-cloud-contract-wiremock/src/test/resources/root/mappings/accept.json deleted file mode 100644 index 192ff161ba..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/root/mappings/accept.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "request": { - "urlPath": "/poster", - "method": "POST", - "headers": { - "Accept": { - "equalTo": "text/plain" - } - } - }, - "response": { - "status": 200, - "body": "Accepted World" - } -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/root/mappings/resource-with-body-file.json b/spring-cloud-contract-wiremock/src/test/resources/root/mappings/resource-with-body-file.json deleted file mode 100644 index 49302315fa..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/root/mappings/resource-with-body-file.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "request": { - "urlPath": "/test", - "method": "GET" - }, - "response": { - "status": 200, - "bodyFileName": "hello.json" - } -} diff --git a/spring-cloud-contract-wiremock/src/test/resources/root/mappings/url-matches.json b/spring-cloud-contract-wiremock/src/test/resources/root/mappings/url-matches.json deleted file mode 100644 index f328fe113c..0000000000 --- a/spring-cloud-contract-wiremock/src/test/resources/root/mappings/url-matches.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "request": { - "method": "GET", - "urlPattern": "^.*[0-9]{3}/hello-url-matcher/" - }, - "response": { - "status": 200, - "body": "Hello Url Matcher" - } -} diff --git a/src/checkstyle/checkstyle-suppressions.xml b/src/checkstyle/checkstyle-suppressions.xml deleted file mode 100644 index b7ce3e5708..0000000000 --- a/src/checkstyle/checkstyle-suppressions.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/supplemental-ui/partials/nav-search.hbs b/supplemental-ui/partials/nav-search.hbs new file mode 100644 index 0000000000..5e37955284 --- /dev/null +++ b/supplemental-ui/partials/nav-search.hbs @@ -0,0 +1,11 @@ +{{#if env.ALGOLIA_API_KEY}} + +{{/if}} diff --git a/supplemental-ui/partials/search.hbs b/supplemental-ui/partials/search.hbs new file mode 100644 index 0000000000..384e505f61 --- /dev/null +++ b/supplemental-ui/partials/search.hbs @@ -0,0 +1,27 @@ + +{{#if env.ALGOLIA_API_KEY}} + + + + + + + + +{{/if}} diff --git a/tests/pom.xml b/tests/pom.xml deleted file mode 100644 index 3e74626619..0000000000 --- a/tests/pom.xml +++ /dev/null @@ -1,88 +0,0 @@ - - - 4.0.0 - - - org.springframework.cloud - spring-cloud-contract-parent - 4.1.0-SNAPSHOT - .. - - - spring-cloud-contract-tests - pom - - Spring Cloud Contract Tests - Spring Cloud Contract Tests - - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - - - - maven-deploy-plugin - 2.8.2 - - true - - - - - - - - CI - - - env.CI - - - - samples-messaging-camel - samples-messaging-integration - samples-messaging-amqp - samples-messaging-jms - spring-cloud-contract-stub-runner-boot-eureka - spring-cloud-contract-stub-runner-boot-zookeeper - spring-cloud-contract-stub-runner-context-path - spring-cloud-contract-stub-runner-integration - spring-cloud-contract-stub-runner-stream - spring-cloud-contract-stub-runner-amqp - spring-cloud-contract-stub-runner-jms - spring-cloud-contract-stub-runner-kafka - - - - default - - - !env.CI - - - - samples-messaging-camel - samples-messaging-integration - samples-messaging-amqp - samples-messaging-jms - spring-cloud-contract-stub-runner-boot-eureka - spring-cloud-contract-stub-runner-boot-zookeeper - spring-cloud-contract-stub-runner-context-path - spring-cloud-contract-stub-runner-moco-contract-jar - spring-cloud-contract-stub-runner-moco - spring-cloud-contract-stub-runner-integration - spring-cloud-contract-stub-runner-stream - spring-cloud-contract-stub-runner-amqp - spring-cloud-contract-stub-runner-jms - spring-cloud-contract-stub-runner-kafka - - - - - diff --git a/tests/samples-messaging-amqp/pom.xml b/tests/samples-messaging-amqp/pom.xml deleted file mode 100644 index 420e16775e..0000000000 --- a/tests/samples-messaging-amqp/pom.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - 4.0.0 - - org.springframework.cloud - spring-cloud-contract-tests - 4.1.0-SNAPSHOT - .. - - spring-cloud-contract-sample-amqp - jar - Spring Cloud Contract Sample Spring Amqp - Spring Cloud Contract Sample Spring Amqp Rabbit - - - org.springframework.boot - spring-boot-starter-actuator - - - org.springframework.boot - spring-boot-starter-json - - - org.springframework.boot - spring-boot-starter-amqp - - - org.springframework.cloud - spring-cloud-contract-verifier - test - - - org.springframework.boot - spring-boot-starter-test - test - - - org.awaitility - awaitility - test - - - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - - - diff --git a/tests/samples-messaging-amqp/src/main/java/com/example/AmqpMessagingApplication.java b/tests/samples-messaging-amqp/src/main/java/com/example/AmqpMessagingApplication.java deleted file mode 100644 index f4d22a28e9..0000000000 --- a/tests/samples-messaging-amqp/src/main/java/com/example/AmqpMessagingApplication.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import org.springframework.amqp.core.Exchange; -import org.springframework.amqp.core.TopicExchange; -import org.springframework.amqp.rabbit.connection.ConnectionFactory; -import org.springframework.amqp.rabbit.core.RabbitTemplate; -import org.springframework.amqp.support.converter.ContentTypeDelegatingMessageConverter; -import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; -import org.springframework.amqp.support.converter.MessageConverter; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.Bean; - -import static org.springframework.amqp.core.MessageProperties.CONTENT_TYPE_JSON; - -@SpringBootApplication -public class AmqpMessagingApplication { - - public static void main(String[] args) { - SpringApplication.run(AmqpMessagingApplication.class, args); - } - - @Bean - public MessageConverter messageConverter() { - final Jackson2JsonMessageConverter jsonMessageConverter = new Jackson2JsonMessageConverter(new ObjectMapper()); - jsonMessageConverter.setCreateMessageIds(true); - final ContentTypeDelegatingMessageConverter messageConverter = new ContentTypeDelegatingMessageConverter( - jsonMessageConverter); - messageConverter.addDelegate(CONTENT_TYPE_JSON, jsonMessageConverter); - return messageConverter; - } - - @Bean - public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory, MessageConverter messageConverter) { - RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); - rabbitTemplate.setMessageConverter(messageConverter); - return rabbitTemplate; - } - - @Bean - public Exchange testExchange() { - return new TopicExchange("test-exchange"); - } - - @Bean - MessagePublisher messagePublisher(RabbitTemplate rabbitTemplate) { - return new MessagePublisher(rabbitTemplate, testExchange()); - } - -} diff --git a/tests/samples-messaging-amqp/src/main/java/com/example/Book.java b/tests/samples-messaging-amqp/src/main/java/com/example/Book.java deleted file mode 100644 index 3a73dfff93..0000000000 --- a/tests/samples-messaging-amqp/src/main/java/com/example/Book.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example; - -public class Book { - - private String name; - - public Book(String name) { - this.name = name; - } - - public Book() { - - } - - public String getName() { - return this.name; - } - - void setName(String name) { - this.name = name; - } - -} diff --git a/tests/samples-messaging-amqp/src/main/java/com/example/Issue178ListenerConfiguration.java b/tests/samples-messaging-amqp/src/main/java/com/example/Issue178ListenerConfiguration.java deleted file mode 100644 index f910f6ea97..0000000000 --- a/tests/samples-messaging-amqp/src/main/java/com/example/Issue178ListenerConfiguration.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; - -import org.springframework.amqp.core.Binding; -import org.springframework.amqp.core.BindingBuilder; -import org.springframework.amqp.core.Message; -import org.springframework.amqp.core.MessageBuilder; -import org.springframework.amqp.core.MessageListener; -import org.springframework.amqp.core.Queue; -import org.springframework.amqp.core.TopicExchange; -import org.springframework.amqp.rabbit.connection.ConnectionFactory; -import org.springframework.amqp.rabbit.core.RabbitTemplate; -import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * @author Marcin Grzejszczak - */ -@Configuration -class Issue178ListenerConfiguration { - - @Bean - SimpleMessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory, - RabbitTemplate rabbitTemplate) { - SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(); - container.setConnectionFactory(connectionFactory); - container.addQueueNames("rated-item-service.rated-item-event.exchange"); - container.setMessageListener(exampleListener(rabbitTemplate)); - return container; - } - - @Bean - MessageListener exampleListener(final RabbitTemplate rabbitTemplate) { - return new MessageListener() { - public void onMessage(Message message) { - System.out.println("received: " + message); - try { - String payload = new ObjectMapper() - .writeValueAsString(new MyPojo("992e46d8-ab05-4a26-a740-6ef7b0daeab3", "CREATED")); - Message outputMessage = MessageBuilder.withBody(payload.getBytes()).build(); - rabbitTemplate.send(issue178OutputExchange().getName(), "routingkey", outputMessage); - } - catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - } - }; - } - - @Bean - Queue issue178InputQueue() { - return new Queue("rated-item-service.rated-item-event.exchange", false); - } - - @Bean - TopicExchange issue178InputExchange() { - return new TopicExchange("rated-item-service.rated-item-event.exchange"); - } - - @Bean - TopicExchange issue178OutputExchange() { - return new TopicExchange("bill-service.rated-item-event.retry-exchange"); - } - - @Bean - Binding binding() { - return BindingBuilder.bind(issue178InputQueue()).to(issue178InputExchange()) - .with("rated-item-service.rated-item-event.exchange"); - } - - static class MyPojo { - - public String ratedItemId; - - public String eventType; - - MyPojo(String ratedItemId, String eventType) { - this.ratedItemId = ratedItemId; - this.eventType = eventType; - } - - MyPojo() { - } - - } - -} diff --git a/tests/samples-messaging-amqp/src/main/java/com/example/MessagePublisher.java b/tests/samples-messaging-amqp/src/main/java/com/example/MessagePublisher.java deleted file mode 100644 index 966d71f63d..0000000000 --- a/tests/samples-messaging-amqp/src/main/java/com/example/MessagePublisher.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example; - -import org.springframework.amqp.core.Exchange; -import org.springframework.amqp.rabbit.core.RabbitTemplate; - -public class MessagePublisher { - - private final RabbitTemplate rabbitTemplate; - - private final Exchange exchange; - - public MessagePublisher(RabbitTemplate rabbitTemplate, Exchange exchange) { - this.rabbitTemplate = rabbitTemplate; - this.exchange = exchange; - } - - public void sendMessage(Book book) { - this.rabbitTemplate.convertAndSend(this.exchange.getName(), "routingkey", book); - } - -} diff --git a/tests/samples-messaging-amqp/src/main/java/com/example/RabbitManager.java b/tests/samples-messaging-amqp/src/main/java/com/example/RabbitManager.java deleted file mode 100644 index f6d56ddeba..0000000000 --- a/tests/samples-messaging-amqp/src/main/java/com/example/RabbitManager.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example; - -import java.util.LinkedList; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.amqp.rabbit.annotation.Exchange; -import org.springframework.amqp.rabbit.annotation.Queue; -import org.springframework.amqp.rabbit.annotation.QueueBinding; -import org.springframework.amqp.rabbit.annotation.RabbitListener; -import org.springframework.amqp.rabbit.core.RabbitTemplate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.messaging.handler.annotation.Header; -import org.springframework.stereotype.Component; - -interface BookService { - - void sendBook(Book book, String replyTo); - - void newBook(Book book); - - Book getBook(int index); - - int noOfBooks(); - - List getBooks(); - -} - -@Component -public class RabbitManager { - - public static final Logger LOG = LoggerFactory.getLogger(RabbitManager.class); - - private BookService service; - - private RabbitTemplate rabbitTemplate; - - @Autowired - public RabbitManager(BookService service, RabbitTemplate rabbitTemplate) { - this.service = service; - this.rabbitTemplate = rabbitTemplate; - } - - @RabbitListener(bindings = @QueueBinding(value = @Queue, - exchange = @Exchange(value = "input", durable = "true", autoDelete = "false", type = "topic"), - key = "event")) - // Workaround for https://github.com/spring-projects/spring-amqp/issues/1285 - // public void newBook(Book book, @Headers Map headers) { - public void newBook(Book book, @Header("amqp_replyTo") String replyTo) { - LOG.info("Received new book with bookname = " + book.getName()); - // LOG.info("Headers = " + headers); - this.service.sendBook(book, replyTo); - } - - @RabbitListener(bindings = @QueueBinding(value = @Queue, - exchange = @Exchange(value = "input", durable = "true", autoDelete = "false", type = "topic"), - key = "event2")) - // Workaround for https://github.com/spring-projects/spring-amqp/issues/1285 - // public void newBook2(Book book, @Headers Map headers) { - public void newBook2(Book book, @Header("amqp_replyTo") String replyTo) { - LOG.info("newBook2 Received new book with bookname = " + book.getName()); - // LOG.info("newBook2 Headers = " + headers); - this.service.sendBook(book, replyTo); - } - -} - -@Component -class BookServiceImpl implements BookService { - - public static final Logger LOG = LoggerFactory.getLogger(BookServiceImpl.class); - - private List books; - - private RabbitTemplate rabbitTemplate; - - @Autowired - BookServiceImpl(RabbitTemplate rabbitTemplate) { - this.books = new LinkedList<>(); - this.rabbitTemplate = rabbitTemplate; - } - - @Override - public void sendBook(Book book, String replyTo) { - LOG.info("Received new book with bookname = " + book.getName()); - newBook(book); - this.rabbitTemplate.convertAndSend("", replyTo, book); - } - - @Override - public void newBook(Book book) { - this.books.add(book); - } - - @Override - public Book getBook(int index) { - return this.books.get(index); - } - - @Override - public int noOfBooks() { - return this.books.size(); - } - - @Override - public List getBooks() { - return this.books; - } - -} diff --git a/tests/samples-messaging-amqp/src/test/groovy/com/example/AmqpMessagingApplicationSpec.groovy b/tests/samples-messaging-amqp/src/test/groovy/com/example/AmqpMessagingApplicationSpec.groovy deleted file mode 100644 index 30b4a3a653..0000000000 --- a/tests/samples-messaging-amqp/src/test/groovy/com/example/AmqpMessagingApplicationSpec.groovy +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example - -import javax.inject.Inject - -import com.jayway.jsonpath.DocumentContext -import com.jayway.jsonpath.JsonPath -import com.toomuchcoding.jsonassert.JsonAssertion -import groovy.json.JsonOutput -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.messaging.boot.AutoConfigureMessageVerifier -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper - -import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson -import static org.assertj.core.api.Assertions.assertThat -import static org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers - -// Context configuration would end up in base class -@AutoConfigureMessageVerifier -@SpringBootTest(classes = AmqpMessagingApplication, properties = "stubrunner.amqp.enabled=true") -@Disabled("TODO: Migrate to middleware based approach") -class AmqpMessagingApplicationSpec { - - // ALL CASES - @Inject - ContractVerifierMessaging contractVerifierMessaging - @Inject - ContractVerifierObjectMapper contractVerifierObjectMapper - - @Test - void should_work_for_triggered_based_messaging() { - // given: - def dsl = Contract.make { - // Human readable description - description 'Some description' - // Label by means of which the output message can be triggered - label 'some_label' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('publishBook()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo('test-exchange') - // the body of the output message - body('''{ "name" : "some" }''') - // the headers of the output message - headers { - header('contentType', 'application/json') - header('__TypeId__', 'com.example.Book') - } - } - } - // generated test should look like this: - // when: - publishBook() - // then: - def response = contractVerifierMessaging.receive('test-exchange') - response.headers.get('contentType') == 'application/json' - // and: - DocumentContext parsedJson = JsonPath. - parse(contractVerifierObjectMapper.writeValueAsString(response.payload)) - JsonAssertion.assertThat(parsedJson).field('name').isEqualTo('some') - } - - // BASE CLASS WOULD HAVE THIS: - - @Autowired - MessagePublisher messagePublisher - - void publishBook() { - this.messagePublisher.sendMessage(new Book("some")) - } -} diff --git a/tests/samples-messaging-amqp/src/test/resources/application.yml b/tests/samples-messaging-amqp/src/test/resources/application.yml deleted file mode 100644 index 13f5f325d6..0000000000 --- a/tests/samples-messaging-amqp/src/test/resources/application.yml +++ /dev/null @@ -1 +0,0 @@ -stubrunner.amqp.enabled: true diff --git a/tests/samples-messaging-camel/.springBeans b/tests/samples-messaging-camel/.springBeans deleted file mode 100644 index b74cfc29b8..0000000000 --- a/tests/samples-messaging-camel/.springBeans +++ /dev/null @@ -1,16 +0,0 @@ - - - 1 - - - - - - - java:com.example.fraud.CamelMessagingApplication - - - - - - diff --git a/tests/samples-messaging-camel/log.log b/tests/samples-messaging-camel/log.log new file mode 100644 index 0000000000..44cdbc6400 --- /dev/null +++ b/tests/samples-messaging-camel/log.log @@ -0,0 +1,164 @@ +[INFO] Scanning for projects... +[INFO] +[INFO] ----< org.springframework.cloud:spring-cloud-contract-sample-camel >---- +[INFO] Building Spring Cloud Contract Sample Camel 4.0.0-SNAPSHOT +[INFO] --------------------------------[ jar ]--------------------------------- +[INFO] +[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ spring-cloud-contract-sample-camel --- +[WARNING] The artifact xml-apis:xml-apis:jar:2.0.2 has been relocated to xml-apis:xml-apis:jar:1.0.b2 +[INFO] org.springframework.cloud:spring-cloud-contract-sample-camel:jar:4.0.0-SNAPSHOT +[INFO] +- org.apache.camel.springboot:camel-amqp-starter:jar:3.19.0:compile +[INFO] | +- org.springframework.boot:spring-boot-starter:jar:3.0.0-SNAPSHOT:compile +[INFO] | | +- org.springframework.boot:spring-boot:jar:3.0.0-SNAPSHOT:compile +[INFO] | | | \- org.springframework:spring-context:jar:6.0.0-RC4:compile +[INFO] | | | +- org.springframework:spring-aop:jar:6.0.0-RC4:compile +[INFO] | | | \- org.springframework:spring-expression:jar:6.0.0-RC4:compile +[INFO] | | +- org.springframework.boot:spring-boot-autoconfigure:jar:3.0.0-SNAPSHOT:compile +[INFO] | | +- org.springframework.boot:spring-boot-starter-logging:jar:3.0.0-SNAPSHOT:compile +[INFO] | | | +- ch.qos.logback:logback-classic:jar:1.4.4:compile +[INFO] | | | | \- ch.qos.logback:logback-core:jar:1.4.4:compile +[INFO] | | | +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.19.0:compile +[INFO] | | | | \- org.apache.logging.log4j:log4j-api:jar:2.19.0:compile +[INFO] | | | \- org.slf4j:jul-to-slf4j:jar:2.0.3:compile +[INFO] | | \- jakarta.annotation:jakarta.annotation-api:jar:2.1.1:compile +[INFO] | +- org.apache.camel:camel-amqp:jar:3.19.0:compile +[INFO] | | +- org.apache.camel:camel-jms:jar:3.19.0:compile +[INFO] | | | +- org.apache.camel:camel-spring:jar:3.19.0:compile +[INFO] | | | +- org.springframework:spring-jms:jar:6.0.0-RC4:compile +[INFO] | | | | \- org.springframework:spring-messaging:jar:6.0.0-RC4:compile +[INFO] | | | +- org.springframework:spring-tx:jar:6.0.0-RC4:compile +[INFO] | | | +- org.springframework:spring-beans:jar:6.0.0-RC4:compile +[INFO] | | | \- org.apache.geronimo.specs:geronimo-jms_2.0_spec:jar:1.0-alpha-2:compile +[INFO] | | +- org.apache.qpid:qpid-jms-client:jar:1.7.0:compile +[INFO] | | | +- jakarta.jms:jakarta.jms-api:jar:3.1.0:compile +[INFO] | | | +- io.netty:netty-transport-native-epoll:jar:linux-x86_64:4.1.84.Final:compile +[INFO] | | | | \- io.netty:netty-transport-classes-epoll:jar:4.1.84.Final:compile +[INFO] | | | \- io.netty:netty-transport-native-kqueue:jar:osx-x86_64:4.1.84.Final:compile +[INFO] | | | \- io.netty:netty-transport-classes-kqueue:jar:4.1.84.Final:compile +[INFO] | | +- org.apache.qpid:proton-j:jar:0.34.0:compile +[INFO] | | +- io.netty:netty-buffer:jar:4.1.84.Final:compile +[INFO] | | +- io.netty:netty-common:jar:4.1.84.Final:compile +[INFO] | | +- io.netty:netty-handler:jar:4.1.84.Final:compile +[INFO] | | | +- io.netty:netty-resolver:jar:4.1.84.Final:compile +[INFO] | | | +- io.netty:netty-transport-native-unix-common:jar:4.1.84.Final:compile +[INFO] | | | \- io.netty:netty-codec:jar:4.1.84.Final:compile +[INFO] | | +- io.netty:netty-transport:jar:4.1.84.Final:compile +[INFO] | | \- io.netty:netty-codec-http:jar:4.1.84.Final:compile +[INFO] | \- org.apache.camel.springboot:camel-core-starter:jar:3.19.0:compile +[INFO] | \- org.apache.camel.springboot:camel-spring-boot:jar:3.19.0:compile +[INFO] | +- org.apache.camel:camel-spring-main:jar:3.19.0:compile +[INFO] | | \- org.apache.camel:camel-main:jar:3.19.0:compile +[INFO] | | \- org.apache.camel:camel-core-languages:jar:3.19.0:compile +[INFO] | +- org.apache.camel:camel-util-json:jar:3.19.0:compile +[INFO] | +- org.apache.camel:camel-xml-jaxb-dsl:jar:3.19.0:compile +[INFO] | | +- org.apache.camel:camel-xml-jaxb:jar:3.19.0:compile +[INFO] | | | +- com.sun.xml.bind:jaxb-core:jar:4.0.1:compile +[INFO] | | | | \- org.eclipse.angus:angus-activation:jar:1.0.0:runtime +[INFO] | | | \- com.sun.xml.bind:jaxb-impl:jar:4.0.1:compile +[INFO] | | \- org.apache.camel:camel-dsl-support:jar:3.19.0:compile +[INFO] | +- org.apache.camel:camel-spring-xml:jar:3.19.0:compile +[INFO] | | +- org.apache.camel:camel-xml-jaxp:jar:3.19.0:compile +[INFO] | | | \- org.apache.camel:camel-xml-io-util:jar:3.19.0:compile +[INFO] | | +- org.apache.camel:camel-core-xml:jar:3.19.0:compile +[INFO] | | \- javax.annotation:javax.annotation-api:jar:1.3.2:compile +[INFO] | +- org.apache.camel:camel-cloud:jar:3.19.0:compile +[INFO] | +- org.apache.camel:camel-cluster:jar:3.19.0:compile +[INFO] | \- org.apache.camel:camel-health:jar:3.19.0:compile +[INFO] +- org.apache.camel.springboot:camel-direct-starter:jar:3.19.0:compile +[INFO] | \- org.apache.camel:camel-direct:jar:3.19.0:compile +[INFO] | \- org.apache.camel:camel-support:jar:3.19.0:compile +[INFO] +- org.apache.camel.springboot:camel-bean-starter:jar:3.19.0:compile +[INFO] | \- org.apache.camel:camel-bean:jar:3.19.0:compile +[INFO] +- org.apache.camel:camel-jackson:jar:3.19.0:compile +[INFO] | +- org.apache.camel:camel-core-engine:jar:3.19.0:compile +[INFO] | | +- org.apache.camel:camel-api:jar:3.19.0:compile +[INFO] | | +- org.apache.camel:camel-base-engine:jar:3.19.0:compile +[INFO] | | | \- org.apache.camel:camel-base:jar:3.19.0:compile +[INFO] | | +- org.apache.camel:camel-core-reifier:jar:3.19.0:compile +[INFO] | | | +- org.apache.camel:camel-core-model:jar:3.19.0:compile +[INFO] | | | \- org.apache.camel:camel-core-processor:jar:3.19.0:compile +[INFO] | | +- org.apache.camel:camel-management-api:jar:3.19.0:compile +[INFO] | | \- org.apache.camel:camel-util:jar:3.19.0:compile +[INFO] | \- com.fasterxml.jackson.core:jackson-databind:jar:2.14.0-rc3:compile +[INFO] | +- com.fasterxml.jackson.core:jackson-annotations:jar:2.14.0-rc3:compile +[INFO] | \- com.fasterxml.jackson.core:jackson-core:jar:2.14.0-rc3:compile +[INFO] +- org.springframework.cloud:spring-cloud-contract-verifier:jar:4.0.0-SNAPSHOT:test +[INFO] | +- org.springframework.cloud:spring-cloud-contract-spec:jar:4.0.0-SNAPSHOT:test +[INFO] | | +- org.springframework.cloud:spring-cloud-contract-spec-java:jar:4.0.0-SNAPSHOT:test +[INFO] | | | \- dk.brics:automaton:jar:1.12-4:test +[INFO] | | \- org.springframework.cloud:spring-cloud-contract-spec-groovy:jar:4.0.0-SNAPSHOT:test +[INFO] | +- org.springframework.cloud:spring-cloud-contract-shade:jar:4.0.0-SNAPSHOT:test +[INFO] | +- org.springframework.boot:spring-boot-test-autoconfigure:jar:3.0.0-SNAPSHOT:test +[INFO] | +- org.apache.commons:commons-text:jar:1.10.0:test +[INFO] | | \- org.apache.commons:commons-lang3:jar:3.12.0:test +[INFO] | +- javax.inject:javax.inject:jar:1:test +[INFO] | +- com.github.tomakehurst:wiremock-jre8-standalone:jar:2.35.0:test +[INFO] | +- com.toomuchcoding.jsonassert:jsonassert:jar:0.6.2:test +[INFO] | +- org.apache.maven.resolver:maven-resolver-api:jar:1.4.1:test +[INFO] | +- com.rackspace.eclipse.webtools.sourceediting:org.eclipse.wst.xml.xpath2.processor:jar:2.1.100:test +[INFO] | | +- edu.princeton.cup:java-cup:jar:10k:test +[INFO] | | \- com.ibm.icu:icu4j:jar:4.6:test +[INFO] | +- org.apache.groovy:groovy:jar:4.0.0:test +[INFO] | +- org.apache.groovy:groovy-nio:jar:4.0.0:test +[INFO] | +- org.apache.groovy:groovy-json:jar:4.0.0:test +[INFO] | +- org.apache.groovy:groovy-xml:jar:4.0.0:test +[INFO] | +- org.skyscreamer:jsonassert:jar:1.5.1:test +[INFO] | | \- com.vaadin.external.google:android-json:jar:0.0.20131108.vaadin1:test +[INFO] | +- com.github.jknack:handlebars:jar:4.3.0:test +[INFO] | | \- org.slf4j:slf4j-api:jar:2.0.3:provided (version selected from constraint [2.0.0,)) +[INFO] | +- commons-beanutils:commons-beanutils:jar:1.9.4:test +[INFO] | | +- commons-logging:commons-logging:jar:1.2:test +[INFO] | | \- commons-collections:commons-collections:jar:3.2.2:test +[INFO] | +- org.yaml:snakeyaml:jar:1.33:compile +[INFO] | +- com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:jar:2.14.0-rc3:test +[INFO] | +- org.mockito:mockito-core:jar:2.23.0:test +[INFO] | | +- net.bytebuddy:byte-buddy:jar:1.12.18:test +[INFO] | | +- net.bytebuddy:byte-buddy-agent:jar:1.12.18:test +[INFO] | | \- org.objenesis:objenesis:jar:2.6:test +[INFO] | +- net.javacrumbs.json-unit:json-unit-assertj:jar:2.32.0:test +[INFO] | | +- net.javacrumbs.json-unit:json-unit-core:jar:2.32.0:test +[INFO] | | | \- org.hamcrest:hamcrest-core:jar:1.3:test +[INFO] | | \- net.javacrumbs.json-unit:json-unit-json-path:jar:2.32.0:test +[INFO] | \- org.junit.jupiter:junit-jupiter-api:jar:5.9.1:test +[INFO] | +- org.opentest4j:opentest4j:jar:1.2.0:test +[INFO] | +- org.junit.platform:junit-platform-commons:jar:1.9.1:test +[INFO] | \- org.apiguardian:apiguardian-api:jar:1.1.2:test +[INFO] +- org.spockframework:spock-spring:jar:2.3-groovy-4.0:test +[INFO] | \- org.spockframework:spock-core:jar:2.3-groovy-4.0:test +[INFO] | \- org.junit.platform:junit-platform-engine:jar:1.9.1:test +[INFO] +- org.springframework.boot:spring-boot-starter-test:jar:3.0.0-SNAPSHOT:test +[INFO] | +- org.springframework.boot:spring-boot-test:jar:3.0.0-SNAPSHOT:test +[INFO] | +- com.jayway.jsonpath:json-path:jar:2.7.0:test +[INFO] | | \- net.minidev:json-smart:jar:2.4.8:test +[INFO] | | \- net.minidev:accessors-smart:jar:2.4.8:test +[INFO] | | \- org.ow2.asm:asm:jar:9.1:test +[INFO] | +- jakarta.xml.bind:jakarta.xml.bind-api:jar:4.0.0:compile +[INFO] | | \- jakarta.activation:jakarta.activation-api:jar:2.1.0:compile +[INFO] | +- org.assertj:assertj-core:jar:3.23.1:test +[INFO] | +- org.hamcrest:hamcrest:jar:2.2:test +[INFO] | +- org.junit.jupiter:junit-jupiter:jar:5.9.1:test +[INFO] | | +- org.junit.jupiter:junit-jupiter-params:jar:5.9.1:test +[INFO] | | \- org.junit.jupiter:junit-jupiter-engine:jar:5.9.1:test +[INFO] | +- org.mockito:mockito-junit-jupiter:jar:4.8.1:test +[INFO] | +- org.springframework:spring-core:jar:6.0.0-RC4:compile +[INFO] | | \- org.springframework:spring-jcl:jar:6.0.0-RC4:compile +[INFO] | +- org.springframework:spring-test:jar:6.0.0-RC4:test +[INFO] | \- org.xmlunit:xmlunit-core:jar:2.9.0:test +[INFO] +- org.awaitility:awaitility:jar:4.2.0:test +[INFO] +- org.testcontainers:rabbitmq:jar:1.17.5:test +[INFO] | \- org.testcontainers:testcontainers:jar:1.17.5:test +[INFO] | +- junit:junit:jar:4.12:test +[INFO] | +- org.apache.commons:commons-compress:jar:1.21:test +[INFO] | +- org.rnorth.duct-tape:duct-tape:jar:1.0.8:test +[INFO] | | \- org.jetbrains:annotations:jar:17.0.0:test +[INFO] | +- com.github.docker-java:docker-java-api:jar:3.2.13:test +[INFO] | \- com.github.docker-java:docker-java-transport-zerodep:jar:3.2.13:test +[INFO] | +- com.github.docker-java:docker-java-transport:jar:3.2.13:test +[INFO] | \- net.java.dev.jna:jna:jar:5.8.0:test +[INFO] \- org.testcontainers:junit-jupiter:jar:1.17.5:test +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ +[INFO] Total time: 0.759 s +[INFO] Finished at: 2022-11-14T15:58:28+01:00 +[INFO] ------------------------------------------------------------------------ diff --git a/tests/samples-messaging-camel/pom.xml b/tests/samples-messaging-camel/pom.xml deleted file mode 100644 index dac3cb0967..0000000000 --- a/tests/samples-messaging-camel/pom.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - 4.0.0 - - org.springframework.cloud - spring-cloud-contract-tests - 4.1.0-SNAPSHOT - .. - - spring-cloud-contract-sample-camel - jar - Spring Cloud Contract Sample Camel - Spring Cloud Contract Sample Camel - - - org.apache.camel.springboot - camel-rabbitmq-starter - - - org.apache.camel.springboot - camel-direct-starter - - - org.apache.camel.springboot - camel-bean-starter - - - org.apache.camel.springboot - camel-jackson-starter - - - org.springframework.boot - spring-boot-starter-amqp - - - org.springframework.cloud - spring-cloud-contract-verifier - test - - - org.spockframework - spock-spring - test - - - org.springframework.boot - spring-boot-starter-test - test - - - org.awaitility - awaitility - test - - - org.testcontainers - rabbitmq - test - - - org.testcontainers - junit-jupiter - test - - - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - - - diff --git a/tests/samples-messaging-camel/src/main/java/com/example/BookReturned.java b/tests/samples-messaging-camel/src/main/java/com/example/BookReturned.java deleted file mode 100644 index c89fb38bca..0000000000 --- a/tests/samples-messaging-camel/src/main/java/com/example/BookReturned.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example; - -import java.io.Serializable; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -@SuppressWarnings("serial") -public class BookReturned implements Serializable { - - public final String bookName; - - @JsonCreator - BookReturned(@JsonProperty("bookName") String bookName) { - this.bookName = bookName; - } - - @Override - public String toString() { - return "BookReturned{" + "bookName='" + bookName + '\'' + '}'; - } - -} diff --git a/tests/samples-messaging-camel/src/main/java/com/example/BookRouteConfiguration.java b/tests/samples-messaging-camel/src/main/java/com/example/BookRouteConfiguration.java deleted file mode 100644 index d01b279fd9..0000000000 --- a/tests/samples-messaging-camel/src/main/java/com/example/BookRouteConfiguration.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example; - -import org.apache.camel.CamelContext; -import org.apache.camel.RoutesBuilder; -import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.component.rabbitmq.RabbitMQComponent; -import org.apache.camel.model.dataformat.JsonLibrary; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * @author Marcin Grzejszczak - */ -@Configuration(proxyBeanMethods = false) -public class BookRouteConfiguration { - - @Bean - RoutesBuilder myRouter(final BookService bookService, CamelContext context, - @Value("${spring.rabbitmq.port}") int port) { - return new RouteBuilder() { - - @Override - public void configure() throws Exception { - RabbitMQComponent component = context.getComponent("rabbitmq", RabbitMQComponent.class); - component.setAddresses("localhost:" + port); - - // scenario 1 - from bean to output - from("direct:start").unmarshal().json(JsonLibrary.Jackson, BookReturned.class).bean(bookService) - .marshal().json(JsonLibrary.Jackson, BookReturned.class).to("rabbitmq:output?queue=output"); - } - - }; - } - -} diff --git a/tests/samples-messaging-camel/src/main/java/com/example/BookService.java b/tests/samples-messaging-camel/src/main/java/com/example/BookService.java deleted file mode 100644 index 13fb7423ed..0000000000 --- a/tests/samples-messaging-camel/src/main/java/com/example/BookService.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example; - -import org.apache.camel.Exchange; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.stereotype.Service; - -@Service -public class BookService { - - private static final Logger log = LoggerFactory.getLogger(BookService.class); - - /** - * Scenario for "should generate tests triggered by a method": client side: must have - * a possibility to "trigger" sending of a message to the given message - * @param exchange - input exchange. - */ - public void returnBook(Exchange exchange) { - BookReturned bookReturned = exchange.getIn().getBody(BookReturned.class); - log.info("Returning book [" + bookReturned + "]"); - exchange.getMessage().setBody(bookReturned); - exchange.getMessage().setHeader("BOOK-NAME", bookReturned.bookName); - } - -} diff --git a/tests/samples-messaging-camel/src/main/java/com/example/CamelMessagingApplication.java b/tests/samples-messaging-camel/src/main/java/com/example/CamelMessagingApplication.java deleted file mode 100644 index 1108da7198..0000000000 --- a/tests/samples-messaging-camel/src/main/java/com/example/CamelMessagingApplication.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class CamelMessagingApplication { - - public static void main(String[] args) { - SpringApplication.run(CamelMessagingApplication.class, args); - } - -} diff --git a/tests/samples-messaging-camel/src/test/groovy/com/example/CamelMessagingApplicationSpec.groovy b/tests/samples-messaging-camel/src/test/groovy/com/example/CamelMessagingApplicationSpec.groovy deleted file mode 100644 index 96702d9001..0000000000 --- a/tests/samples-messaging-camel/src/test/groovy/com/example/CamelMessagingApplicationSpec.groovy +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example - -import javax.inject.Inject - -import com.jayway.jsonpath.DocumentContext -import com.jayway.jsonpath.JsonPath -import com.toomuchcoding.jsonassert.JsonAssertion -import org.apache.camel.model.ModelCamelContext -import org.junit.jupiter.api.Test -import org.testcontainers.containers.RabbitMQContainer -import org.testcontainers.junit.jupiter.Container -import org.testcontainers.junit.jupiter.Testcontainers - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.messaging.boot.AutoConfigureMessageVerifier -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper -import org.springframework.test.context.DynamicPropertyRegistry -import org.springframework.test.context.DynamicPropertySource -/** - * SPIKE ON TESTS FROM NOTES IN MessagingSpec - */ -// Context configuration would end up in base class -@AutoConfigureMessageVerifier -@SpringBootTest(classes = CamelMessagingApplication, properties = 'camel.component.rabbitmq.declare=true') -@Testcontainers -class CamelMessagingApplicationSpec { - - // ALL CASES - @Autowired - ModelCamelContext camelContext - @Inject - ContractVerifierMessaging contractVerifierMessaging - - ContractVerifierObjectMapper contractVerifierObjectMapper = new ContractVerifierObjectMapper() - - @Container - static RabbitMQContainer broker = new RabbitMQContainer("rabbitmq:3.7.25-management-alpine"); - - @DynamicPropertySource - static void setup(DynamicPropertyRegistry registry) { - registry.add("spring.rabbitmq.port", () -> broker.getAmqpPort()); - } - - @Test - void "should work for triggered based messaging"() { - given: - // tag::sample_dsl[] - Contract.make { - label 'return_book_1' - input { - triggeredBy('bookReturnedTriggered()') - } - outputMessage { - sentTo('rabbitmq:output?queue=output') - body('''{ "bookName" : "foo" }''') - headers { - header('BOOK-NAME', 'foo') - } - } - } - // end::sample_dsl[] - // generated test should look like this: - when: - bookReturnedTriggered() - then: - def response = contractVerifierMessaging.receive('rabbitmq:output?queue=output') - assert response.headers.get('BOOK-NAME') == 'foo' - and: - DocumentContext parsedJson = JsonPath. - parse(contractVerifierObjectMapper.writeValueAsString(response.getPayload())) - JsonAssertion.assertThat(parsedJson).field('bookName').isEqualTo('foo') - } - - void bookReturnedTriggered() { - camelContext.createProducerTemplate(). - sendBody('direct:start', '''{"bookName" : "foo" }''') - } - -} diff --git a/tests/samples-messaging-camel/src/test/resources/logback-test.xml b/tests/samples-messaging-camel/src/test/resources/logback-test.xml deleted file mode 100644 index 3951c629f7..0000000000 --- a/tests/samples-messaging-camel/src/test/resources/logback-test.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n - - - - - - - - - - - diff --git a/tests/samples-messaging-integration/.springBeans b/tests/samples-messaging-integration/.springBeans deleted file mode 100644 index 34d395dc49..0000000000 --- a/tests/samples-messaging-integration/.springBeans +++ /dev/null @@ -1,16 +0,0 @@ - - - 1 - - - - - - - java:com.example.fraud.IntegrationMessagingApplication - - - - - - diff --git a/tests/samples-messaging-integration/pom.xml b/tests/samples-messaging-integration/pom.xml deleted file mode 100644 index 08de9fa2e1..0000000000 --- a/tests/samples-messaging-integration/pom.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - 4.0.0 - - org.springframework.cloud - spring-cloud-contract-tests - 4.1.0-SNAPSHOT - .. - - spring-cloud-contract-sample-integration - jar - Spring Cloud Contract Sample Spring Integration - Spring Cloud Contract Sample Spring Integration - - - org.springframework.boot - spring-boot-starter-actuator - - - org.springframework.boot - spring-boot-starter-integration - - - org.springframework.cloud - spring-cloud-contract-verifier - test - - - org.spockframework - spock-spring - test - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - - - diff --git a/tests/samples-messaging-integration/src/main/java/com/example/BookDeleted.java b/tests/samples-messaging-integration/src/main/java/com/example/BookDeleted.java deleted file mode 100644 index 14f363e9ea..0000000000 --- a/tests/samples-messaging-integration/src/main/java/com/example/BookDeleted.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example; - -import java.io.Serializable; - -@SuppressWarnings("serial") -public class BookDeleted implements Serializable { - - public String bookName; - - public BookDeleted(String bookName) { - this.bookName = bookName; - } - - public BookDeleted() { - } - - public String getBookName() { - return this.bookName; - } - - void setBookName(String bookName) { - this.bookName = bookName; - } - -} diff --git a/tests/samples-messaging-integration/src/main/java/com/example/BookListener.java b/tests/samples-messaging-integration/src/main/java/com/example/BookListener.java deleted file mode 100644 index 3119db8590..0000000000 --- a/tests/samples-messaging-integration/src/main/java/com/example/BookListener.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.messaging.Message; -import org.springframework.messaging.support.MessageBuilder; - -public class BookListener { - - private static final Logger log = LoggerFactory.getLogger(BookListener.class); - - /** - * Scenario for "should generate tests triggered by a message": client side: if sends - * a message to input.messageFrom then message will be sent to output.messageFrom - * server side: will send a message to input, verify the message contents and await - * upon receiving message on the output messageFrom. - * @param bookReturned - payload - * @return message with the returned book - */ - public Message returnBook(BookReturned bookReturned) { - log.info("Returning book [" + bookReturned + "]"); - return MessageBuilder.withPayload(bookReturned).setHeader("BOOK-NAME", bookReturned.bookName).build(); - } - -} diff --git a/tests/samples-messaging-integration/src/main/java/com/example/BookReturned.java b/tests/samples-messaging-integration/src/main/java/com/example/BookReturned.java deleted file mode 100644 index d0bc9acf65..0000000000 --- a/tests/samples-messaging-integration/src/main/java/com/example/BookReturned.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example; - -import java.io.Serializable; - -@SuppressWarnings("serial") -public class BookReturned implements Serializable { - - public String bookName; - - public BookReturned(String bookName) { - this.bookName = bookName; - } - - public BookReturned() { - } - - public String getBookName() { - return this.bookName; - } - - void setBookName(String bookName) { - this.bookName = bookName; - } - -} diff --git a/tests/samples-messaging-integration/src/main/java/com/example/BookService.java b/tests/samples-messaging-integration/src/main/java/com/example/BookService.java deleted file mode 100644 index e9624e3dfd..0000000000 --- a/tests/samples-messaging-integration/src/main/java/com/example/BookService.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.support.MessageBuilder; -import org.springframework.stereotype.Service; - -@Service -public class BookService { - - private static final Logger log = LoggerFactory.getLogger(BookService.class); - - private @Autowired @Qualifier("outputChannel") MessageChannel outputChannel; - - /** - * Scenario for "should generate tests triggered by a method": client side: must have - * a possibility to "trigger" sending of a message to the given messageFrom server - * side: will run the method and await upon receiving message on the output - * messageFrom - * - * Method triggers sending a message to a source. - * @param bookReturned - payload - */ - public void returnBook(BookReturned bookReturned) { - log.info("Returning book " + bookReturned); - this.outputChannel - .send(MessageBuilder.withPayload(bookReturned).setHeader("BOOK-NAME", bookReturned.bookName).build()); - } - -} diff --git a/tests/samples-messaging-integration/src/main/java/com/example/IntegrationMessagingApplication.java b/tests/samples-messaging-integration/src/main/java/com/example/IntegrationMessagingApplication.java deleted file mode 100644 index a82f02163d..0000000000 --- a/tests/samples-messaging-integration/src/main/java/com/example/IntegrationMessagingApplication.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.ImportResource; - -@SpringBootApplication -@ImportResource("classpath*:integration-context.xml") -public class IntegrationMessagingApplication { - - public static void main(String[] args) { - SpringApplication.run(IntegrationMessagingApplication.class, args); - } - -} diff --git a/tests/samples-messaging-integration/src/main/resources/integration-context.xml b/tests/samples-messaging-integration/src/main/resources/integration-context.xml deleted file mode 100644 index 87116fb2b8..0000000000 --- a/tests/samples-messaging-integration/src/main/resources/integration-context.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/tests/samples-messaging-integration/src/test/groovy/com/example/IntegrationMessagingApplicationSpec.groovy b/tests/samples-messaging-integration/src/test/groovy/com/example/IntegrationMessagingApplicationSpec.groovy deleted file mode 100644 index b67f332f2c..0000000000 --- a/tests/samples-messaging-integration/src/test/groovy/com/example/IntegrationMessagingApplicationSpec.groovy +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example - -import javax.inject.Inject - -import com.jayway.jsonpath.DocumentContext -import com.jayway.jsonpath.JsonPath -import com.toomuchcoding.jsonassert.JsonAssertion -import org.junit.jupiter.api.Test - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.messaging.boot.AutoConfigureMessageVerifier -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper -import org.springframework.messaging.Message - -// Context configuration would end up in base class -@AutoConfigureMessageVerifier -@SpringBootTest(classes = IntegrationMessagingApplication) -class IntegrationMessagingApplicationSpec { - - // ALL CASES - @Inject - ContractVerifierMessaging> contractVerifierMessaging - ContractVerifierObjectMapper contractVerifierObjectMapper = new ContractVerifierObjectMapper() - - @Test - void "should work for triggered based messaging"() { - given: - // tag::method_trigger[] - def dsl = Contract.make { - // Human readable description - description 'Some description' - // Label by means of which the output message can be triggered - label 'some_label' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('bookReturnedTriggered()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo('output') - // the body of the output message - body('''{ "bookName" : "foo" }''') - // the headers of the output message - headers { - header('BOOK-NAME', 'foo') - } - } - } - // end::method_trigger[] - // generated test should look like this: - when: - bookReturnedTriggered() - then: - def response = contractVerifierMessaging.receive('output') - response.headers.get('BOOK-NAME') == 'foo' - and: - DocumentContext parsedJson = JsonPath. - parse(contractVerifierObjectMapper.writeValueAsString(response.payload)) - JsonAssertion.assertThat(parsedJson).field('bookName').isEqualTo('foo') - } - - // BASE CLASS WOULD HAVE THIS: - - @Autowired - BookService bookService - @Autowired - BookListener bookListener - - void bookReturnedTriggered() { - bookService.returnBook(new BookReturned("foo")) - } - -} diff --git a/tests/samples-messaging-jms/.springBeans b/tests/samples-messaging-jms/.springBeans deleted file mode 100644 index b74cfc29b8..0000000000 --- a/tests/samples-messaging-jms/.springBeans +++ /dev/null @@ -1,16 +0,0 @@ - - - 1 - - - - - - - java:com.example.fraud.CamelMessagingApplication - - - - - - diff --git a/tests/samples-messaging-jms/pom.xml b/tests/samples-messaging-jms/pom.xml deleted file mode 100644 index 17e9574577..0000000000 --- a/tests/samples-messaging-jms/pom.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - 4.0.0 - - org.springframework.cloud - spring-cloud-contract-tests - 4.1.0-SNAPSHOT - .. - - spring-cloud-contract-sample-jms - jar - Spring Cloud Contract Sample Jms - Spring Cloud Contract Sample Jms - - - org.springframework.boot - spring-boot-starter-artemis - - - org.apache.activemq - artemis-jms-server - - - com.fasterxml.jackson.core - jackson-databind - - - org.springframework.cloud - spring-cloud-contract-verifier - test - - - org.spockframework - spock-core - test - - - org.springframework.boot - spring-boot-starter-test - test - - - org.awaitility - awaitility - test - - - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - - - diff --git a/tests/samples-messaging-jms/src/main/java/com/example/BookDeleted.java b/tests/samples-messaging-jms/src/main/java/com/example/BookDeleted.java deleted file mode 100644 index 28bf966944..0000000000 --- a/tests/samples-messaging-jms/src/main/java/com/example/BookDeleted.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example; - -import java.io.Serializable; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -@SuppressWarnings("serial") -public class BookDeleted implements Serializable { - - public final String bookName; - - @JsonCreator - public BookDeleted(@JsonProperty("bookName") String bookName) { - this.bookName = bookName; - } - -} diff --git a/tests/samples-messaging-jms/src/main/java/com/example/BookReturned.java b/tests/samples-messaging-jms/src/main/java/com/example/BookReturned.java deleted file mode 100644 index 525c9f6211..0000000000 --- a/tests/samples-messaging-jms/src/main/java/com/example/BookReturned.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example; - -import java.io.Serializable; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -@SuppressWarnings("serial") -public class BookReturned implements Serializable { - - public final String bookName; - - @JsonCreator - BookReturned(@JsonProperty("bookName") String bookName) { - this.bookName = bookName; - } - -} diff --git a/tests/samples-messaging-jms/src/main/java/com/example/BookService.java b/tests/samples-messaging-jms/src/main/java/com/example/BookService.java deleted file mode 100644 index 2c5717069d..0000000000 --- a/tests/samples-messaging-jms/src/main/java/com/example/BookService.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.jms.annotation.JmsListener; -import org.springframework.jms.core.JmsTemplate; -import org.springframework.stereotype.Service; - -@Service -public class BookService { - - private static final Logger log = LoggerFactory.getLogger(BookService.class); - - private final JmsTemplate jmsTemplate; - - public BookService(JmsTemplate jmsTemplate) { - this.jmsTemplate = jmsTemplate; - } - - /** - * Scenario for "should generate tests triggered by a method": client side: must have - * a possibility to "trigger" sending of a message to the given messageFrom server - * side: will run the method and await upon receiving message on the output - * messageFrom. Method triggers sending a message to a source - */ - @JmsListener(destination = "input2") - public void returnBook() { - BookReturned bookReturned = new BookReturned("foo"); - jmsTemplate.convertAndSend("output2", "{\"bookName\":\"foo\"}", message -> { - message.setStringProperty("BOOKNAME", bookReturned.bookName); - return message; - }); - } - -} diff --git a/tests/samples-messaging-jms/src/main/java/com/example/JmsMessagingApplication.java b/tests/samples-messaging-jms/src/main/java/com/example/JmsMessagingApplication.java deleted file mode 100644 index d5d1a6d774..0000000000 --- a/tests/samples-messaging-jms/src/main/java/com/example/JmsMessagingApplication.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.jms.annotation.EnableJms; - -@SpringBootApplication -@EnableJms -public class JmsMessagingApplication { - - public static void main(String[] args) { - SpringApplication.run(JmsMessagingApplication.class, args); - } - -} diff --git a/tests/samples-messaging-jms/src/test/groovy/com/example/JmsMessagingApplicationSpec.groovy b/tests/samples-messaging-jms/src/test/groovy/com/example/JmsMessagingApplicationSpec.groovy deleted file mode 100644 index 06b6604de2..0000000000 --- a/tests/samples-messaging-jms/src/test/groovy/com/example/JmsMessagingApplicationSpec.groovy +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example - -import javax.inject.Inject - -import com.jayway.jsonpath.DocumentContext -import com.jayway.jsonpath.JsonPath -import com.toomuchcoding.jsonassert.JsonAssertion -import jakarta.jms.JMSException -import jakarta.jms.Message -import org.junit.jupiter.api.BeforeAll -import org.junit.jupiter.api.Test - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.messaging.boot.AutoConfigureMessageVerifier -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging -import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper -import org.springframework.jms.core.JmsTemplate -import org.springframework.jms.core.MessagePostProcessor -/** - * SPIKE ON TESTS FROM NOTES IN MessagingSpec - */ -// Context configuration would end up in base class -@AutoConfigureMessageVerifier -@SpringBootTest(classes = JmsMessagingApplication) -class JmsMessagingApplicationSpec { - - // ALL CASES - @Autowired - JmsTemplate jmsTemplate - @Inject - ContractVerifierMessaging contractVerifierMessaging - @Inject - ContractVerifierObjectMapper contractVerifierObjectMapper - - @BeforeAll - static void setupSpec() { - System.setProperty("debug", "true") - } - - @Test - void "should work for triggered based messaging"() { - given: - Contract.make { - label 'some_label' - input { - triggeredBy('bookReturnedTriggered()') - } - outputMessage { - sentTo('output') - body('''{ "bookName" : "foo" }''') - headers { - header('BOOKNAME', 'foo') - } - } - } - // generated test should look like this: - when: - bookReturnedTriggered() - then: - ContractVerifierMessage response = contractVerifierMessaging.receive('output') - assert response.getHeader('BOOKNAME') == 'foo' - and: - DocumentContext parsedJson = JsonPath. - parse(contractVerifierObjectMapper.writeValueAsString(response.getPayload())) - JsonAssertion.assertThat(parsedJson).field('bookName').isEqualTo('foo') - } - - void bookReturnedTriggered() { - jmsTemplate.convertAndSend("output", '''{"bookName" : "foo" }''', new MessagePostProcessor() { - @Override - Message postProcessMessage(Message message) throws JMSException { - message.setStringProperty("BOOKNAME", "foo") - return message - } - }) - } - -} diff --git a/tests/samples-messaging-jms/src/test/resources/application.yml b/tests/samples-messaging-jms/src/test/resources/application.yml deleted file mode 100644 index a26da67063..0000000000 --- a/tests/samples-messaging-jms/src/test/resources/application.yml +++ /dev/null @@ -1,2 +0,0 @@ -activemq: - broker-url: vm://embedded-broker?broker.persistent=false \ No newline at end of file diff --git a/tests/spring-cloud-contract-stub-runner-amqp/pom.xml b/tests/spring-cloud-contract-stub-runner-amqp/pom.xml deleted file mode 100644 index 26f3764f3f..0000000000 --- a/tests/spring-cloud-contract-stub-runner-amqp/pom.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - 4.0.0 - - org.springframework.cloud - spring-cloud-contract-tests - 4.1.0-SNAPSHOT - .. - - spring-cloud-contract-stub-runner-amqp - jar - Spring Cloud Contract Stub Runner AMQP - Spring Cloud Contract Stub Runner AMQP - - 17 - - - - org.springframework.cloud - spring-cloud-contract-stub-runner - - - org.springframework.cloud - spring-cloud-starter-contract-stub-runner-jetty - test - - - org.springframework.cloud - spring-cloud-contract-verifier - - - org.springframework.amqp - spring-rabbit - - - junit - junit - test - - - org.spockframework - spock-core - test - - - org.spockframework - spock-spring - test - - - org.springframework.boot - spring-boot-starter-test - - - org.springframework.boot - spring-boot-starter-web - test - - - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - - - diff --git a/tests/spring-cloud-contract-stub-runner-amqp/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/amqp/AmqpMessagingApplication.java b/tests/spring-cloud-contract-stub-runner-amqp/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/amqp/AmqpMessagingApplication.java deleted file mode 100644 index 4240ee8d46..0000000000 --- a/tests/spring-cloud-contract-stub-runner-amqp/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/amqp/AmqpMessagingApplication.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.messaging.amqp; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import org.springframework.amqp.core.Binding; -import org.springframework.amqp.core.BindingBuilder; -import org.springframework.amqp.core.DirectExchange; -import org.springframework.amqp.core.Queue; -import org.springframework.amqp.rabbit.annotation.EnableRabbit; -import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; -import org.springframework.amqp.rabbit.connection.ConnectionFactory; -import org.springframework.amqp.rabbit.core.RabbitTemplate; -import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; -import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter; -import org.springframework.amqp.support.converter.ContentTypeDelegatingMessageConverter; -import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; -import org.springframework.amqp.support.converter.MessageConverter; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; - -import static org.springframework.amqp.core.MessageProperties.CONTENT_TYPE_JSON; - -@SpringBootApplication -public class AmqpMessagingApplication { - - public static void main(String[] args) { - SpringApplication.run(AmqpMessagingApplication.class, args); - } - - @Bean - public MessageConverter messageConverter(ObjectMapper objectMapper) { - final Jackson2JsonMessageConverter jsonMessageConverter = new Jackson2JsonMessageConverter(objectMapper); - jsonMessageConverter.setCreateMessageIds(true); - final ContentTypeDelegatingMessageConverter messageConverter = new ContentTypeDelegatingMessageConverter( - jsonMessageConverter); - messageConverter.addDelegate(CONTENT_TYPE_JSON, jsonMessageConverter); - return messageConverter; - } - - @Bean - public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory, MessageConverter messageConverter) { - RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); - rabbitTemplate.setMessageConverter(messageConverter); - return rabbitTemplate; - } - - @Configuration(proxyBeanMethods = false) - @Profile("!listener") - static class MessageListenerAdapterConfig { - - @Bean - public MessageListenerAdapter messageListenerAdapter(MessageSubscriber messageSubscriber, - MessageConverter messageConverter) { - return new MessageListenerAdapter(messageSubscriber, messageConverter); - } - - // tag::amqp_binding[] - - @Bean - public Binding binding() { - return BindingBuilder.bind(new Queue("test.queue")).to(new DirectExchange("contract-test.exchange")) - .with("#"); - } - // end::amqp_binding[] - - // tag::amqp_listener[] - @Bean - public SimpleMessageListenerContainer simpleMessageListenerContainer(ConnectionFactory connectionFactory, - MessageListenerAdapter listenerAdapter) { - SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(); - container.setConnectionFactory(connectionFactory); - container.setQueueNames("test.queue"); - container.setMessageListener(listenerAdapter); - - return container; - } - // end::amqp_listener[] - - @Bean - public MessageSubscriber messageSubscriber() { - return new MessageSubscriber(); - } - - } - - @Configuration(proxyBeanMethods = false) - @EnableRabbit - @Profile("listener") - static class RabbitListenerConfig { - - @Bean - public MessageSubscriberRabbitListener messageSubscriberRabbitLister() { - return new MessageSubscriberRabbitListener(); - } - - @Bean - public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory, - MessageConverter messageConverter) { - SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory(); - factory.setConnectionFactory(connectionFactory); - factory.setConcurrentConsumers(3); - factory.setMaxConcurrentConsumers(10); - factory.setMessageConverter(messageConverter); - return factory; - } - - } - -} diff --git a/tests/spring-cloud-contract-stub-runner-amqp/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/amqp/MessageSubscriber.java b/tests/spring-cloud-contract-stub-runner-amqp/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/amqp/MessageSubscriber.java deleted file mode 100644 index 2721757bb7..0000000000 --- a/tests/spring-cloud-contract-stub-runner-amqp/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/amqp/MessageSubscriber.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.messaging.amqp; - -/** - * No op message subscriber. - * - * @author Mathias Düsterhöft - */ -public class MessageSubscriber { - - public void handleMessage(Person person) { - - } - -} diff --git a/tests/spring-cloud-contract-stub-runner-amqp/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/amqp/MessageSubscriberRabbitListener.java b/tests/spring-cloud-contract-stub-runner-amqp/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/amqp/MessageSubscriberRabbitListener.java deleted file mode 100644 index 6b8bddb199..0000000000 --- a/tests/spring-cloud-contract-stub-runner-amqp/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/amqp/MessageSubscriberRabbitListener.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.messaging.amqp; - -import org.springframework.amqp.rabbit.annotation.Exchange; -import org.springframework.amqp.rabbit.annotation.Queue; -import org.springframework.amqp.rabbit.annotation.QueueBinding; -import org.springframework.amqp.rabbit.annotation.RabbitListener; - -/** - * Rabbit listener. - * - * @author Mathias Düsterhöft - */ -public class MessageSubscriberRabbitListener { - - private Person person; - - // tag::amqp_annotated_listener[] - @RabbitListener(bindings = @QueueBinding(value = @Queue("test.queue"), - exchange = @Exchange(value = "contract-test.exchange", ignoreDeclarationExceptions = "true"))) - public void handlePerson(Person person) { - this.person = person; - } - - // end::amqp_annotated_listener[] - public Person getPerson() { - return this.person; - } - -} diff --git a/tests/spring-cloud-contract-stub-runner-amqp/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/amqp/Person.java b/tests/spring-cloud-contract-stub-runner-amqp/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/amqp/Person.java deleted file mode 100644 index de87563885..0000000000 --- a/tests/spring-cloud-contract-stub-runner-amqp/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/amqp/Person.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.messaging.amqp; - -/** - * Person pojo. - * - * @author Mathias Düsterhöft - */ -public class Person { - - private Integer id; - - private String name; - - public Integer getId() { - return this.id; - } - - public void setId(Integer id) { - this.id = id; - } - - public String getName() { - return this.name; - } - - public void setName(String name) { - this.name = name; - } - -} diff --git a/tests/spring-cloud-contract-stub-runner-amqp/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/amqp/AmqpStubRunnerRabbitListenerSpec.groovy b/tests/spring-cloud-contract-stub-runner-amqp/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/amqp/AmqpStubRunnerRabbitListenerSpec.groovy deleted file mode 100644 index dc8bc35c39..0000000000 --- a/tests/spring-cloud-contract-stub-runner-amqp/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/amqp/AmqpStubRunnerRabbitListenerSpec.groovy +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.messaging.amqp - -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.cloud.contract.stubrunner.StubTrigger -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner -import org.springframework.test.context.ActiveProfiles - -@AutoConfigureStubRunner -@SpringBootTest(classes = AmqpMessagingApplication) -@ActiveProfiles("listener") -@Disabled("TODO: Migrate to middleware based approach") -class AmqpStubRunnerRabbitListenerSpec { - - @Autowired - StubTrigger stubTrigger - - @Autowired - MessageSubscriberRabbitListener messageSubscriber - - @Test - void "should trigger stub amqp message consumed by annotated listener"() { - when: - stubTrigger.trigger("contract-test.person.created.event") - then: - assert messageSubscriber.person != null - assert messageSubscriber.person.name != null - } -} diff --git a/tests/spring-cloud-contract-stub-runner-amqp/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/amqp/AmqpStubRunnerSpec.groovy b/tests/spring-cloud-contract-stub-runner-amqp/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/amqp/AmqpStubRunnerSpec.groovy deleted file mode 100644 index 826deef269..0000000000 --- a/tests/spring-cloud-contract-stub-runner-amqp/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/amqp/AmqpStubRunnerSpec.groovy +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.messaging.amqp - -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test -import org.mockito.ArgumentCaptor - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.boot.test.mock.mockito.SpyBean -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.stubrunner.StubTrigger -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner - -import static org.mockito.BDDMockito.then - -@AutoConfigureStubRunner -@SpringBootTest(classes = AmqpMessagingApplication) -@Disabled("TODO: Migrate to middleware based approach") -class AmqpStubRunnerSpec { - - @Autowired - StubTrigger stubTrigger - - @SpyBean - MessageSubscriber messageSubscriber - - ArgumentCaptor personArgumentCaptor = ArgumentCaptor.forClass(Person) - - @Test - void "should trigger stub amqp message"() { - given: - // tag::amqp_contract[] - - Contract.make { - // Human readable description - description 'Should produce valid person data' - // Label by means of which the output message can be triggered - label 'contract-test.person.created.event' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('createPerson()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'contract-test.exchange' - headers { - header('contentType': 'application/json') - header('__TypeId__': 'org.springframework.cloud.contract.stubrunner.messaging.amqp.Person') - } - // the body of the output message - body([ - id : $(consumer(9), producer(regex("[0-9]+"))), - name: "me" - ]) - } - } - // end::amqp_contract[] - when: - // tag::client_trigger[] - stubTrigger.trigger("contract-test.person.created.event") - // end::client_trigger[] - then: - then(messageSubscriber).should().handleMessage(personArgumentCaptor.capture()) - assert personArgumentCaptor.value.name != null - } -} diff --git a/tests/spring-cloud-contract-stub-runner-amqp/src/test/resources/application.yml b/tests/spring-cloud-contract-stub-runner-amqp/src/test/resources/application.yml deleted file mode 100644 index e80226b65d..0000000000 --- a/tests/spring-cloud-contract-stub-runner-amqp/src/test/resources/application.yml +++ /dev/null @@ -1,8 +0,0 @@ -stubrunner: - repositoryRoot: classpath:m2repo/repository/ - ids: org.springframework.cloud.contract.verifier.stubs.amqp:spring-cloud-contract-amqp-test:0.4.0-SNAPSHOT:stubs - stubs-mode: remote - amqp: - enabled: true -server: - port: 0 diff --git a/tests/spring-cloud-contract-stub-runner-amqp/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/amqp/spring-cloud-contract-amqp-test/0.4.0-SNAPSHOT/maven-metadata-local.xml b/tests/spring-cloud-contract-stub-runner-amqp/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/amqp/spring-cloud-contract-amqp-test/0.4.0-SNAPSHOT/maven-metadata-local.xml deleted file mode 100644 index 87479713d5..0000000000 --- a/tests/spring-cloud-contract-stub-runner-amqp/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/amqp/spring-cloud-contract-amqp-test/0.4.0-SNAPSHOT/maven-metadata-local.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - org.springframework.cloud.contract.verifier.stubs.amqp - spring-cloud-contract-amqp-test - 0.4.0-SNAPSHOT - - - true - - 20161007155639 - - diff --git a/tests/spring-cloud-contract-stub-runner-amqp/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/amqp/spring-cloud-contract-amqp-test/0.4.0-SNAPSHOT/spring-cloud-contract-amqp-test-0.4.0-SNAPSHOT-stubs.jar b/tests/spring-cloud-contract-stub-runner-amqp/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/amqp/spring-cloud-contract-amqp-test/0.4.0-SNAPSHOT/spring-cloud-contract-amqp-test-0.4.0-SNAPSHOT-stubs.jar deleted file mode 100644 index 2fa845f66bd1df8f8636350bb6b3036cbeaf4f8b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3013 zcmWIWW@h1H0D;PVzMfzPlrUuwU??sq%FIjGP0qxx&nqcPOfJz)%q=X?ElDjd z(KXOB(lgKv_Hzsf_V5qUEiNfdD%KB;;9(GAVu<+02*M%^0YEE67&w5i2F(gPa;?yF z362jg$uCL;+4Tcx&u^$*Z)cqLYjzNEcpnhbVYta)ZKMV(s9_tLzZ&)+3nx?I-RA|JWVp2O>5 zxcIvF9i58D_6a}xxIE0nhx-%z*DYBx+i$Iv$~U|1*?WAh-`->2quD(dY3;7=Jv{l} z-NVU$rr7Kkku+>unfu@4YiZf4?`aRJ5AARLqpZf!6v0}sBiKy*w-k$`j^fQ92QFGw zMa@Xu*)q+$)WpR7^^45JwnCvOH|-4Gvmhx6cHOqw{B8beJDd}xW-b0|ztl%S+j;4P zX=nc*|NQ+wi{qc<8Fx%~vz__>f8yD#HnzX!i$3`6#PI&4#BATAS1;A}UAuVs&=vuO z4%d&20p9E!%;^uFH!?CXut+d~BOj8!I?*DZ6BzmN@xG4E{=pIOGy_RDkTio`8z{}d zwNaElk?q2sK0PV6OD`U0QcX?}O-@fpO8DUG6ZU~WtRtX-X@Uf^x_~s}MrncOAEFLt z7{V0~G%#DVwXitO6g7x_0SZlajxUne_m}|lXax|1vKAzmWcu7ua<4tPSqqlS5&8JV z;qT$7`M3csDw8O;tT-dTG$$pXC_kk%IW;UXCo?4=wWv5h&n2-WQ7^qHKfkOJl-EJ| z{693W_XeHLyKNw_=eM?)8-u5Z(|0NP%ii2e92&lev9P)3sT>nI`AP7&#-I1Gfy=V2 zH3II2S#P#BjyZmGS~aOtf>~|vfr#jtMiDV3vX8j$tsxe=% zPQPK_Rjz$Y8>K&-P|Y`OI-;PR=oBmiRo!b)lAW(81v%2;FGiy)qO*wQ%zI*;RBa1%*w&t>7#_N_p zSNp0y`~SbS#?>-g$|Ke;d~_~TbqOC&%s5|Cm&twf@Hzq)*ml zGPe6ul;ia+<^01>U!%0YtKR&ake1SR<$QY7XWJ8|F;|x;Eom&dZ)*N@LG9a(hx@C3 z{(1WC-P5X@CTGv8?@~0+j^NudCtCk017AHjwQ}^U)-D8=1@oElrB<>l0$7%Di;LzAq&-6|jm~SP)d6$t%lo?mu%L7ya1`Y=tK{Qz|4vpY|*Tezd zAnOq295YfOZO4GHZb@S@xz-^SbsX?o8DcN?vYZpi-oK6sObm#U9p-dUA&t)nWT*di zoQ`Y+ML~wJ7ZGI0C9fxv)0Z?d15-C;l@dxtfj#ul6S6&$6W%)R13G~$A0rp|kmLeN z%*e?FRNN!y<0K@Dmo#d#P;4<#g+B+p@JCJ$=z)Tq9^N|Uu#xFDcwUF4L-a5K*^8W; iQPaZ>itR-yV>sYtOn^5l&}aq*P9QV|27DDehz9_ziP2C1 diff --git a/tests/spring-cloud-contract-stub-runner-amqp/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/amqp/spring-cloud-contract-amqp-test/0.4.0-SNAPSHOT/spring-cloud-contract-amqp-test-0.4.0-SNAPSHOT.pom b/tests/spring-cloud-contract-stub-runner-amqp/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/amqp/spring-cloud-contract-amqp-test/0.4.0-SNAPSHOT/spring-cloud-contract-amqp-test-0.4.0-SNAPSHOT.pom deleted file mode 100644 index b7595d8390..0000000000 --- a/tests/spring-cloud-contract-stub-runner-amqp/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/amqp/spring-cloud-contract-amqp-test/0.4.0-SNAPSHOT/spring-cloud-contract-amqp-test-0.4.0-SNAPSHOT.pom +++ /dev/null @@ -1,27 +0,0 @@ - - - - - 4.0.0 - org.springframework.cloud.contract.verifier.stubs.amqp - spring-cloud-contract-amqp-test - 0.4.0-SNAPSHOT - pom - diff --git a/tests/spring-cloud-contract-stub-runner-amqp/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/amqp/spring-cloud-contract-amqp-test/maven-metadata-local.xml b/tests/spring-cloud-contract-stub-runner-amqp/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/amqp/spring-cloud-contract-amqp-test/maven-metadata-local.xml deleted file mode 100644 index de5ad1f63f..0000000000 --- a/tests/spring-cloud-contract-stub-runner-amqp/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/amqp/spring-cloud-contract-amqp-test/maven-metadata-local.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - org.springframework.cloud.contract.verifier.stubs.amqp - spring-cloud-contract-amqp-test - 0.4.0-SNAPSHOT - - - 0.4.0-SNAPSHOT - - 20160409062112 - - diff --git a/tests/spring-cloud-contract-stub-runner-amqp/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/amqp/spring-cloud-contract-amqp-test/maven-metadata.xml b/tests/spring-cloud-contract-stub-runner-amqp/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/amqp/spring-cloud-contract-amqp-test/maven-metadata.xml deleted file mode 100644 index de5ad1f63f..0000000000 --- a/tests/spring-cloud-contract-stub-runner-amqp/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/amqp/spring-cloud-contract-amqp-test/maven-metadata.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - org.springframework.cloud.contract.verifier.stubs.amqp - spring-cloud-contract-amqp-test - 0.4.0-SNAPSHOT - - - 0.4.0-SNAPSHOT - - 20160409062112 - - diff --git a/tests/spring-cloud-contract-stub-runner-boot-eureka/pom.xml b/tests/spring-cloud-contract-stub-runner-boot-eureka/pom.xml deleted file mode 100644 index 114dd8d5d6..0000000000 --- a/tests/spring-cloud-contract-stub-runner-boot-eureka/pom.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - 4.0.0 - - org.springframework.cloud - spring-cloud-contract-tests - 4.1.0-SNAPSHOT - .. - - spring-cloud-contract-stub-runner-boot-eureka - jar - Spring Cloud Contract Stub Runner Boot Eureka - Spring Cloud Contract Stub Runner Boot Eureka - - - org.springframework.cloud - spring-cloud-contract-stub-runner - - - org.springframework.cloud - spring-cloud-starter-contract-stub-runner-jetty - test - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - true - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-server - true - - - org.spockframework - spock-core - test - - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.boot - spring-boot-starter-web - test - - - org.springframework.boot - spring-boot-starter-webflux - test - - - org.awaitility - awaitility - test - - - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - - - diff --git a/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/eureka/StubRunnerSpringCloudEurekaAutoConfigurationSpec.groovy b/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/eureka/StubRunnerSpringCloudEurekaAutoConfigurationSpec.groovy deleted file mode 100644 index 913aa7cf13..0000000000 --- a/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/eureka/StubRunnerSpringCloudEurekaAutoConfigurationSpec.groovy +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring.cloud.eureka - -import org.springframework.cloud.netflix.eureka.http.EurekaClientHttpRequestFactorySupplier -import org.springframework.cloud.netflix.eureka.http.RestTemplateDiscoveryClientOptionalArgs -import org.springframework.cloud.netflix.eureka.http.RestTemplateTransportClientFactories - -import java.util.concurrent.TimeUnit - -import groovy.util.logging.Slf4j -import jakarta.servlet.Filter -import jakarta.servlet.FilterChain -import jakarta.servlet.FilterConfig -import jakarta.servlet.ServletException -import jakarta.servlet.ServletRequest -import jakarta.servlet.ServletResponse -import org.awaitility.Awaitility -import org.junit.jupiter.api.AfterAll -import org.junit.jupiter.api.BeforeAll -import org.junit.jupiter.api.Test - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.SpringApplication -import org.springframework.boot.autoconfigure.EnableAutoConfiguration -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.cloud.client.loadbalancer.LoadBalanced -import org.springframework.cloud.contract.stubrunner.StubFinder -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties -import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer -import org.springframework.context.ConfigurableApplicationContext -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.http.client.ClientHttpResponse -import org.springframework.web.client.DefaultResponseErrorHandler -import org.springframework.web.client.RestTemplate -/** - * @author Marcin Grzejszczak - */ -//TODO: Speed up this test somehow (move it out of Spring Cloud Contract core to samples) -@SpringBootTest(classes = Config, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - properties = ["stubrunner.cloud.eureka.enabled=true", - "stubrunner.cloud.stubbed.discovery.enabled=false", - "eureka.client.enabled=true", - "debug=true", - "eureka.instance.leaseRenewalIntervalInSeconds=1"]) -@AutoConfigureStubRunner(ids = ["org.springframework.cloud.contract.verifier.stubs:loanIssuance", - "org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer", "org.springframework.cloud.contract.verifier.stubs:bootService"] , -repositoryRoot = "classpath:m2repo/repository/" , -stubsMode = StubRunnerProperties.StubsMode.REMOTE ) -@Slf4j -class StubRunnerSpringCloudEurekaAutoConfigurationSpec { - - @Autowired - StubFinder stubFinder - - @Autowired - @LoadBalanced - RestTemplate restTemplate - - static ConfigurableApplicationContext eurekaServer - - @BeforeAll - static void setupSpec() { - System.clearProperty("stubrunner.stubs.repository.root") - System.clearProperty("stubrunner.stubs.classifier") - eurekaServer = SpringApplication.run(EurekaServer, - "--stubrunner.cloud.eureka.enabled=true", - "--stubrunner.cloud.stubbed.discovery.enabled=false", - "--eureka.client.enabled=true", - "--server.port=8761", - "--spring.profiles.active=eureka") - } - - @AfterAll - static void cleanupSpec() { - System.clearProperty("stubrunner.stubs.repository.root") - System.clearProperty("stubrunner.stubs.classifier") - } - - @Test - void 'should make service discovery work'() { - expect: 'WireMocks are running' - assert "${stubFinder.findStubUrl('loanIssuance').toString()}/name".toURL().text == 'loanIssuance' - assert "${stubFinder.findStubUrl('fraudDetectionServer').toString()}/name".toURL().text == 'fraudDetectionServer' - and: 'Stubs can be reached via load service discovery' - log.info("Waiting for stubs to register in Eureka...") - Awaitility.await() - .pollInterval(1, TimeUnit.SECONDS) - .pollDelay(10, TimeUnit.SECONDS) - .atMost(1, TimeUnit.MINUTES) - .untilAsserted(() -> { - try { - assert restTemplate.getForObject('http://loanIssuance/name', String) == 'loanIssuance' - } catch (Exception ex) { - throw new AssertionError(ex) - } - }) - assert restTemplate.getForObject('http://someNameThatShouldMapFraudDetectionServer/name', String) == 'fraudDetectionServer' - } - - @Configuration - @EnableAutoConfiguration - static class Config { - - @Bean - @LoadBalanced - RestTemplate restTemplate() { - def template = new RestTemplate() - template.errorHandler = new DefaultResponseErrorHandler() { - @Override - void handleError(ClientHttpResponse response) throws IOException { - try { - super.handleError(response) - } - catch (Exception e) { - throw new AssertionError(e) - } - } - } - return template - } - - // because eureka server has JerseyClient, need these beans for eureka client in same jvm to work - @Bean - RestTemplateDiscoveryClientOptionalArgs restTemplateDiscoveryClientOptionalArgs(EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier) { - return new RestTemplateDiscoveryClientOptionalArgs(eurekaClientHttpRequestFactorySupplier); - } - - @Bean - RestTemplateTransportClientFactories restTemplateTransportClientFactories( - RestTemplateDiscoveryClientOptionalArgs optionalArgs) { - return new RestTemplateTransportClientFactories(optionalArgs); - } - } - - @Configuration - @EnableAutoConfiguration - @EnableEurekaServer - static class EurekaServer { - - @Bean - Filter httpTraceFilter() { - return new Filter() { - @Override - void init(FilterConfig filterConfig) throws ServletException { - - } - - @Override - void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { - filterChain.doFilter(servletRequest, servletResponse) - } - - @Override - void destroy() { - - } - } - } - - - } -} diff --git a/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/application.yml b/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/application.yml deleted file mode 100644 index 2b91381a2c..0000000000 --- a/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/application.yml +++ /dev/null @@ -1,5 +0,0 @@ -stubrunner: - idsToServiceIds: - fraudDetectionServer: someNameThatShouldMapFraudDetectionServer -server: - port: 0 diff --git a/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/logback.xml b/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/logback.xml deleted file mode 100644 index 96d75b755b..0000000000 --- a/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/logback.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - diff --git a/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/0.0.1-SNAPSHOT/bootService-0.0.1-SNAPSHOT-stubs.jar b/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/0.0.1-SNAPSHOT/bootService-0.0.1-SNAPSHOT-stubs.jar deleted file mode 100644 index 7916329c40a4bdf72ab7b04c163a9c5fcc023c1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1583 zcmWIWW@h1HVBp|j&|{wF!2kqIAOZ+Df!NnI#8KDN&rP41Apk|;rh2A#(m(~0KrDi+ z(AUw=)6F$FM9W7$;qWfsl_EwJs?>Q2Aj^i9!u4p-QN!6{Rd(V1{th+lJfJj zgHlUMi}F%a4E55B^7G3oLqj+jm=8ZG4&MvJr4`%^j4a<785meVCY$yh@>9NA|eAD=Q{xc6`6Mc4J@eSr2QMl>d3wcMbPUpDr-_4)2|a&k0u_ckej+y3cLy z^%UFHx7d41>tdG0ZPl>vd=b(*m&MI~ldkrnZFiiMq^x`FiXQGXWRv{*aIWK%?UAmv z@ebRXLY0=eTzGLftnr+t@$pvY*YBqs?04}ES>nv`K>2dS?w0)Eos(ZSYfKGh2&`Ik z=|o=MpLQO;>#r+|Z;Go&cys*9@%#Ac3o9ZLwa{W4EiiKv3kovx(u+|7^U%z<9(Mcs zujK0qHO1!%+$OR$6~jl#L^VxV7*h;77oH_!CE^p(EpHu zNbCHY>ocS#^R^lWgj6U?%;!AR-PV39cKgPQ=eEtBl=}bfw%abATljt7?LE8mdCgf) zUr&~fqGc=#y{!1eC+ZhZ-0;G80&`8l#9tv1z5C*}8TZ7Q=RCT_6?+?(-F-5(-F>}wRj&*GWgW(4VG4?ei)#X>s%Rg` z-Zig*!_M}*s>Hdns}?Kn*3~ztbO^OP?^C~Se);z9-;oP$o62ozl2p$re83u9VQ0L2 zTXSCF{dYm57 zzU2IF&u4Q^_RR`$5f$=ndT`|6i&vW4qP&}5p4@k+xPh=e1p4whx#M8JR?wac6&ELI(l?hPRF&8eSNnYeO##K#DRf8ju}_!AOSW2n7$br z8n5Co0ee}&3Mnhl5;U@Vv1K{1b-)n*>-Y|6DUy5P84%gMm>Ce+y-L6kL^1*HV?x;x Z=yEJsF~FOZ4dgm@Ad~@`{FfQT0|2R$^o;-j diff --git a/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/0.0.1-SNAPSHOT/bootService-0.0.1-SNAPSHOT.pom b/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/0.0.1-SNAPSHOT/bootService-0.0.1-SNAPSHOT.pom deleted file mode 100644 index dd16575a19..0000000000 --- a/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/0.0.1-SNAPSHOT/bootService-0.0.1-SNAPSHOT.pom +++ /dev/null @@ -1,27 +0,0 @@ - - - - - 4.0.0 - org.springframework.cloud.contract.verifier.stubs - bootService - 0.0.1-SNAPSHOT - pom - diff --git a/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/maven-metadata.xml b/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/maven-metadata.xml deleted file mode 100644 index 8461d4b2a6..0000000000 --- a/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/maven-metadata.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - org.springframework.cloud.contract.verifier.stubs - bootService - 0.0.1-SNAPSHOT - - - 0.0.1-SNAPSHOT - - 20160409062112 - - diff --git a/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/0.0.1-SNAPSHOT/fraudDetectionServer-0.0.1-SNAPSHOT-stubs.jar b/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/0.0.1-SNAPSHOT/fraudDetectionServer-0.0.1-SNAPSHOT-stubs.jar deleted file mode 100644 index fdb70e383f00ec1a31fd06d81aa618347b8aa5b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1897 zcmWIWW@h1HVBp|jSmxB}!2kqIAOZ+Df!NnI#8KDN&rP41Apk|;rh2A#(m(~0KrDi+ z(AUw=)6F$FM9Q}aq3i`_uh=w%h>=Y@uFGBCR?

Ai(h6<{MwahD zlUYEPO`YKDf7pPh?fqZTiLE9AOJ5&*uI6jNTlgTP_uZB^0#VLZo0gcoT$1^!Uj3xi zi^3-YC+prG|F)Z-qmgTW_7%1hGv4Ip7?-NXu>9@sx>|Y6@ORS(h1?4TQ>#rQmmGhy z`&2onF`M?vx!ZC)*ELFVUsxaI8GW$!`OQxs|7Z$zoqXwb_0oisEj@R3M>M|AJ`~I_ zQzKv&iz%1;3*NTt=G)7^^Do}5`^e1o3HeZ_Sr<~2P( zH|KW#zDb8>96DXIt74fzkatY-vuQJwH#hIS^(%df(w-krM5KNk-@82KnLgJnc~DA1 zM2gvpoP`p=ppybdiXAzT;+J1SY`mQHJ8U4(^1hZUyEQ~W(f4%yQm%mf0)?i6tSW<( ziv-!GI;H&mEnmgsMH^J#SL~lVH|>DLl^@B0(h0%WF3i^2CiaeX@%mY}ZL|%3 zweJikKn{gkJOx;e1dsn^|PRW04*WXbl^_R{e!^wjnA)jN6SJhz{&mbWg`>|>$aKwmL3i7?|X+JN2z0s)4% zjvyLd(4lKXFX%vuL10OvCXj?{Ln`*rO#rDzE>l5#h{a_<8eW9q(*`Q*AOPgv`9LOI z8}^b9WSAT?B2rOHJ_)c{z&yv$(0GrqVff2IR!BLBRtBOw05z8*JD?aCHUxZw=>W7m lPn;W2Q#P_2m|2K)16n%AWiKlmD1_O8unOqAn?TbU7yzYKYMcN7 diff --git a/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/0.0.1-SNAPSHOT/fraudDetectionServer-0.0.1-SNAPSHOT.pom b/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/0.0.1-SNAPSHOT/fraudDetectionServer-0.0.1-SNAPSHOT.pom deleted file mode 100644 index 33e8194127..0000000000 --- a/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/0.0.1-SNAPSHOT/fraudDetectionServer-0.0.1-SNAPSHOT.pom +++ /dev/null @@ -1,27 +0,0 @@ - - - - - 4.0.0 - org.springframework.cloud.contract.verifier.stubs - fraudDetectionServer - 0.0.1-SNAPSHOT - pom - diff --git a/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/maven-metadata.xml b/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/maven-metadata.xml deleted file mode 100644 index 75dc4041ba..0000000000 --- a/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/maven-metadata.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - org.springframework.cloud.contract.verifier.stubs - fraudDetectionServer - 0.0.1-SNAPSHOT - - - 0.0.1-SNAPSHOT - - 20160409062112 - - diff --git a/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/loanIssuance/0.0.1-SNAPSHOT/loanIssuance-0.0.1-SNAPSHOT-stubs.jar b/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/loanIssuance/0.0.1-SNAPSHOT/loanIssuance-0.0.1-SNAPSHOT-stubs.jar deleted file mode 100644 index e322590636a2642f1814bfec0720ea78f93fc4ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 639 zcmWIWW@h1HVBp|jSnAa2!2kqIAOZ+Df!NnI#8KDN&rP41Apk|;rh2A#(m(~0KrDi+ z(AUw=)6F$FM9tz+^=Y@uFGB8Ii z

Ai(h6<{Mwai43=AwF(^fwV3JB2h($(?R)e8*T5VV5rQ=`&SS4)L?lj`D<@>Wga zb1^XAs-kSqs`Kuh)FKv;A - - - - 4.0.0 - org.springframework.cloud.contract.verifier.stubs - loanIssuance - 0.0.1-SNAPSHOT - pom - diff --git a/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/loanIssuance/maven-metadata.xml b/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/loanIssuance/maven-metadata.xml deleted file mode 100644 index 4533bc03e8..0000000000 --- a/tests/spring-cloud-contract-stub-runner-boot-eureka/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/loanIssuance/maven-metadata.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - org.springframework.cloud.contract.verifier.stubs - loanIssuance - 0.0.1-SNAPSHOT - - - 0.0.1-SNAPSHOT - - 20160409062111 - - diff --git a/tests/spring-cloud-contract-stub-runner-boot-zookeeper/pom.xml b/tests/spring-cloud-contract-stub-runner-boot-zookeeper/pom.xml deleted file mode 100644 index 32397f47a4..0000000000 --- a/tests/spring-cloud-contract-stub-runner-boot-zookeeper/pom.xml +++ /dev/null @@ -1,88 +0,0 @@ - - - 4.0.0 - - org.springframework.cloud - spring-cloud-contract-tests - 4.1.0-SNAPSHOT - .. - - spring-cloud-contract-stub-runner-boot-zookeeper - jar - Spring Cloud Contract Stub Runner Boot Zookeeper - Spring Cloud Contract Stub Runner Boot Zookeeper - - - org.springframework.cloud - spring-cloud-contract-stub-runner - - - org.springframework.cloud - spring-cloud-test-support - test - - - org.springframework.cloud - spring-cloud-starter-contract-stub-runner-jetty - test - - - org.springframework.cloud - spring-cloud-starter-zookeeper-discovery - true - - - junit - junit - test - - - org.apache.groovy - groovy - - - org.spockframework - spock-core - test - - - org.spockframework - spock-spring - test - - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.boot - spring-boot-starter-web - test - - - org.apache.curator - curator-test - test - - - org.springframework.boot - spring-boot-starter-webflux - test - - - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - - - diff --git a/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/zookeeper/StubRunnerSpringCloudZookeeperAutoConfigurationSpec.groovy b/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/zookeeper/StubRunnerSpringCloudZookeeperAutoConfigurationSpec.groovy deleted file mode 100644 index 39f7a16b3b..0000000000 --- a/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/zookeeper/StubRunnerSpringCloudZookeeperAutoConfigurationSpec.groovy +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.spring.cloud.zookeeper - -import org.apache.curator.test.TestingServer -import org.junit.jupiter.api.AfterAll -import org.junit.jupiter.api.BeforeAll -import org.junit.jupiter.api.Test - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.autoconfigure.EnableAutoConfiguration -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.cloud.client.discovery.EnableDiscoveryClient -import org.springframework.cloud.client.loadbalancer.LoadBalanced -import org.springframework.cloud.contract.stubrunner.StubFinder -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties -import org.springframework.cloud.test.TestSocketUtils -import org.springframework.cloud.zookeeper.ZookeeperProperties -import org.springframework.cloud.zookeeper.discovery.ZookeeperDiscoveryClient -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.web.client.RestTemplate - -/** - * @author Marcin Grzejszczak - */ -@SpringBootTest(classes = Config, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - properties = ["stubrunner.cloud.stubbed.discovery.enabled=false", - "debug=true"]) -@AutoConfigureStubRunner(ids = ["org.springframework.cloud.contract.verifier.stubs:loanIssuance", - "org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer", - "org.springframework.cloud.contract.verifier.stubs:bootService"] , repositoryRoot = "classpath:m2repo/repository/" , stubsMode = StubRunnerProperties.StubsMode.REMOTE ) -class StubRunnerSpringCloudZookeeperAutoConfigurationSpec { - - @Autowired - StubFinder stubFinder - @Autowired - @LoadBalanced - RestTemplate restTemplate - @Autowired - ZookeeperDiscoveryClient zookeeperServiceDiscovery - - @BeforeAll - static void setupSpec() { - System.clearProperty("stubrunner.stubs.repository.root") - System.clearProperty("stubrunner.stubs.classifier") - } - - @AfterAll - static void cleanupSpec() { - setupSpec() - } - - @Test - void 'should make service discovery work'() { - expect: 'WireMocks are running' - "${stubFinder.findStubUrl('loanIssuance').toString()}/name".toURL().text == 'loanIssuance' - "${stubFinder.findStubUrl('fraudDetectionServer').toString()}/name".toURL().text == 'fraudDetectionServer' - and: 'Stubs can be reached via load service discovery' - assert restTemplate.getForObject('http://loanIssuance/name', String) == 'loanIssuance' - assert restTemplate.getForObject('http://someNameThatShouldMapFraudDetectionServer/name', String) == 'fraudDetectionServer' - } - - @Test - void 'should have all apps registered in Service Discovery'() { - expect: - assert !zookeeperServiceDiscovery.getInstances('loanIssuance').empty - assert !zookeeperServiceDiscovery.getInstances('someNameThatShouldMapFraudDetectionServer').empty - } - - @Configuration - @EnableAutoConfiguration - @EnableDiscoveryClient - static class Config { - - @Bean - TestingServer testingServer() { - return new TestingServer(TestSocketUtils.findAvailableTcpPort()) - } - - @Bean - ZookeeperProperties zookeeperProperties() { - return new ZookeeperProperties(connectString: testingServer().connectString) - } - - @Bean - @LoadBalanced - RestTemplate restTemplate() { - return new RestTemplate() - } - } -} diff --git a/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/application.yml b/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/application.yml deleted file mode 100644 index 2b91381a2c..0000000000 --- a/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/application.yml +++ /dev/null @@ -1,5 +0,0 @@ -stubrunner: - idsToServiceIds: - fraudDetectionServer: someNameThatShouldMapFraudDetectionServer -server: - port: 0 diff --git a/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/logback.xml b/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/logback.xml deleted file mode 100644 index 96d75b755b..0000000000 --- a/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/logback.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - diff --git a/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/0.0.1-SNAPSHOT/bootService-0.0.1-SNAPSHOT-stubs.jar b/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/0.0.1-SNAPSHOT/bootService-0.0.1-SNAPSHOT-stubs.jar deleted file mode 100644 index 7916329c40a4bdf72ab7b04c163a9c5fcc023c1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1583 zcmWIWW@h1HVBp|j&|{wF!2kqIAOZ+Df!NnI#8KDN&rP41Apk|;rh2A#(m(~0KrDi+ z(AUw=)6F$FM9W7$;qWfsl_EwJs?>Q2Aj^i9!u4p-QN!6{Rd(V1{th+lJfJj zgHlUMi}F%a4E55B^7G3oLqj+jm=8ZG4&MvJr4`%^j4a<785meVCY$yh@>9NA|eAD=Q{xc6`6Mc4J@eSr2QMl>d3wcMbPUpDr-_4)2|a&k0u_ckej+y3cLy z^%UFHx7d41>tdG0ZPl>vd=b(*m&MI~ldkrnZFiiMq^x`FiXQGXWRv{*aIWK%?UAmv z@ebRXLY0=eTzGLftnr+t@$pvY*YBqs?04}ES>nv`K>2dS?w0)Eos(ZSYfKGh2&`Ik z=|o=MpLQO;>#r+|Z;Go&cys*9@%#Ac3o9ZLwa{W4EiiKv3kovx(u+|7^U%z<9(Mcs zujK0qHO1!%+$OR$6~jl#L^VxV7*h;77oH_!CE^p(EpHu zNbCHY>ocS#^R^lWgj6U?%;!AR-PV39cKgPQ=eEtBl=}bfw%abATljt7?LE8mdCgf) zUr&~fqGc=#y{!1eC+ZhZ-0;G80&`8l#9tv1z5C*}8TZ7Q=RCT_6?+?(-F-5(-F>}wRj&*GWgW(4VG4?ei)#X>s%Rg` z-Zig*!_M}*s>Hdns}?Kn*3~ztbO^OP?^C~Se);z9-;oP$o62ozl2p$re83u9VQ0L2 zTXSCF{dYm57 zzU2IF&u4Q^_RR`$5f$=ndT`|6i&vW4qP&}5p4@k+xPh=e1p4whx#M8JR?wac6&ELI(l?hPRF&8eSNnYeO##K#DRf8ju}_!AOSW2n7$br z8n5Co0ee}&3Mnhl5;U@Vv1K{1b-)n*>-Y|6DUy5P84%gMm>Ce+y-L6kL^1*HV?x;x Z=yEJsF~FOZ4dgm@Ad~@`{FfQT0|2R$^o;-j diff --git a/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/0.0.1-SNAPSHOT/bootService-0.0.1-SNAPSHOT.pom b/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/0.0.1-SNAPSHOT/bootService-0.0.1-SNAPSHOT.pom deleted file mode 100644 index dd16575a19..0000000000 --- a/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/0.0.1-SNAPSHOT/bootService-0.0.1-SNAPSHOT.pom +++ /dev/null @@ -1,27 +0,0 @@ - - - - - 4.0.0 - org.springframework.cloud.contract.verifier.stubs - bootService - 0.0.1-SNAPSHOT - pom - diff --git a/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/maven-metadata.xml b/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/maven-metadata.xml deleted file mode 100644 index 8461d4b2a6..0000000000 --- a/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/bootService/maven-metadata.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - org.springframework.cloud.contract.verifier.stubs - bootService - 0.0.1-SNAPSHOT - - - 0.0.1-SNAPSHOT - - 20160409062112 - - diff --git a/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/0.0.1-SNAPSHOT/fraudDetectionServer-0.0.1-SNAPSHOT-stubs.jar b/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/0.0.1-SNAPSHOT/fraudDetectionServer-0.0.1-SNAPSHOT-stubs.jar deleted file mode 100644 index fdb70e383f00ec1a31fd06d81aa618347b8aa5b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1897 zcmWIWW@h1HVBp|jSmxB}!2kqIAOZ+Df!NnI#8KDN&rP41Apk|;rh2A#(m(~0KrDi+ z(AUw=)6F$FM9Q}aq3i`_uh=w%h>=Y@uFGBCR?

Ai(h6<{MwahD zlUYEPO`YKDf7pPh?fqZTiLE9AOJ5&*uI6jNTlgTP_uZB^0#VLZo0gcoT$1^!Uj3xi zi^3-YC+prG|F)Z-qmgTW_7%1hGv4Ip7?-NXu>9@sx>|Y6@ORS(h1?4TQ>#rQmmGhy z`&2onF`M?vx!ZC)*ELFVUsxaI8GW$!`OQxs|7Z$zoqXwb_0oisEj@R3M>M|AJ`~I_ zQzKv&iz%1;3*NTt=G)7^^Do}5`^e1o3HeZ_Sr<~2P( zH|KW#zDb8>96DXIt74fzkatY-vuQJwH#hIS^(%df(w-krM5KNk-@82KnLgJnc~DA1 zM2gvpoP`p=ppybdiXAzT;+J1SY`mQHJ8U4(^1hZUyEQ~W(f4%yQm%mf0)?i6tSW<( ziv-!GI;H&mEnmgsMH^J#SL~lVH|>DLl^@B0(h0%WF3i^2CiaeX@%mY}ZL|%3 zweJikKn{gkJOx;e1dsn^|PRW04*WXbl^_R{e!^wjnA)jN6SJhz{&mbWg`>|>$aKwmL3i7?|X+JN2z0s)4% zjvyLd(4lKXFX%vuL10OvCXj?{Ln`*rO#rDzE>l5#h{a_<8eW9q(*`Q*AOPgv`9LOI z8}^b9WSAT?B2rOHJ_)c{z&yv$(0GrqVff2IR!BLBRtBOw05z8*JD?aCHUxZw=>W7m lPn;W2Q#P_2m|2K)16n%AWiKlmD1_O8unOqAn?TbU7yzYKYMcN7 diff --git a/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/0.0.1-SNAPSHOT/fraudDetectionServer-0.0.1-SNAPSHOT.pom b/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/0.0.1-SNAPSHOT/fraudDetectionServer-0.0.1-SNAPSHOT.pom deleted file mode 100644 index 33e8194127..0000000000 --- a/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/0.0.1-SNAPSHOT/fraudDetectionServer-0.0.1-SNAPSHOT.pom +++ /dev/null @@ -1,27 +0,0 @@ - - - - - 4.0.0 - org.springframework.cloud.contract.verifier.stubs - fraudDetectionServer - 0.0.1-SNAPSHOT - pom - diff --git a/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/maven-metadata.xml b/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/maven-metadata.xml deleted file mode 100644 index 75dc4041ba..0000000000 --- a/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/fraudDetectionServer/maven-metadata.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - org.springframework.cloud.contract.verifier.stubs - fraudDetectionServer - 0.0.1-SNAPSHOT - - - 0.0.1-SNAPSHOT - - 20160409062112 - - diff --git a/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/loanIssuance/0.0.1-SNAPSHOT/loanIssuance-0.0.1-SNAPSHOT-stubs.jar b/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/loanIssuance/0.0.1-SNAPSHOT/loanIssuance-0.0.1-SNAPSHOT-stubs.jar deleted file mode 100644 index e322590636a2642f1814bfec0720ea78f93fc4ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 639 zcmWIWW@h1HVBp|jSnAa2!2kqIAOZ+Df!NnI#8KDN&rP41Apk|;rh2A#(m(~0KrDi+ z(AUw=)6F$FM9tz+^=Y@uFGB8Ii z

Ai(h6<{Mwai43=AwF(^fwV3JB2h($(?R)e8*T5VV5rQ=`&SS4)L?lj`D<@>Wga zb1^XAs-kSqs`Kuh)FKv;A - - - - 4.0.0 - org.springframework.cloud.contract.verifier.stubs - loanIssuance - 0.0.1-SNAPSHOT - pom - diff --git a/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/loanIssuance/maven-metadata.xml b/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/loanIssuance/maven-metadata.xml deleted file mode 100644 index 4533bc03e8..0000000000 --- a/tests/spring-cloud-contract-stub-runner-boot-zookeeper/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/loanIssuance/maven-metadata.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - org.springframework.cloud.contract.verifier.stubs - loanIssuance - 0.0.1-SNAPSHOT - - - 0.0.1-SNAPSHOT - - 20160409062111 - - diff --git a/tests/spring-cloud-contract-stub-runner-context-path/pom.xml b/tests/spring-cloud-contract-stub-runner-context-path/pom.xml deleted file mode 100644 index 18da01ad54..0000000000 --- a/tests/spring-cloud-contract-stub-runner-context-path/pom.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - 4.0.0 - - org.springframework.cloud - spring-cloud-contract-tests - 4.1.0-SNAPSHOT - .. - - spring-cloud-contract-stub-runner-context-path - jar - Spring Cloud Contract Stub Runner With Context Path - Spring Cloud Contract Stub Runner With Context Path - - 17 - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-actuator - - - - org.springframework.cloud - spring-cloud-starter-contract-stub-runner - test - - - junit - junit - test - - - org.springframework.boot - spring-boot-starter-test - test - - - - diff --git a/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/Application.java b/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/Application.java deleted file mode 100644 index 733b271284..0000000000 --- a/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/Application.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -@SpringBootApplication -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } - -} - -@RestController -class CustomController { - - @GetMapping("/foo") - String foo() { - return "bar"; - } - -} diff --git a/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/LoanApplicationService.java b/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/LoanApplicationService.java deleted file mode 100644 index df0a6c93a8..0000000000 --- a/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/LoanApplicationService.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan; - -import com.example.loan.model.FraudCheckStatus; -import com.example.loan.model.FraudServiceRequest; -import com.example.loan.model.FraudServiceResponse; -import com.example.loan.model.LoanApplication; -import com.example.loan.model.LoanApplicationResult; -import com.example.loan.model.LoanApplicationStatus; - -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Service; -import org.springframework.web.client.RestTemplate; - -@Service -public class LoanApplicationService { - - private static final String FRAUD_SERVICE_JSON_VERSION_1 = "application/vnd.fraud.v1+json"; - - private final RestTemplate restTemplate; - - private String fraudUrl = "http://localhost:8080"; - - public LoanApplicationService() { - this.restTemplate = new RestTemplate(); - } - - public LoanApplicationResult loanApplication(LoanApplication loanApplication) { - FraudServiceRequest request = new FraudServiceRequest(loanApplication); - - FraudServiceResponse response = sendRequestToFraudDetectionService(request); - - return buildResponseFromFraudResult(response); - } - - private FraudServiceResponse sendRequestToFraudDetectionService(FraudServiceRequest request) { - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.add(HttpHeaders.CONTENT_TYPE, FRAUD_SERVICE_JSON_VERSION_1); - - // tag::client_call_server[] - ResponseEntity response = this.restTemplate.exchange(this.fraudUrl + "/fraudcheck", - HttpMethod.PUT, new HttpEntity<>(request, httpHeaders), FraudServiceResponse.class); - // end::client_call_server[] - - return response.getBody(); - } - - private LoanApplicationResult buildResponseFromFraudResult(FraudServiceResponse response) { - LoanApplicationStatus applicationStatus = null; - if (FraudCheckStatus.OK == response.getFraudCheckStatus()) { - applicationStatus = LoanApplicationStatus.LOAN_APPLIED; - } - else if (FraudCheckStatus.FRAUD == response.getFraudCheckStatus()) { - applicationStatus = LoanApplicationStatus.LOAN_APPLICATION_REJECTED; - } - - return new LoanApplicationResult(applicationStatus, response.getRejectionReason()); - } - - public void setFraudUrl(String fraudUrl) { - this.fraudUrl = fraudUrl; - } - -} diff --git a/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/Client.java b/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/Client.java deleted file mode 100644 index ca2a18364c..0000000000 --- a/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/Client.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -public class Client { - - private String clientId; - - public Client() { - } - - public Client(String clientId) { - this.clientId = clientId; - } - - public String getClientId() { - return this.clientId; - } - - public void setClientId(String clientId) { - this.clientId = clientId; - } - -} diff --git a/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/FraudCheckStatus.java b/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/FraudCheckStatus.java deleted file mode 100644 index 01f2969113..0000000000 --- a/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/FraudCheckStatus.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -public enum FraudCheckStatus { - - OK, FRAUD - -} diff --git a/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/FraudServiceRequest.java b/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/FraudServiceRequest.java deleted file mode 100644 index 0c0b78f727..0000000000 --- a/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/FraudServiceRequest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -import java.math.BigDecimal; - -public class FraudServiceRequest { - - private String clientPesel; - - private BigDecimal loanAmount; - - public FraudServiceRequest() { - } - - public FraudServiceRequest(LoanApplication loanApplication) { - this.clientPesel = loanApplication.getClient().getClientId(); - this.loanAmount = loanApplication.getAmount(); - } - - public String getClientPesel() { - return this.clientPesel; - } - - public void setClientPesel(String clientPesel) { - this.clientPesel = clientPesel; - } - - public BigDecimal getLoanAmount() { - return this.loanAmount; - } - - public void setLoanAmount(BigDecimal loanAmount) { - this.loanAmount = loanAmount; - } - -} diff --git a/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/FraudServiceResponse.java b/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/FraudServiceResponse.java deleted file mode 100644 index 4ca6dfc623..0000000000 --- a/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/FraudServiceResponse.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -public class FraudServiceResponse { - - private FraudCheckStatus fraudCheckStatus; - - private String rejectionReason; - - public FraudServiceResponse() { - } - - public FraudCheckStatus getFraudCheckStatus() { - return this.fraudCheckStatus; - } - - public void setFraudCheckStatus(FraudCheckStatus fraudCheckStatus) { - this.fraudCheckStatus = fraudCheckStatus; - } - - public String getRejectionReason() { - return this.rejectionReason; - } - - public void setRejectionReason(String rejectionReason) { - this.rejectionReason = rejectionReason; - } - -} diff --git a/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/LoanApplication.java b/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/LoanApplication.java deleted file mode 100644 index 54ae63b0fe..0000000000 --- a/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/LoanApplication.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -import java.math.BigDecimal; - -public class LoanApplication { - - private Client client; - - private BigDecimal amount; - - private String loanApplicationId; - - public LoanApplication() { - } - - public LoanApplication(Client client, double amount) { - this.client = client; - this.amount = BigDecimal.valueOf(amount); - } - - public Client getClient() { - return this.client; - } - - public void setClient(Client client) { - this.client = client; - } - - public BigDecimal getAmount() { - return this.amount; - } - - public void setAmount(BigDecimal amount) { - this.amount = amount; - } - - public String getLoanApplicationId() { - return this.loanApplicationId; - } - - public void setLoanApplicationId(String loanApplicationId) { - this.loanApplicationId = loanApplicationId; - } - -} diff --git a/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/LoanApplicationResult.java b/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/LoanApplicationResult.java deleted file mode 100644 index 80c36b0227..0000000000 --- a/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/LoanApplicationResult.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -public class LoanApplicationResult { - - private LoanApplicationStatus loanApplicationStatus; - - private String rejectionReason; - - public LoanApplicationResult() { - } - - public LoanApplicationResult(LoanApplicationStatus loanApplicationStatus, String rejectionReason) { - this.loanApplicationStatus = loanApplicationStatus; - this.rejectionReason = rejectionReason; - } - - public LoanApplicationStatus getLoanApplicationStatus() { - return this.loanApplicationStatus; - } - - public void setLoanApplicationStatus(LoanApplicationStatus loanApplicationStatus) { - this.loanApplicationStatus = loanApplicationStatus; - } - - public String getRejectionReason() { - return this.rejectionReason; - } - - public void setRejectionReason(String rejectionReason) { - this.rejectionReason = rejectionReason; - } - -} diff --git a/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/LoanApplicationStatus.java b/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/LoanApplicationStatus.java deleted file mode 100644 index 5afde21afc..0000000000 --- a/tests/spring-cloud-contract-stub-runner-context-path/src/main/java/com/example/loan/model/LoanApplicationStatus.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -public enum LoanApplicationStatus { - - LOAN_APPLIED, LOAN_APPLICATION_REJECTED - -} diff --git a/tests/spring-cloud-contract-stub-runner-context-path/src/main/resources/application.yml b/tests/spring-cloud-contract-stub-runner-context-path/src/main/resources/application.yml deleted file mode 100644 index b11d0372e2..0000000000 --- a/tests/spring-cloud-contract-stub-runner-context-path/src/main/resources/application.yml +++ /dev/null @@ -1,4 +0,0 @@ -server: - port: 0 - servlet: - context-path: /my-path diff --git a/tests/spring-cloud-contract-stub-runner-context-path/src/test/java/com/example/loan/FailFastLoanApplicationServiceTests.java b/tests/spring-cloud-contract-stub-runner-context-path/src/test/java/com/example/loan/FailFastLoanApplicationServiceTests.java deleted file mode 100644 index 88db9a47b7..0000000000 --- a/tests/spring-cloud-contract-stub-runner-context-path/src/test/java/com/example/loan/FailFastLoanApplicationServiceTests.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan; - -import org.junit.Test; -import shaded.com.google.common.collect.ImmutableMap; - -import org.springframework.beans.BeanInstantiationException; -import org.springframework.beans.factory.BeanCreationException; -import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.catchThrowable; - -/** - * @author Andrew Morgan - */ -public class FailFastLoanApplicationServiceTests { - - @Test - public void shouldFailToStartContextWhenNoStubCanBeFound() { - // When - final Throwable throwable = catchThrowable( - () -> new SpringApplicationBuilder(Application.class, StubRunnerConfiguration.class) - .properties(ImmutableMap.of("stubrunner.stubsMode", "REMOTE", "stubrunner.repositoryRoot", - "classpath:m2repo/repository/", "stubrunner.ids", - new String[] { - "org.springframework.cloud.contract.verifier.stubs:should-not-be-found" })) - .run()); - - // Then - assertThat(throwable).isInstanceOf(BeanCreationException.class); - assertThat(throwable.getCause().getCause()).isInstanceOf(BeanInstantiationException.class).hasMessageContaining( - "No stubs or contracts were found for [org.springframework.cloud.contract.verifier.stubs:should-not-be-found:+:stubs] and the switch to fail on no stubs was set."); - } - - @Test - public void shouldNotTryAndWorkOfflineWhenRemoteModeIsOn() { - // When - final Throwable throwable = catchThrowable( - () -> new SpringApplicationBuilder(Application.class, StubRunnerConfiguration.class) - .properties(ImmutableMap.of("stubrunner.stubsMode", "CLASSPATH", "stubrunner.ids", - new String[] { - "org.springframework.cloud.contract.verifier.stubs:should-not-be-found" })) - .run()); - - // Then - assertThat(throwable).isInstanceOf(BeanCreationException.class); - assertThat(throwable.getCause().getCause()).isInstanceOf(BeanInstantiationException.class) - .hasMessageContaining("No stubs were found on classpath "); - } - -} diff --git a/tests/spring-cloud-contract-stub-runner-context-path/src/test/java/com/example/loan/LoanApplicationServiceTests.java b/tests/spring-cloud-contract-stub-runner-context-path/src/test/java/com/example/loan/LoanApplicationServiceTests.java deleted file mode 100644 index 9917072cfa..0000000000 --- a/tests/spring-cloud-contract-stub-runner-context-path/src/test/java/com/example/loan/LoanApplicationServiceTests.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan; - -import com.example.loan.model.Client; -import com.example.loan.model.LoanApplication; -import com.example.loan.model.LoanApplicationResult; -import com.example.loan.model.LoanApplicationStatus; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.cloud.contract.stubrunner.StubFinder; -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.web.client.RestTemplate; - -import static org.assertj.core.api.Assertions.assertThat; - -// tag::autoconfigure_stubrunner[] -@RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -@AutoConfigureStubRunner(repositoryRoot = "classpath:m2repo/repository/", - ids = { "org.springframework.cloud.contract.verifier.stubs:contextPathFraudDetectionServer" }, - stubsMode = StubRunnerProperties.StubsMode.REMOTE) -public class LoanApplicationServiceTests { - - // end::autoconfigure_stubrunner[] - - @Value("${local.server.port}") - Integer port; - - @Autowired - private LoanApplicationService service; - - @Autowired - private StubFinder stubFinder; - - @Before - public void setPort() { - this.service.setFraudUrl( - this.stubFinder.findStubUrl("contextPathFraudDetectionServer").toString() + "/fraud-path/"); - } - - @Test - public void shouldStartThisAppWithContextPath() { - String response = new RestTemplate().getForObject("http://localhost:" + this.port + "/my-path/foo", - String.class); - - assertThat(response).isNotEmpty(); - } - - @Test - public void shouldSuccessfullyApplyForLoan() { - // given: - LoanApplication application = new LoanApplication(new Client("1234567890"), 123.123); - // when: - LoanApplicationResult loanApplication = this.service.loanApplication(application); - // then: - assertThat(loanApplication.getLoanApplicationStatus()).isEqualTo(LoanApplicationStatus.LOAN_APPLIED); - assertThat(loanApplication.getRejectionReason()).isNull(); - } - - // tag::client_tdd[] - @Test - public void shouldBeRejectedDueToAbnormalLoanAmount() { - // given: - LoanApplication application = new LoanApplication(new Client("1234567890"), 99999); - // when: - LoanApplicationResult loanApplication = this.service.loanApplication(application); - // then: - assertThat(loanApplication.getLoanApplicationStatus()) - .isEqualTo(LoanApplicationStatus.LOAN_APPLICATION_REJECTED); - assertThat(loanApplication.getRejectionReason()).isEqualTo("Amount too high"); - } - // end::client_tdd[] - -} diff --git a/tests/spring-cloud-contract-stub-runner-context-path/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/contextPathFraudDetectionServer/0.0.1-SNAPSHOT/contextPathFraudDetectionServer-0.0.1-SNAPSHOT-stubs.jar b/tests/spring-cloud-contract-stub-runner-context-path/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/contextPathFraudDetectionServer/0.0.1-SNAPSHOT/contextPathFraudDetectionServer-0.0.1-SNAPSHOT-stubs.jar deleted file mode 100644 index 5dccb5df1c57b08b2d7b93694687a22a68c57586..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1916 zcmWIWW@h1HVBp|jSmxB}!2kqIAOZ+Df!NnI#8KDN&rP41Apk|;rh2A#(m(~0KrDi+ z(AUw=)6F$FM9(go1*!b6O+x<;PC7%2UUZ9wu9CmAeuSn&qx(mP0xC)jVIc}&1Qx@YvFEV5v^--l$dAn zeD)L>oAOt8>b_5vag&LAKKUtkdqeaiHf8f8GOf99Huu&qF`ayJ`jdcz_TOyNjrRwx zwgM*sNYs=8qvqHX<@d6{08|A=jU72r z-_yH;SXWp_2slQV#?D9y2#T>jGTAG1N`3m9B@znWotlxbgcFk znL{ikb%Hr}yU#eL1kBt&Rdd@FF3%$t_of^81a$ET8C}ck)9{X5!o9x#MrTQ&DD3e1Xr3x4+X+j0YMZg3-3y6(~jg;WTN{`f> zoP0z!*#V4%O_&j}`dLswfR>l8j<2p>V9Ogxm6p0%D$JWy7ZsS4*_G#*YzF= z)d=Go71OUwy7FYwnLm3TTv@c~iqeM6n61Dh$H*kYjJvc0dJ_l)7~VR9Xn5I&t_{8H z11Sc9C5@Uu60QxYBt$m>q#C)H1@R#kmjP*bsfJG*sQ7~bkbCC?nQ(2`3qz1$a?H32 zLkX~1zzoRH(0GrqVfc$iR!Gr^RxBbr05i)YJD?I6HUxZw=>W6>0O$r#0f5I1m?<3D j4SXy_x&bY{1MLN+cMN-3*+3!84un-e-@O5v&cFZw1D1Ok diff --git a/tests/spring-cloud-contract-stub-runner-context-path/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/contextPathFraudDetectionServer/0.0.1-SNAPSHOT/contextPathFraudDetectionServer-0.0.1-SNAPSHOT.pom b/tests/spring-cloud-contract-stub-runner-context-path/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/contextPathFraudDetectionServer/0.0.1-SNAPSHOT/contextPathFraudDetectionServer-0.0.1-SNAPSHOT.pom deleted file mode 100644 index 8a90d85b9b..0000000000 --- a/tests/spring-cloud-contract-stub-runner-context-path/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/contextPathFraudDetectionServer/0.0.1-SNAPSHOT/contextPathFraudDetectionServer-0.0.1-SNAPSHOT.pom +++ /dev/null @@ -1,27 +0,0 @@ - - - - - 4.0.0 - org.springframework.cloud.contract.verifier.stubs - contextPathFraudDetectionServer - 0.0.1-SNAPSHOT - pom - diff --git a/tests/spring-cloud-contract-stub-runner-context-path/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/contextPathFraudDetectionServer/maven-metadata.xml b/tests/spring-cloud-contract-stub-runner-context-path/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/contextPathFraudDetectionServer/maven-metadata.xml deleted file mode 100644 index 415676edc9..0000000000 --- a/tests/spring-cloud-contract-stub-runner-context-path/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/contextPathFraudDetectionServer/maven-metadata.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - org.springframework.cloud.contract.verifier.stubs - contextPathFraudDetectionServer - 0.0.1-SNAPSHOT - - - 0.0.1-SNAPSHOT - - 20160409062112 - - diff --git a/tests/spring-cloud-contract-stub-runner-integration/pom.xml b/tests/spring-cloud-contract-stub-runner-integration/pom.xml deleted file mode 100644 index 58923dac65..0000000000 --- a/tests/spring-cloud-contract-stub-runner-integration/pom.xml +++ /dev/null @@ -1,75 +0,0 @@ - - - 4.0.0 - - org.springframework.cloud - spring-cloud-contract-tests - 4.1.0-SNAPSHOT - .. - - spring-cloud-contract-stub-runner-integration - jar - Spring Cloud Contract Stub Runner Integration - Spring Cloud Contract Stub Runner Integration - - 17 - - - - org.springframework.boot - spring-boot-starter-integration - - - org.springframework.cloud - spring-cloud-contract-stub-runner - - - org.springframework.cloud - spring-cloud-starter-contract-stub-runner-jetty - test - - - org.springframework.cloud - spring-cloud-contract-verifier - - - junit - junit - test - - - org.spockframework - spock-core - test - - - org.spockframework - spock-spring - test - - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.boot - spring-boot-starter-web - test - - - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - - - diff --git a/tests/spring-cloud-contract-stub-runner-integration/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/BookReturned.groovy b/tests/spring-cloud-contract-stub-runner-integration/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/BookReturned.groovy deleted file mode 100644 index 5d14aaf569..0000000000 --- a/tests/spring-cloud-contract-stub-runner-integration/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/BookReturned.groovy +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.messaging.integration - -import com.fasterxml.jackson.annotation.JsonCreator -import groovy.transform.CompileStatic -import groovy.transform.EqualsAndHashCode - -@CompileStatic -@EqualsAndHashCode -class BookReturned implements Serializable { - final String bookName - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - BookReturned(String bookName) { - this.bookName = bookName - } -} diff --git a/tests/spring-cloud-contract-stub-runner-integration/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/IntegrationStubRunnerSpec.groovy b/tests/spring-cloud-contract-stub-runner-integration/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/IntegrationStubRunnerSpec.groovy deleted file mode 100644 index 6754cd08c7..0000000000 --- a/tests/spring-cloud-contract-stub-runner-integration/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/IntegrationStubRunnerSpec.groovy +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.messaging.integration - -import java.util.concurrent.TimeUnit - -import groovy.json.JsonOutput -import groovy.json.JsonSlurper -import org.assertj.core.api.BDDAssertions -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.condition.DisabledOnOs -import org.junit.jupiter.api.condition.OS - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.autoconfigure.EnableAutoConfiguration -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.stubrunner.StubFinder -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver -import org.springframework.context.annotation.ComponentScan -import org.springframework.context.annotation.Configuration -import org.springframework.context.annotation.ImportResource -import org.springframework.messaging.Message -/** - * @author Marcin Grzejszczak - */ -@ImportResource("classpath*:integration-context.xml") -@AutoConfigureStubRunner -@SpringBootTest(classes = Config) -@DisabledOnOs(OS.WINDOWS) -class IntegrationStubRunnerSpec { - - @Autowired - StubFinder stubFinder - @Autowired - MessageVerifierReceiver> messaging - - @BeforeEach - void setup() { - // ensure that message were taken from the queue - messaging.receive('outputTest', 100, TimeUnit.MILLISECONDS) - } - - @Test - void 'should trigger a message by label'() { - when: - // tag::client_trigger[] - stubFinder.trigger('return_book_1') - // end::client_trigger[] - then: - // tag::client_trigger_receive[] - Message receivedMessage = messaging.receive('outputTest') - // end::client_trigger_receive[] - and: - // tag::client_trigger_message[] - assert receivedMessage != null - assert assertJsons(receivedMessage.payload) - assert receivedMessage.headers.get('BOOK-NAME') == 'foo' - // end::client_trigger_message[] - } - - @Test - void 'should trigger a label for the existing groupId and artifactId'() { - when: - // tag::trigger_group_artifact[] - stubFinder. - trigger('org.springframework.cloud.contract.verifier.stubs:integrationService', 'return_book_1') - // end::trigger_group_artifact[] - then: - Message receivedMessage = messaging.receive('outputTest') - and: - assert receivedMessage != null - assert assertJsons(receivedMessage.payload) - assert receivedMessage.headers.get('BOOK-NAME') == 'foo' - } - - @Test - void 'should trigger a label for the existing artifactId'() { - when: - // tag::trigger_artifact[] - stubFinder.trigger('integrationService', 'return_book_1') - // end::trigger_artifact[] - then: - Message receivedMessage = messaging.receive('outputTest') - and: - assert receivedMessage != null - assert assertJsons(receivedMessage.payload) - assert receivedMessage.headers.get('BOOK-NAME') == 'foo' - } - - @Test - void 'should throw exception when missing label is passed'() { - when: - BDDAssertions.thenThrownBy(() -> stubFinder.trigger('missing label')).isInstanceOf(IllegalArgumentException) - } - - @Test - void 'should throw exception when missing label and artifactid is passed'() { - when: - BDDAssertions.thenThrownBy(() -> stubFinder.trigger('some:service', 'return_book_1')).isInstanceOf(IllegalArgumentException) - } - - @Test - void 'should trigger messages by running all triggers'() { - when: - // tag::trigger_all[] - stubFinder.trigger() - // end::trigger_all[] - then: - Message receivedMessage = messaging.receive('outputTest') - and: - assert receivedMessage != null - assert assertJsons(receivedMessage.payload) - assert receivedMessage.headers.get('BOOK-NAME') == 'foo' - } - - private boolean assertJsons(Object payload) { - String objectAsString = payload instanceof String ? payload : - JsonOutput.toJson(payload) - def json = new JsonSlurper().parseText(objectAsString) - return json.bookName == 'foo' - } - - Contract dsl = - // tag::sample_dsl[] - Contract.make { - label 'return_book_1' - input { - triggeredBy('bookReturnedTriggered()') - } - outputMessage { - sentTo('output') - body('''{ "bookName" : "foo" }''') - headers { - header('BOOK-NAME', 'foo') - } - } - } - // end::sample_dsl[] - - @Configuration - @ComponentScan - @EnableAutoConfiguration - static class Config { - - } - -} diff --git a/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/application.yml b/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/application.yml deleted file mode 100644 index 3b928a4dad..0000000000 --- a/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/application.yml +++ /dev/null @@ -1,5 +0,0 @@ -stubrunner.repositoryRoot: classpath:m2repo/repository/ -stubrunner.ids: org.springframework.cloud.contract.verifier.stubs:integrationService:0.0.1-SNAPSHOT -stubrunner.stubs-mode: remote -server: - port: 0 diff --git a/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/integration-context.xml b/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/integration-context.xml deleted file mode 100644 index 07b0a46feb..0000000000 --- a/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/integration-context.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - diff --git a/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/0.0.1-SNAPSHOT/integrationService-0.0.1-SNAPSHOT-stubs.jar b/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/0.0.1-SNAPSHOT/integrationService-0.0.1-SNAPSHOT-stubs.jar deleted file mode 100644 index 88086ec06665220ee6b2b8840b5d4b346170dc0d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 988 zcmWIWW@h1HVBp|j&|{wF!2kqIAOZ+Df!NnI#8KDN&rP41Apk|;rh2A#(m(~0KrDi+ z(AUw=)6F$FM9W7$;qWfsl_EwJs?>QhBa+>J(j9HyT2XC`wzq#3^G{tB<1I4 z2c?#j7UiX;80w`L<>!}GhK6u5Fh6-v9DWywODnh;7+JnEGBB`!Og8O1$aTno$Km|l z@F}rIj_h%JS5{2Y?D&3h?Z&>`vmVwiDgX1V?;7rzK3!n;9o{<;pA)V=?%r|sb)VbZ z>nXOYZ?X53*2OG~+p1yT`68rsE{mJ}CSC1C+wM3iNm=*U6+PT($R_#q;atZj+aq0T z;~lm&g(@v`x$xp}SmQZOfdB!9zm8=Z~_2b76Hrv diff --git a/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/0.0.1-SNAPSHOT/integrationService-0.0.1-SNAPSHOT.pom b/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/0.0.1-SNAPSHOT/integrationService-0.0.1-SNAPSHOT.pom deleted file mode 100644 index 01cb127ce1..0000000000 --- a/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/0.0.1-SNAPSHOT/integrationService-0.0.1-SNAPSHOT.pom +++ /dev/null @@ -1,27 +0,0 @@ - - - - - 4.0.0 - org.springframework.cloud.contract.verifier.stubs - integrationService - 0.0.1-SNAPSHOT - pom - diff --git a/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/0.0.1-SNAPSHOT/maven-metadata-local.xml b/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/0.0.1-SNAPSHOT/maven-metadata-local.xml deleted file mode 100644 index 982df7b50e..0000000000 --- a/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/0.0.1-SNAPSHOT/maven-metadata-local.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - org.springframework.cloud.contract.verifier.stubs - integrationService - 0.0.1-SNAPSHOT - - - true - - 20160409062112 - - diff --git a/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/maven-metadata-local.xml b/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/maven-metadata-local.xml deleted file mode 100644 index 8fe506f0e9..0000000000 --- a/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/maven-metadata-local.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - org.springframework.cloud.contract.verifier.stubs - integrationService - 0.0.1-SNAPSHOT - - - 0.0.1-SNAPSHOT - - 20160409062112 - - diff --git a/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/maven-metadata.xml b/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/maven-metadata.xml deleted file mode 100644 index 8fe506f0e9..0000000000 --- a/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/maven-metadata.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - org.springframework.cloud.contract.verifier.stubs - integrationService - 0.0.1-SNAPSHOT - - - 0.0.1-SNAPSHOT - - 20160409062112 - - diff --git a/tests/spring-cloud-contract-stub-runner-jms/pom.xml b/tests/spring-cloud-contract-stub-runner-jms/pom.xml deleted file mode 100644 index 3ccb4f7f5c..0000000000 --- a/tests/spring-cloud-contract-stub-runner-jms/pom.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - 4.0.0 - - org.springframework.cloud - spring-cloud-contract-tests - 4.1.0-SNAPSHOT - .. - - spring-cloud-contract-stub-runner-jms - jar - Spring Cloud Contract Stub Runner JMS - Spring Cloud Contract Stub Runner JMS - - - org.springframework.boot - spring-boot-starter-artemis - - - org.apache.activemq - artemis-jms-server - - - org.springframework.cloud - spring-cloud-contract-stub-runner - test - - - org.spockframework - spock-core - test - - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.boot - spring-boot-starter-web - test - - - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - - - diff --git a/tests/spring-cloud-contract-stub-runner-jms/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/jms/BookReturned.groovy b/tests/spring-cloud-contract-stub-runner-jms/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/jms/BookReturned.groovy deleted file mode 100644 index e05d78fda9..0000000000 --- a/tests/spring-cloud-contract-stub-runner-jms/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/jms/BookReturned.groovy +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.messaging.jms - -import com.fasterxml.jackson.annotation.JsonCreator -import groovy.transform.CompileStatic -import groovy.transform.EqualsAndHashCode - -@CompileStatic -@EqualsAndHashCode -class BookReturned implements Serializable { - final String bookName - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - BookReturned(String bookName) { - this.bookName = bookName - } -} diff --git a/tests/spring-cloud-contract-stub-runner-jms/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/jms/JmsStubRunnerSpec.groovy b/tests/spring-cloud-contract-stub-runner-jms/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/jms/JmsStubRunnerSpec.groovy deleted file mode 100644 index e4356ba3e0..0000000000 --- a/tests/spring-cloud-contract-stub-runner-jms/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/jms/JmsStubRunnerSpec.groovy +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.messaging.jms - -import groovy.json.JsonOutput -import groovy.json.JsonSlurper -import jakarta.jms.JMSException -import jakarta.jms.Message -import jakarta.jms.TextMessage -import org.assertj.core.api.BDDAssertions -import org.junit.jupiter.api.AfterEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.condition.DisabledOnOs -import org.junit.jupiter.api.condition.OS - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.autoconfigure.EnableAutoConfiguration -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.stubrunner.StubFinder -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner -import org.springframework.context.annotation.ComponentScan -import org.springframework.context.annotation.Configuration -import org.springframework.jms.annotation.EnableJms -import org.springframework.jms.core.JmsTemplate -import org.springframework.jms.core.MessagePostProcessor -/** - * @author Marcin Grzejszczak - */ -@SpringBootTest(classes = Config, properties = ["debug=true"]) -@AutoConfigureStubRunner -@DisabledOnOs(OS.WINDOWS) -class JmsStubRunnerSpec { - - @Autowired - StubFinder stubFinder - @Autowired - JmsTemplate jmsTemplate - - @AfterEach - void cleanup() { - // ensure that message were taken from the queue - jmsTemplate.receive('output') - jmsTemplate.receive('input') - } - - @Test - void 'should trigger a message by label'() { - when: - // tag::client_trigger[] - stubFinder.trigger('return_book_1') - // end::client_trigger[] - then: - // tag::client_trigger_receive[] - TextMessage receivedMessage = (TextMessage) jmsTemplate.receive('output') - // end::client_trigger_receive[] - and: - // tag::client_trigger_message[] - assert receivedMessage != null - assert assertThatBodyContainsBookNameFoo(receivedMessage.getText()) - assert receivedMessage.getStringProperty('BOOKNAME') == 'foo' - // end::client_trigger_message[] - } - - @Test - void 'should trigger a label for the existing groupId and artifactId'() { - when: - // tag::trigger_group_artifact[] - stubFinder. - trigger('my:stubs', 'return_book_1') - // end::trigger_group_artifact[] - then: - TextMessage receivedMessage = (TextMessage) jmsTemplate.receive('output') - and: - assert receivedMessage != null - assert assertThatBodyContainsBookNameFoo(receivedMessage.getText()) - assert receivedMessage.getStringProperty('BOOKNAME') == 'foo' - } - - @Test - void 'should trigger a label for the existing artifactId'() { - when: - // tag::trigger_artifact[] - stubFinder.trigger('stubs', 'return_book_1') - // end::trigger_artifact[] - then: - TextMessage receivedMessage = (TextMessage) jmsTemplate.receive('output') - and: - assert receivedMessage != null - assert assertThatBodyContainsBookNameFoo(receivedMessage.getText()) - assert receivedMessage.getStringProperty('BOOKNAME') == 'foo' - } - - @Test - void 'should throw an exception when missing label is passed'() { - when: - BDDAssertions.thenThrownBy(() -> stubFinder.trigger('missing label')).isInstanceOf(IllegalArgumentException) - } - - @Test - void 'should throw an exception when missing label and artifactid is passed'() { - when: - BDDAssertions.thenThrownBy(() -> stubFinder.trigger('some:service', 'return_book_1')).isInstanceOf(IllegalArgumentException) - } - - @Test - void 'should trigger messages by running all triggers'() { - when: - // tag::trigger_all[] - stubFinder.trigger() - // end::trigger_all[] - then: - TextMessage receivedMessage = (TextMessage) jmsTemplate.receive('output') - and: - assert receivedMessage != null - assert assertThatBodyContainsBookNameFoo(receivedMessage.getText()) - assert receivedMessage.getStringProperty('BOOKNAME') == 'foo' - } - - @Test - void 'should trigger a label with no output message'() { - when: - // tag::trigger_no_output[] - jmsTemplate. - convertAndSend('delete', new BookReturned('foo'), new MessagePostProcessor() { - @Override - Message postProcessMessage(Message message) throws JMSException { - message.setStringProperty("sample", "header") - return message - } - }) - // end::trigger_no_output[] - } - - @Test - void 'should not trigger a message that does not match input'() { - when: - jmsTemplate. - convertAndSend('input', new BookReturned('notmatching'), new MessagePostProcessor() { - @Override - Message postProcessMessage(Message message) throws JMSException { - message.setStringProperty("wrong", "header") - return message - } - }) - then: - TextMessage receivedMessage = (TextMessage) jmsTemplate.receive('output') - and: - assert receivedMessage == null - } - - private boolean assertThatBodyContainsBookNameFoo(Object payload) { - String objectAsString = payload instanceof String ? payload : - JsonOutput.toJson(payload) - def json = new JsonSlurper().parseText(objectAsString) - return json.bookName == 'foo' - } - - @Configuration - @ComponentScan - @EnableAutoConfiguration - @EnableJms - static class Config { - - } - - Contract dsl = - // tag::sample_dsl[] - Contract.make { - label 'return_book_1' - input { - triggeredBy('bookReturnedTriggered()') - } - outputMessage { - sentTo('output') - body('''{ "bookName" : "foo" }''') - headers { - header('BOOKNAME', 'foo') - } - } - } - // end::sample_dsl[] -} diff --git a/tests/spring-cloud-contract-stub-runner-jms/src/test/resources/application.yml b/tests/spring-cloud-contract-stub-runner-jms/src/test/resources/application.yml deleted file mode 100644 index 2782cdc1a5..0000000000 --- a/tests/spring-cloud-contract-stub-runner-jms/src/test/resources/application.yml +++ /dev/null @@ -1,14 +0,0 @@ -stubrunner: - repository-root: stubs:classpath:/stubs/ - ids: my:stubs - stubs-mode: remote -spring: - activemq: - send-timeout: 1000 - jms: - template: - receive-timeout: 1000 -server: - port: 0 -debug: true -logging.level.org.springframework.cloud.contract: debug \ No newline at end of file diff --git a/tests/spring-cloud-contract-stub-runner-jms/src/test/resources/stubs/bookReturned1.groovy b/tests/spring-cloud-contract-stub-runner-jms/src/test/resources/stubs/bookReturned1.groovy deleted file mode 100644 index 7fc403e12f..0000000000 --- a/tests/spring-cloud-contract-stub-runner-jms/src/test/resources/stubs/bookReturned1.groovy +++ /dev/null @@ -1,13 +0,0 @@ -org.springframework.cloud.contract.spec.Contract.make { - label 'return_book_1' - input { - triggeredBy('bookReturnedTriggered()') - } - outputMessage { - sentTo('output') - body('''{ "bookName" : "foo" }''') - headers { - header('BOOKNAME', 'foo') - } - } -} diff --git a/tests/spring-cloud-contract-stub-runner-kafka/pom.xml b/tests/spring-cloud-contract-stub-runner-kafka/pom.xml deleted file mode 100644 index a9585a14dd..0000000000 --- a/tests/spring-cloud-contract-stub-runner-kafka/pom.xml +++ /dev/null @@ -1,73 +0,0 @@ - - - 4.0.0 - - org.springframework.cloud - spring-cloud-contract-tests - 4.1.0-SNAPSHOT - .. - - spring-cloud-contract-stub-runner-kafka - jar - Spring Cloud Contract Stub Runner Kafka - Spring Cloud Contract Stub Runner Kafka - - - org.springframework.cloud - spring-cloud-contract-stub-runner - - - org.springframework.cloud - spring-cloud-starter-contract-stub-runner-jetty - test - - - org.springframework.kafka - spring-kafka - - - org.springframework.kafka - spring-kafka-test - test - - - org.slf4j - slf4j-log4j12 - - - - - org.apache.groovy - groovy - - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.boot - spring-boot-starter-web - test - - - org.awaitility - awaitility - test - - - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - - - diff --git a/tests/spring-cloud-contract-stub-runner-kafka/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/kafka/BookReturned.groovy b/tests/spring-cloud-contract-stub-runner-kafka/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/kafka/BookReturned.groovy deleted file mode 100644 index 2df7166b28..0000000000 --- a/tests/spring-cloud-contract-stub-runner-kafka/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/kafka/BookReturned.groovy +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.messaging.kafka - - -import groovy.transform.CompileStatic -import groovy.transform.EqualsAndHashCode - -@CompileStatic -@EqualsAndHashCode -class BookReturned implements Serializable { - String bookName - - BookReturned(String bookName) { - this.bookName = bookName - } - - BookReturned() { - } -} diff --git a/tests/spring-cloud-contract-stub-runner-kafka/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/kafka/KafkaStubRunnerSpec.groovy b/tests/spring-cloud-contract-stub-runner-kafka/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/kafka/KafkaStubRunnerSpec.groovy deleted file mode 100644 index 14711ee956..0000000000 --- a/tests/spring-cloud-contract-stub-runner-kafka/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/kafka/KafkaStubRunnerSpec.groovy +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.messaging.kafka - -import java.util.concurrent.CountDownLatch -import java.util.concurrent.TimeUnit - -import groovy.json.JsonOutput -import groovy.json.JsonSlurper -import groovy.transform.CompileStatic -import groovy.util.logging.Commons -import org.assertj.core.api.BDDAssertions -import org.awaitility.Awaitility -import org.junit.jupiter.api.AfterEach -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.condition.DisabledOnOs -import org.junit.jupiter.api.condition.OS - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.autoconfigure.EnableAutoConfiguration -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.stubrunner.StubFinder -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner -import org.springframework.context.annotation.ComponentScan -import org.springframework.context.annotation.Configuration -import org.springframework.kafka.annotation.EnableKafka -import org.springframework.kafka.annotation.KafkaListener -import org.springframework.kafka.core.KafkaTemplate -import org.springframework.kafka.test.context.EmbeddedKafka -import org.springframework.messaging.Message -import org.springframework.messaging.MessageHeaders -import org.springframework.messaging.support.MessageBuilder -import org.springframework.stereotype.Component -/** - * @author Marcin Grzejszczak - */ -@SpringBootTest(classes = Config, properties = ["debug=true"]) -@AutoConfigureStubRunner -@DisabledOnOs(value = OS.WINDOWS) -@EmbeddedKafka(topics = ["input", "input2", "output", "delete"]) -@Commons -@Disabled("TODO: Migrate to middleware based approach") -class KafkaStubRunnerSpec { - - @Autowired - StubFinder stubFinder - @Autowired - KafkaTemplate kafkaTemplate - @Autowired - MyMessageListener myMessageListener - - @BeforeEach - @AfterEach - void setup() { - this.myMessageListener.clear() - } - - @CompileStatic - private Message receiveFromOutput() { - Message m = null - Awaitility.await().untilAsserted(() -> { - m = this.myMessageListener.output() - log.info("Received from message [" + m + "]") - assert m != null - }) - return m - } - - @CompileStatic - private Message receiveNullableMessageFromOutput() { - Message m = this.myMessageListener.output() - log.info("Received message [" + m + "]") - return m - } - - // Skipping the test on Jenkins cause it's for some reason flakey only there - @Test - void 'should download the stub and register a route for it'() { - expect: - log.info("Sending the message") - // tag::client_send[] - Message message = MessageBuilder.createMessage(new BookReturned('foo'), new MessageHeaders([sample: "header",])) - kafkaTemplate.setDefaultTopic('input') - kafkaTemplate.send(message) - // end::client_send[] - log.info("Message sent") - Awaitility.await().pollInterval(200, TimeUnit.MILLISECONDS).untilAsserted { - log.info("Receiving the message") - // tag::client_receive[] - Message receivedMessage = receiveFromOutput() - // end::client_receive[] - log.info("Message received [" + receivedMessage + "]") - // tag::client_receive_message[] - assert receivedMessage != null - assert assertThatBodyContainsBookNameFoo(receivedMessage.getPayload()) - assert receivedMessage.getHeaders().get('BOOK-NAME') == 'foo' - // end::client_receive_message[] - } - } - - @Test - void 'should propagate the Kafka record key via message headers'() { - expect: - log.info("Sending the message") - // tag::client_send[] - Message message = MessageBuilder.createMessage(new BookReturned('bar'), new MessageHeaders([kafka_messageKey: "bar5150",])) - kafkaTemplate.setDefaultTopic('input2') - kafkaTemplate.send(message) - // end::client_send[] - log.info("Message sent") - Awaitility.await().pollInterval(200, TimeUnit.MILLISECONDS).untilAsserted { - log.info("Receiving the message") - // tag::client_receive[] - Message receivedMessage = receiveFromOutput() - // end::client_receive[] - log.info("Message received [" + receivedMessage + "]") - // tag::client_receive_message[] - assert receivedMessage != null - assert assertThatBodyContainsBookName(receivedMessage.getPayload(), 'bar') - assert receivedMessage.getHeaders().get('BOOK-NAME') == 'bar' - assert receivedMessage.getHeaders().get("kafka_receivedMessageKey") == 'bar5150' - // end::client_receive_message[] - } - } - - @Test - void 'should trigger a message by label'() { - expect: - // tag::client_trigger[] - stubFinder.trigger('return_book_1') - // end::client_trigger[] - Awaitility.await().pollInterval(200, TimeUnit.MILLISECONDS).untilAsserted { - // tag::client_trigger_receive[] - Message receivedMessage = receiveFromOutput() - // end::client_trigger_receive[] - // tag::client_trigger_message[] - assert receivedMessage != null - assert assertThatBodyContainsBookNameFoo(receivedMessage.getPayload()) - assert receivedMessage.getHeaders().get('BOOK-NAME') == 'foo' - // end::client_trigger_message[] - } - } - - @Test - void 'should trigger a label for the existing groupId and artifactId'() { - expect: - // tag::trigger_group_artifact[] - stubFinder. - trigger('my:stubs', 'return_book_1') - // end::trigger_group_artifact[] - Awaitility.await().pollInterval(200, TimeUnit.MILLISECONDS).untilAsserted { - Message receivedMessage = receiveFromOutput() - assert receivedMessage != null - assert assertThatBodyContainsBookNameFoo(receivedMessage.getPayload()) - assert receivedMessage.getHeaders().get('BOOK-NAME') == 'foo' - } - } - - @Test - void 'should trigger a label for the existing artifactId'() { - expect: - // tag::trigger_artifact[] - stubFinder.trigger('stubs', 'return_book_1') - // end::trigger_artifact[] - Awaitility.await().pollInterval(200, TimeUnit.MILLISECONDS).untilAsserted { - Message receivedMessage = receiveFromOutput() - assert receivedMessage != null - assert assertThatBodyContainsBookNameFoo(receivedMessage.getPayload()) - assert receivedMessage.getHeaders().get('BOOK-NAME') == 'foo' - } - } - - @Test - void 'should throw an exception when missing label is passed'() { - expect: - BDDAssertions.thenThrownBy(() -> stubFinder.trigger('missing label')).isInstanceOf(IllegalArgumentException) - } - - @Test - void 'should throw an exception when missing label and artifactid is passed'() { - expect: - BDDAssertions.thenThrownBy(() -> stubFinder.trigger('some:service', 'return_book_1')).isInstanceOf(IllegalArgumentException) - } - - @Test - void 'should trigger messages by running all triggers'() { - expect: - // tag::trigger_all[] - stubFinder.trigger() - // end::trigger_all[] - Awaitility.await().pollInterval(200, TimeUnit.MILLISECONDS).untilAsserted { - Message receivedMessage = receiveFromOutput() - assert receivedMessage != null - assert assertThatBodyContainsBookName(receivedMessage.getPayload()) - assert receivedMessage.getHeaders().get('BOOK-NAME') != null - } - } - - @Test - void 'should trigger a label with no output message'() { - when: - // tag::trigger_no_output[] - Message message = MessageBuilder.createMessage(new BookReturned('foo'), new MessageHeaders([sample: "header",])) - kafkaTemplate.setDefaultTopic('delete') - kafkaTemplate.send(message) - // end::trigger_no_output[] - } - - @Test - void 'should not trigger a message that does not match input'() { - when: - Message message = MessageBuilder.createMessage(new BookReturned('notmatching'), new MessageHeaders([wrong: "header",])) - kafkaTemplate.setDefaultTopic('input') - kafkaTemplate.send(message) - then: - Message receivedMessage = receiveNullableMessageFromOutput() - and: - assert receivedMessage == null - } - - private boolean assertThatBodyContainsBookNameFoo(Object payload) { - return assertThatBodyContainsBookName(payload, 'foo') - } - - private boolean assertThatBodyContainsBookName(Object payload, String expectedValue) { - log.info("Got payload [" + payload + "]") - String objectAsString = payload instanceof String ? payload : - JsonOutput.toJson(payload) - def json = new JsonSlurper().parseText(objectAsString) - return json.bookName == expectedValue - } - - private boolean assertThatBodyContainsBookName(Object payload) { - log.info("Got payload [" + payload + "]") - String objectAsString = payload instanceof String ? payload : - JsonOutput.toJson(payload) - def json = new JsonSlurper().parseText(objectAsString) - return json.bookName != null - } - - @Configuration - @ComponentScan - @EnableAutoConfiguration - @EnableKafka - static class Config { - } - - @Commons - @Component - static class MyMessageListener { - - CountDownLatch latch = new CountDownLatch(1) - - Message output - - @KafkaListener(topics = ["output"]) - void output(Message message) { - log.info("I got the message [${message}]") - this.output = message - } - - void clear() { - this.output = null - } - - Message output() { - return this.output - } - } - - Contract dsl = - // tag::sample_dsl[] - Contract.make { - label 'return_book_1' - input { - triggeredBy('bookReturnedTriggered()') - } - outputMessage { - sentTo('output') - body('''{ "bookName" : "foo" }''') - headers { - header('BOOK-NAME', 'foo') - } - } - } - // end::sample_dsl[] - -} diff --git a/tests/spring-cloud-contract-stub-runner-kafka/src/test/resources/application.yml b/tests/spring-cloud-contract-stub-runner-kafka/src/test/resources/application.yml deleted file mode 100644 index 5f8b6211aa..0000000000 --- a/tests/spring-cloud-contract-stub-runner-kafka/src/test/resources/application.yml +++ /dev/null @@ -1,22 +0,0 @@ -stubrunner: - repository-root: stubs:classpath:/stubs/ - ids: my:stubs - stubs-mode: remote -spring: - kafka: - bootstrap-servers: ${spring.embedded.kafka.brokers} - producer: - key-serializer: org.apache.kafka.common.serialization.StringSerializer - value-serializer: org.springframework.kafka.support.serializer.JsonSerializer - properties: - "spring.json.trusted.packages": "*" - consumer: - key-deserializer: org.apache.kafka.common.serialization.StringDeserializer - value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer - properties: - "spring.json.trusted.packages": "*" - group-id: ${random.value} -server: - port: 0 -debug: true -logging.level.org.springframework.cloud.contract: debug \ No newline at end of file diff --git a/tests/spring-cloud-contract-stub-runner-kafka/src/test/resources/stubs/bookReturned1.groovy b/tests/spring-cloud-contract-stub-runner-kafka/src/test/resources/stubs/bookReturned1.groovy deleted file mode 100644 index 0094bc7b1d..0000000000 --- a/tests/spring-cloud-contract-stub-runner-kafka/src/test/resources/stubs/bookReturned1.groovy +++ /dev/null @@ -1,13 +0,0 @@ -org.springframework.cloud.contract.spec.Contract.make { - label 'return_book_1' - input { - triggeredBy('bookReturnedTriggered()') - } - outputMessage { - sentTo('output') - body('''{ "bookName" : "foo" }''') - headers { - header('BOOK-NAME', 'foo') - } - } -} \ No newline at end of file diff --git a/tests/spring-cloud-contract-stub-runner-moco-contract-jar/pom.xml b/tests/spring-cloud-contract-stub-runner-moco-contract-jar/pom.xml deleted file mode 100644 index be5b07c874..0000000000 --- a/tests/spring-cloud-contract-stub-runner-moco-contract-jar/pom.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - 4.0.0 - - org.springframework.cloud - spring-cloud-contract-tests - 4.1.0-SNAPSHOT - .. - - spring-cloud-contract-stub-runner-moco-contract-jar - jar - Spring Cloud Contract Stub Runner Moco Contract Jar - Spring Cloud Contract Stub Runner Moco Contract Jar - - 17 - - - - org.springframework.cloud - spring-cloud-contract-verifier - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - - maven-deploy-plugin - 2.8.2 - - false - - - - - diff --git a/tests/spring-cloud-contract-stub-runner-moco-contract-jar/src/main/resources/META-INF/com.example/fraudDetectionServerMoco/1.0.0/contracts/nested/contract2.groovy b/tests/spring-cloud-contract-stub-runner-moco-contract-jar/src/main/resources/META-INF/com.example/fraudDetectionServerMoco/1.0.0/contracts/nested/contract2.groovy deleted file mode 100644 index 437eba8000..0000000000 --- a/tests/spring-cloud-contract-stub-runner-moco-contract-jar/src/main/resources/META-INF/com.example/fraudDetectionServerMoco/1.0.0/contracts/nested/contract2.groovy +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -org.springframework.cloud.contract.spec.Contract.make { - // Human readable description - description 'Sends an order message' - // Label by means of which the output message can be triggered - label 'send_order' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('orderTrigger()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo('orders') - // any headers for the output message - headers { - header('contentType': 'application/json') - } - // the body of the output message - body( - orderId: value( - consumer('40058c70-891c-4176-a033-f70bad0c5f77'), - producer(regex('([0-9|a-f]*-*)*'))), - description: "This is the order description" - ) - } -} diff --git a/tests/spring-cloud-contract-stub-runner-moco-contract-jar/src/main/resources/META-INF/com.example/fraudDetectionServerMoco/1.0.0/mappings/nested/shouldSayBye.json b/tests/spring-cloud-contract-stub-runner-moco-contract-jar/src/main/resources/META-INF/com.example/fraudDetectionServerMoco/1.0.0/mappings/nested/shouldSayBye.json deleted file mode 100644 index d5299f5b42..0000000000 --- a/tests/spring-cloud-contract-stub-runner-moco-contract-jar/src/main/resources/META-INF/com.example/fraudDetectionServerMoco/1.0.0/mappings/nested/shouldSayBye.json +++ /dev/null @@ -1,12 +0,0 @@ -[ - { - "request": { - "method": "get", - "uri": "/bye" - }, - "response": { - "text": "bye", - "status": 200 - } - } -] diff --git a/tests/spring-cloud-contract-stub-runner-moco-contract-jar/src/main/resources/META-INF/com.example/fraudDetectionServerMoco/1.0.0/mappings/shouldSayHello.json b/tests/spring-cloud-contract-stub-runner-moco-contract-jar/src/main/resources/META-INF/com.example/fraudDetectionServerMoco/1.0.0/mappings/shouldSayHello.json deleted file mode 100644 index c4992c4352..0000000000 --- a/tests/spring-cloud-contract-stub-runner-moco-contract-jar/src/main/resources/META-INF/com.example/fraudDetectionServerMoco/1.0.0/mappings/shouldSayHello.json +++ /dev/null @@ -1,12 +0,0 @@ -[ - { - "request": { - "method": "get", - "uri": "/name" - }, - "response": { - "text": "fraudDetectionServerMoco", - "status": 200 - } - } -] diff --git a/tests/spring-cloud-contract-stub-runner-moco-contract-jar/src/main/resources/contracts/com.example/fraudDetectionServerMoco/nested/contract3.groovy b/tests/spring-cloud-contract-stub-runner-moco-contract-jar/src/main/resources/contracts/com.example/fraudDetectionServerMoco/nested/contract3.groovy deleted file mode 100644 index 507eb4b2a6..0000000000 --- a/tests/spring-cloud-contract-stub-runner-moco-contract-jar/src/main/resources/contracts/com.example/fraudDetectionServerMoco/nested/contract3.groovy +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -org.springframework.cloud.contract.spec.Contract.make { - // Human readable description - description 'Sends an order message' - // Label by means of which the output message can be triggered - label 'send_order2' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('orderTrigger()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo('orders') - // any headers for the output message - headers { - header('contentType': 'application/json') - } - // the body of the output message - body( - orderId: value( - consumer('40058c70-891c-4176-a033-f70bad0c5f77'), - producer(regex('([0-9|a-f]*-*)*'))), - description: "This is the order description" - ) - } -} diff --git a/tests/spring-cloud-contract-stub-runner-moco-contract-jar/src/main/resources/mappings/com.example/fraudDetectionServerMoco/nested/shouldSayBye2.json b/tests/spring-cloud-contract-stub-runner-moco-contract-jar/src/main/resources/mappings/com.example/fraudDetectionServerMoco/nested/shouldSayBye2.json deleted file mode 100644 index 34690b30e9..0000000000 --- a/tests/spring-cloud-contract-stub-runner-moco-contract-jar/src/main/resources/mappings/com.example/fraudDetectionServerMoco/nested/shouldSayBye2.json +++ /dev/null @@ -1,12 +0,0 @@ -[ - { - "request": { - "method": "get", - "uri": "/bye2" - }, - "response": { - "text": "bye", - "status": 200 - } - } -] diff --git a/tests/spring-cloud-contract-stub-runner-moco-contract-jar/src/main/resources/mappings/shouldSayHello2.json b/tests/spring-cloud-contract-stub-runner-moco-contract-jar/src/main/resources/mappings/shouldSayHello2.json deleted file mode 100644 index df5bd894ac..0000000000 --- a/tests/spring-cloud-contract-stub-runner-moco-contract-jar/src/main/resources/mappings/shouldSayHello2.json +++ /dev/null @@ -1,12 +0,0 @@ -[ - { - "request": { - "method": "get", - "uri": "/name2" - }, - "response": { - "text": "fraudDetectionServerMoco", - "status": 200 - } - } -] diff --git a/tests/spring-cloud-contract-stub-runner-moco/pom.xml b/tests/spring-cloud-contract-stub-runner-moco/pom.xml deleted file mode 100644 index 9a3fd9b8fd..0000000000 --- a/tests/spring-cloud-contract-stub-runner-moco/pom.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - 4.0.0 - - org.springframework.cloud - spring-cloud-contract-tests - 4.1.0-SNAPSHOT - .. - - spring-cloud-contract-stub-runner-moco - jar - Spring Cloud Contract Stub Runner Moco - Spring Cloud Contract Stub Runner Moco - - 17 - 1.3.0 - - - - org.springframework.cloud - spring-cloud-contract-stub-runner - - - com.github.dreamhead - moco-runner - ${moco-runner.version} - - - org.springframework.cloud - spring-cloud-contract-verifier - - - org.springframework.cloud - spring-cloud-contract-stub-runner-moco-contract-jar - runtime - ${project.version} - - - junit - junit - test - - - org.spockframework - spock-core - test - - - org.spockframework - spock-spring - test - - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.boot - spring-boot-starter-web - test - - - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - - - diff --git a/tests/spring-cloud-contract-stub-runner-moco/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/moco/MocoHttpServerStub.groovy b/tests/spring-cloud-contract-stub-runner-moco/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/moco/MocoHttpServerStub.groovy deleted file mode 100644 index d781f2eae9..0000000000 --- a/tests/spring-cloud-contract-stub-runner-moco/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/moco/MocoHttpServerStub.groovy +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.provider.moco - -import com.github.dreamhead.moco.bootstrap.arg.HttpArgs -import com.github.dreamhead.moco.runner.JsonRunner -import com.github.dreamhead.moco.runner.RunnerSetting -import groovy.transform.CompileStatic -import groovy.util.logging.Commons - -import org.springframework.cloud.contract.stubrunner.HttpServerStub -import org.springframework.cloud.contract.stubrunner.HttpServerStubConfiguration - -@Commons -@CompileStatic -class MocoHttpServerStub implements HttpServerStub { - - private boolean started - private JsonRunner runner - private int port - - @Override - int port() { - if (!isRunning()) { - return -1 - } - return port - } - - @Override - boolean isRunning() { - return started - } - - @Override - HttpServerStub start(HttpServerStubConfiguration configuration) { - this.port = configuration.port - return this - } - - @Override - HttpServerStub stop() { - if (!isRunning()) { - return this - } - this.runner.stop() - return this - } - - @Override - HttpServerStub registerMappings(Collection stubFiles) { - List settings = stubFiles.findAll { it.name.endsWith("json") } - .collect { - log.info("Trying to parse [${it.name}]") - try { - return RunnerSetting.aRunnerSetting().addStream(it.newInputStream()). - build() - } - catch (Exception e) { - log.warn("Exception occurred while trying to parse file [${it.name}]", e) - return null - } - }.findAll { it } - this.runner = JsonRunner.newJsonRunnerWithSetting(settings, - HttpArgs.httpArgs().withPort(this.port).build()) - this.runner.run() - this.started = true - return this - } - - @Override - String registeredMappings() { - return "" - } - - @Override - boolean isAccepted(File file) { - return file.name.endsWith(".json") - } -} diff --git a/tests/spring-cloud-contract-stub-runner-moco/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/moco/MocoHttpServerStubSpec.groovy b/tests/spring-cloud-contract-stub-runner-moco/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/moco/MocoHttpServerStubSpec.groovy deleted file mode 100644 index 8f4ffafc6f..0000000000 --- a/tests/spring-cloud-contract-stub-runner-moco/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/moco/MocoHttpServerStubSpec.groovy +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.provider.moco - -import org.assertj.core.api.BDDAssertions -import org.junit.jupiter.api.Test - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.autoconfigure.EnableAutoConfiguration -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.cloud.contract.stubrunner.StubFinder -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties -import org.springframework.context.annotation.Configuration -import org.springframework.test.context.ActiveProfiles -/** - * @author Marcin Grzejszczak - */ -// tag::[classpath_stub_runner] -@SpringBootTest(classes = MocoConfig, webEnvironment = SpringBootTest.WebEnvironment.NONE) -@AutoConfigureStubRunner(ids = ["com.example:fraudDetectionServerMoco"], - stubsMode = StubRunnerProperties.StubsMode.CLASSPATH) -// end::[classpath_stub_runner] -@ActiveProfiles("test") -class MocoHttpServerStubSpec { - - @Autowired - StubFinder stubFinder - - @Test - void 'should successfully receive a response from a stub'() { - given: - String url = stubFinder.findStubUrl('fraudDetectionServerMoco').toString() - expect: - assert "${url.toString()}/name".toURL().text == 'fraudDetectionServerMoco' - assert "${url.toString()}/bye".toURL().text == 'bye' - assert "${url.toString()}/bye2".toURL().text == 'bye' - and: - BDDAssertions.thenThrownBy(() -> "${url.toString()}/name2".toURL().text).isInstanceOf(IOException) - } - - @Configuration - @EnableAutoConfiguration - static class MocoConfig { - } - -} - diff --git a/tests/spring-cloud-contract-stub-runner-moco/src/test/resources/META-INF/spring.factories b/tests/spring-cloud-contract-stub-runner-moco/src/test/resources/META-INF/spring.factories deleted file mode 100644 index 6ffd1b43fd..0000000000 --- a/tests/spring-cloud-contract-stub-runner-moco/src/test/resources/META-INF/spring.factories +++ /dev/null @@ -1,4 +0,0 @@ -# Example of a custom HTTP Server Stub -org.springframework.cloud.contract.stubrunner.HttpServerStub=\ -org.springframework.cloud.contract.stubrunner.provider.moco.MocoHttpServerStub - diff --git a/tests/spring-cloud-contract-stub-runner-moco/src/test/resources/application-test.yaml b/tests/spring-cloud-contract-stub-runner-moco/src/test/resources/application-test.yaml deleted file mode 100644 index 64cce1aef0..0000000000 --- a/tests/spring-cloud-contract-stub-runner-moco/src/test/resources/application-test.yaml +++ /dev/null @@ -1,2 +0,0 @@ -spring: - cloud.stream.bindings.input.destination: orders diff --git a/tests/spring-cloud-contract-stub-runner-moco/src/test/resources/application.yml b/tests/spring-cloud-contract-stub-runner-moco/src/test/resources/application.yml deleted file mode 100644 index 0d7455ff18..0000000000 --- a/tests/spring-cloud-contract-stub-runner-moco/src/test/resources/application.yml +++ /dev/null @@ -1,5 +0,0 @@ -stubrunner: - idsToServiceIds: - fraudDetectionServerMoco: someNameThatShouldMapFraudDetectionServer -server: - port: 0 diff --git a/tests/spring-cloud-contract-stub-runner-moco/src/test/resources/logback.xml b/tests/spring-cloud-contract-stub-runner-moco/src/test/resources/logback.xml deleted file mode 100644 index 96d75b755b..0000000000 --- a/tests/spring-cloud-contract-stub-runner-moco/src/test/resources/logback.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - diff --git a/tests/spring-cloud-contract-stub-runner-stream/pom.xml b/tests/spring-cloud-contract-stub-runner-stream/pom.xml deleted file mode 100644 index e2435ca3b5..0000000000 --- a/tests/spring-cloud-contract-stub-runner-stream/pom.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - 4.0.0 - - org.springframework.cloud - spring-cloud-contract-tests - 4.1.0-SNAPSHOT - .. - - spring-cloud-contract-stub-runner-stream - jar - Spring Cloud Contract Stub Runner Stream - Spring Cloud Contract Stub Runner Stream - - - org.springframework.cloud - spring-cloud-starter-stream-rabbit - - - org.springframework.cloud - spring-cloud-contract-stub-runner - - - org.springframework.cloud - spring-cloud-starter-contract-stub-runner-jetty - test - - - org.springframework.cloud - spring-cloud-contract-verifier - test - - - org.springframework.cloud - spring-cloud-stream-test-binder - test - - - org.springframework.boot - spring-boot-starter-test - test - - - org.awaitility - awaitility - test - - - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - - - diff --git a/tests/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/BookReturned.groovy b/tests/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/BookReturned.groovy deleted file mode 100644 index 9db3e6411c..0000000000 --- a/tests/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/BookReturned.groovy +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.messaging.stream - -import com.fasterxml.jackson.annotation.JsonCreator -import groovy.transform.CompileStatic -import groovy.transform.EqualsAndHashCode - -@CompileStatic -@EqualsAndHashCode -class BookReturned implements Serializable { - final String bookName - - @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) - BookReturned(String bookName) { - this.bookName = bookName - } -} diff --git a/tests/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy b/tests/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy deleted file mode 100644 index 20167646a0..0000000000 --- a/tests/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner.messaging.stream - -import java.util.function.Function - -import groovy.json.JsonOutput -import groovy.json.JsonSlurper -import org.assertj.core.api.BDDAssertions -import org.awaitility.Awaitility -import org.junit.jupiter.api.Test - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.autoconfigure.EnableAutoConfiguration -import org.springframework.boot.autoconfigure.ImportAutoConfiguration -import org.springframework.boot.test.context.SpringBootContextLoader -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.stubrunner.StubFinder -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner -import org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver -import org.springframework.cloud.contract.verifier.messaging.boot.AutoConfigureMessageVerifier -import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.messaging.Message -import org.springframework.test.context.ContextConfiguration -/** - * @author Marcin Grzejszczak - */ -@ContextConfiguration(classes = Config, loader = SpringBootContextLoader) -@SpringBootTest(properties = "debug=true") -@AutoConfigureStubRunner -@AutoConfigureMessageVerifier -class StreamStubRunnerSpec { - - @Autowired - StubFinder stubFinder - @Autowired - MessageVerifierReceiver> messaging - - @Test - void 'should trigger a message by label'() { - when: - // tag::client_trigger[] - stubFinder.trigger('return_book_1') - // end::client_trigger[] - then: - Awaitility.await().untilAsserted(() -> { - // tag::client_trigger_receive[] - Message receivedMessage = messaging.receive('outputToAssertBook') - // end::client_trigger_receive[] - and: - // tag::client_trigger_message[] - assert receivedMessage != null - assertJsons(receivedMessage.payload) - assert receivedMessage.headers.get('BOOK-NAME') == 'foo' - // end::client_trigger_message[] - }); - } - - @Test - void 'should trigger a label for the existing groupId and artifactId'() { - when: - // tag::trigger_group_artifact[] - stubFinder.trigger('org.springframework.cloud.contract.verifier.stubs:streamService', 'return_book_1') - // end::trigger_group_artifact[] - then: - Message receivedMessage = messaging.receive('outputToAssertBook') - and: - assert receivedMessage != null - assertJsons(receivedMessage.payload) - assert receivedMessage.headers.get('BOOK-NAME') == 'foo' - } - - @Test - void 'should trigger a label for the existing artifactId'() { - when: - // tag::trigger_artifact[] - stubFinder.trigger('streamService', 'return_book_1') - // end::trigger_artifact[] - then: - Message receivedMessage = messaging.receive('outputToAssertBook') - and: - assert receivedMessage != null - assertJsons(receivedMessage.payload) - assert receivedMessage.headers.get('BOOK-NAME') == 'foo' - } - - @Test - void 'should throw exception when missing label is passed'() { - when: - BDDAssertions.thenThrownBy(() -> stubFinder.trigger('missing label')).isInstanceOf(IllegalArgumentException) - } - - @Test - void 'should throw exception when missing label and artifactid is passed'() { - when: - BDDAssertions.thenThrownBy(() -> stubFinder.trigger('some:service', 'return_book_1')).isInstanceOf(IllegalArgumentException) - } - - @Test - void 'should trigger messages by running all triggers'() { - when: - // tag::trigger_all[] - stubFinder.trigger() - // end::trigger_all[] - then: - Message receivedMessage = messaging.receive('outputToAssertBook') - and: - assert receivedMessage != null - assertJsons(receivedMessage.payload) - assert receivedMessage.headers.get('BOOK-NAME') == 'foo' - } - - private boolean assertJsons(Object payload) { - String objectAsString = payload instanceof String ? payload : - payload instanceof byte[] ? new String(payload) - : JsonOutput.toJson(payload) - def json = new JsonSlurper().parseText(objectAsString) - return json.bookName == 'foo' - } - - // Contract from the other service that is a producer (I'm a consumer) - Contract dsl = - // tag::sample_dsl[] - Contract.make { - label 'return_book_1' - input { triggeredBy('bookReturnedTriggered()') } - outputMessage { - sentTo('returnBook') - body('''{ "bookName" : "foo" }''') - headers { header('BOOK-NAME', 'foo') } - } - } - // end::sample_dsl[] - - // Contract from my service that is processing the input message and sending out another message (I'm a producer) - Contract myDsl = - // tag::sample_producer_dsl[] - Contract.make { - label 'return_book_2' - input { triggeredBy('gotAMessageFromFunction()') } - outputMessage { - sentTo('outputToAssertBook') - body('''{ "bookName" : "foo" }''') - headers { header('BOOK-NAME', 'foo') } - } - } - // end::sample_producer_dsl[] - - // tag::setup[] - @ImportAutoConfiguration(TestChannelBinderConfiguration.class) - @Configuration(proxyBeanMethods = true) - @EnableAutoConfiguration - protected static class Config { - - @Bean - Function test1() { - return (input) -> { - println "Test 1 [${input}]" - return input - } - } - - } - // end::setup[] - -} diff --git a/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/application.yml b/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/application.yml deleted file mode 100644 index 85438a4ff7..0000000000 --- a/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/application.yml +++ /dev/null @@ -1,18 +0,0 @@ -stubrunner.repositoryRoot: classpath:m2repo/repository/ -stubrunner.ids: org.springframework.cloud.contract.verifier.stubs:streamService:0.0.1-SNAPSHOT:stubs -stubrunner.stubs-mode: remote -spring: - cloud: - stream: - bindings: - test1-in-0: - destination: returnBook - test1-out-0: - destination: outputToAssertBook - function: - definition: test1 - -server: - port: 0 - -debug: true diff --git a/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/0.0.1-SNAPSHOT/maven-metadata-local.xml b/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/0.0.1-SNAPSHOT/maven-metadata-local.xml deleted file mode 100644 index 3b70294371..0000000000 --- a/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/0.0.1-SNAPSHOT/maven-metadata-local.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - org.springframework.cloud.contract.verifier.stubs - streamService - 0.0.1-SNAPSHOT - - - true - - 20160409062112 - - diff --git a/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/0.0.1-SNAPSHOT/streamService-0.0.1-SNAPSHOT-stubs.jar b/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/0.0.1-SNAPSHOT/streamService-0.0.1-SNAPSHOT-stubs.jar deleted file mode 100644 index 498ec1e112db9474ea6f378c7f50ae97ba891f3e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 990 zcmWIWW@h1HVBp|j&|{wF!2kqIAOZ+Df!NnI#8KDN&rP41Apk|;rh2A#(m(~0KrDi+ z(AUw=)6F$FM9W7$;qWfsl_EwJs?>QhVyNAJuY)U(B28;F*7nSXfViN)svK; zpBh)XND85mi<1C3w-nQYp3kn4~EkHh)9 z;ZtIb9NFXcT7Fas7I?onI$8GitchhEC;r_nJCj_YudisfQ+nstXD71`m={hrxAnEk zKT#Fd%P%qe&zJdZR~PAb&ytNaI2v6G - - - - 4.0.0 - org.springframework.cloud.contract.verifier.stubs - streamService - 0.0.1-SNAPSHOT - pom - diff --git a/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/maven-metadata-local.xml b/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/maven-metadata-local.xml deleted file mode 100644 index 3b08747f82..0000000000 --- a/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/maven-metadata-local.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - org.springframework.cloud.contract.verifier.stubs - streamService - 0.0.1-SNAPSHOT - - - 0.0.1-SNAPSHOT - - 20160409062112 - - diff --git a/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/maven-metadata.xml b/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/maven-metadata.xml deleted file mode 100644 index 3b08747f82..0000000000 --- a/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/maven-metadata.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - org.springframework.cloud.contract.verifier.stubs - streamService - 0.0.1-SNAPSHOT - - - 0.0.1-SNAPSHOT - - 20160409062112 - - diff --git a/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/request.pdf b/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/request.pdf deleted file mode 100644 index 69503635d87cbdfa660d5cd8be66d3e74b3b20e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14631 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 diff --git a/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/response.pdf b/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/response.pdf deleted file mode 100644 index c3b233056b758d1cc9bf3176e99a95add89ba607..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15767 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 diff --git a/samples/standalone/dsl/http-client/gradle/wrapper/gradle-wrapper.properties b/samples/standalone/dsl/http-client/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index c30b486a89..0000000000 --- a/samples/standalone/dsl/http-client/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip -networkTimeout=10000 -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/samples/standalone/dsl/http-client/gradlew b/samples/standalone/dsl/http-client/gradlew deleted file mode 100755 index aeb74cbb43..0000000000 --- a/samples/standalone/dsl/http-client/gradlew +++ /dev/null @@ -1,245 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/samples/standalone/dsl/http-client/gradlew.bat b/samples/standalone/dsl/http-client/gradlew.bat deleted file mode 100644 index 6689b85bee..0000000000 --- a/samples/standalone/dsl/http-client/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/samples/standalone/dsl/http-client/mvnw b/samples/standalone/dsl/http-client/mvnw deleted file mode 100755 index 5643201c7d..0000000000 --- a/samples/standalone/dsl/http-client/mvnw +++ /dev/null @@ -1,316 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Maven Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /usr/local/etc/mavenrc ] ; then - . /usr/local/etc/mavenrc - fi - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`\\unset -f command; \\command -v java`" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` - fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" - fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi -else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - if [ -n "$MVNW_REPOURL" ]; then - jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - else - jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - fi - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - if $cygwin; then - wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` - fi - - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - else - wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - fi - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl -o "$wrapperJarPath" "$jarUrl" -f - else - curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f - fi - - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - # For Cygwin, switch paths to Windows format before running javac - if $cygwin; then - javaClass=`cygpath --path --windows "$javaClass"` - fi - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` -fi - -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" -export MAVEN_CMD_LINE_ARGS - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -exec "$JAVACMD" \ - $MAVEN_OPTS \ - $MAVEN_DEBUG_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" \ - "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/samples/standalone/dsl/http-client/mvnw.cmd b/samples/standalone/dsl/http-client/mvnw.cmd deleted file mode 100644 index 23b7079a3d..0000000000 --- a/samples/standalone/dsl/http-client/mvnw.cmd +++ /dev/null @@ -1,188 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* -if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% ^ - %JVM_CONFIG_MAVEN_PROPS% ^ - %MAVEN_OPTS% ^ - %MAVEN_DEBUG_OPTS% ^ - -classpath %WRAPPER_JAR% ^ - "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ - %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" -if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%"=="on" pause - -if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% - -cmd /C exit /B %ERROR_CODE% diff --git a/samples/standalone/dsl/http-client/pom.xml b/samples/standalone/dsl/http-client/pom.xml deleted file mode 100644 index 7bff1c7eae..0000000000 --- a/samples/standalone/dsl/http-client/pom.xml +++ /dev/null @@ -1,253 +0,0 @@ - - - 4.0.0 - - com.example - http-client-dsl - 0.0.1 - - Spring Cloud Contract Verifier Http Client Sample - Spring Cloud Contract Verifier Http Client Sample - - - org.springframework.boot - spring-boot-starter-parent - 3.2.0-SNAPSHOT - - - - - UTF-8 - 17 - 4.1.0-SNAPSHOT - 4.1.0-SNAPSHOT - - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-actuator - - - org.apache.httpcomponents.client5 - httpclient5 - - - org.slf4j - slf4j-api - - - - - org.springframework.cloud - spring-cloud-starter-stream-rabbit - ${spring-cloud-stream.version} - - - - org.springframework.cloud - spring-cloud-stream-test-binder - ${spring-cloud-stream.version} - test - - - - - org.springframework.cloud - spring-cloud-starter-contract-stub-runner - test - - - - - - org.springframework.cloud - spring-cloud-starter-contract-verifier - test - - - - - - - - org.springframework.cloud - spring-cloud-contract-dependencies - ${spring-cloud-contract.version} - pom - import - - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - maven-deploy-plugin - 2.8.2 - - true - - - - org.apache.maven.plugins - maven-clean-plugin - 3.0.0 - - - - build - - - target - - - - - - maven-surefire-plugin - - true - - - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - spring-releases - Spring Releases - https://repo.spring.io/release - - false - - - - - - - integration - - - - org.codehaus.mojo - exec-maven-plugin - 1.6.0 - - - gradle - test - - ./gradlew - - clean - build - publishToMavenLocal - - -x - test - - -PverifierVersion=${spring-cloud-contract.version} - - - - - exec - - - - - - - - - windows - - - - org.codehaus.mojo - exec-maven-plugin - 1.6.0 - - - gradle - test - - gradlew.bat - - clean - build - publishToMavenLocal - - -x - test - - -PverifierVersion=${spring-cloud-contract.version} - - - - - exec - - - - - - - - - - diff --git a/samples/standalone/dsl/http-client/settings.gradle b/samples/standalone/dsl/http-client/settings.gradle deleted file mode 100644 index 5bf417ac54..0000000000 --- a/samples/standalone/dsl/http-client/settings.gradle +++ /dev/null @@ -1,15 +0,0 @@ -pluginManagement { - repositories { - mavenLocal() - maven { url "https://repo.spring.io/snapshot" } - maven { url "https://repo.spring.io/milestone" } -// maven { url "https://repo.spring.io/release" } - gradlePluginPortal() - } - plugins { - id "org.springframework.boot" version "${bootVersion}" - id "io.spring.dependency-management" version "1.1.3" - } -} - -rootProject.name = 'http-client-dsl-gradle' diff --git a/samples/standalone/dsl/http-client/src/main/java/com/example/loan/Application.java b/samples/standalone/dsl/http-client/src/main/java/com/example/loan/Application.java deleted file mode 100644 index 6e1c77d277..0000000000 --- a/samples/standalone/dsl/http-client/src/main/java/com/example/loan/Application.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } - -} diff --git a/samples/standalone/dsl/http-client/src/main/java/com/example/loan/Listener.java b/samples/standalone/dsl/http-client/src/main/java/com/example/loan/Listener.java deleted file mode 100644 index 51f6cd3015..0000000000 --- a/samples/standalone/dsl/http-client/src/main/java/com/example/loan/Listener.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan; - -import java.util.function.Consumer; - -import org.springframework.stereotype.Component; - -@Component("listener") -class Listener implements Consumer { - - int count = 0; - - public void logSensorData(SensorData data) { - System.out.println(data); - this.count = this.count + 1; - } - - public int getCount() { - return this.count; - } - - @Override - public void accept(SensorData sensorData) { - this.logSensorData(sensorData); - } -} diff --git a/samples/standalone/dsl/http-client/src/main/java/com/example/loan/LoanApplicationService.java b/samples/standalone/dsl/http-client/src/main/java/com/example/loan/LoanApplicationService.java deleted file mode 100644 index ad400366fb..0000000000 --- a/samples/standalone/dsl/http-client/src/main/java/com/example/loan/LoanApplicationService.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan; - -import com.example.loan.model.FraudCheckStatus; -import com.example.loan.model.FraudServiceRequest; -import com.example.loan.model.FraudServiceResponse; -import com.example.loan.model.LoanApplication; -import com.example.loan.model.LoanApplicationResult; -import com.example.loan.model.LoanApplicationStatus; -import com.example.loan.model.Response; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Service; -import org.springframework.web.client.RestTemplate; - -@Service -public class LoanApplicationService { - - private final RestTemplate restTemplate; - - private int port = 6565; - - private String prefix = ""; - - @Autowired - public LoanApplicationService(RestTemplateBuilder builder) { - this.restTemplate = builder.build(); - } - - public LoanApplicationResult loanApplication(LoanApplication loanApplication) { - FraudServiceRequest request = new FraudServiceRequest(loanApplication); - - FraudServiceResponse response = sendRequestToFraudDetectionService(request); - - return buildResponseFromFraudResult(response); - } - - private FraudServiceResponse sendRequestToFraudDetectionService( - FraudServiceRequest request) { - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); - - // tag::client_call_server[] - ResponseEntity response = restTemplate.exchange( - "http://localhost:" + port + fraudCheck(), HttpMethod.PUT, - new HttpEntity<>(request, httpHeaders), FraudServiceResponse.class); - // end::client_call_server[] - - return response.getBody(); - } - - private String fraudCheck() { - return "/" + prefix + "fraudcheck"; - } - - private LoanApplicationResult buildResponseFromFraudResult( - FraudServiceResponse response) { - LoanApplicationStatus applicationStatus = null; - if (FraudCheckStatus.OK == response.getFraudCheckStatus()) { - applicationStatus = LoanApplicationStatus.LOAN_APPLIED; - } - else if (FraudCheckStatus.FRAUD == response.getFraudCheckStatus()) { - applicationStatus = LoanApplicationStatus.LOAN_APPLICATION_REJECTED; - } - - return new LoanApplicationResult(applicationStatus, - response.getRejectionReason()); - } - - public int countAllFrauds() { - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); - ResponseEntity response = restTemplate.exchange( - "http://localhost:" + port + "/" + prefix + "frauds", HttpMethod.GET, - new HttpEntity<>(httpHeaders), Response.class); - return response.getBody().getCount(); - } - - public int countDrunks() { - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); - ResponseEntity response = restTemplate.exchange( - "http://localhost:" + port + "/"+ prefix + "drunks", HttpMethod.GET, - new HttpEntity<>(httpHeaders), Response.class); - return response.getBody().getCount(); - } - - public String getCookies() { - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.add("Cookie", "name=foo"); - httpHeaders.add("Cookie", "name2=bar"); - ResponseEntity response = restTemplate.exchange( - "http://localhost:" + port + "/" + prefix + "frauds/name", HttpMethod.GET, - new HttpEntity<>(httpHeaders), String.class); - return response.getBody(); - } - - public void setPort(int port) { - this.port = port; - } - - public void setPrefix(String prefix) { - this.prefix = prefix; - } -} diff --git a/samples/standalone/dsl/http-client/src/main/java/com/example/loan/SensorData.java b/samples/standalone/dsl/http-client/src/main/java/com/example/loan/SensorData.java deleted file mode 100644 index c2f496de97..0000000000 --- a/samples/standalone/dsl/http-client/src/main/java/com/example/loan/SensorData.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2016-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan; - -/** - * @author Marius Bogoevici - */ -public class SensorData { - - private Long id; - - private Double temperature; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Double getTemperature() { - return temperature; - } - - public void setTemperature(Double temperature) { - this.temperature = temperature; - } - -} diff --git a/samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/Client.java b/samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/Client.java deleted file mode 100644 index 8fac47b2fd..0000000000 --- a/samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/Client.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -public class Client { - - private String pesel; - - public Client() { - } - - public Client(String pesel) { - this.pesel = pesel; - } - - public String getPesel() { - return pesel; - } - - public void setPesel(String pesel) { - this.pesel = pesel; - } - -} diff --git a/samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/FraudCheckStatus.java b/samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/FraudCheckStatus.java deleted file mode 100644 index 01f2969113..0000000000 --- a/samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/FraudCheckStatus.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -public enum FraudCheckStatus { - - OK, FRAUD - -} diff --git a/samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/FraudServiceRequest.java b/samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/FraudServiceRequest.java deleted file mode 100644 index 2933acb39d..0000000000 --- a/samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/FraudServiceRequest.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -import java.math.BigDecimal; - -import com.fasterxml.jackson.annotation.JsonProperty; - -public class FraudServiceRequest { - - @JsonProperty("client.id") - private String clientId; - - private BigDecimal loanAmount; - - public FraudServiceRequest() { - } - - public FraudServiceRequest(LoanApplication loanApplication) { - this.clientId = loanApplication.getClient().getPesel(); - this.loanAmount = loanApplication.getAmount(); - } - - public String getClientId() { - return clientId; - } - - public void setClientId(String clientId) { - this.clientId = clientId; - } - - public BigDecimal getLoanAmount() { - return loanAmount; - } - - public void setLoanAmount(BigDecimal loanAmount) { - this.loanAmount = loanAmount; - } - -} diff --git a/samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/FraudServiceResponse.java b/samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/FraudServiceResponse.java deleted file mode 100644 index 1847a12483..0000000000 --- a/samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/FraudServiceResponse.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -import com.fasterxml.jackson.annotation.JsonProperty; - -public class FraudServiceResponse { - - private FraudCheckStatus fraudCheckStatus; - - @JsonProperty("rejection.reason") - private String rejectionReason; - - public FraudServiceResponse() { - } - - public FraudCheckStatus getFraudCheckStatus() { - return fraudCheckStatus; - } - - public void setFraudCheckStatus(FraudCheckStatus fraudCheckStatus) { - this.fraudCheckStatus = fraudCheckStatus; - } - - public String getRejectionReason() { - return rejectionReason; - } - - public void setRejectionReason(String rejectionReason) { - this.rejectionReason = rejectionReason; - } - -} diff --git a/samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/LoanApplication.java b/samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/LoanApplication.java deleted file mode 100644 index e2f4aa2513..0000000000 --- a/samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/LoanApplication.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -import java.math.BigDecimal; - -public class LoanApplication { - - private Client client; - - private BigDecimal amount; - - private String loanApplicationId; - - public LoanApplication() { - } - - public LoanApplication(Client client, double amount) { - this.client = client; - this.amount = BigDecimal.valueOf(amount); - } - - public Client getClient() { - return client; - } - - public void setClient(Client client) { - this.client = client; - } - - public BigDecimal getAmount() { - return amount; - } - - public void setAmount(BigDecimal amount) { - this.amount = amount; - } - - public String getLoanApplicationId() { - return loanApplicationId; - } - - public void setLoanApplicationId(String loanApplicationId) { - this.loanApplicationId = loanApplicationId; - } - -} diff --git a/samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/LoanApplicationResult.java b/samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/LoanApplicationResult.java deleted file mode 100644 index 73501084bb..0000000000 --- a/samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/LoanApplicationResult.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -public class LoanApplicationResult { - - private LoanApplicationStatus loanApplicationStatus; - - private String rejectionReason; - - public LoanApplicationResult() { - } - - public LoanApplicationResult(LoanApplicationStatus loanApplicationStatus, - String rejectionReason) { - this.loanApplicationStatus = loanApplicationStatus; - this.rejectionReason = rejectionReason; - } - - public LoanApplicationStatus getLoanApplicationStatus() { - return loanApplicationStatus; - } - - public void setLoanApplicationStatus(LoanApplicationStatus loanApplicationStatus) { - this.loanApplicationStatus = loanApplicationStatus; - } - - public String getRejectionReason() { - return rejectionReason; - } - - public void setRejectionReason(String rejectionReason) { - this.rejectionReason = rejectionReason; - } - -} diff --git a/samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/LoanApplicationStatus.java b/samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/LoanApplicationStatus.java deleted file mode 100644 index 5afde21afc..0000000000 --- a/samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/LoanApplicationStatus.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -public enum LoanApplicationStatus { - - LOAN_APPLIED, LOAN_APPLICATION_REJECTED - -} diff --git a/samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/Response.java b/samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/Response.java deleted file mode 100644 index 37ea6013e5..0000000000 --- a/samples/standalone/dsl/http-client/src/main/java/com/example/loan/model/Response.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan.model; - -public class Response { - - private int count; - - public Response(int count) { - this.count = count; - } - - public Response() { - } - - public int getCount() { - return this.count; - } - - public void setCount(int count) { - this.count = count; - } - -} diff --git a/samples/standalone/dsl/http-client/src/main/resources/application.yml b/samples/standalone/dsl/http-client/src/main/resources/application.yml deleted file mode 100644 index 2de2007e6b..0000000000 --- a/samples/standalone/dsl/http-client/src/main/resources/application.yml +++ /dev/null @@ -1,7 +0,0 @@ -server.port: 8090 -spring: - cloud: - function: - definition: listener - stream: - bindings.listener-in-0.destination: sensor_data \ No newline at end of file diff --git a/samples/standalone/dsl/http-client/src/test/java/com/example/loan/GoodbyeWorldTests.java b/samples/standalone/dsl/http-client/src/test/java/com/example/loan/GoodbyeWorldTests.java deleted file mode 100644 index 1328eba404..0000000000 --- a/samples/standalone/dsl/http-client/src/test/java/com/example/loan/GoodbyeWorldTests.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan; - -import org.junit.jupiter.api.Test; - - -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerPort; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; - -import org.springframework.web.client.RestTemplate; - -import static org.assertj.core.api.Assertions.assertThat; - -// tag::autoconfigure_stubrunner[] - -@SpringBootTest(webEnvironment = WebEnvironment.NONE) -@AutoConfigureStubRunner(ids = { - "com.example:http-server-dsl"}, - repositoryRoot = "stubs://classpath:contractsAtRuntime/", - stubsMode = StubRunnerProperties.StubsMode.LOCAL, - generateStubs = true) -public class GoodbyeWorldTests { - // end::autoconfigure_stubrunner[] - - @StubRunnerPort("http-server-dsl") - int port; - - @Test - public void shouldGenerateStubsAtRuntime() { - // when: - String response = new RestTemplate().getForObject("http://localhost:" + this.port + "/goodbye", String.class); - // then: - assertThat(response) - .isEqualTo("Goodbye World!"); - } - -} diff --git a/samples/standalone/dsl/http-client/src/test/java/com/example/loan/LoanApplicationServiceContextPathTests.java b/samples/standalone/dsl/http-client/src/test/java/com/example/loan/LoanApplicationServiceContextPathTests.java deleted file mode 100644 index f30cac7186..0000000000 --- a/samples/standalone/dsl/http-client/src/test/java/com/example/loan/LoanApplicationServiceContextPathTests.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan; - -import com.example.loan.model.Client; -import com.example.loan.model.LoanApplication; -import com.example.loan.model.LoanApplicationResult; -import com.example.loan.model.LoanApplicationStatus; -import org.junit.jupiter.api.Test; - - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; - - -import static org.assertj.core.api.Assertions.assertThat; - - -@SpringBootTest(webEnvironment = WebEnvironment.NONE, properties = "server.context-path=/app") -@AutoConfigureStubRunner(ids = { - "com.example:http-server-dsl:0.0.1:stubs:6565" }, stubsMode = StubRunnerProperties.StubsMode.LOCAL) -public class LoanApplicationServiceContextPathTests { - - @Autowired - private LoanApplicationService service; - - @Test - public void shouldSuccessfullyApplyForLoan() { - // given: - LoanApplication application = new LoanApplication(new Client("1234567890"), - 123.123); - // when: - LoanApplicationResult loanApplication = service.loanApplication(application); - // then: - assertThat(loanApplication.getLoanApplicationStatus()) - .isEqualTo(LoanApplicationStatus.LOAN_APPLIED); - assertThat(loanApplication.getRejectionReason()).isNull(); - } - - @Test - public void shouldBeRejectedDueToAbnormalLoanAmount() { - // given: - LoanApplication application = new LoanApplication(new Client("1234567890"), - 99999); - // when: - LoanApplicationResult loanApplication = service.loanApplication(application); - // then: - assertThat(loanApplication.getLoanApplicationStatus()) - .isEqualTo(LoanApplicationStatus.LOAN_APPLICATION_REJECTED); - assertThat(loanApplication.getRejectionReason()).isEqualTo("Amount too high"); - } - -} diff --git a/samples/standalone/dsl/http-client/src/test/java/com/example/loan/LoanApplicationServiceTests.java b/samples/standalone/dsl/http-client/src/test/java/com/example/loan/LoanApplicationServiceTests.java deleted file mode 100644 index 2d419b6a02..0000000000 --- a/samples/standalone/dsl/http-client/src/test/java/com/example/loan/LoanApplicationServiceTests.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan; - -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.nio.file.Files; -import java.time.Duration; - -import com.example.loan.model.Client; -import com.example.loan.model.LoanApplication; -import com.example.loan.model.LoanApplicationResult; -import com.example.loan.model.LoanApplicationStatus; -import com.jayway.jsonpath.DocumentContext; -import com.jayway.jsonpath.JsonPath; -import io.restassured.RestAssured; -import io.restassured.response.ResponseOptions; -import io.restassured.specification.RequestSpecification; -import org.assertj.core.api.BDDAssertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerPort; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.http.RequestEntity; -import org.springframework.http.ResponseEntity; -import org.springframework.web.client.RestTemplate; - -import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson; -import static org.assertj.core.api.Assertions.assertThat; - -// tag::autoconfigure_stubrunner[] - -@SpringBootTest(webEnvironment = WebEnvironment.NONE) -@AutoConfigureStubRunner(ids = { - "com.example:http-server-dsl:0.0.1:stubs"}, stubsMode = StubRunnerProperties.StubsMode.LOCAL) -public class LoanApplicationServiceTests { - - // end::autoconfigure_stubrunner[] - - @StubRunnerPort("com.example:http-server-dsl") - private int stubPort; - - @Autowired - private LoanApplicationService service; - - @BeforeEach - public void setup() { - this.service.setPrefix(""); - this.service.setPort(this.stubPort); - } - - @Test - public void shouldSuccessfullyApplyForLoan() { - // given: - LoanApplication application = new LoanApplication(new Client("1234567890"), - 123.123); - // when: - LoanApplicationResult loanApplication = service.loanApplication(application); - // then: - assertThat(loanApplication.getLoanApplicationStatus()) - .isEqualTo(LoanApplicationStatus.LOAN_APPLIED); - assertThat(loanApplication.getRejectionReason()).isNull(); - } - - // tag::client_tdd[] - @Test - public void shouldBeRejectedDueToAbnormalLoanAmount() { - // given: - LoanApplication application = new LoanApplication(new Client("1234567890"), - 99999); - // when: - LoanApplicationResult loanApplication = service.loanApplication(application); - // then: - assertThat(loanApplication.getLoanApplicationStatus()) - .isEqualTo(LoanApplicationStatus.LOAN_APPLICATION_REJECTED); - assertThat(loanApplication.getRejectionReason()).isEqualTo("Amount too high"); - } - // end::client_tdd[] - - @Test - public void shouldSuccessfullyGetAllFrauds() { - // when: - int count = service.countAllFrauds(); - // then: - assertThat(count).isGreaterThanOrEqualTo(200); - } - - @Test - public void shouldSuccessfullyGetAllDrunks() { - // when: - int count = service.countDrunks(); - // then: - assertThat(count).isEqualTo(100); - } - - // metadata - @Test - public void shouldFailToSuccessfullyGetAllDrunksDueToTimeout() { - LoanApplicationService service = new LoanApplicationService(new RestTemplateBuilder().setReadTimeout(Duration.ofSeconds(1))); - service.setPort(this.stubPort); - // when: - BDDAssertions.thenThrownBy(service::countDrunks).hasMessageContaining("Read timed out"); - } - - @Test - public void shouldSuccessfullyGetCookies() { - // when: - String cookies = service.getCookies(); - // then: - assertThat(cookies).isEqualTo("foo bar"); - } - - @Test - public void shouldSuccessfullyWorkWithMultipart() { - // given: - RequestSpecification request = RestAssured.given() - .baseUri("http://localhost:" + stubPort + "/") - .header("Content-Type", "multipart/form-data") - .multiPart("file1", "filename1", "content1".getBytes()) - .multiPart("file2", "filename1", "content2".getBytes()).multiPart("test", - "filename1", "{\n \"status\": \"test\"\n}".getBytes(), - "application/json"); - - // when: - ResponseOptions response = RestAssured.given().spec(request).post("/tests"); - - // then: - assertThat(response.statusCode()).isEqualTo(200); - assertThat(response.header("Content-Type")).matches("application/json.*"); - // and: - DocumentContext parsedJson = JsonPath.parse(response.getBody().asString()); - assertThatJson(parsedJson).field("['status']").isEqualTo("ok"); - } - - @Test - public void shouldSuccessfullyWorkWithBinary() throws IOException { - // given: - File request = new File(LoanApplicationServiceTests.class - .getResource("/binary/request.pdf").getFile()); - File response = new File(LoanApplicationServiceTests.class - .getResource("/binary/response.pdf").getFile()); - - // when: - ResponseEntity exchange = new RestTemplate() - .exchange( - RequestEntity.put(URI.create("http://localhost:" + stubPort + "/1")) - .header("Content-Type", "application/octet-stream") - .body(Files.readAllBytes(request.toPath())), - byte[].class); - - // then: - assertThat(exchange.getStatusCodeValue()).isEqualTo(200); - assertThat(exchange.getHeaders().get("Content-Type").get(0)) - .isEqualTo("application/octet-stream"); - // and: - assertThat(exchange.getBody()).isEqualTo(Files.readAllBytes(response.toPath())); - } - - - @Test - public void shouldSuccessfullyApplyForLoanForYaml() { - this.service.setPrefix("yaml"); - // given: - LoanApplication application = new LoanApplication(new Client("1234567890"), - 123.123); - // when: - LoanApplicationResult loanApplication = service.loanApplication(application); - // then: - assertThat(loanApplication.getLoanApplicationStatus()) - .isEqualTo(LoanApplicationStatus.LOAN_APPLIED); - assertThat(loanApplication.getRejectionReason()).isNull(); - } - - @Test - public void shouldBeRejectedDueToAbnormalLoanAmountForYaml() { - this.service.setPrefix("yaml"); - // given: - LoanApplication application = new LoanApplication(new Client("1234567890"), - 99999); - // when: - LoanApplicationResult loanApplication = service.loanApplication(application); - // then: - assertThat(loanApplication.getLoanApplicationStatus()) - .isEqualTo(LoanApplicationStatus.LOAN_APPLICATION_REJECTED); - assertThat(loanApplication.getRejectionReason()).isEqualTo("Amount too high"); - } - - @Test - public void shouldSuccessfullyGetAllFraudsForYaml() { - this.service.setPrefix("yaml"); - // when: - int count = service.countAllFrauds(); - // then: - assertThat(count).isGreaterThanOrEqualTo(200); - } - - // metadata - @Test - public void shouldFailToSuccessfullyGetAllDrunksDueToTimeoutForYaml() { - LoanApplicationService service = new LoanApplicationService(new RestTemplateBuilder().setReadTimeout(Duration.ofSeconds(1))); - service.setPort(this.stubPort); - service.setPrefix("yaml"); - // when: - BDDAssertions.thenThrownBy(service::countAllFrauds).hasMessageContaining("Read timed out"); - } - -} \ No newline at end of file diff --git a/samples/standalone/dsl/http-client/src/test/java/com/example/loan/MessageConsumedTests.java b/samples/standalone/dsl/http-client/src/test/java/com/example/loan/MessageConsumedTests.java deleted file mode 100644 index a581f3da18..0000000000 --- a/samples/standalone/dsl/http-client/src/test/java/com/example/loan/MessageConsumedTests.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2016-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan; - -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.ImportAutoConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.cloud.contract.stubrunner.StubTrigger; -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Marius Bogoevici - */ -@SpringBootTest(webEnvironment = WebEnvironment.NONE, properties = "spring.cloud.stream.bindings.input.destination=sensor-data", classes = {MessageConsumedTests.Config.class, Application.class}) -@AutoConfigureStubRunner(ids = "com.example:http-server-dsl:0.0.1", stubsMode = StubRunnerProperties.StubsMode.LOCAL) -public class MessageConsumedTests { - - @Autowired - StubTrigger stubTrigger; - - @Autowired - Listener listener; - - @Test - public void testMessageConsumed() throws Exception { - int count = this.listener.getCount(); - stubTrigger.trigger("sensor1"); - assertThat(this.listener.getCount()).isEqualTo(count + 1); - } - - @TestConfiguration - @ImportAutoConfiguration(TestChannelBinderConfiguration.class) - static class Config { - - } -} diff --git a/samples/standalone/dsl/http-client/src/test/java/com/example/loan/TestControllerTests.java b/samples/standalone/dsl/http-client/src/test/java/com/example/loan/TestControllerTests.java deleted file mode 100644 index 01f0ff4b41..0000000000 --- a/samples/standalone/dsl/http-client/src/test/java/com/example/loan/TestControllerTests.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.loan; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - - -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerPort; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.http.ResponseEntity; - -import org.springframework.web.client.RestTemplate; - -import static org.assertj.core.api.Assertions.assertThat; - -// tag::autoconfigure_stubrunner[] - -@SpringBootTest(webEnvironment = WebEnvironment.NONE) -@AutoConfigureStubRunner(ids = { - "com.example:http-server-dsl:0.0.1:stubs:6565"}, stubsMode = StubRunnerProperties.StubsMode.LOCAL) -@Disabled("TODO: Need to fix java parsing") -public class TestControllerTests { - // end::autoconfigure_stubrunner[] - - @StubRunnerPort("http-server-dsl") - int port; - - @Test - public void should_work_with_java_dsl() { - // when: - ResponseEntity response = new RestTemplate() - .getForEntity("http://localhost:" + this.port + "/example", String.class); - // then: - assertThat(response.getStatusCodeValue()).isEqualTo(200); - } - -} diff --git a/samples/standalone/dsl/http-client/src/test/resources/application-gradle.yaml b/samples/standalone/dsl/http-client/src/test/resources/application-gradle.yaml deleted file mode 100644 index 3de9f8be98..0000000000 --- a/samples/standalone/dsl/http-client/src/test/resources/application-gradle.yaml +++ /dev/null @@ -1,3 +0,0 @@ -stubrunner: - stubs-mode: local - stubs.ids: 'com.example:http-server-dsl-gradle:+:stubs:6565' diff --git a/samples/standalone/dsl/http-client/src/test/resources/application-test-repo.yaml b/samples/standalone/dsl/http-client/src/test/resources/application-test-repo.yaml deleted file mode 100644 index 512cbc68e7..0000000000 --- a/samples/standalone/dsl/http-client/src/test/resources/application-test-repo.yaml +++ /dev/null @@ -1,3 +0,0 @@ -stubrunner: - ids: 'com.example:http-server-dsl:+:stubs:8080' - repositoryRoot: https://repo.spring.io/libs-snapshot diff --git a/samples/standalone/dsl/http-client/src/test/resources/application.yaml b/samples/standalone/dsl/http-client/src/test/resources/application.yaml deleted file mode 100644 index 78a78e6fa6..0000000000 --- a/samples/standalone/dsl/http-client/src/test/resources/application.yaml +++ /dev/null @@ -1,5 +0,0 @@ -server: - port: 6565 -logging: - level: - org.springframework.cloud.contract: debug diff --git a/samples/standalone/dsl/http-client/src/test/resources/binary/request.pdf b/samples/standalone/dsl/http-client/src/test/resources/binary/request.pdf deleted file mode 100644 index 69503635d87cbdfa660d5cd8be66d3e74b3b20e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14631 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 diff --git a/samples/standalone/dsl/http-client/src/test/resources/binary/response.pdf b/samples/standalone/dsl/http-client/src/test/resources/binary/response.pdf deleted file mode 100644 index c3b233056b758d1cc9bf3176e99a95add89ba607..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15767 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

omEMx;XC*w+_GfbLVbr$D&}6) z~`ztu?@@8<{rnj-b{fU$$AwTOO_cs_=QIjIKx46UR_Gu?QE;Vgp#EaBPW}>>MnNJ+&AYxIuju;!2aA0$;ZdUELW9s ze=(9yyKK#>6&8yv`MrrnST4nOVVzUUMW@ixU$Pw&-Tlo(qXX%j)uO;5f`DDt*}i3P zD6FI4pie=(HF;{E$mB^MAz!W+=7j*@wkCC)%8`m!3Ta)*D%V#!C|BG=(4xhT`AB6< z>42#%w;_TnpK|`rNW+PP5t$#%!CA(lyzXKHRPU0AKMtZ!OQYI=7Lehm-KkK$p&K$H5Iycv@LHCIm#fNV4ZYKvinBJ$)qHqUkhKxhEm^rLr$t>LGBm0m zA)qkQ7>fbnSE2>UGmCT-ub01Lt*8Nnw$Tqv<)cz9O$2OxQ##tbQe_`@1MzJW*1ObD zZt!^^>?13Leagm^LwKZ6zEBs90_?M}=J~C1I(k?(G=oJdRP#AcTJ|Lv^9c9WZ zt!Bf8J_y=+bC@SKt$a(=g(b!?X7{=WF=kfl&)^Aa8c-AP^$~4UA*S~d*#qGeZ2tAD zvs~?hJ&;hQ08h<9I(Ev{2AMa?fpS+|MBkaE?M*{}5Klscu@d7K(`bvbRN%f*CM "myService" "artifactId" -> "myOtherService" -|stubrunner.integration.enabled | `+++true+++` | Whether to enable Stub Runner integration with Spring Integration. -|stubrunner.jms.enabled | `+++true+++` | Whether to enable Stub Runner integration with Spring JMS. -|stubrunner.kafka.enabled | `+++true+++` | Whether to enable Stub Runner integration with Spring Kafka. -|stubrunner.kafka.initializer.enabled | `+++true+++` | Whether to allow Stub Runner to take care of polling for messages instead of the KafkaStubMessages component. The latter should be used only on the producer side. -|stubrunner.mappings-output-folder | | Dumps the mappings of each HTTP server to the selected folder. -|stubrunner.max-port | `+++15000+++` | Max value of a port for the automatically started WireMock server. -|stubrunner.min-port | `+++10000+++` | Min value of a port for the automatically started WireMock server. -|stubrunner.password | | Repository password. -|stubrunner.properties | | Map of properties that can be passed to custom {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder}. -|stubrunner.proxy-host | | Repository proxy host. -|stubrunner.proxy-port | | Repository proxy port. -|stubrunner.server-id | | -|stubrunner.stream.enabled | `+++true+++` | Whether to enable Stub Runner integration with Spring Cloud Stream. -|stubrunner.stubs-mode | | Pick where the stubs should come from. -|stubrunner.stubs-per-consumer | `+++false+++` | Should only stubs for this particular consumer get registered in HTTP server stub. -|stubrunner.username | | Repository username. -|wiremock.placeholders.enabled | `+++true+++` | Flag to indicate that http URLs in generated wiremock stubs should be filtered to add or resolve a placeholder for a dynamic port. -|wiremock.reset-mappings-after-each-test | `+++false+++` | -|wiremock.rest-template-ssl-enabled | `+++false+++` | -|wiremock.server.files | `+++[]+++` | -|wiremock.server.https-port | `+++-1+++` | -|wiremock.server.https-port-dynamic | `+++false+++` | -|wiremock.server.port | `+++8080+++` | -|wiremock.server.port-dynamic | `+++false+++` | -|wiremock.server.stubs | `+++[]+++` | - -|=== diff --git a/docs/modules/ROOT/pages/_index.adoc b/docs/modules/ROOT/pages/_index.adoc deleted file mode 100644 index b2a57fca62..0000000000 --- a/docs/modules/ROOT/pages/_index.adoc +++ /dev/null @@ -1,18 +0,0 @@ -[[spring-cloud-contract-reference-documentation]] -= Spring Cloud Contract Reference Documentation -:page-section-summary-toc: 1 -Adam Dudczak, Mathias Düsterhöft, Marcin Grzejszczak, Dennis Kieselhorst, Jakub Kubryński, Karol Lassak, Olga Maciaszek-Sharma, Mariusz Smykuła, Dave Syer, Jay Bryant - -:docinfo: shared - -The reference documentation consists of the following sections: - -[horizontal] -<> :: Legal information. -<> :: About the Documentation, Getting Help, First Steps, and more. -xref:getting-started.adoc[Getting Started] :: Introducing {project-full-name}, Developing Your First {project-full-name}-based Application -xref:using.adoc[Using {project-full-name}] :: {project-full-name} usage examples and workflows. -xref:project-features.adoc[{project-full-name} Features] :: Contract DSL, Messaging, Spring Cloud Contract Stub Runner, and Spring Cloud Contract WireMock. -xref:project-features.adoc#features-build-tools[Build Tools] :: Maven Plugin, Gradle Plugin, and Docker. -xref:howto.adoc["`How-to`" Guides] :: Stubs versioning, Debugging, and more. -<> :: Properties, Metadata, Configuration, Dependencies, and more. diff --git a/docs/modules/ROOT/pages/_index_pdf.adoc b/docs/modules/ROOT/pages/_index_pdf.adoc deleted file mode 100644 index 07072dfaa3..0000000000 --- a/docs/modules/ROOT/pages/_index_pdf.adoc +++ /dev/null @@ -1,6 +0,0 @@ -[[spring-cloud-contract-reference-documentation]] -= Spring Cloud Contract Reference Documentation -:page-section-summary-toc: 1 -Adam Dudczak, Mathias Düsterhöft, Marcin Grzejszczak, Dennis Kieselhorst, Jakub Kubryński, Karol Lassak, Olga Maciaszek-Sharma, Mariusz Smykuła, Dave Syer, Jay Bryant - - diff --git a/docs/modules/ROOT/pages/_index_single.adoc b/docs/modules/ROOT/pages/_index_single.adoc deleted file mode 100644 index 332ec80b0b..0000000000 --- a/docs/modules/ROOT/pages/_index_single.adoc +++ /dev/null @@ -1,7 +0,0 @@ -[[spring-cloud-contract-reference-documentation]] -= Spring Cloud Contract Reference Documentation -:page-section-summary-toc: 1 -Adam Dudczak, Mathias Düsterhöft, Marcin Grzejszczak, Dennis Kieselhorst, Jakub Kubryński, Karol Lassak, Olga Maciaszek-Sharma, Mariusz Smykuła, Dave Syer, Jay Bryant - -:docinfo: shared - diff --git a/docs/modules/ROOT/pages/_project-features-contract.adoc b/docs/modules/ROOT/pages/_project-features-contract.adoc deleted file mode 100644 index e5dbd42061..0000000000 --- a/docs/modules/ROOT/pages/_project-features-contract.adoc +++ /dev/null @@ -1,50 +0,0 @@ -[[contract-dsl]] -= Contract DSL - - -Spring Cloud Contract supports DSLs written in the following languages: - -* Groovy -* YAML -* Java -* Kotlin - -TIP: Spring Cloud Contract supports defining multiple contracts in a single file (In Groovy return a list instead of a single contract). - -The following example shows a contract definition: - -==== -[source,groovy,indent=0,subs="verbatim,attributes",role="primary"] -.Groovy ----- -include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SpringTestMethodBodyBuildersSpec.groovy[tags=dsl_example,indent=0] ----- - -[source,yml,indent=0,subs="verbatim,attributes",role="secondary"] -.YAML ----- -include::{verifier_core_path}/src/test/resources/yml/contract_rest.yml[indent=0] ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Java ----- -include::{verifier_core_path}/src/test/resources/contractsToCompile/contract_rest.java[tags=class,indent=0] ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.Kotlin ----- -include::{verifier_core_path}/src/test/resources/kotlin/contract_rest.kts[tags=class,indent=0] ----- -==== - -[TIP] -==== -You can compile contracts to stubs mapping by using the following standalone Maven command: - ----- -mvn org.springframework.cloud:spring-cloud-contract-maven-plugin:convert ----- -==== - diff --git a/docs/modules/ROOT/pages/_project-features-contract/common-top-elements.adoc b/docs/modules/ROOT/pages/_project-features-contract/common-top-elements.adoc deleted file mode 100644 index dcf8fc1b48..0000000000 --- a/docs/modules/ROOT/pages/_project-features-contract/common-top-elements.adoc +++ /dev/null @@ -1,305 +0,0 @@ -[[contract-common-top-elements]] -= Common Top-Level Elements - -The following sections describe the most common top-level elements: - -* xref:_project-features-contract/common-top-elements.adoc#contract-dsl-description[Description] -* xref:_project-features-contract/common-top-elements.adoc#contract-dsl-name[Name] -* xref:_project-features-contract/common-top-elements.adoc#contract-dsl-ignoring-contracts[Ignoring Contracts] -* xref:_project-features-contract/common-top-elements.adoc#contract-dsl-in-progress[Contracts in Progress] -* xref:_project-features-contract/common-top-elements.adoc#contract-dsl-passing-values-from-files[Passing Values from Files] -* xref:_project-features-contract/common-top-elements.adoc#contract-dsl-metadata[Metadata] - -[[contract-dsl-description]] -== Description - -You can add a `description` to your contract. The description is arbitrary text. The -following code shows an example: - -==== -[source,groovy,indent=0,role="primary"] -.Groovy ----- -include:../:{contract_spec_tests_path}/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy[tags=description,indent=0] ----- - -[source,yaml,indent=0,role="secondary"] -.YAML ----- -include:../:{verifier_core_path}/src/test/resources/yml/contract_rest.yml[indent=0] ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Java ----- -include:../:{verifier_core_path}/src/test/resources/contractsToCompile/contract_rest_with_tags.java[tags=description,indent=0] ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.Kotlin ----- -include:../:{contract_kotlin_spec_path}/src/test/kotlin/org/springframework/cloud/contract/spec/ContractTests.kt[tags=description,indent=0] ----- -==== - -[[contract-dsl-name]] -== Name - -You can provide a name for your contract. Assume that you provide the following name: -`should register a user`. If you do so, the name of the autogenerated test is -`validate_should_register_a_user`. Also, the name of the stub in a WireMock stub is -`should_register_a_user.json`. - -IMPORTANT: You must ensure that the name does not contain any characters that make the -generated test not compile. Also, remember that, if you provide the same name for -multiple contracts, your autogenerated tests fail to compile and your generated stubs -override each other. - -The following example shows how to add a name to a contract: - -==== -[source,groovy,indent=0,role="primary"] -.Groovy ----- -include:../:{contract_spec_tests_path}/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy[tags=name,indent=0] ----- - -[source,yaml,indent=0,role="secondary"] -.YAML ----- -include:../:{verifier_core_path}/src/test/resources/yml/contract.yml[tags=name,indent=0] ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Java ----- -include:../:{verifier_core_path}/src/test/resources/contractsToCompile/contract_rest_with_tags.java[tags=name,indent=0] ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.Kotlin ----- -include:../:{contract_kotlin_spec_path}/src/test/kotlin/org/springframework/cloud/contract/spec/ContractTests.kt[tags=name,indent=0] ----- -==== - -[[contract-dsl-ignoring-contracts]] -== Ignoring Contracts - -If you want to ignore a contract, you can either set a value for ignored contracts in the -plugin configuration or set the `ignored` property on the contract itself. The following -example shows how to do so: - -==== -[source,groovy,indent=0,role="primary"] -.Groovy ----- -include:../:{contract_spec_tests_path}/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy[tags=ignored,indent=0] ----- - -[source,yaml,indent=0,role="secondary"] -.YAML ----- -include:../:{verifier_core_path}/src/test/resources/yml/contract.yml[tags=ignored,indent=0] ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Java ----- -include:../:{verifier_core_path}/src/test/resources/contractsToCompile/contract_rest_with_tags.java[tags=ignored,indent=0] ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.Kotlin ----- -include:../:{contract_kotlin_spec_path}/src/test/kotlin/org/springframework/cloud/contract/spec/ContractTests.kt[tags=ignored,indent=0] ----- -==== - -[[contract-dsl-in-progress]] -== Contracts in Progress - -A contract in progress does not generate tests on the producer side but does allow generation of stubs. - -IMPORTANT: Use this feature with caution as it may lead to false positives, because you generate stubs for your consumers to use without actually having the implementation in place. - -If you want to set a contract in progress, the following -example shows how to do so: - -==== -[source,groovy,indent=0,role="primary"] -.Groovy ----- -include:../:{contract_spec_tests_path}/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy[tags=in_progress,indent=0] ----- - -[source,yaml,indent=0,role="secondary"] -.YAML ----- -include:../:{verifier_core_path}/src/test/resources/yml/contract.yml[tags=in_progress,indent=0] ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Java ----- -include:../:{verifier_core_path}/src/test/resources/contractsToCompile/contract_rest_with_tags.java[tags=in_progress,indent=0] ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.Kotlin ----- -include:../:{contract_kotlin_spec_path}/src/test/kotlin/org/springframework/cloud/contract/spec/ContractTests.kt[tags=in_progress,indent=0] ----- -==== - -You can set the value of the `failOnInProgress` Spring Cloud Contract plugin property to ensure that your build breaks when at least one contract in progress remains in your sources. - -[[contract-dsl-passing-values-from-files]] -== Passing Values from Files - -Starting with version `1.2.0`, you can pass values from files. Assume that you have the -following resources in your project: - -[source,bash,indent=0] ----- -└── src -    └── test -       └── resources -          └── contracts -    ├── readFromFile.groovy -    ├── request.json -    └── response.json ----- - -Further assume that your contract is as follows: - -==== -[source,groovy,indent=0,role="primary"] -.Groovy ----- -include:../:{verifier_core_path}/src/test/resources/classpath/readFromFile.groovy[indent=0] ----- - -[source,yaml,indent=0,role="secondary"] -.YAML ----- -include:../:{verifier_core_path}/src/test/resources/yml/contract_from_file.yml[indent=0] ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Java ----- -include:../:{verifier_core_path}/src/test/resources/contractsToCompile/contract_rest_from_file.java[tags=class,indent=0] ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.Kotlin ----- -include:../:{verifier_core_path}/src/test/resources/kotlin/readFromFile.kts[tags=class,indent=0] ----- -==== - -Further assume that the JSON files are as follows: - -==== -[source,json,indent=0,subs="verbatim,attributes",role="primary"] -.request.json ----- -include:../:{verifier_core_path}/src/test/resources/classpath/request.json[indent=0] ----- - -[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] -.response.json ----- -include:../:{verifier_core_path}/src/test/resources/classpath/response.json[indent=0] ----- -==== - -When test or stub generation takes place, the contents of the `request.json` and `response.json` files are passed to the body -of a request or a response. The name of the file needs to be a file in a location -relative to the folder in which the contract resides. - -If you need to pass the contents of a file in binary form, -you can use the `fileAsBytes` method in the coded DSL or a `bodyFromFileAsBytes` field in YAML. - -The following example shows how to pass the contents of binary files: - -==== -[source,groovy,indent=0,role="primary"] -.Groovy ----- -include:../:{verifier_core_path}/src/test/resources/body_builder/worksWithPdf.groovy[indent=0] ----- - -[source,yaml,indent=0,role="secondary"] -.YAML ----- -include:../:{verifier_core_path}/src/test/resources/yml/contract_pdf.yml[indent=0] ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Java ----- -include:../:{verifier_core_path}/src/test/resources/contractsToCompile/contract_rest_from_pdf.java[tags=class,indent=0] ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.Kotlin ----- -include:../:{contract_kotlin_spec_path}/src/test/resources/contracts/shouldWorkWithBinaryPayload.kts[tags=class,indent=0] ----- -==== - -IMPORTANT: You should use this approach whenever you want to work with binary payloads, -both for HTTP and messaging. - -[[contract-dsl-metadata]] -== Metadata - -You can add `metadata` to your contract. Via the metadata you can pass in configuration to extensions. Below you can find -an example of using the `wiremock` key. Its value is a map whose key is `stubMapping` and value being WireMock's `StubMapping` object. Spring Cloud Contract is able to -patch parts of your generated stub mapping with your custom code. You may want to do that in order to add webhooks, custom -delays or integrate with third party WireMock extensions. - -==== -[source,groovy,indent=0,role="primary"] -.groovy ----- -include:../:{standalone_samples_path}/http-server/src/test/resources/contracts/fraud/shouldReturnFraudStats.groovy[tags=metadata,indent=0] ----- - -[source,yaml,indent=0,role="secondary"] -.yml ----- -include:../:{standalone_samples_path}/http-server/src/test/resources/contracts/yml/fraud/shouldReturnFraudStats.yml[tags=metadata,indent=0] ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.java ----- -include:../:{verifier_core_path}/src/test/resources/contractsToCompile/contract_rest_with_tags.java[tags=metadata,indent=0] ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.kotlin ----- -include:../:{contract_kotlin_spec_path}/src/test/kotlin/org/springframework/cloud/contract/spec/ContractTests.kt[tags=metadata,indent=0] ----- -==== - -In the following sections you can find examples of the supported metadata entries. - -//// -include:../:{project-root}/docs/target/metadata.adoc[indent=0] -//// - -[[features-http]] -= Contracts for HTTP - -Spring Cloud Contract lets you verify applications that use REST or HTTP as a -means of communication. Spring Cloud Contract verifies that, for a request that matches the -criteria from the `request` part of the contract, the server provides a response that is in -keeping with the `response` part of the contract. Subsequently, the contracts are used to -generate WireMock stubs that, for any request matching the provided criteria, provide a -suitable response. - diff --git a/docs/modules/ROOT/pages/_project-features-contract/dsl-async.adoc b/docs/modules/ROOT/pages/_project-features-contract/dsl-async.adoc deleted file mode 100644 index c1763f0314..0000000000 --- a/docs/modules/ROOT/pages/_project-features-contract/dsl-async.adoc +++ /dev/null @@ -1,134 +0,0 @@ -[[contract-dsl-async]] -= Asynchronous Support - -If you use asynchronous communication on the server side (your controllers are -returning `Callable`, `DeferredResult`, and so on), then, inside your contract, you must -provide an `async()` method in the `response` section. The following code shows an example: - -==== -[source,groovy,indent=0,subs="verbatim,attributes",role="primary"] -.Groovy ----- -org.springframework.cloud.contract.spec.Contract.make { - request { - method GET() - url '/get' - } - response { - status OK() - body 'Passed' - async() - } -} ----- - -[source,yml,indent=0,subs="verbatim,attributes",role="secondary"] -.YAML ----- -response: - async: true ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Java ----- -class contract implements Supplier> { - - @Override - public Collection get() { - return Collections.singletonList(Contract.make(c -> { - c.request(r -> { - // ... - }); - c.response(r -> { - r.async(); - // ... - }); - })); - } - -} ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.Kotlin ----- -import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract - -contract { - request { - // ... - } - response { - async = true - // ... - } -} ----- -==== - -You can also use the `fixedDelayMilliseconds` method or property to add delay to your stubs. -The following example shows how to do so: - -==== -[source,groovy,indent=0,subs="verbatim,attributes",role="primary"] -.Groovy ----- -org.springframework.cloud.contract.spec.Contract.make { - request { - method GET() - url '/get' - } - response { - status 200 - body 'Passed' - fixedDelayMilliseconds 1000 - } -} ----- - -[source,yml,indent=0,subs="verbatim,attributes",role="secondary"] -.YAML ----- -response: - fixedDelayMilliseconds: 1000 ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Java ----- -class contract implements Supplier> { - - @Override - public Collection get() { - return Collections.singletonList(Contract.make(c -> { - c.request(r -> { - // ... - }); - c.response(r -> { - r.fixedDelayMilliseconds(1000); - // ... - }); - })); - } - -} ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.Kotlin ----- -import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract - -contract { - request { - // ... - } - response { - delay = fixedMilliseconds(1000) - // ... - } -} ----- -==== - diff --git a/docs/modules/ROOT/pages/_project-features-contract/dsl-dynamic-properties.adoc b/docs/modules/ROOT/pages/_project-features-contract/dsl-dynamic-properties.adoc deleted file mode 100644 index 0a38b44f02..0000000000 --- a/docs/modules/ROOT/pages/_project-features-contract/dsl-dynamic-properties.adoc +++ /dev/null @@ -1,797 +0,0 @@ -[[contract-dsl-dynamic-properties]] -= Dynamic properties - -The contract can contain some dynamic properties: timestamps, IDs, and so on. You do not -want to force the consumers to stub their clocks to always return the same value of time -so that it gets matched by the stub. - -For the Groovy DSL, you can provide the dynamic parts in your contracts -in two ways: pass them directly in the body or set them in a separate section called -`bodyMatchers`. - -NOTE: Before 2.0.0, these were set by using `testMatchers` and `stubMatchers`. -See the https://github.com/spring-cloud/spring-cloud-contract/wiki/Spring-Cloud-Contract-2.0-Migration-Guide[migration guide] for more information. - -For YAML, you can use only the `matchers` section. - -IMPORTANT: Entries inside the `matchers` must reference existing elements of the payload. For more information, see https://github.com/spring-cloud/spring-cloud-contract/issues/722[this issue]. - -[[contract-dsl-dynamic-properties-in-body]] -== Dynamic Properties inside the Body - -IMPORTANT: This section is valid only for the Coded DSL (Groovy, Java, and so on). See the -xref:_project-features-contract/dsl-dynamic-properties.adoc#contract-dsl-matchers[Dynamic Properties in the Matchers Sections] section for YAML examples of a similar feature. - -You can set the properties inside the body either with the `value` method or, if you use -the Groovy map notation, with `$()`. The following example shows how to set dynamic -properties with the value method: - -==== -[source,groovy,indent=0,subs="verbatim,attributes",role="primary"] -.value ----- -value(consumer(...), producer(...)) -value(c(...), p(...)) -value(stub(...), test(...)) -value(client(...), server(...)) ----- - -[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] -.$ ----- -$(consumer(...), producer(...)) -$(c(...), p(...)) -$(stub(...), test(...)) -$(client(...), server(...)) ----- -==== - -Both approaches work equally well. The `stub` and `client` methods are aliases over the `consumer` -method. Subsequent sections take a closer look at what you can do with those values. - -[[contract-dsl-regex]] -== Regular Expressions - -IMPORTANT: This section is valid only for the Groovy DSL. See the -xref:_project-features-contract/dsl-dynamic-properties.adoc#contract-dsl-matchers[Dynamic Properties in the Matchers Sections] section for YAML examples of a similar feature. - -You can use regular expressions to write your requests in the contract DSL. Doing so is -particularly useful when you want to indicate that a given response should be provided -for requests that follow a given pattern. Also, you can use regular expressions when you -need to use patterns and not exact values both for your tests and your server-side tests. - -Make sure that regex matches a whole region of a sequence, as, internally, -https://docs.oracle.com/javase/8/docs/api/java/util/regex/Matcher.html#matches[`Pattern.matches()`] -is called. For instance, `abc` does not match `aabc`, but `.abc` does. -There are several additional xref:_project-features-contract/dsl-dynamic-properties.adoc#contract-dsl-regex-limitations[known limitations] as well. - -The following example shows how to use regular expressions to write a request: - -==== -[source,groovy,indent=0,role="primary"] -.Groovy ----- -include:../:{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=regex,indent=0] ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Java ----- -include:../:{verifier_core_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=regex,indent=0] ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.Kotlin ----- -include:../:{verifier_core_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=regex,indent=0] ----- -==== - -You can also provide only one side of the communication with a regular expression. If you -do so, then the contract engine automatically provides the generated string that matches -the provided regular expression. The following code shows an example for Groovy: - -[source,groovy,indent=0] ----- -include:../:{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SpringTestMethodBodyBuildersSpec.groovy[tags=dsl_one_side_data_generation_example,indent=0] ----- - -In the preceding example, the opposite side of the communication has the respective data -generated for request and response. - -Spring Cloud Contract comes with a series of predefined regular expressions that you can -use in your contracts, as the following example shows: - -[source,java,indent=0] ----- -include:../:{contract_spec_path}/src/main/java/org/springframework/cloud/contract/spec/internal/RegexPatterns.java[tags=regexps,indent=0] ----- - -In your contract, you can use it as follows (example for the Groovy DSL): - -[source,groovy,indent=0] ----- -include:../:{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SpringTestMethodBodyBuildersSpec.groovy[tags=contract_with_regex,indent=0] ----- - -To make matters even simpler, you can use a set of predefined objects that automatically -assume that you want a regular expression to be passed. -All of those methods start with the `any` prefix, as follows: - -[source,java,indent=0] ----- -include:../:{contract_spec_path}/src/main/java/org/springframework/cloud/contract/spec/internal/RegexCreatingProperty.java[tags=regex_creating_props,indent=0] ----- - -The following example shows how you can reference those methods: - -==== -[source,groovy,indent=0,role="primary"] -.Groovy ----- -include:../:{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy[tags=regex_creating_props,indent=0] ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.Kotlin ----- -include:../:{verifier_core_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=regex_creating_props,indent=0] ----- -==== - -[[contract-dsl-regex-limitations]] -=== Limitations - -CAUTION: Due to certain limitations of the `Xeger` library that generates a string out of -a regex, do not use the `$` and `^` signs in your regex if you rely on automatic -generation. See https://github.com/spring-cloud/spring-cloud-contract/issues/899[Issue 899]. - -CAUTION: Do not use a `LocalDate` instance as a value for `$` (for example, `$(consumer(LocalDate.now()))`). -It causes a `java.lang.StackOverflowError`. Use `$(consumer(LocalDate.now().toString()))` instead. -See https://github.com/spring-cloud/spring-cloud-contract/issues/900[Issue 900]. - -[[contract-dsl-optional-params]] -== Passing Optional Parameters - -IMPORTANT: This section is valid only for Groovy DSL. See the -xref:_project-features-contract/dsl-dynamic-properties.adoc#contract-dsl-matchers[Dynamic Properties in the Matchers Sections] section for YAML examples of a similar feature. - -You can provide optional parameters in your contract. However, you can provide -optional parameters only for the following: - -* The STUB side of the Request -* The TEST side of the Response - -The following example shows how to provide optional parameters: - -==== -[source,groovy,indent=0,role="primary"] -.Groovy ----- -include:../:{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=optionals,indent=0] ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Java ----- -include:../:{verifier_core_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=optionals,indent=0] ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.Kotlin ----- -include:../:{verifier_core_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=optionals,indent=0] ----- -==== - -By wrapping a part of the body with the `optional()` method, you create a regular -expression that must be present 0 or more times. - -If you use Spock, the following test would be generated from the previous example: - -==== -[source,groovy,indent=0] -.Groovy ----- -include:../:{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=optionals_test,indent=0] ----- -==== - -The following stub would also be generated: - -[source,groovy,indent=0] ----- -include:../:{plugins_path}/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverterSpec.groovy[tags=wiremock,indent=0] ----- - -[[contract-dsl-custom-methods]] -== Calling Custom Methods on the Server Side - -IMPORTANT: This section is valid only for the Groovy DSL. See the -xref:_project-features-contract/dsl-dynamic-properties.adoc#contract-dsl-matchers[Dynamic Properties in the Matchers Sections] section for YAML examples of a similar feature. - -You can define a method call that runs on the server side during the test. Such a -method can be added to the class defined as `baseClassForTests` in the configuration. The -following code shows an example of the contract portion of the test case: - -==== -[source,groovy,indent=0,role="primary"] -.Groovy ----- -include:../:{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=method,indent=0] ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Java ----- -include:../:{verifier_core_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=method,indent=0] ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.Kotlin ----- -include:../:{verifier_core_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=method,indent=0] ----- -==== - -The following code shows the base class portion of the test case: - -[source,groovy,indent=0] ----- -include:../:{plugins_path}/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/src/test/groovy/org/springframework/cloud/contract/verifier/twitter/places/BaseMockMvcSpec.groovy[tags=base_class,indent=0] ----- - -IMPORTANT: You cannot use both a `String` and `execute` to perform concatenation. For -example, calling `header('Authorization', 'Bearer ' + execute('authToken()'))` leads to -improper results. Instead, call `header('Authorization', execute('authToken()'))` and -ensure that the `authToken()` method returns everything you need. - -The type of the object read from the JSON can be one of the following, depending on the -JSON path: - -* `String`: If you point to a `String` value in the JSON. -* `JSONArray`: If you point to a `List` in the JSON. -* `Map`: If you point to a `Map` in the JSON. -* `Number`: If you point to `Integer`, `Double`, and other numeric type in the JSON. -* `Boolean`: If you point to a `Boolean` in the JSON. - -In the request part of the contract, you can specify that the `body` should be taken from -a method. - -IMPORTANT: You must provide both the consumer and the producer side. The `execute` part -is applied for the whole body, not for parts of it. - -The following example shows how to read an object from JSON: - -[source,groovy,indent=0] ----- -include:../:{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilderSpec.groovy[tags=body_execute,indent=0] ----- - -The preceding example results in calling the `hashCode()` method in the request body. -It should resemble the following code: - -[source,java,indent=0] ----- - // given: - MockMvcRequestSpecification request = given() - .body(hashCode()); - - // when: - ResponseOptions response = given().spec(request) - .get("/something"); - - // then: - assertThat(response.statusCode()).isEqualTo(200); ----- - -[[contract-dsl-referencing-request-from-response]] -== Referencing the Request from the Response - -The best situation is to provide fixed values, but sometimes you need to reference a -request in your response. - -If you write contracts in the Groovy DSL, you can use the `fromRequest()` method, which lets -you reference a bunch of elements from the HTTP request. You can use the following -options: - -* `fromRequest().url()`: Returns the request URL and query parameters. -* `fromRequest().query(String key)`: Returns the first query parameter with the given name. -* `fromRequest().query(String key, int index)`: Returns the nth query parameter with the -given name. -* `fromRequest().path()`: Returns the full path. -* `fromRequest().path(int index)`: Returns the nth path element. -* `fromRequest().header(String key)`: Returns the first header with the given name. -* `fromRequest().header(String key, int index)`: Returns the nth header with the given name. -* `fromRequest().body()`: Returns the full request body. -* `fromRequest().body(String jsonPath)`: Returns the element from the request that -matches the JSON Path. - -If you use the YAML contract definition or the Java one, you have to use the -https://handlebarsjs.com/[Handlebars] `{{{ }}}` notation with custom Spring Cloud Contract -functions to achieve this. In that case, you can use the following options: - -* `{{{ request.url }}}`: Returns the request URL and query parameters. -* `{{{ request.query.key.[index] }}}`: Returns the nth query parameter with the given name. -For example, for a key of `thing`, the first entry is `{{{ request.query.thing.[0] }}}` -* `{{{ request.path }}}`: Returns the full path. -* `{{{ request.path.[index] }}}`: Returns the nth path element. For example, -the first entry is ```{{{ request.path.[0] }}} -* `{{{ request.headers.key }}}`: Returns the first header with the given name. -* `{{{ request.headers.key.[index] }}}`: Returns the nth header with the given name. -* `{{{ request.body }}}`: Returns the full request body. -* `{{{ jsonpath this 'your.json.path' }}}`: Returns the element from the request that -matches the JSON Path. For example, for a JSON path of `$.here`, use `{{{ jsonpath this '$.here' }}}` - -Consider the following contract: - -==== -[source,groovy,indent=0,role="primary"] -.Groovy ----- -include:../:{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SpringTestMethodBodyBuildersSpec.groovy[tags=template_contract,indent=0] ----- - -[source,yaml,indent=0,role="secondary"] -.YAML ----- -include:../:{verifier_core_path}/src/test/resources/yml/contract_reference_request.yml[indent=0] ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Java ----- -package contracts.beer.rest; - -import java.util.function.Supplier; - -import org.springframework.cloud.contract.spec.Contract; - -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.map; - -class shouldReturnStatsForAUser implements Supplier { - - @Override - public Contract get() { - return Contract.make(c -> { - c.request(r -> { - r.method("POST"); - r.url("/stats"); - r.body(map().entry("name", r.anyAlphaUnicode())); - r.headers(h -> { - h.contentType(h.applicationJson()); - }); - }); - c.response(r -> { - r.status(r.OK()); - r.body(map() - .entry("text", - "Dear {{{jsonPath request.body '$.name'}}} thanks for your interested in drinking beer") - .entry("quantity", r.$(r.c(5), r.p(r.anyNumber())))); - r.headers(h -> { - h.contentType(h.applicationJson()); - }); - }); - }); - } - -} ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.Kotlin ----- -package contracts.beer.rest - -import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract - -contract { - request { - method = method("POST") - url = url("/stats") - body(mapOf( - "name" to anyAlphaUnicode - )) - headers { - contentType = APPLICATION_JSON - } - } - response { - status = OK - body(mapOf( - "text" to "Don't worry ${fromRequest().body("$.name")} thanks for your interested in drinking beer", - "quantity" to v(c(5), p(anyNumber)) - )) - headers { - contentType = fromRequest().header(CONTENT_TYPE) - } - } -} ----- -==== - -Running a JUnit test generation leads to a test that resembles the following example: - -==== -[source,java,indent=0] ----- - // given: - MockMvcRequestSpecification request = given() - .header("Authorization", "secret") - .header("Authorization", "secret2") - .body("{\"foo\":\"bar\",\"baz\":5}"); - - // when: - ResponseOptions response = given().spec(request) - .queryParam("foo","bar") - .queryParam("foo","bar2") - .get("/api/v1/xxxx"); - - // then: - assertThat(response.statusCode()).isEqualTo(200); - assertThat(response.header("Authorization")).isEqualTo("foo secret bar"); - // and: - DocumentContext parsedJson = JsonPath.parse(response.getBody().asString()); - assertThatJson(parsedJson).field("['fullBody']").isEqualTo("{\"foo\":\"bar\",\"baz\":5}"); - assertThatJson(parsedJson).field("['authorization']").isEqualTo("secret"); - assertThatJson(parsedJson).field("['authorization2']").isEqualTo("secret2"); - assertThatJson(parsedJson).field("['path']").isEqualTo("/api/v1/xxxx"); - assertThatJson(parsedJson).field("['param']").isEqualTo("bar"); - assertThatJson(parsedJson).field("['paramIndex']").isEqualTo("bar2"); - assertThatJson(parsedJson).field("['pathIndex']").isEqualTo("v1"); - assertThatJson(parsedJson).field("['responseBaz']").isEqualTo(5); - assertThatJson(parsedJson).field("['responseFoo']").isEqualTo("bar"); - assertThatJson(parsedJson).field("['url']").isEqualTo("/api/v1/xxxx?foo=bar&foo=bar2"); - assertThatJson(parsedJson).field("['responseBaz2']").isEqualTo("Bla bla bar bla bla"); ----- -==== - -As you can see, elements from the request have been properly referenced in the response. - -The generated WireMock stub should resemble the following example: - -==== -[source,json,indent=0] ----- -{ - "request" : { - "urlPath" : "/api/v1/xxxx", - "method" : "POST", - "headers" : { - "Authorization" : { - "equalTo" : "secret2" - } - }, - "queryParameters" : { - "foo" : { - "equalTo" : "bar2" - } - }, - "bodyPatterns" : [ { - "matchesJsonPath" : "$[?(@.['baz'] == 5)]" - }, { - "matchesJsonPath" : "$[?(@.['foo'] == 'bar')]" - } ] - }, - "response" : { - "status" : 200, - "body" : "{\"authorization\":\"{{{request.headers.Authorization.[0]}}}\",\"path\":\"{{{request.path}}}\",\"responseBaz\":{{{jsonpath this '$.baz'}}} ,\"param\":\"{{{request.query.foo.[0]}}}\",\"pathIndex\":\"{{{request.path.[1]}}}\",\"responseBaz2\":\"Bla bla {{{jsonpath this '$.foo'}}} bla bla\",\"responseFoo\":\"{{{jsonpath this '$.foo'}}}\",\"authorization2\":\"{{{request.headers.Authorization.[1]}}}\",\"fullBody\":\"{{{escapejsonbody}}}\",\"url\":\"{{{request.url}}}\",\"paramIndex\":\"{{{request.query.foo.[1]}}}\"}", - "headers" : { - "Authorization" : "{{{request.headers.Authorization.[0]}}};foo" - }, - "transformers" : [ "response-template" ] - } -} ----- -==== - -Sending a request such as the one presented in the `request` part of the contract results -in sending the following response body: - -==== -[source,json,indent=0] ----- -{ - "url" : "/api/v1/xxxx?foo=bar&foo=bar2", - "path" : "/api/v1/xxxx", - "pathIndex" : "v1", - "param" : "bar", - "paramIndex" : "bar2", - "authorization" : "secret", - "authorization2" : "secret2", - "fullBody" : "{\"foo\":\"bar\",\"baz\":5}", - "responseFoo" : "bar", - "responseBaz" : 5, - "responseBaz2" : "Bla bla bar bla bla" -} ----- -==== - -IMPORTANT: This feature works only with WireMock versions greater than or equal -to 2.5.1. The Spring Cloud Contract Verifier uses WireMock's -`response-template` response transformer. It uses Handlebars to convert the Mustache `{{{ }}}` templates into -proper values. Additionally, it registers two helper functions: - -* `escapejsonbody`: Escapes the request body in a format that can be embedded in JSON. -* `jsonpath`: For a given parameter, finds an object in the request body. - -[[contract-dsl-matchers]] -== Dynamic Properties in the Matchers Sections - -If you work with https://docs.pact.io/[Pact], the following discussion may seem familiar. -Quite a few users are used to having a separation between the body and setting the -dynamic parts of a contract. - -You can use the `bodyMatchers` section for two reasons: - -* Define the dynamic values that should end up in a stub. -You can set it in the `request` part of your contract. -* Verify the result of your test. -This section is present in the `response` or `outputMessage` side of the -contract. - -Currently, Spring Cloud Contract Verifier supports only JSON path-based matchers with the -following matching possibilities: - -[[coded-dsl]] -=== Coded DSL - -For the stubs (in tests on the consumer's side): - -* `byEquality()`: The value taken from the consumer's request in the provided JSON path must be -equal to the value provided in the contract. -* `byRegex(...)`: The value taken from the consumer's request in the provided JSON path must -match the regex. You can also pass the type of the expected matched value (for example, `asString()`, `asLong()`, and so on). -* `byDate()`: The value taken from the consumer's request in the provided JSON path must -match the regex for an ISO Date value. -* `byTimestamp()`: The value taken from the consumer's request in the provided JSON path must -match the regex for an ISO DateTime value. -* `byTime()`: The value taken from the consumer's request in the provided JSON path must -match the regex for an ISO Time value. - -For the verification (in generated tests on the Producer's side): - -* `byEquality()`: The value taken from the producer's response in the provided JSON path must be -equal to the provided value in the contract. -* `byRegex(...)`: The value taken from the producer's response in the provided JSON path must -match the regex. -* `byDate()`: The value taken from the producer's response in the provided JSON path must match -the regex for an ISO Date value. -* `byTimestamp()`: The value taken from the producer's response in the provided JSON path must -match the regex for an ISO DateTime value. -* `byTime()`: The value taken from the producer's response in the provided JSON path must match -the regex for an ISO Time value. -* `byType()`: The value taken from the producer's response in the provided JSON path needs to be -of the same type as the type defined in the body of the response in the contract. -`byType` can take a closure, in which you can set `minOccurrence` and `maxOccurrence`. For the -request side, you should use the closure to assert size of the collection. -That way, you can assert the size of the flattened collection. To check the size of an -unflattened collection, use a custom method with the `byCommand(...)` `testMatcher`. -* `byCommand(...)`: The value taken from the producer's response in the provided JSON path is -passed as an input to the custom method that you provide. For example, -`byCommand('thing($it)')` results in calling a `thing` method to which the value matching the -JSON Path gets passed. The type of the object read from the JSON can be one of the -following, depending on the JSON path: -** `String`: If you point to a `String` value. -** `JSONArray`: If you point to a `List`. -** `Map`: If you point to a `Map`. -** `Number`: If you point to `Integer`, `Double`, or another kind of number. -** `Boolean`: If you point to a `Boolean`. -* `byNull()`: The value taken from the response in the provided JSON path must be null. - -[[yaml]] -=== YAML - -NOTE: See the Groovy section for a detailed explanation of -what the types mean. - -For YAML, the structure of a matcher resembles the following example: - -[source,yml,indent=0] ----- -- path: $.thing1 - type: by_regex - value: thing2 - regexType: as_string ----- - -Alternatively, if you want to use one of the predefined regular expressions -`[only_alpha_unicode, number, any_boolean, ip_address, hostname, -email, url, uuid, iso_date, iso_date_time, iso_time, iso_8601_with_offset, non_empty, -non_blank]`, you can use something similar to the following example: - -[source,yml,indent=0] ----- -- path: $.thing1 - type: by_regex - predefined: only_alpha_unicode ----- - -The following list shows the allowed list of `type` values: - -* For `stubMatchers`: -** `by_equality` -** `by_regex` -** `by_date` -** `by_timestamp` -** `by_time` -** `by_type` -*** Two additional fields (`minOccurrence` and `maxOccurrence`) are accepted. -* For `testMatchers`: -** `by_equality` -** `by_regex` -** `by_date` -** `by_timestamp` -** `by_time` -** `by_type` -*** Two additional fields (`minOccurrence` and `maxOccurrence`) are accepted. -** `by_command` -** `by_null` - -You can also define which type the regular expression corresponds to in the `regexType` -field. The following list shows the allowed regular expression types: - -* `as_integer` -* `as_double` -* `as_float` -* `as_long` -* `as_short` -* `as_boolean` -* `as_string` - -Consider the following example: - -==== -[source,groovy,indent=0,role="primary"] -.Groovy ----- -include:../:{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderWithMatchersSpec.groovy[tags=matchers,indent=0] ----- - -[source,yaml,indent=0,role="secondary"] -.YAML ----- -include:../:{verifier_core_path}/src/test/resources/yml/contract_matchers.yml[indent=0] ----- -==== - -In the preceding example, you can see the dynamic portions of the contract in the -`matchers` sections. For the request part, you can see that, for all fields but -`valueWithoutAMatcher`, the values of the regular expressions that the stub should -contain are explicitly set. For `valueWithoutAMatcher`, the verification takes place -in the same way as without the use of matchers. In that case, the test performs an -equality check. - -For the response side in the `bodyMatchers` section, we define the dynamic parts in a -similar manner. The only difference is that the `byType` matchers are also present. The -verifier engine checks four fields to verify whether the response from the test -has a value for which the JSON path matches the given field, is of the same type as the one -defined in the response body, and passes the following check (based on the method being called): - -* For `$.valueWithTypeMatch`, the engine checks whether the type is the same. -* For `$.valueWithMin`, the engine checks the type and asserts whether the size is greater -than or equal to the minimum occurrence. -* For `$.valueWithMax`, the engine checks the type and asserts whether the size is -smaller than or equal to the maximum occurrence. -* For `$.valueWithMinMax`, the engine checks the type and asserts whether the size is -between the minimum and maximum occurrence. - -The resulting test resembles the following example (note that an `and` section -separates the autogenerated assertions and the assertion from matchers): - -[source,java,indent=0] ----- - // given: - MockMvcRequestSpecification request = given() - .header("Content-Type", "application/json") - .body("{\"duck\":123,\"alpha\":\"abc\",\"number\":123,\"aBoolean\":true,\"date\":\"2017-01-01\",\"dateTime\":\"2017-01-01T01:23:45\",\"time\":\"01:02:34\",\"valueWithoutAMatcher\":\"foo\",\"valueWithTypeMatch\":\"string\",\"key\":{\"complex.key\":\"foo\"}}"); - - // when: - ResponseOptions response = given().spec(request) - .get("/get"); - - // then: - assertThat(response.statusCode()).isEqualTo(200); - assertThat(response.header("Content-Type")).matches("application/json.*"); - // and: - DocumentContext parsedJson = JsonPath.parse(response.getBody().asString()); - assertThatJson(parsedJson).field("['valueWithoutAMatcher']").isEqualTo("foo"); - // and: - assertThat(parsedJson.read("$.duck", String.class)).matches("[0-9]{3}"); - assertThat(parsedJson.read("$.duck", Integer.class)).isEqualTo(123); - assertThat(parsedJson.read("$.alpha", String.class)).matches("[\\p{L}]*"); - assertThat(parsedJson.read("$.alpha", String.class)).isEqualTo("abc"); - assertThat(parsedJson.read("$.number", String.class)).matches("-?(\\d*\\.\\d+|\\d+)"); - assertThat(parsedJson.read("$.aBoolean", String.class)).matches("(true|false)"); - assertThat(parsedJson.read("$.date", String.class)).matches("(\\d\\d\\d\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])"); - assertThat(parsedJson.read("$.dateTime", String.class)).matches("([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])"); - assertThat(parsedJson.read("$.time", String.class)).matches("(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])"); - assertThat((Object) parsedJson.read("$.valueWithTypeMatch")).isInstanceOf(java.lang.String.class); - assertThat((Object) parsedJson.read("$.valueWithMin")).isInstanceOf(java.util.List.class); - assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMin", java.util.Collection.class)).as("$.valueWithMin").hasSizeGreaterThanOrEqualTo(1); - assertThat((Object) parsedJson.read("$.valueWithMax")).isInstanceOf(java.util.List.class); - assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMax", java.util.Collection.class)).as("$.valueWithMax").hasSizeLessThanOrEqualTo(3); - assertThat((Object) parsedJson.read("$.valueWithMinMax")).isInstanceOf(java.util.List.class); - assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMinMax", java.util.Collection.class)).as("$.valueWithMinMax").hasSizeBetween(1, 3); - assertThat((Object) parsedJson.read("$.valueWithMinEmpty")).isInstanceOf(java.util.List.class); - assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMinEmpty", java.util.Collection.class)).as("$.valueWithMinEmpty").hasSizeGreaterThanOrEqualTo(0); - assertThat((Object) parsedJson.read("$.valueWithMaxEmpty")).isInstanceOf(java.util.List.class); - assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMaxEmpty", java.util.Collection.class)).as("$.valueWithMaxEmpty").hasSizeLessThanOrEqualTo(0); - assertThatValueIsANumber(parsedJson.read("$.duck")); - assertThat(parsedJson.read("$.['key'].['complex.key']", String.class)).isEqualTo("foo"); ----- - -IMPORTANT: Notice that, for the `byCommand` method, the example calls the -`assertThatValueIsANumber`. This method must be defined in the test base class or be -statically imported to your tests. Notice that the `byCommand` call was converted to -`assertThatValueIsANumber(parsedJson.read("$.duck"));`. That means that the engine took -the method name and passed the proper JSON path as a parameter to it. - -The resulting WireMock stub is in the following example: - -[source,json,indent=0] ----- -include:../:{plugins_path}/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverterSpec.groovy[tags=matchers,indent=0] ----- - -IMPORTANT: If you use a `matcher`, the part of the request and response that the -`matcher` addresses with the JSON Path gets removed from the assertion. In the case of -verifying a collection, you must create matchers for *all* the elements of the -collection. - -Consider the following example: - -==== -[source,groovy,indent=0] ----- -Contract.make { - request { - method 'GET' - url("/foo") - } - response { - status OK() - body(events: [[ - operation : 'EXPORT', - eventId : '16f1ed75-0bcc-4f0d-a04d-3121798faf99', - status : 'OK' - ], [ - operation : 'INPUT_PROCESSING', - eventId : '3bb4ac82-6652-462f-b6d1-75e424a0024a', - status : 'OK' - ] - ] - ) - bodyMatchers { - jsonPath('$.events[0].operation', byRegex('.+')) - jsonPath('$.events[0].eventId', byRegex('^([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})$')) - jsonPath('$.events[0].status', byRegex('.+')) - } - } -} ----- -==== - -The preceding code leads to creating the following test (the code block shows only the assertion section): - -==== -[source,java,indent=0] ----- - and: - DocumentContext parsedJson = JsonPath.parse(response.body.asString()) - assertThatJson(parsedJson).array("['events']").contains("['eventId']").isEqualTo("16f1ed75-0bcc-4f0d-a04d-3121798faf99") - assertThatJson(parsedJson).array("['events']").contains("['operation']").isEqualTo("EXPORT") - assertThatJson(parsedJson).array("['events']").contains("['operation']").isEqualTo("INPUT_PROCESSING") - assertThatJson(parsedJson).array("['events']").contains("['eventId']").isEqualTo("3bb4ac82-6652-462f-b6d1-75e424a0024a") - assertThatJson(parsedJson).array("['events']").contains("['status']").isEqualTo("OK") - and: - assertThat(parsedJson.read("\$.events[0].operation", String.class)).matches(".+") - assertThat(parsedJson.read("\$.events[0].eventId", String.class)).matches("^([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})\$") - assertThat(parsedJson.read("\$.events[0].status", String.class)).matches(".+") ----- -==== - -Note that the assertion is malformed. Only the first element of the array got -asserted. To fix this, apply the assertion to the whole `$.events` -collection and assert it with the `byCommand(...)` method. - diff --git a/docs/modules/ROOT/pages/_project-features-contract/dsl-http-top-level-elements.adoc b/docs/modules/ROOT/pages/_project-features-contract/dsl-http-top-level-elements.adoc deleted file mode 100644 index 557f079f78..0000000000 --- a/docs/modules/ROOT/pages/_project-features-contract/dsl-http-top-level-elements.adoc +++ /dev/null @@ -1,45 +0,0 @@ -[[contract-dsl-http-top-level-elements]] -= HTTP Top-Level Elements - -You can call the following methods in the top-level closure of a contract definition: - -* `request`: Mandatory -* `response` : Mandatory -* `priority`: Optional - -The following example shows how to define an HTTP request contract: - -==== -[source,groovy,indent=0,subs="verbatim,attributes",role="primary"] -.Groovy ----- -include:../:{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=http_dsl,indent=0] ----- - -[source,yml,indent=0,subs="verbatim,attributes",role="secondary"] -.YAML ----- -include:../:{verifier_core_path}/src/test/resources/yml/contract.yml[tags=priority,indent=0] -include:../:{verifier_core_path}/src/test/resources/yml/contract.yml[tags=request,indent=0] -... -include:../:{verifier_core_path}/src/test/resources/yml/contract.yml[tags=response,indent=0] -... ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Java ----- -include:../:{verifier_core_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=http_dsl,indent=0] ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.Kotlin ----- -include:../:{verifier_core_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=http_dsl,indent=0] ----- -==== - -IMPORTANT: If you want to make your contract have a higher priority, -you need to pass a lower number to the `priority` tag or method. For example, a `priority` with -a value of `5` has higher priority than a `priority` with a value of `10`. - diff --git a/docs/modules/ROOT/pages/_project-features-contract/dsl-multiple.adoc b/docs/modules/ROOT/pages/_project-features-contract/dsl-multiple.adoc deleted file mode 100644 index e3d3f70ce2..0000000000 --- a/docs/modules/ROOT/pages/_project-features-contract/dsl-multiple.adoc +++ /dev/null @@ -1,134 +0,0 @@ -[[contract-dsl-multiple]] -= Multiple Contracts in One File - -You can define multiple contracts in one file. Such a contract might resemble the -following example: - -==== -[source,groovy,indent=0,role="primary"] -.Groovy ----- -include:../:{plugins_path}/spring-cloud-contract-maven-plugin/src/test/projects/multiple-contracts/src/test/resources/contracts/com/hello/v1/WithList.groovy[lines=18..-1,indent=0] ----- - -[source,yaml,indent=0,role="secondary"] -.YAML ----- -include:../:{verifier_core_path}/src/test/resources/yml/multiple_contracts.yml[indent=0] ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Java ----- -class contract implements Supplier> { - - @Override - public Collection get() { - return Arrays.asList( - Contract.make(c -> { - c.name("should post a user"); - // ... - }), Contract.make(c -> { - // ... - }), Contract.make(c -> { - // ... - }) - ); - } - -} ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.Kotlin ----- -import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract - -arrayOf( - contract { - name("should post a user") - // ... - }, - contract { - // ... - }, - contract { - // ... - } -} ----- -==== - -In the preceding example, one contract has the `name` field and the other does not. This -leads to generation of two tests that look like the following: - -==== -[source,java,indent=0] ----- -package org.springframework.cloud.contract.verifier.tests.com.hello; - -import com.example.TestBase; -import com.jayway.jsonpath.DocumentContext; -import com.jayway.jsonpath.JsonPath; -import com.jayway.restassured.module.mockmvc.specification.MockMvcRequestSpecification; -import com.jayway.restassured.response.ResponseOptions; -import org.junit.Test; - -import static com.jayway.restassured.module.mockmvc.RestAssuredMockMvc.*; -import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson; -import static org.assertj.core.api.Assertions.assertThat; - -public class V1Test extends TestBase { - - @Test - public void validate_should_post_a_user() throws Exception { - // given: - MockMvcRequestSpecification request = given(); - - // when: - ResponseOptions response = given().spec(request) - .post("/users/1"); - - // then: - assertThat(response.statusCode()).isEqualTo(200); - } - - @Test - public void validate_withList_1() throws Exception { - // given: - MockMvcRequestSpecification request = given(); - - // when: - ResponseOptions response = given().spec(request) - .post("/users/2"); - - // then: - assertThat(response.statusCode()).isEqualTo(200); - } - -} ----- -==== - -Notice that, for the contract that has the `name` field, the generated test method is named -`validate_should_post_a_user`. The one that does not have the `name` field is called -`validate_withList_1`. It corresponds to the name of the file `WithList.groovy` and the -index of the contract in the list. - -The generated stubs are shown in the following example: - -==== -[source] ----- -should post a user.json -1_WithList.json ----- -==== - -The first file got the `name` parameter from the contract. The second -got the name of the contract file (`WithList.groovy`) prefixed with the index (in this -case, the contract had an index of `1` in the list of contracts in the file). - -TIP: It is much better to name your contracts, because doing so makes -your tests far more meaningful. - diff --git a/docs/modules/ROOT/pages/_project-features-contract/dsl-request.adoc b/docs/modules/ROOT/pages/_project-features-contract/dsl-request.adoc deleted file mode 100644 index 906600ca8b..0000000000 --- a/docs/modules/ROOT/pages/_project-features-contract/dsl-request.adoc +++ /dev/null @@ -1,271 +0,0 @@ -[[contract-dsl-request]] -= HTTP Request - -The HTTP protocol requires only the method and the URL to be specified in a request. The -same information is mandatory in request definition of the contract. - -The following example shows a contract for a request: - -==== -[source,groovy,indent=0,role="primary"] -.Groovy ----- -include:../:{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=request,indent=0] ----- - -[source,yaml,indent=0,role="secondary"] -.YAML ----- -include:../:{verifier_core_path}/src/test/resources/yml/contract.yml[tags=request_obligatory,indent=0] ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Java ----- -include:../:{verifier_core_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=request,indent=0] ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.Kotlin ----- -include:../:{verifier_core_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=request,indent=0] ----- -==== - -You can specify an absolute rather than a relative `url`, but using `urlPath` is -the recommended way, as doing so makes the tests be host-independent. - -The following example uses `url`: - -==== -[source,groovy,indent=0,role="primary"] -.Groovy ----- -include:../:{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=url,indent=0] ----- - -[source,yaml,indent=0,role="secondary"] -.YAML ----- -include:../:{verifier_core_path}/src/test/resources/yml/contract_rest_with_path.yml[tags=url_path,indent=0] ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Java ----- -include:../:{verifier_core_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=url,indent=0] ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.Kotlin ----- -include:../:{verifier_core_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=url,indent=0] ----- -==== - -`request` may contain query parameters, as the following example (which uses `urlPath`) shows: - -==== -[source,groovy,indent=0,subs="verbatim,attributes",role="primary"] -.Groovy ----- -include:../:{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=urlpath,indent=0] ----- - -[source,yml,indent=0,subs="verbatim,attributes",role="secondary"] -.YAML ----- -include:../:{verifier_core_path}/src/test/resources/yml/contract.yml[tags=request,indent=0] -... -include:../:{verifier_core_path}/src/test/resources/yml/contract.yml[tags=query_params,indent=0] ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Java ----- -include:../:{verifier_core_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=urlpath,indent=0] ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.Kotlin ----- -include:../:{verifier_core_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=urlpath,indent=0] ----- -==== - -`request` can contain additional request headers, as the following example shows: - -==== -[source,groovy,indent=0,subs="verbatim,attributes",role="primary"] -.Groovy ----- -include:../:{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=headers,indent=0] ----- - -[source,yml,indent=0,subs="verbatim,attributes",role="secondary"] -.YAML ----- -include:../:{verifier_core_path}/src/test/resources/yml/contract.yml[tags=request,indent=0] -... -include:../:{verifier_core_path}/src/test/resources/yml/contract.yml[tags=headers,indent=0] ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Java ----- -include:../:{verifier_core_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=headers,indent=0] ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.Kotlin ----- -include:../:{verifier_core_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=headers,indent=0] ----- -==== - -`request` may contain additional request cookies, as the following example shows: - -==== -[source,groovy,indent=0,subs="verbatim,attributes",role="primary"] -.Groovy ----- -include:../:{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=cookies,indent=0] ----- - -[source,yml,indent=0,subs="verbatim,attributes",role="secondary"] -.YAML ----- -include:../:{verifier_core_path}/src/test/resources/yml/contract.yml[tags=request,indent=0] -... -include:../:{verifier_core_path}/src/test/resources/yml/contract.yml[tags=cookies,indent=0] ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Java ----- -include:../:{verifier_core_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=cookies,indent=0] ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.Kotlin ----- -include:../:{verifier_core_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=cookies,indent=0] ----- -==== - -`request` may contain a request body, as the following example shows: - -==== -[source,groovy,indent=0,subs="verbatim,attributes",role="primary"] -.Groovy ----- -include:../:{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=body,indent=0] ----- - -[source,yml,indent=0,subs="verbatim,attributes",role="secondary"] -.YAML ----- -include:../:{verifier_core_path}/src/test/resources/yml/contract.yml[tags=request,indent=0] -... -include:../:{verifier_core_path}/src/test/resources/yml/contract.yml[tags=body,indent=0] ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Java ----- -include:../:{verifier_core_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=body,indent=0] ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.Kotlin ----- -include:../:{verifier_core_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=body,indent=0] ----- -==== - -`request` can contain multipart elements. To include multipart elements, use the -`multipart` method/section, as the following examples show: - -==== -[source,groovy,indent=0,role="primary"] -.Groovy ----- -include:../:{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SpringTestMethodBodyBuildersSpec.groovy[tags=multipartdsl,indent=0] ----- - -[source,yaml,indent=0,role="secondary"] -.YAML ----- -include:../:{verifier_core_path}/src/test/resources/yml/contract_multipart.yml[indent=0] ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Java ----- -include:../:{verifier_core_path}/src/test/resources/contractsToCompile/contract_multipart.java[tags=class,indent=0] ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.Kotlin ----- -include:../:{verifier_core_path}/src/test/resources/kotlin/multipart.kts[tags=class,indent=0] ----- -==== - -In the preceding example, we defined parameters in either of two ways: - -.Coded DSL -* Directly, by using the map notation, where the value can be a dynamic property (such as -`formParameter: $(consumer(...), producer(...))`). -* By using the `named(...)` method that lets you set a named parameter. A named parameter -can set a `name` and `content`. You can call it either by using a method with two arguments, -such as `named("fileName", "fileContent")`, or by using a map notation, such as -`named(name: "fileName", content: "fileContent")`. - -.YAML -* The multipart parameters are set in the `multipart.params` section. -* The named parameters (the `fileName` and `fileContent` for a given parameter name) -can be set in the `multipart.named` section. That section contains -the `paramName` (the name of the parameter), `fileName` (the name of the file), -`fileContent` (the content of the file) fields. -* The dynamic bits can be set in the `matchers.multipart` section. -** For parameters, use the `params` section, which can accept -`regex` or a `predefined` regular expression. -** For named parameters, use the `named` section where you first -define the parameter name with `paramName`. Then you can pass the -parametrization of either `fileName` or `fileContent` in a -`regex` or in a `predefined` regular expression. - -IMPORTANT: For the `named(...)` section you always have to add a pair of -`value(producer(...), consumer(...))` calls. Just setting DSL properties such -as just `value(producer(...))` or just `file(...)` will not work. -Check this https://github.com/spring-cloud/spring-cloud-contract/issues/1886[issue] for more information. - -From the contract in the preceding example, the generated test and stub look as follows: - -==== -[source,java,indent=0,subs="verbatim,attributes",role="primary"] -.Test ----- -// given: - MockMvcRequestSpecification request = given() - .header("Content-Type", "multipart/form-data;boundary=AaB03x") - .param("formParameter", "\"formParameterValue\"") - .param("someBooleanParameter", "true") - .multiPart("file", "filename.csv", "file content".getBytes()); - - // when: - ResponseOptions response = given().spec(request) - .put("/multipart"); - - // then: - assertThat(response.statusCode()).isEqualTo(200); ----- - -[source,json,indent=0,subs="verbatim,attributes",role="secondary"] -.Stub ----- -include:../:{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockGroovyDslSpec.groovy[tags=multipartwiremock,indent=0] ----- -==== - diff --git a/docs/modules/ROOT/pages/_project-features-contract/dsl-response.adoc b/docs/modules/ROOT/pages/_project-features-contract/dsl-response.adoc deleted file mode 100644 index e656e4e802..0000000000 --- a/docs/modules/ROOT/pages/_project-features-contract/dsl-response.adoc +++ /dev/null @@ -1,41 +0,0 @@ -[[contract-dsl-response]] -= HTTP Response - -The response must contain an HTTP status code and may contain other information. The -following code shows an example: - -==== -[source,groovy,indent=0,subs="verbatim,attributes",role="primary"] -.Groovy ----- -include:../:{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=response,indent=0] ----- - -[source,yml,indent=0,subs="verbatim,attributes",role="secondary"] -.YAML ----- -include:../:{verifier_core_path}/src/test/resources/yml/contract.yml[tags=response,indent=0] -... -include:../:{verifier_core_path}/src/test/resources/yml/contract.yml[tags=response_obligatory,indent=0] ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Java ----- -include:../:{verifier_core_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=response,indent=0] ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.Kotlin ----- -include:../:{verifier_core_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=response,indent=0] ----- -==== - -Besides status, the response may contain headers, cookies, and a body, which are -specified the same way as in the request (see xref:_project-features-contract/dsl-request.adoc[HTTP Request]). - -TIP: In the Groovy DSL, you can reference the `org.springframework.cloud.contract.spec.internal.HttpStatus` -methods to provide a meaningful status instead of a digit. For example, you can call -`OK()` for a status `200` or `BAD_REQUEST()` for `400`. - diff --git a/docs/modules/ROOT/pages/_project-features-contract/dsl-xml.adoc b/docs/modules/ROOT/pages/_project-features-contract/dsl-xml.adoc deleted file mode 100644 index 4d8166088c..0000000000 --- a/docs/modules/ROOT/pages/_project-features-contract/dsl-xml.adoc +++ /dev/null @@ -1,121 +0,0 @@ -[[contract-dsl-xml]] -= XML Support for HTTP - -For HTTP contracts, we also support using XML in the request and response body. -The XML body has to be passed within the `body` element -as a `String` or `GString`. Also, body matchers can be provided for -both the request and the response. In place of the `jsonPath(...)` method, the `org.springframework.cloud.contract.spec.internal.BodyMatchers.xPath` -method should be used, with the desired `xPath` provided as the first argument -and the appropriate `MatchingType` as the second argument. All the body matchers apart from `byType()` are supported. - -The following example shows a Groovy DSL contract with XML in the response body: - -==== -[source,groovy,indent=0,subs="verbatim,attributes",role="primary"] -.Groovy ----- -include:../:{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/XmlMethodBodyBuilderSpec.groovy[tags=xmlgroovy] ----- - -[source,yml,indent=0,subs="verbatim,attributes",role="secondary"] -.YAML ----- -include:../:{verifier_core_path}/src/test/resources/yml/contract_rest_xml.yml[indent=0] ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Java ----- -include:../:{verifier_core_path}/src/test/resources/contractsToCompile/contract_xml.java[tags=class,indent=0] ----- - -[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"] -.Kotlin ----- -include:../:{verifier_core_path}/src/test/resources/kotlin/contract_xml.kts[tags=class,indent=0] ----- -==== - -The following example shows an automatically generated test for XML in the response body: - -==== -[source,java,indent=0] ----- -@Test -public void validate_xmlMatches() throws Exception { - // given: - MockMvcRequestSpecification request = given() - .header("Content-Type", "application/xml"); - - // when: - ResponseOptions response = given().spec(request).get("/get"); - - // then: - assertThat(response.statusCode()).isEqualTo(200); - // and: - DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance() - .newDocumentBuilder(); - Document parsedXml = documentBuilder.parse(new InputSource( - new StringReader(response.getBody().asString()))); - // and: - assertThat(valueFromXPath(parsedXml, "/test/list/elem/text()")).isEqualTo("abc"); - assertThat(valueFromXPath(parsedXml,"/test/list/elem[2]/text()")).isEqualTo("def"); - assertThat(valueFromXPath(parsedXml, "/test/duck/text()")).matches("[0-9]{3}"); - assertThat(nodeFromXPath(parsedXml, "/test/duck/xxx")).isNull(); - assertThat(valueFromXPath(parsedXml, "/test/alpha/text()")).matches("[\\p{L}]*"); - assertThat(valueFromXPath(parsedXml, "/test/*/complex/text()")).isEqualTo("foo"); - assertThat(valueFromXPath(parsedXml, "/test/duck/@type")).isEqualTo("xtype"); - } ----- -==== - -[[xml-support-for-namespaces]] -== XML Support for Namespaces -Namespaced XML is supported. However, any XPath expresssions used to select namespaced content must be updated. - -Consider the following explicitly namespaced XML document: - -[source,xml,indent=0] ----- - - customer@test.com - ----- -The XPath expression to select the email address is: `/ns1:customer/email/text()`. - -WARNING: Beware as the unqualified expression (`/customer/email/text()`) results in `""`. - -For content that uses an unqualified namespace, the expression is more verbose. Consider the following XML document that -uses an unqualified namespace: - -[source,xml,indent=0] ----- - - customer@test.com - ----- -The XPath expression to select the email address is -``` -*/[local-name()='customer' and namespace-uri()='http://demo.com/customer']/*[local-name()='email']/text() -``` -WARNING: Beware, as the unqualified expressions (`/customer/email/text()` or `*/[local-name()='customer' and namespace-uri()='http://demo.com/customer']/email/text()`) -result in `""`. Even the child elements have to be referenced with the `local-name` syntax. - -[[general-namespaced-node-expression-syntax]] -=== General Namespaced Node Expression Syntax -- Node using qualified namespace: -``` -/ -``` -- Node using and defining an unqualified namespace: -``` -/*[local-name=()='' and namespace-uri=()=''] -``` -NOTE: In some cases, you can omit the `namespace_uri` portion, but doing so may lead to ambiguity. - -- Node using an unqualified namespace (one of its ancestor's defines the xmlns attribute): -``` -/*[local-name=()=''] -``` - - diff --git a/docs/modules/ROOT/pages/_project-features-contract/groovy.adoc b/docs/modules/ROOT/pages/_project-features-contract/groovy.adoc deleted file mode 100644 index 640b9a8f97..0000000000 --- a/docs/modules/ROOT/pages/_project-features-contract/groovy.adoc +++ /dev/null @@ -1,18 +0,0 @@ -[[contract-groovy]] -= Contract DSL in Groovy -:page-section-summary-toc: 1 - -If you are not familiar with Groovy, do not worry. You can use Java syntax in the -Groovy DSL files as well. - -If you decide to write the contract in Groovy, do not be alarmed if you have not used Groovy -before. Knowledge of the language is not really needed, as the Contract DSL uses only a -tiny subset of it (only literals, method calls, and closures). Also, the DSL is statically -typed, to make it programmer-readable without any knowledge of the DSL itself. - -IMPORTANT: Remember that, inside the Groovy contract file, you have to provide the fully -qualified name to the `Contract` class and `make` static imports, such as -`org.springframework.cloud.spec.Contract.make { ... }`. You can also provide an import to -the `Contract` class (`import org.springframework.cloud.spec.Contract`) and then call -`Contract.make { ... }`. - diff --git a/docs/modules/ROOT/pages/_project-features-contract/java.adoc b/docs/modules/ROOT/pages/_project-features-contract/java.adoc deleted file mode 100644 index fba47a5c12..0000000000 --- a/docs/modules/ROOT/pages/_project-features-contract/java.adoc +++ /dev/null @@ -1,33 +0,0 @@ -[[contract-java]] -= Contract DSL in Java - -To write a contract definition in Java, you need to create a class that implements either the `Supplier` interface (for a single contract) or `Supplier>` (for multiple contracts). - -You can also write the contract definitions under `src/test/java` (for example, `src/test/java/contracts`) so that you do not have to modify the classpath of your project. In this case, you have to provide a new location of contract definitions to your Spring Cloud Contract plugin. - -The following example (in both Maven and Gradle) has the contract definitions under `src/test/java`: - -==== -[source,xml,indent=0,subs="verbatim,attributes",role="primary"] -.Maven ----- - - org.springframework.cloud - spring-cloud-contract-maven-plugin - ${spring-cloud-contract.version} - true - - src/test/java/contracts - - ----- - -[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] -.Gradle ----- -contracts { - contractsDslDir = new File(project.rootDir, "src/test/java/contracts") -} ----- -==== - diff --git a/docs/modules/ROOT/pages/_project-features-contract/kotlin.adoc b/docs/modules/ROOT/pages/_project-features-contract/kotlin.adoc deleted file mode 100644 index 5621cb7d0e..0000000000 --- a/docs/modules/ROOT/pages/_project-features-contract/kotlin.adoc +++ /dev/null @@ -1,73 +0,0 @@ -[[contract-kotlin]] -= Contract DSL in Kotlin - -To get started with writing contracts in Kotlin, you need to start with a (newly created) Kotlin Script file (`.kts`). -As with the Java DSL, you can put your contracts in any directory of your choice. -By default, the Maven plugin will look at the `src/test/resources/contracts` directory and Gradle plugin will -look at the `src/contractTest/resources/contracts` directory. - -NOTE: Since 3.0.0, the Gradle plugin will also look at the legacy -directory `src/test/resources/contracts` for migration purposes. When contracts are found in this directory, a warning -will be logged during your build. - -You need to explicitly pass the `spring-cloud-contract-spec-kotlin` dependency to your project plugin setup. -The following example (in both Maven and Gradle) shows how to do so: - -==== -[source,xml,indent=0,subs="verbatim,attributes",role="primary"] -.Maven ----- - - org.springframework.cloud - spring-cloud-contract-maven-plugin - ${spring-cloud-contract.version} - true - - - - - - org.springframework.cloud - spring-cloud-contract-spec-kotlin - ${spring-cloud-contract.version} - - - - - - - - org.springframework.cloud - spring-cloud-contract-spec-kotlin - test - - ----- - -[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] -.Gradle ----- -buildscript { - repositories { - // ... - } - dependencies { - classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:${scContractVersion}" - } -} - -dependencies { - // ... - - // Remember to add this for the DSL support in the IDE and on the consumer side - testImplementation "org.springframework.cloud:spring-cloud-contract-spec-kotlin" - // Kotlin versions are very particular down to the patch version. The needs to be the same as you have imported for your project. - testImplementation "org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:" -} ----- -==== - -IMPORTANT: Remember that, inside the Kotlin Script file, you have to provide the fully qualified name to the `ContractDSL` class. -Generally you would use its contract function as follows: `org.springframework.cloud.contract.spec.ContractDsl.contract { ... }`. -You can also provide an import to the `contract` function (`import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract`) and then call `contract { ... }`. - diff --git a/docs/modules/ROOT/pages/_project-features-contract/limitations.adoc b/docs/modules/ROOT/pages/_project-features-contract/limitations.adoc deleted file mode 100644 index 0191619c34..0000000000 --- a/docs/modules/ROOT/pages/_project-features-contract/limitations.adoc +++ /dev/null @@ -1,13 +0,0 @@ -[[contract-limitations]] -= Limitations -:page-section-summary-toc: 1 - -WARNING: The support for verifying the size of JSON arrays is experimental. If you want -to turn it on, set the value of the following system property to `true`: -`spring.cloud.contract.verifier.assert.size`. By default, this feature is set to `false`. -You can also set the `assertJsonSize` property in the plugin configuration. - -WARNING: Because JSON structure can have any form, it can be impossible to parse it -properly when using the Groovy DSL and the `value(consumer(...), producer(...))` notation in `GString`. That -is why you should use the Groovy Map notation. - diff --git a/docs/modules/ROOT/pages/_project-features-contract/stateful-contracts.adoc b/docs/modules/ROOT/pages/_project-features-contract/stateful-contracts.adoc deleted file mode 100644 index c141a8b00b..0000000000 --- a/docs/modules/ROOT/pages/_project-features-contract/stateful-contracts.adoc +++ /dev/null @@ -1,38 +0,0 @@ -[[contract-stateful-contracts]] -= Stateful Contracts - -Stateful contracts (also known as scenarios) are contract definitions that should be read -in order. This might be useful in the following situations: - -* You want to invoke the contract in a precisely defined order, since you use Spring -Cloud Contract to test your stateful application. - -TIP: We really discourage you from doing that, since contract tests should be stateless. - -* You want the same endpoint to return different results for the same request. - -To create stateful contracts (or scenarios), you need to -use the proper naming convention while creating your contracts. The convention -requires including an order number followed by an underscore. This works regardless -of whether you work with YAML or Groovy. The following listing shows an example: - -==== -[source,indent=0] ----- -my_contracts_dir\ - scenario1\ - 1_login.groovy - 2_showCart.groovy - 3_logout.groovy ----- -==== - -Such a tree causes Spring Cloud Contract Verifier to generate WireMock's scenario with a -name of `scenario1` and the three following steps: - -. `login`, marked as `Started` pointing to... -. `showCart`, marked as `Step1` pointing to... -. `logout`, marked as `Step2` (which closes the scenario). - -You can find more details about WireMock scenarios at -https://wiremock.org/docs/stateful-behaviour/[https://wiremock.org/docs/stateful-behaviour/]. diff --git a/docs/modules/ROOT/pages/_project-features-contract/yml.adoc b/docs/modules/ROOT/pages/_project-features-contract/yml.adoc deleted file mode 100644 index 3198fc1d10..0000000000 --- a/docs/modules/ROOT/pages/_project-features-contract/yml.adoc +++ /dev/null @@ -1,6 +0,0 @@ -[[contract-yml]] -= Contract DSL in YAML -:page-section-summary-toc: 1 - -To see a schema of a YAML contract, visit the {docs-url}/reference/html/yml-schema.html[YML Schema] page. - diff --git a/docs/modules/ROOT/pages/_project-features-flows.adoc b/docs/modules/ROOT/pages/_project-features-flows.adoc deleted file mode 100644 index 027ad53950..0000000000 --- a/docs/modules/ROOT/pages/_project-features-flows.adoc +++ /dev/null @@ -1,5 +0,0 @@ -[[feature-integrations]] -= Integrations -:page-section-summary-toc: 1 - - diff --git a/docs/modules/ROOT/pages/_project-features-flows/context-paths.adoc b/docs/modules/ROOT/pages/_project-features-flows/context-paths.adoc deleted file mode 100644 index 8f806362d6..0000000000 --- a/docs/modules/ROOT/pages/_project-features-flows/context-paths.adoc +++ /dev/null @@ -1,62 +0,0 @@ -[[features-context-paths]] -= Working with Context Paths - -Spring Cloud Contract supports context paths. - -[IMPORTANT] -===== -The only change needed to fully support context paths is the switch on the -producer side. Also, the autogenerated tests must use explicit mode. The consumer -side remains untouched. In order for the generated test to pass, you must use explicit -mode. The following example shows how to set the test mode to `EXPLICIT`: - -==== -[source,xml,indent=0,subs="verbatim,attributes",role="primary"] -.Maven ----- - - org.springframework.cloud - spring-cloud-contract-maven-plugin - ${spring-cloud-contract.version} - true - - EXPLICIT - - ----- - -[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] -.Gradle ----- -contracts { - testMode = 'EXPLICIT' -} ----- -==== -===== - -That way, you generate a test that does not use MockMvc. It means that you generate -real requests and you need to set up your generated test's base class to work on a real -socket. - -Consider the following contract: - -[source,groovy,indent=0] ----- -include:../:{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGeneratorSpec.groovy[tags=context_path_contract,indent=0] ----- - -The following example shows how to set up a base class and RestAssured: - -[source,groovy,indent=0] ----- -include:../:{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGeneratorSpec.groovy[tags=context_path_baseclass,indent=0] ----- - -If you do it this way: - -* All of your requests in the autogenerated tests are sent to the real endpoint with your -context path included (for example, `/my-context-path/url`). -* Your contracts reflect that you have a context path. Your generated stubs also have -that information (for example, in the stubs, you have to call `/my-context-path/url`). - diff --git a/docs/modules/ROOT/pages/_project-features-flows/custom-mode.adoc b/docs/modules/ROOT/pages/_project-features-flows/custom-mode.adoc deleted file mode 100644 index 5258dd6741..0000000000 --- a/docs/modules/ROOT/pages/_project-features-flows/custom-mode.adoc +++ /dev/null @@ -1,104 +0,0 @@ -[[features-custom-mode]] -= Custom Mode - -IMPORTANT: This mode is experimental and can change in the future. - -The Spring Cloud Contract lets you provide your own, custom, implementation of the -`org.springframework.cloud.contract.verifier.http.HttpVerifier`. That way, you can use any client you want to send and receive a request. The default implementation in Spring Cloud Contract is `OkHttpHttpVerifier` and it uses OkHttp3 http client. - -To get started, set `testMode` to `CUSTOM`: - -==== -[source,groovy,indent=0] ----- -testMode = 'CUSTOM' ----- -==== - -The following example shows a generated test: - -==== -[source,java,indent=0] ----- -package com.example.beer; - -import com.example.BeerRestBase; -import javax.inject.Inject; -import org.springframework.cloud.contract.verifier.http.HttpVerifier; -import org.springframework.cloud.contract.verifier.http.Request; -import org.springframework.cloud.contract.verifier.http.Response; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat; -import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.*; -import static org.springframework.cloud.contract.verifier.http.Request.given; - -@SuppressWarnings("rawtypes") -public class RestTest extends BeerRestBase { - @Inject HttpVerifier httpVerifier; - - @Test - public void validate_shouldGrantABeerIfOldEnough() throws Exception { - // given: - Request request = given() - .post("/beer.BeerService/check") - .scheme("HTTP") - .protocol("h2_prior_knowledge") - .header("Content-Type", "application/grpc") - .header("te", "trailers") - .body(fileToBytes(this, "shouldGrantABeerIfOldEnough_request_PersonToCheck_old_enough.bin")) - .build(); - - - // when: - Response response = httpVerifier.exchange(request); - - - // then: - assertThat(response.statusCode()).isEqualTo(200); - assertThat(response.header("Content-Type")).matches("application/grpc.*"); - assertThat(response.header("grpc-encoding")).isEqualTo("identity"); - assertThat(response.header("grpc-accept-encoding")).isEqualTo("gzip"); - - // and: - assertThat(response.getBody().asByteArray()).isEqualTo(fileToBytes(this, "shouldGrantABeerIfOldEnough_response_Response_old_enough.bin")); - } - -} ----- -==== - -The following example shows a corresponding base class: - -==== -[source,java,indent=0] ----- -@SpringBootTest(classes = BeerRestBase.Config.class, - webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -public abstract class BeerRestBase { - - @Configuration - @EnableAutoConfiguration - static class Config { - - @Bean - ProducerController producerController(PersonCheckingService personCheckingService) { - return new ProducerController(personCheckingService); - } - - @Bean - PersonCheckingService testPersonCheckingService() { - return argument -> argument.getAge() >= 20; - } - - @Bean - HttpVerifier httpOkVerifier(@LocalServerPort int port) { - return new OkHttpHttpVerifier("localhost:" + port); - } - - } -} ----- -==== - diff --git a/docs/modules/ROOT/pages/_project-features-flows/feature-webflux-explicit.adoc b/docs/modules/ROOT/pages/_project-features-flows/feature-webflux-explicit.adoc deleted file mode 100644 index d33bf0da45..0000000000 --- a/docs/modules/ROOT/pages/_project-features-flows/feature-webflux-explicit.adoc +++ /dev/null @@ -1,46 +0,0 @@ -[[feature-webflux-explicit]] -= WebFlux with Explicit Mode - -You can also use WebFlux with the explicit mode in your generated tests -to work with WebFlux. The following example shows how to configure using explicit mode: - -==== -[source,xml,indent=0,subs="verbatim,attributes",role="primary"] -.Maven ----- - - org.springframework.cloud - spring-cloud-contract-maven-plugin - ${spring-cloud-contract.version} - true - - EXPLICIT - - ----- - -[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] -.Gradle ----- -contracts { - testMode = 'EXPLICIT' -} ----- -==== - -The following example shows how to set up a base class and RestAssured for Web Flux: - -==== -[source,groovy,indent=0] ----- -include:../:{samples_url}/producer_webflux/src/test/java/com/example/BeerRestBase.java[tags=annotations,indent=0] - - // your tests go here - - // in this config class you define all controllers and mocked services -include:../:{samples_url}/producer_webflux/src/test/java/com/example/BeerRestBase.java[tags=config,indent=0] - -} ----- -==== - diff --git a/docs/modules/ROOT/pages/_project-features-flows/feature-webflux.adoc b/docs/modules/ROOT/pages/_project-features-flows/feature-webflux.adoc deleted file mode 100644 index 016113e6d0..0000000000 --- a/docs/modules/ROOT/pages/_project-features-flows/feature-webflux.adoc +++ /dev/null @@ -1,53 +0,0 @@ -[[feature-webflux]] -= WebFlux with WebTestClient - -You can work with WebFlux by using WebTestClient. The following listing shows how to -configure WebTestClient as the test mode: - -==== -[source,xml,indent=0,subs="verbatim,attributes",role="primary"] -.Maven ----- - - org.springframework.cloud - spring-cloud-contract-maven-plugin - ${spring-cloud-contract.version} - true - - WEBTESTCLIENT - - ----- - -[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] -.Gradle ----- -contracts { - testMode = 'WEBTESTCLIENT' -} ----- -==== - -The following example shows how to set up a WebTestClient base class and RestAssured -for WebFlux: - -==== -[source,groovy,indent=0] ----- -import io.restassured.module.webtestclient.RestAssuredWebTestClient; -import org.junit.Before; - -public abstract class BeerRestBase { - - @Before - public void setup() { - RestAssuredWebTestClient.standaloneSetup( - new ProducerController(personToCheck -> personToCheck.age >= 20)); - } -} -} ----- -==== - -TIP: The `WebTestClient` mode is faster than the `EXPLICIT` mode. - diff --git a/docs/modules/ROOT/pages/_project-features-flows/graphql.adoc b/docs/modules/ROOT/pages/_project-features-flows/graphql.adoc deleted file mode 100644 index f4c67cbca3..0000000000 --- a/docs/modules/ROOT/pages/_project-features-flows/graphql.adoc +++ /dev/null @@ -1,185 +0,0 @@ -[[features-graphql]] -= GraphQL - -Since https://graphql.org/[GraphQL] is essentially HTTP you can write a contract for it by creating a standard HTTP contract with an additional `metadata` entry with key `verifier` and a mapping `tool=graphql`. - -==== -[source,groovy,indent=0,subs="verbatim,attributes",role="primary"] -.Groovy ----- -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - - request { - method(POST()) - url("/graphql") - headers { - contentType("application/json") - } - body(''' -{ - "query":"query queryName($personName: String!) {\\n personToCheck(name: $personName) {\\n name\\n age\\n }\\n}\\n\\n\\n\\n", - "variables":{"personName":"Old Enough"}, - "operationName":"queryName" -} -''') - } - - response { - status(200) - headers { - contentType("application/json") - } - body('''\ -{ - "data": { - "personToCheck": { - "name": "Old Enough", - "age": "40" - } - } -} -''') - } - metadata(verifier: [ - tool: "graphql" - ]) -} ----- - -[source,yml,indent=0,subs="verbatim,attributes",role="secondary"] -.YAML ----- ---- -request: - method: "POST" - url: "/graphql" - headers: - Content-Type: "application/json" - body: - query: "query queryName($personName: String!) { personToCheck(name: $personName) - { name age } }" - variables: - personName: "Old Enough" - operationName: "queryName" - matchers: - headers: - - key: "Content-Type" - regex: "application/json.*" - regexType: "as_string" -response: - status: 200 - headers: - Content-Type: "application/json" - body: - data: - personToCheck: - name: "Old Enough" - age: "40" - matchers: - headers: - - key: "Content-Type" - regex: "application/json.*" - regexType: "as_string" -name: "shouldRetrieveOldEnoughPerson" -metadata: - verifier: - tool: "graphql" ----- -==== - -Adding the metadata section will change the way the default, WireMock stub is built. It will now use the Spring Cloud Contract request matcher, so that e.g. the `query` part of the GraphQL request gets compared against the real request by ignoring whitespaces. - -[[features-graphql-producer]] -== Producer Side Setup - -On the producer side your configuration can look as follows. - -==== -[source,xml,indent=0,subs="verbatim,attributes",role="primary"] -.Maven ----- - - org.springframework.cloud - spring-cloud-contract-maven-plugin - ${spring-cloud-contract.version} - true - - EXPLICIT - com.example.BaseClass - - ----- - -[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] -.Gradle ----- -contracts { - testMode = "EXPLICIT" - baseClassForTests = "com.example.BaseClass" -} ----- -==== - -The base class would set up the application running on a random port. - -==== -[source,java,indent=0,subs="verbatim,attributes"] -.Base Class ----- -@SpringBootTest(classes = ProducerApplication.class, - properties = "graphql.servlet.websocket.enabled=false", - webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -public abstract class BaseClass { - - @LocalServerPort int port; - - @BeforeEach - public void setup() { - RestAssured.baseURI = "http://localhost:" + port; - } -} - ----- -==== - -[[features-graphql-consumer]] -== Consumer Side Setup - -Example of a consumer side test of the GraphQL API. - -==== -[source,java,indent=0,subs="verbatim,attributes"] -.Consumer Side Test ----- -@SpringBootTest(webEnvironment = WebEnvironment.NONE) -public class BeerControllerGraphQLTest { - - @RegisterExtension - static StubRunnerExtension rule = new StubRunnerExtension() - .downloadStub("com.example","beer-api-producer-graphql") - .stubsMode(StubRunnerProperties.StubsMode.LOCAL); - - private static final String REQUEST_BODY = "{\n" - + "\"query\":\"query queryName($personName: String!) {\\n personToCheck(name: $personName) {\\n name\\n age\\n }\\n}\"," - + "\"variables\":{\"personName\":\"Old Enough\"},\n" - + "\"operationName\":\"queryName\"\n" - + "}"; - - @Test - public void should_send_a_graphql_request() { - ResponseEntity responseEntity = new RestTemplate() - .exchange(RequestEntity - .post(URI.create("http://localhost:" + rule.findStubUrl("beer-api-producer-graphql").getPort() + "/graphql")) - .contentType(MediaType.APPLICATION_JSON) - .body(REQUEST_BODY), String.class); - - BDDAssertions.then(responseEntity.getStatusCodeValue()).isEqualTo(200); - - } -} - ----- -==== - diff --git a/docs/modules/ROOT/pages/_project-features-flows/grpc.adoc b/docs/modules/ROOT/pages/_project-features-flows/grpc.adoc deleted file mode 100644 index d8c5d7d75b..0000000000 --- a/docs/modules/ROOT/pages/_project-features-flows/grpc.adoc +++ /dev/null @@ -1,277 +0,0 @@ -[[features-grpc]] -= GRPC - -https://grpc.io/[GRPC] is an RPC framework built on top of HTTP/2 for which Spring Cloud Contract has basic support. - -IMPORTANT: Spring Cloud Contract has an experimental support for basic use cases of GRPC. Unfortunately, due to GRPC's tweaking of the HTTP/2 Header frames, it's impossible to assert the `grpc-status` header. - -Let's look at the following contract. - -==== -[source,groovy,indent=0,subs="verbatim,attributes"] -.Groovy contract ----- -package contracts.beer.rest - - -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.http.ContractVerifierHttpMetaData - -Contract.make { - description(""" -Represents a successful scenario of getting a beer - -``` -given: - client is old enough -when: - he applies for a beer -then: - we'll grant him the beer -``` - -""") - request { - method 'POST' - url '/beer.BeerService/check' - body(fileAsBytes("PersonToCheck_old_enough.bin")) - headers { - contentType("application/grpc") - header("te", "trailers") - } - } - response { - status 200 - body(fileAsBytes("Response_old_enough.bin")) - headers { - contentType("application/grpc") - header("grpc-encoding", "identity") - header("grpc-accept-encoding", "gzip") - } - } - metadata([ - "verifierHttp": [ - "protocol": ContractVerifierHttpMetaData.Protocol.H2_PRIOR_KNOWLEDGE.toString() - ] - ]) -} ----- -==== - -[[features-grpc-producer]] -== Producer Side Setup - -In order to leverage the HTTP/2 support you must set the `CUSTOM` test mode as follow. - -==== -[source,xml,indent=0,subs="verbatim,attributes",role="primary"] -.Maven ----- - - org.springframework.cloud - spring-cloud-contract-maven-plugin - ${spring-cloud-contract.version} - true - - CUSTOM - com.example - - ----- - -[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] -.Gradle ----- -contracts { - packageWithBaseClasses = 'com.example' - testMode = "CUSTOM" -} ----- -==== - -The base class would set up the application running on a random port. It will also set the `HttpVerifier` implementation to one that can use the HTTP/2 protocol. Spring Cloud Contract comes with the `OkHttpHttpVerifier` implementation. - -==== -[source,java,indent=0,subs="verbatim,attributes"] -.Base Class ----- -@SpringBootTest(classes = BeerRestBase.Config.class, - webEnvironment = SpringBootTest.WebEnvironment.NONE, - properties = { - "grpc.server.port=0" - }) -public abstract class BeerRestBase { - - @Autowired - GrpcServerProperties properties; - - @Configuration - @EnableAutoConfiguration - static class Config { - - @Bean - ProducerController producerController(PersonCheckingService personCheckingService) { - return new ProducerController(personCheckingService); - } - - @Bean - PersonCheckingService testPersonCheckingService() { - return argument -> argument.getAge() >= 20; - } - - @Bean - HttpVerifier httpOkVerifier(GrpcServerProperties properties) { - return new OkHttpHttpVerifier("localhost:" + properties.getPort()); - } - - } -} ----- -==== - -[[features-grpc-consumer]] -== Consumer Side Setup - -Example of GRPC consumer side test. Due to the unusual behaviour of the GRPC server side, the stub is unable to return the `grpc-status` header in the proper moment. This is why we need to manually set the return status. - -==== -[source,java,indent=0,subs="verbatim,attributes"] -.Consumer Side Test ----- -@SpringBootTest(webEnvironment = WebEnvironment.NONE, classes = GrpcTests.TestConfiguration.class, properties = { - "grpc.client.beerService.address=static://localhost:5432", "grpc.client.beerService.negotiationType=TLS" -}) -public class GrpcTests { - - @GrpcClient(value = "beerService", interceptorNames = "fixedStatusSendingClientInterceptor") - BeerServiceGrpc.BeerServiceBlockingStub beerServiceBlockingStub; - - int port; - - @RegisterExtension - static StubRunnerExtension rule = new StubRunnerExtension() - .downloadStub("com.example", "beer-api-producer-grpc") - // With WireMock PlainText mode you can just set an HTTP port -// .withPort(5432) - .stubsMode(StubRunnerProperties.StubsMode.LOCAL) - .withHttpServerStubConfigurer(MyWireMockConfigurer.class); - - @BeforeEach - public void setupPort() { - this.port = rule.findStubUrl("beer-api-producer-grpc").getPort(); - } - - @Test - public void should_give_me_a_beer_when_im_old_enough() throws Exception { - Response response = beerServiceBlockingStub.check(PersonToCheck.newBuilder().setAge(23).build()); - - BDDAssertions.then(response.getStatus()).isEqualTo(Response.BeerCheckStatus.OK); - } - - @Test - public void should_reject_a_beer_when_im_too_young() throws Exception { - Response response = beerServiceBlockingStub.check(PersonToCheck.newBuilder().setAge(17).build()); - response = response == null ? Response.newBuilder().build() : response; - - BDDAssertions.then(response.getStatus()).isEqualTo(Response.BeerCheckStatus.NOT_OK); - } - - // Not necessary with WireMock PlainText mode - static class MyWireMockConfigurer extends WireMockHttpServerStubConfigurer { - @Override - public WireMockConfiguration configure(WireMockConfiguration httpStubConfiguration, HttpServerStubConfiguration httpServerStubConfiguration) { - return httpStubConfiguration - .httpsPort(5432); - } - } - - @Configuration - @ImportAutoConfiguration(GrpcClientAutoConfiguration.class) - static class TestConfiguration { - - // Not necessary with WireMock PlainText mode - @Bean - public GrpcChannelConfigurer keepAliveClientConfigurer() { - return (channelBuilder, name) -> { - if (channelBuilder instanceof NettyChannelBuilder) { - try { - ((NettyChannelBuilder) channelBuilder) - .sslContext(GrpcSslContexts.forClient() - .trustManager(InsecureTrustManagerFactory.INSTANCE) - .build()); - } - catch (SSLException e) { - throw new IllegalStateException(e); - } - } - }; - } - - /** - * GRPC client interceptor that sets the returned status always to OK. - * You might want to change the return status depending on the received stub payload. - * - * Hopefully in the future this will be unnecessary and will be removed. - */ - @Bean - ClientInterceptor fixedStatusSendingClientInterceptor() { - return new ClientInterceptor() { - @Override - public ClientCall interceptCall(MethodDescriptor method, CallOptions callOptions, Channel next) { - ClientCall call = next.newCall(method, callOptions); - return new ClientCall() { - @Override - public void start(Listener responseListener, Metadata headers) { - Listener listener = new Listener() { - @Override - public void onHeaders(Metadata headers) { - responseListener.onHeaders(headers); - } - - @Override - public void onMessage(RespT message) { - responseListener.onMessage(message); - } - - @Override - public void onClose(Status status, Metadata trailers) { - // TODO: This must be fixed somehow either in Jetty (WireMock) or somewhere else - responseListener.onClose(Status.OK, trailers); - } - - @Override - public void onReady() { - responseListener.onReady(); - } - }; - call.start(listener, headers); - } - - @Override - public void request(int numMessages) { - call.request(numMessages); - } - - @Override - public void cancel(@Nullable String message, @Nullable Throwable cause) { - call.cancel(message, cause); - } - - @Override - public void halfClose() { - call.halfClose(); - } - - @Override - public void sendMessage(ReqT message) { - call.sendMessage(message); - } - }; - } - }; - } - } -} - ----- -==== diff --git a/docs/modules/ROOT/pages/_project-features-flows/jax-rs.adoc b/docs/modules/ROOT/pages/_project-features-flows/jax-rs.adoc deleted file mode 100644 index 9f951c19fb..0000000000 --- a/docs/modules/ROOT/pages/_project-features-flows/jax-rs.adoc +++ /dev/null @@ -1,26 +0,0 @@ -[[features-jax-rs]] -= JAX-RS - -The Spring Cloud Contract supports the JAX-RS 2 Client API. The base class needs -to define `protected WebTarget webTarget` and server initialization. The only option for -testing JAX-RS API is to start a web server. Also, a request with a body needs to have a -content type be set. Otherwise, the default of `application/octet-stream` gets used. - -To use JAX-RS mode, use the following setting: - -==== -[source,groovy,indent=0] ----- -testMode = 'JAXRSCLIENT' ----- -==== - -The following example shows a generated test API: - -==== -[source,groovy,indent=0] ----- -include:../:{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientMethodBuilderSpec.groovy[tags=jaxrs,indent=0] ----- -==== - diff --git a/docs/modules/ROOT/pages/_project-features-flows/rest-docs.adoc b/docs/modules/ROOT/pages/_project-features-flows/rest-docs.adoc deleted file mode 100644 index b9b540717a..0000000000 --- a/docs/modules/ROOT/pages/_project-features-flows/rest-docs.adoc +++ /dev/null @@ -1,307 +0,0 @@ -[[features-rest-docs]] -= Working with REST Docs - -You can use https://projects.spring.io/spring-restdocs[Spring REST Docs] to generate -documentation (for example, in Asciidoc format) for an HTTP API with Spring MockMvc, -WebTestClient, or RestAssured. At the same time that you generate documentation for your API, you can also -generate WireMock stubs by using Spring Cloud Contract WireMock. To do so, write your -normal REST Docs test cases and use `@AutoConfigureRestDocs` to have stubs be -automatically generated in the REST Docs output directory. The following UML diagram shows -the REST Docs flow: - -[plantuml, rest-docs, png] ----- -"API Producer"->"API Producer": Add Spring Cloud Contract (SCC) \nStub Runner dependency -"API Producer"->"API Producer": Set up stub jar assembly -"API Producer"->"API Producer": Write and set up REST Docs tests -"API Producer"->"Build": Run build -"Build"->"REST Docs": Generate API \ndocumentation -"REST Docs"->"SCC": Generate stubs from the \nREST Docs tests -"REST Docs"->"SCC": Generate contracts from the \nREST Docs tests -"Build"->"Build": Assemble stubs jar with \nstubs and contracts -"Build"->"Nexus / Artifactory": Upload contracts \nand stubs and the project arifact -"Build"->"API Producer": Build successful -"API Consumer"->"API Consumer": Add SCC Stub Runner \ndependency -"API Consumer"->"API Consumer": Write a SCC Stub Runner \nbased contract test -"SCC Stub Runner"->"Nexus / Artifactory": Test asks for [API Producer] stubs -"Nexus / Artifactory"->"SCC Stub Runner": Fetch the [API Producer] stubs -"SCC Stub Runner"->"SCC Stub Runner": Run in memory\n HTTP server stubs -"API Consumer"->"SCC Stub Runner": Send a request \nto the HTTP server stub -"SCC Stub Runner"->"API Consumer": Communication is correct ----- - -The following example uses `MockMvc`: - -==== -[source,java,indent=0] ----- -@RunWith(SpringRunner.class) -@SpringBootTest -@AutoConfigureRestDocs(outputDir = "target/snippets") -@AutoConfigureMockMvc -public class ApplicationTests { - - @Autowired - private MockMvc mockMvc; - - @Test - public void contextLoads() throws Exception { - mockMvc.perform(get("/resource")) - .andExpect(content().string("Hello World")) - .andDo(document("resource")); - } -} ----- -==== - -This test generates a WireMock stub at `target/snippets/stubs/resource.json`. It matches -all `GET` requests to the `/resource` path. The same example with WebTestClient (used -for testing Spring WebFlux applications) would be as follows: - -==== -[source,java,indent=0] ----- -@RunWith(SpringRunner.class) -@SpringBootTest -@AutoConfigureRestDocs(outputDir = "target/snippets") -@AutoConfigureWebTestClient -public class ApplicationTests { - - @Autowired - private WebTestClient client; - - @Test - public void contextLoads() throws Exception { - client.get().uri("/resource").exchange() - .expectBody(String.class).isEqualTo("Hello World") - .consumeWith(document("resource")); - } -} ----- -==== - -Without any additional configuration, these tests create a stub with a request matcher -for the HTTP method and all headers except `host` and `content-length`. To match the -request more precisely (for example, to match the body of a POST or PUT), we need to -explicitly create a request matcher. Doing so has two effects: - -* Creating a stub that matches only in the way you specify. -* Asserting that the request in the test case also matches the same conditions. - -The main entry point for this feature is `WireMockRestDocs.verify()`, which can be used -as a substitute for the `document()` convenience method, as the following -example shows: - -==== -[source,java,indent=0] ----- -import static org.springframework.cloud.contract.wiremock.restdocs.WireMockRestDocs.verify; - -@RunWith(SpringRunner.class) -@SpringBootTest -@AutoConfigureRestDocs(outputDir = "target/snippets") -@AutoConfigureMockMvc -public class ApplicationTests { - - @Autowired - private MockMvc mockMvc; - - @Test - public void contextLoads() throws Exception { - mockMvc.perform(post("/resource") - .content("{\"id\":\"123456\",\"message\":\"Hello World\"}")) - .andExpect(status().isOk()) - .andDo(verify().jsonPath("$.id")) - .andDo(document("resource")); - } -} ----- -==== - -The preceding contract specifies that any valid POST with an `id` field receives the response -defined in this test. You can chain together calls to `.jsonPath()` to add additional -matchers. If JSON Path is unfamiliar, the https://github.com/jayway/JsonPath[JayWay -documentation] can help you get up to speed. The WebTestClient version of this test -has a similar `verify()` static helper that you insert in the same place. - -Instead of the `jsonPath` and `contentType` convenience methods, you can also use the -WireMock APIs to verify that the request matches the created stub, as the -following example shows: - -==== -[source,java,indent=0] ----- - @Test - public void contextLoads() throws Exception { - mockMvc.perform(post("/resource") - .content("{\"id\":\"123456\",\"message\":\"Hello World\"}")) - .andExpect(status().isOk()) - .andDo(verify() - .wiremock(WireMock.post(urlPathEquals("/resource")) - .withRequestBody(matchingJsonPath("$.id")) - .andDo(document("post-resource")))); - } ----- -==== - -The WireMock API is rich. You can match headers, query parameters, and the request body by -regex as well as by JSON path. You can use these features to create stubs with a wider -range of parameters. The preceding example generates a stub resembling the following example: - -==== -.post-resource.json -[source,json] ----- -{ - "request" : { - "url" : "/resource", - "method" : "POST", - "bodyPatterns" : [ { - "matchesJsonPath" : "$.id" - }] - }, - "response" : { - "status" : 200, - "body" : "Hello World", - "headers" : { - "X-Application-Context" : "application:-1", - "Content-Type" : "text/plain" - } - } -} ----- -==== - -NOTE: You can use either the `wiremock()` method or the `jsonPath()` and `contentType()` -methods to create request matchers, but you cannot use both approaches. - -On the consumer side, you can make the `resource.json` generated earlier in this section -available on the classpath (by -xref:_project-features-stubrunner/stub-runner-publishing-stubs-as-jars.adoc[Publishing Stubs as JARs], for example). After that, you can create a stub that uses WireMock in a -number of different ways, including by using -`@AutoConfigureWireMock(stubs="classpath:resource.json")`, as described earlier in this -document. - -[[features-rest-docs-contracts]] -== Generating Contracts with REST Docs - -You can also generate Spring Cloud Contract DSL files and documentation with Spring REST -Docs. If you do so in combination with Spring Cloud WireMock, you get both the contracts -and the stubs. - -Why would you want to use this feature? Some people in the community asked questions -about a situation in which they would like to move to DSL-based contract definition, -but they already have a lot of Spring MVC tests. Using this feature lets you generate -the contract files that you can later modify and move to folders (defined in your -configuration) so that the plugin finds them. - -NOTE: You might wonder why this functionality is in the WireMock module. The functionality -is there because it makes sense to generate both the contracts and the stubs. - -Consider the following test: - -==== -[source,java] ----- -include:../:{wiremock_tests}/src/test/java/org/springframework/cloud/contract/wiremock/restdocs/ContractDslSnippetTests.java[tags=contract_snippet] ----- -==== - -The preceding test creates the stub presented in the previous section, generating both -the contract and a documentation file. - -The contract is called `index.groovy` and might resemble the following example: - -==== -[source,groovy] ----- -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - request { - method 'POST' - url '/foo' - body(''' - {"foo": 23 } - ''') - headers { - header('''Accept''', '''application/json''') - header('''Content-Type''', '''application/json''') - } - } - response { - status OK() - body(''' - bar - ''') - headers { - header('''Content-Type''', '''application/json;charset=UTF-8''') - header('''Content-Length''', '''3''') - } - bodyMatchers { - jsonPath('$[?(@.foo >= 20)]', byType()) - } - } -} ----- -==== - -The generated document (formatted in Asciidoc in this case) contains a formatted -contract. The location of this file would be `index/dsl-contract.adoc`. - -[[features-restdocs-priority-attribute]] -== Specifying the priority attribute - -The method `SpringCloudContractRestDocs.dslContract()` takes an optional Map parameter that allows you to specify additional attributes in the template. - -One of these attributes is the xref:_project-features-contract/dsl-http-top-level-elements.adoc[priority] field that you may specify as follows: - -[source,java,indent=0] ----- -SpringCloudContractRestDocs.dslContract(Map.of("priority", 1)) ----- - -[[features-restdocs-override]] -== Overriding the DSL contract template - -By default, the output of the contract is based on a file named `default-dsl-contract-only.snippet`. - -You may provide a custom template file instead by overriding the getTemplate() method as follows: - -[source,java,indent=0] ----- -new ContractDslSnippet(){ - @Override - protected String getTemplate() { - return "custom-dsl-contract"; - } -})); ----- - -so the example above showing this line -[source,java,indent=0] ----- -.andDo(document("index", SpringCloudContractRestDocs.dslContract())); ----- - -should be changed to: -[source,java,indent=0] ----- -.andDo(document("index", new ContractDslSnippet(){ - @Override - protected String getTemplate() { - return "custom-dsl-template"; - } - })); ----- - -Templates are resolved by looking for resources on the classpath. The following locations are checked in order: - -* `org/springframework/restdocs/templates/${templateFormatId}/${name}.snippet` -* `org/springframework/restdocs/templates/${name}.snippet` -* `org/springframework/restdocs/templates/${templateFormatId}/default-${name}.snippet` - -Therefore in the example above you should place a file named custom-dsl-template.snippet in `src/test/resources/org/springframework/restdocs/templates/custom-dsl-template.snippet` - - - diff --git a/docs/modules/ROOT/pages/_project-features-messaging.adoc b/docs/modules/ROOT/pages/_project-features-messaging.adoc deleted file mode 100644 index a51d0b6b8b..0000000000 --- a/docs/modules/ROOT/pages/_project-features-messaging.adoc +++ /dev/null @@ -1,621 +0,0 @@ -[[features-messaging]] -= Messaging - - -Spring Cloud Contract lets you verify applications that use messaging as a -means of communication. All of the integrations shown in this document work with Spring, -but you can also create one of your own and use that. - -[[contract-dsl-messaging-top-level]] -== Messaging DSL Top-level Elements - -The DSL for messaging looks a little bit different than the one that focuses on HTTP. The -following sections explain the differences: - -* xref:_project-features-messaging.adoc#contract-dsl-output-triggered-method[Output Triggered by a Method] -* xref:_project-features-messaging.adoc#contract-dsl-consumer-producer[Consumer/Producer] -* xref:_project-features-messaging.adoc#contract-dsl-messaging-common[Common] - -[[contract-dsl-output-triggered-method]] -=== Output Triggered by a Method - -The output message can be triggered by calling a method (such as a `Scheduler` when a contract was -started and when a message was sent), as shown in the following example: - -==== -[source,groovy,indent=0,subs="verbatim,attributes",role="primary"] -.Groovy ----- -include::{tests_path}/samples-messaging-integration/src/test/groovy/com/example/IntegrationMessagingApplicationSpec.groovy[tags=method_trigger,indent=0] ----- - -[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] -.YAML ----- -include::{verifier_core_path}/src/test/resources/yml/contract_message_method.yml[indent=0] ----- -==== - -In the previous example case, the output message is sent to `output` if a method called -`bookReturnedTriggered` is invoked. On the message publisher's side, we generate a -test that calls that method to trigger the message. On the consumer side, you can use -`some_label` to trigger the message. - - -[[contract-dsl-consumer-producer]] -=== Consumer/Producer - -IMPORTANT: This section is valid only for the Groovy DSL. - -In HTTP, you have a notion of `client`/`stub and `server`/`test` notation. You can also -use those paradigms in messaging. In addition, Spring Cloud Contract Verifier also -provides the `consumer` and `producer` methods -(note that you can use either `$` or `value` methods to provide `consumer` and `producer` -parts). - -[[contract-dsl-messaging-common]] -=== Common - -In the `input` or `outputMessage` section, you can call `assertThat` with the name -of a `method` (for example, `assertThatMessageIsOnTheQueue()`) that you have defined in the -base class or in a static import. Spring Cloud Contract runs that method -in the generated test. - -[[features-messaging-integrations]] -== Integrations - -You can use one of the following integration configurations: - -* Apache Camel -* Spring Integration -* Spring Cloud Stream -* Spring JMS - -Since we use Spring Boot, if you have added one of these libraries to the classpath, all -the messaging configuration is automatically set up. - -IMPORTANT: Remember to put `@AutoConfigureMessageVerifier` on the base class of your -generated tests. Otherwise, the messaging part of Spring Cloud Contract does not -work. - -[IMPORTANT] -===== -If you want to use Spring Cloud Stream, remember to add a test dependency on -`org.springframework.cloud:spring-cloud-stream`, as follows: - -==== -[source,xml,indent=0,subs="verbatim,attributes",role="primary"] -.Maven ----- - - org.springframework.cloud - spring-cloud-stream - test-jar - test - test-binder - ----- - -[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] -.Gradle ----- -testImplementation(group: 'org.springframework.cloud', name: 'spring-cloud-stream', classifier: 'test-binder') ----- -==== -===== - -[[features-messaging-manual]] -=== Manual Integration Testing - -The main interface used by the tests is -`org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender` and `org.springframework.cloud.contract.verifier.messaging.MessageVerifierReceiver`. -It defines how to send and receive messages. - -In a test, you can inject a `ContractVerifierMessageExchange` to send and receive -messages that follow the contract. Then add `@AutoConfigureMessageVerifier` to your test. -The following example shows how to do so: - -==== -[source,java,indent=0] ----- -@RunWith(SpringTestRunner.class) -@SpringBootTest -@AutoConfigureMessageVerifier -public static class MessagingContractTests { - - @Autowired - private MessageVerifier verifier; - ... -} ----- -==== - -NOTE: If your tests require stubs as well, then `@AutoConfigureStubRunner` includes the -messaging configuration, so you only need the one annotation. - -[[features-messaging-test-generation]] -== Producer Side Messaging Test Generation - -Having the `input` or `outputMessage` sections in your DSL results in creation of tests -on the publisher's side. By default, JUnit 4 tests are created. However, there is also a -possibility to create JUnit 5, TestNG, or Spock tests. - -IMPORTANT: The destination passed to `messageFrom` or `sentTo` can have different -meanings for different messaging implementations. For Stream and Integration, it is -first resolved as a `destination` of a channel. Then, if there is no such `destination`, -it is resolved as a channel name. For Camel, that's a certain component (for example, -`jms`). - -Consider the following contract: - -===== -[source,groovy,indent=0,subs="verbatim,attributes",role="primary"] -.Groovy ----- -include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy[tags=trigger_method_dsl] ----- - -[source,yml,indent=0,subs="verbatim,attributes",role="secondary"] -.YAML -[source,yml,indent=0] ----- -include::{verifier_core_path}/src/test/resources/yml/contract_message_scenario1.yml[indent=0] ----- -===== - -For the preceding example, the following test would be created: - -==== -[source,java,indent=0,subs="verbatim,attributes",role="primary"] -.JUnit ----- -include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy[tags=trigger_method_junit_test] ----- - -[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] -.Spock ----- -include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy[tags=trigger_method_test] ----- -==== - -[[features-messaging-consumer]] -== Consumer Stub Generation - -Unlike in the HTTP part, in messaging, we need to publish the contract definition inside the JAR with -a stub. Then it is parsed on the consumer side, and proper stubbed routes are created. - -IMPORTANT: If you have multiple frameworks on the classpath, Stub Runner needs to -define which one should be used. Assume that you have AMQP, Spring Cloud Stream, and Spring Integration -on the classpath and that you want to use Spring AMQP. Then you need to set -`stubrunner.stream.enabled=false` and `stubrunner.integration.enabled=false`. -That way, the only remaining framework is Spring AMQP. - -[[features-messaging-stub-triggering]] -=== Stub triggering - -To trigger a message, use the `StubTrigger` interface, as the following example shows: - -==== -[source,groovy] ----- -include::{stubrunner_core_path}/src/main/java/org/springframework/cloud/contract/stubrunner/StubTrigger.java[lines=16..-1] ----- -==== - -For convenience, the `StubFinder` interface extends `StubTrigger`, so you need only one -or the other in your tests. - -`StubTrigger` gives you the following options to trigger a message: - -* xref:_project-features-messaging.adoc#features-messaging-trigger-label[Trigger by Label] -* xref:_project-features-messaging.adoc#features-messaging-trigger-group-artifact-ids[Trigger by Group and Artifact IDs] -* xref:_project-features-messaging.adoc#features-messaging-trigger-artifact-ids[Trigger by Artifact IDs] -* xref:_project-features-messaging.adoc#features-messaging-trigger-all-messages[Trigger All Messages] - -[[features-messaging-trigger-label]] -=== Trigger by Label - -The following example shows how to trigger a message with a label: - -==== -[source,groovy] ----- -include::{tests_path}/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=client_trigger,indent=0] ----- -==== - -[[features-messaging-trigger-group-artifact-ids]] -=== Trigger by Group and Artifact IDs - -The following example shows how to trigger a message by group and artifact IDs: - -==== -[source,groovy] ----- -include::{tests_path}/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=trigger_group_artifact,indent=0] ----- -==== - -[[features-messaging-trigger-artifact-ids]] -=== Trigger by Artifact IDs - -The following example shows how to trigger a message from artifact IDs: - -[source,groovy] ----- -include::{tests_path}/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=trigger_artifact,indent=0] ----- - -[[features-messaging-trigger-all-messages]] -=== Trigger All Messages - -The following example shows how to trigger all messages: - -[source,groovy] ----- -include::{tests_path}/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=trigger_all,indent=0] ----- - -:input_name: jms:input -:output_name: jms:output - -[[features-messaging-stub-runner-camel]] -== Consumer Side Messaging With Apache Camel - -Spring Cloud Contract Stub Runner's messaging module gives you an easy way to integrate with Apache Camel. -For the provided artifacts, it automatically downloads the stubs and registers the required -routes. - -[[features-messaging-stub-runner-camel-adding]] -=== Adding Apache Camel to the Project - -You can have both Apache Camel and Spring Cloud Contract Stub Runner on the classpath. -Remember to annotate your test class with `@AutoConfigureStubRunner`. - -[[features-messaging-stub-runner-camel-disabling]] -=== Disabling the Functionality - -If you need to disable this functionality, set the `stubrunner.camel.enabled=false` property. - -[[features-messaging-stub-runner-camel-example]] -=== Examples - -Assume that we have the following Maven repository with deployed stubs for the -`camelService` application: - -==== -[source,bash,indent=0] ----- -└── .m2 - └── repository - └── io - └── codearte - └── accurest - └── stubs - └── camelService - ├── 0.0.1-SNAPSHOT - │   ├── camelService-0.0.1-SNAPSHOT.pom - │   ├── camelService-0.0.1-SNAPSHOT-stubs.jar - │   └── maven-metadata-local.xml - └── maven-metadata-local.xml ----- -==== - -Further, assume that the stubs contain the following structure: - -==== -[source,bash,indent=0] ----- -├── META-INF -│   └── MANIFEST.MF -└── repository - ├── accurest - │   └── bookReturned1.groovy - └── mappings ----- -==== - -Now consider the following contract: - -==== -[source,groovy] ----- -include::{tests_path}/samples-messaging-camel/src/test/groovy/com/example/CamelMessagingApplicationSpec.groovy[tags=sample_dsl,indent=0] ----- -==== - -To trigger a message from the `return_book_1` label, we use the `StubTrigger` interface, as follows: - -==== -[source,groovy] ----- -stubFinder.trigger("return_book_1") ----- -==== - -That will send out a message to the destination described in the output message of the contract. - -:input_name: input -:output_name: output - -[[features-messaging-stub-runner-integration]] -== Consumer Side Messaging with Spring Integration - -Spring Cloud Contract Stub Runner's messaging module gives you an easy way to -integrate with Spring Integration. For the provided artifacts, it automatically downloads -the stubs and registers the required routes. - -[[features-messaging-stub-runner-integration-adding]] -=== Adding the Runner to the Project - -You can have both Spring Integration and Spring Cloud Contract Stub Runner on the -classpath. Remember to annotate your test class with `@AutoConfigureStubRunner`. - -[[features-messaging-stub-runner-integration-disabling]] -=== Disabling the Functionality - -If you need to disable this functionality, set the -`stubrunner.integration.enabled=false` property. - -[[features-messaging-stub-runner-integration-example]] -=== Examples - -Assume that you have the following Maven repository with deployed stubs for the -`integrationService` application: - -==== -[source,bash,indent=0] ----- -└── .m2 - └── repository - └── io - └── codearte - └── accurest - └── stubs - └── integrationService - ├── 0.0.1-SNAPSHOT - │   ├── integrationService-0.0.1-SNAPSHOT.pom - │   ├── integrationService-0.0.1-SNAPSHOT-stubs.jar - │   └── maven-metadata-local.xml - └── maven-metadata-local.xml ----- -==== - -Further assume the stubs contain the following structure: - -==== -[source,bash,indent=0] ----- -├── META-INF -│   └── MANIFEST.MF -└── repository - ├── accurest - │   └── bookReturned1.groovy - └── mappings ----- -==== - -Consider the following contract: - -==== -[source,groovy] ----- -include::{tests_path}/spring-cloud-contract-stub-runner-integration/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/IntegrationStubRunnerSpec.groovy[tags=sample_dsl,indent=0] ----- -==== - -Now consider the following Spring Integration Route: - -==== -[source,xml] ----- -include::{tests_path}/spring-cloud-contract-stub-runner-integration/src/test/resources/integration-context.xml[lines=1;18..-1] ----- -==== - -To trigger a message from the `return_book_1` label, use the `StubTrigger` interface, as -follows: - -==== -[source,groovy] ----- -include::{tests_path}/spring-cloud-contract-stub-runner-integration/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/IntegrationStubRunnerSpec.groovy[tags=client_trigger,indent=0] ----- -==== - -That will send out a message to the destination described in the output message of the contract. - -[[features-messaging-stub-runner-stream]] -== Consumer Side Messaging With Spring Cloud Stream - -Spring Cloud Contract Stub Runner's messaging module gives you an easy way to -integrate with Spring Stream. For the provided artifacts, it automatically downloads the -stubs and registers the required routes. - -CAUTION: If Stub Runner's integration with the Stream `messageFrom` or `sentTo` strings -are resolved first as the `destination` of a channel and no such `destination` exists, the -destination is resolved as a channel name. - -[IMPORTANT] -===== -If you want to use Spring Cloud Stream, remember to add a dependency on -`org.springframework.cloud:spring-cloud-stream` test support, as follows: - -==== -[source,xml,indent=0,subs="verbatim,attributes",role="primary"] -.Maven ----- - - org.springframework.cloud - spring-cloud-stream-test-binder - test - ----- - -[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] -.Gradle ----- -testImplementation('org.springframework.cloud:spring-cloud-stream-test-binder') ----- -==== -===== - -[[features-messaging-stub-runner-stream-adding]] -=== Adding the Runner to the Project - -You can have both Spring Cloud Stream and Spring Cloud Contract Stub Runner on the -classpath. Remember to annotate your test class with `@AutoConfigureStubRunner`. - -[[features-messaging-stub-runner-stream-disabling]] -=== Disabling the Functionality - -If you need to disable this functionality, set the `stubrunner.stream.enabled=false` -property. - -[[features-messaging-stub-runner-stream-example]] -=== Examples - -Assume that you have the following Maven repository with deployed stubs for the -`streamService` application: - -==== -[source,bash,indent=0] ----- -└── .m2 - └── repository - └── io - └── codearte - └── accurest - └── stubs - └── streamService - ├── 0.0.1-SNAPSHOT - │   ├── streamService-0.0.1-SNAPSHOT.pom - │   ├── streamService-0.0.1-SNAPSHOT-stubs.jar - │   └── maven-metadata-local.xml - └── maven-metadata-local.xml ----- -==== - -Further assume the stubs contain the following structure: - -==== -[source,bash,indent=0] ----- -├── META-INF -│   └── MANIFEST.MF -└── repository - ├── accurest - │   └── bookReturned1.groovy - └── mappings ----- -==== - -Consider the following contract: - -==== -[source,groovy] ----- -include::{tests_path}/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=sample_dsl,indent=0] ----- -==== - -Now consider the following Spring Cloud Stream function configuration: - -==== -[source,groovy] ----- -include::{tests_path}/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=setup,indent=0] ----- -==== - -Now consider the following Spring configuration: - -==== -[source,yaml] ----- -include::{tests_path}/spring-cloud-contract-stub-runner-stream/src/test/resources/application.yml[] ----- -==== - -To trigger a message from the `return_book_1` label, use the `StubTrigger` interface as -follows: - -==== -[source,groovy] ----- -include::{tests_path}/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=client_trigger,indent=0] ----- -==== - - -That will send out a message to the destination described in the output message of the contract. - -[[features-messaging-stub-runner-jms]] -== Consumer Side Messaging With Spring JMS - -Spring Cloud Contract Stub Runner's messaging module provides an easy way to -integrate with Spring JMS. - -The integration assumes that you have a running instance of a JMS broker. - -[[features-messaging-stub-runner-jms-adding]] -=== Adding the Runner to the Project - -You need to have both Spring JMS and Spring Cloud Contract Stub Runner on the classpath. Remember to annotate your test class -with `@AutoConfigureStubRunner`. - -:input_name: input -:output_name: output - -[[features-messaging-stub-runner-jms-example]] -=== Examples - -Assume that the stub structure looks as follows: - -==== -[source,bash,indent=0] ----- -├── stubs - └── bookReturned1.groovy - ----- -==== - -Further assume the following test configuration: - -==== -[source,yml,indent=0] ----- -stubrunner: - repository-root: stubs:classpath:/stubs/ - ids: my:stubs - stubs-mode: remote -spring: - activemq: - send-timeout: 1000 - jms: - template: - receive-timeout: 1000 ----- -==== - -Now consider the following contract: - -==== -[source,groovy] ----- -include::{tests_path}/spring-cloud-contract-stub-runner-jms/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/jms/JmsStubRunnerSpec.groovy[tags=sample_dsl,indent=0] ----- -==== - -To trigger a message from the `return_book_1` label, we use the `StubTrigger` interface, as follows: - -==== -[source,groovy] ----- -include::{tests_path}/spring-cloud-contract-stub-runner-jms/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/jms/JmsStubRunnerSpec.groovy[tags=client_trigger,indent=0] ----- -==== - -That will send out a message to the destination described in the output message of the contract. diff --git a/docs/modules/ROOT/pages/_project-features-stubrunner.adoc b/docs/modules/ROOT/pages/_project-features-stubrunner.adoc deleted file mode 100644 index 2e77df4347..0000000000 --- a/docs/modules/ROOT/pages/_project-features-stubrunner.adoc +++ /dev/null @@ -1,12 +0,0 @@ -[[features-stub-runner]] -= Spring Cloud Contract Stub Runner -:page-section-summary-toc: 1 - -One of the issues that you might encounter while using Spring Cloud Contract Verifier is -passing the generated WireMock JSON stubs from the server side to the client side (or to -various clients). The same takes place in terms of client-side generation for messaging. - -Copying the JSON files and setting the client side for messaging manually is out of the -question. That is why we introduced Spring Cloud Contract Stub Runner. It can -automatically download and run the stubs for you. - diff --git a/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-boot.adoc b/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-boot.adoc deleted file mode 100644 index e63a0b3512..0000000000 --- a/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-boot.adoc +++ /dev/null @@ -1,131 +0,0 @@ -[[features-stub-runner-boot]] -= Using the Stub Runner Boot Application - -Spring Cloud Contract Stub Runner Boot is a Spring Boot application that exposes REST endpoints to -trigger the messaging labels and to access WireMock servers. - -[[features-stub-runner-boot-security]] -== Stub Runner Boot Security - -The Stub Runner Boot application is not secured by design - securing it would require to add security to all -stubs even if they don't actually require it. Since this is a testing utility - the server is **not intended** -to be used in production environments. - -IMPORTANT: It is expected that **only a trusted client** has access to the Stub Runner Boot server. You should not -run this application as a Fat Jar or a link:docker-project.html#docker-stubrunner[Docker Image] in untrusted locations. - -[[features-stub-runner-boot-server]] -== Stub Runner Server - -To use the Stub Runner Server, add the following dependency: - -==== -[source,groovy,indent=0] ----- -compile "org.springframework.cloud:spring-cloud-starter-stub-runner" ----- -==== - -Then annotate a class with `@EnableStubRunnerServer`, build a fat jar, and it is ready to work. - -For the properties, see the xref:_project-features-stubrunner/stub-runner-junit.adoc#features-stub-runner-rule-spring[Stub Runner Spring] section. - -[[features-stub-runner-boot-how-fat-jar]] -== Stub Runner Server Fat Jar - -You can download a standalone JAR from Maven (for example, for version 2.0.1.RELEASE) -by running the following commands: - -==== -[source,bash,indent=0] ----- -$ wget -O stub-runner.jar 'https://search.maven.org/remotecontent?filepath=org/springframework/cloud/spring-cloud-contract-stub-runner-boot/2.0.1.RELEASE/spring-cloud-contract-stub-runner-boot-2.0.1.RELEASE.jar' -$ java -jar stub-runner.jar --stubrunner.ids=... --stubrunner.repositoryRoot=... ----- -==== - -[[features-stub-runner-boot-how-cli]] -== Spring Cloud CLI - -Starting from the `1.4.0.RELEASE` version of the https://cloud.spring.io/spring-cloud-cli[Spring Cloud CLI] -project, you can start Stub Runner Boot by running `spring cloud stubrunner`. - -To pass the configuration, you can create a `stubrunner.yml` file in the current working directory, -in a subdirectory called `config`, or in `~/.spring-cloud`. The file could resemble the following -example for running stubs installed locally: - - -.stubrunner.yml -==== -[source,yml,indent=0] ----- -stubrunner: - stubsMode: LOCAL - ids: - - com.example:beer-api-producer:+:9876 ----- -==== - -Then you can call `spring cloud stubrunner` from your terminal window to start -the Stub Runner server. It is available at port `8750`. - -[[features-stub-runner-boot-endpoints]] -== Endpoints - -Stub Runner Boot offers two endpoints: - -* xref:_project-features-stubrunner/stub-runner-boot.adoc#features-stub-runner-boot-endpoints-http[HTTP] -* xref:_project-features-stubrunner/stub-runner-boot.adoc#features-stub-runner-boot-endpoints-messaging[Messaging] - -[[features-stub-runner-boot-endpoints-http]] -=== HTTP - -For HTTP, Stub Runner Boot makes the following endpoints available: - -- GET `/stubs`: Returns a list of all running stubs in `ivy:integer` notation -- GET `/stubs/{ivy}`: Returns a port for the given `ivy` notation (when calling the endpoint `ivy` can also be `artifactId` only) - -[[features-stub-runner-boot-endpoints-messaging]] -=== Messaging - -For Messaging, Stub Runner Boot makes the following endpoints available: - -- GET `/triggers`: Returns a list of all running labels in `ivy : [ label1, label2 ...]` notation -- POST `/triggers/{label}`: Runs a trigger with `label` -- POST `/triggers/{ivy}/{label}`: Runs a trigger with a `label` for the given `ivy` notation -(when calling the endpoint, `ivy` can also be `artifactId` only) - -[[features-stub-runner-boot-endpoints-example]] -== Example - -The following example shows typical usage of Stub Runner Boot: - -[source,groovy,indent=0] ----- -include:../:{stubrunner_core_path}/src/test/groovy/org/springframework/cloud/contract/stubrunner/server/StubRunnerBootSpec.groovy[tags=boot_usage] ----- - -[[features-stub-runner-boot-service-discovery]] -== Stub Runner Boot with Service Discovery - -One way to use Stub Runner Boot is to use it as a feed of stubs for "`smoke tests`". What does that mean? -Assume that you do not want to deploy 50 microservices to a test environment in order -to see whether your application works. You have already run a suite of tests during the build process, -but you would also like to ensure that the packaging of your application works. You can -deploy your application to an environment, start it, and run a couple of tests on it to see whether -it works. We can call those tests "`smoke tests`", because their purpose is to check only a handful -of testing scenarios. - -The problem with this approach is that, if you use microservices, you most likely also -use a service discovery tool. Stub Runner Boot lets you solve this issue by starting the -required stubs and registering them in a service discovery tool. - -Now assume that we want to start this application so that the stubs get automatically registered. -We can do so by running the application with `java -jar ${SYSTEM_PROPS} stub-runner-boot-eureka-example.jar`, where -`${SYSTEM_PROPS}`. - -That way, your deployed application can send requests to started WireMock servers through service -discovery. Most likely, points 1 through 3 could be set by default in `application.yml`, because they are not -likely to change. That way, you can provide only the list of stubs to download whenever you start -the Stub Runner Boot. - diff --git a/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-cloud.adoc b/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-cloud.adoc deleted file mode 100644 index 70be63c9a6..0000000000 --- a/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-cloud.adoc +++ /dev/null @@ -1,63 +0,0 @@ -[[features-stub-runner-cloud]] -= Stub Runner Spring Cloud - -Stub Runner can integrate with Spring Cloud. - -For real life examples, see: - -- https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/{samples_branch}/producer[The producer application sample] -- https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/{samples_branch}/consumer_with_discovery[The consumer application sample] - -[[features-stub-runner-cloud-stubbing-discovery]] -== Stubbing Service Discovery - -The most important feature of `Stub Runner Spring Cloud` is the fact that it stubs: - -- `DiscoveryClient` -- `ReactorServiceInstanceLoadBalancer` - -That means that, regardless of whether you use Zookeeper, Consul, Eureka, or anything -else, you do not need that in your tests. We are starting WireMock instances of your -dependencies and we are telling your application, whenever you use `Feign`, to load a -balanced `RestTemplate` or `DiscoveryClient` directly, to call those stubbed servers -instead of calling the real Service Discovery tool. - -[[features-stub-runner-cloud-stubbing-profiles]] -=== Test Profiles and Service Discovery - -In your integration tests, you typically do not want to call either a discovery service (such as Eureka) -or Config Server. That is why you create an additional test configuration in which you want to disable -these features. - -Due to certain limitations of https://github.com/spring-cloud/spring-cloud-commons/issues/156[`spring-cloud-commons`], -to achieve this, you have to disable these properties -in a static block such as the following example (for Eureka): - -==== -[source,java] ----- - //Hack to work around https://github.com/spring-cloud/spring-cloud-commons/issues/156 - static { - System.setProperty("eureka.client.enabled", "false"); - System.setProperty("spring.cloud.config.failFast", "false"); - } ----- -==== - -[[features-stub-runner-additional-config]] -== Additional Configuration - -You can match the `artifactId` of the stub with the name of your application by using the `stubrunner.idsToServiceIds:` map. - -TIP: By default, all service discovery is stubbed. This means that, regardless of whether you have -an existing `DiscoveryClient`, its results are ignored. However, if you want to reuse it, you can set - `stubrunner.cloud.delegate.enabled` to `true`, and then your existing `DiscoveryClient` results are - merged with the stubbed ones. - -The default Maven configuration used by Stub Runner can be tweaked either -by setting the following system properties or by setting the corresponding environment variables: - -- `maven.repo.local`: Path to the custom maven local repository location -- `org.apache.maven.user-settings`: Path to custom maven user settings location -- `org.apache.maven.global-settings`: Path to maven global settings location - diff --git a/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-common.adoc b/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-common.adoc deleted file mode 100644 index 487058628c..0000000000 --- a/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-common.adoc +++ /dev/null @@ -1,60 +0,0 @@ -[[features-stub-runner-common]] -= Common Properties - -This section briefly describes common properties, including: - -* xref:_project-features-stubrunner/stub-runner-common.adoc#features-stub-runner-common-properties-junit-spring[Common Properties for JUnit and Spring] -* xref:_project-features-stubrunner/stub-runner-common.adoc#features-stub-runner-stub-runner-stub-ids[Stub Runner Stubs IDs] - -[[features-stub-runner-common-properties-junit-spring]] -== Common Properties for JUnit and Spring - -You can set repetitive properties by using system properties or Spring configuration -properties. The following table shows their names with their default values: - -[frame="topbot",options="header"] -|=============== -| Property name | Default value | Description -|`stubrunner.minPort`|`10000`| Minimum value of a port for a started WireMock with stubs. -|`stubrunner.maxPort`|`15000`| Maximum value of a port for a started WireMock with stubs. -|`stubrunner.repositoryRoot`|| Maven repository URL. If blank, then call the local Maven repo. -|`stubrunner.classifier`|`stubs`| Default classifier for the stub artifacts. -|`stubrunner.stubsMode`|`CLASSPATH`| The way you want to fetch and register the stubs. -|`stubrunner.ids`|| Array of Ivy notation stubs to download. -|`stubrunner.username`|| Optional username to access the tool that stores the JARs with -stubs. -|`stubrunner.password`|| Optional password to access the tool that stores the JARs with -stubs. -|`stubrunner.stubsPerConsumer`|`false`| Set to `true` if you want to use different stubs for -each consumer instead of registering all stubs for every consumer. -|`stubrunner.consumerName`|| If you want to use a stub for each consumer and want to -override the consumer name, change this value. -|=============== - -[[features-stub-runner-stub-runner-stub-ids]] -== Stub Runner Stubs IDs - -You can set the stubs to download in the `stubrunner.ids` system property. They -use the following pattern: - -==== -[source,java,indent=0] ----- -groupId:artifactId:version:classifier:port ----- -==== - -Note that `version`, `classifier`, and `port` are optional. - -* If you do not provide the `port`, a random one is picked. -* If you do not provide the `classifier`, the default is used. (Note that you can -pass an empty classifier this way: `groupId:artifactId:version:`). -* If you do not provide the `version`, then `+` is passed, and the latest one is -downloaded. - -`port` means the port of the WireMock server. - -IMPORTANT: Starting with version 1.0.4, you can provide a range of versions that you -would like the Stub Runner to take into consideration. You can read more about the -Aether versioning ranges -https://wiki.eclipse.org/Aether/New_and_Noteworthy#Version_Ranges[here]. diff --git a/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-core.adoc b/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-core.adoc deleted file mode 100644 index d9b97944d7..0000000000 --- a/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-core.adoc +++ /dev/null @@ -1,304 +0,0 @@ -[[features-stub-runner-core]] -= Stub Runner Core - -The stub runner core runs stubs for service collaborators. Treating stubs as contracts of -services lets you use stub-runner as an implementation of -https://martinfowler.com/articles/consumerDrivenContracts.html[Consumer-driven Contracts]. - -Stub Runner lets you automatically download the stubs of the provided dependencies (or -pick those from the classpath), start WireMock servers for them, and feed them with proper -stub definitions. For messaging, special stub routes are defined. - -[[features-stub-runner-retrieving]] -== Retrieving stubs - -You can pick from the following options of acquiring stubs: - -- Aether-based solution that downloads JARs with stubs from Artifactory or Nexus -- Classpath-scanning solution that searches the classpath with a pattern to retrieve stubs -- Writing your own implementation of the `org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder` for full customization - -The latter example is described in the xref:advanced.adoc#customization-custom-stub-runner[Custom Stub Runner] section. - -[[features-stub-runner-downloading-stub]] -=== Downloading Stubs - -You can control the downloading of stubs with the `stubsMode` switch. It picks value from the -`StubRunnerProperties.StubsMode` enumeration. You can use the following options: - -- `StubRunnerProperties.StubsMode.CLASSPATH` (default value): Picks stubs from the classpath -- `StubRunnerProperties.StubsMode.LOCAL`: Picks stubs from a local storage (for example, `.m2`) -- `StubRunnerProperties.StubsMode.REMOTE`: Picks stubs from a remote location - -The following example picks stubs from a local location: - -==== -[source,java] ----- -@AutoConfigureStubRunner(repositoryRoot="https://foo.bar", ids = "com.example:beer-api-producer:+:stubs:8095", stubsMode = StubRunnerProperties.StubsMode.LOCAL) ----- -==== - -[[features-stub-runner-classpath-scanning]] -=== Classpath scanning - -If you set the `stubsMode` property to `StubRunnerProperties.StubsMode.CLASSPATH` -(or set nothing since `CLASSPATH` is the default value), the classpath is scanned. -Consider the following example: - -==== -[source,java] ----- -@AutoConfigureStubRunner(ids = { - "com.example:beer-api-producer:+:stubs:8095", - "com.example.foo:bar:1.0.0:superstubs:8096" -}) ----- -==== - -You can add the dependencies to your classpath, as follows: - -==== -[source,xml,indent=0,subs="verbatim,attributes",role="primary"] -.Maven ----- - - com.example - beer-api-producer-restdocs - stubs - 0.0.1-SNAPSHOT - test - - - * - * - - - - - com.example.thing1 - thing2 - superstubs - 1.0.0 - test - - - * - * - - - ----- - -[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] -.Gradle ----- -testCompile("com.example:beer-api-producer-restdocs:0.0.1-SNAPSHOT:stubs") { - transitive = false -} -testCompile("com.example.thing1:thing2:1.0.0:superstubs") { - transitive = false -} ----- -==== - -Then the specified locations on your classpath get scanned. For `com.example:beer-api-producer-restdocs`, -the following locations are scanned: - -- /META-INF/com.example/beer-api-producer-restdocs/**/*.* -- /contracts/com.example/beer-api-producer-restdocs/**/*.* -- /mappings/com.example/beer-api-producer-restdocs/**/*.* - -For `com.example.thing1:thing2`, the following locations are scanned: - -- /META-INF/com.example.thing1/thing2/**/*.* -- /contracts/com.example.thing1/thing2/**/*.* -- /mappings/com.example.thing1/thing2/**/*.* - -TIP: You have to explicitly provide the group and artifact IDs when you package the -producer stubs. - -To achieve proper stub packaging, the producer would set up the contracts as follows: - -==== -[source,bash] ----- -└── src - └── test - └── resources - └── contracts -    └── com.example -       └── beer-api-producer-restdocs -       └── nested -       └── contract3.groovy - ----- -==== - -By using the https://github.com/spring-cloud-samples/spring-cloud-contract-samples/blob/{samples_branch}/producer_with_restdocs/pom.xml[Maven `assembly` plugin] or the -https://github.com/spring-cloud-samples/spring-cloud-contract-samples/blob/{samples_branch}/producer_with_restdocs/build.gradle[Gradle Jar] task, you have to create the following -structure in your stubs jar: - -==== -[source,bash] ----- -└── META-INF - └── com.example - └── beer-api-producer-restdocs - └── 2.0.0 - ├── contracts - │   └── nested -    │ └── contract2.groovy -    └── mappings -    └── mapping.json - ----- -==== - -By maintaining this structure, the classpath gets scanned and you can profit from the messaging or -HTTP stubs without the need to download artifacts. - -[[features-stub-runner-configuring-http-server-stubs]] -=== Configuring HTTP Server Stubs - -Stub Runner has a notion of a `HttpServerStub` that abstracts the underlying -concrete implementation of the HTTP server (for example, WireMock is one of the implementations). -Sometimes, you need to perform some additional tuning (which is concrete for the given implementation) of the stub servers. -To do that, Stub Runner gives you -the `httpServerStubConfigurer` property that is available in the annotation and the -JUnit rule and is accessible through system properties, where you can provide -your implementation of the `org.springframework.cloud.contract.stubrunner.HttpServerStubConfigurer` -interface. The implementations can alter -the configuration files for the given HTTP server stub. - -Spring Cloud Contract Stub Runner comes with an implementation that you -can extend for WireMock: -`org.springframework.cloud.contract.stubrunner.provider.wiremock.WireMockHttpServerStubConfigurer`. -In the `configure` method, -you can provide your own custom configuration for the given stub. The use -case might be starting WireMock for the given artifact ID, on an HTTPS port. The following -example shows how to do so: - -.WireMockHttpServerStubConfigurer implementation -==== -[source,groovy,indent=0] ----- -include:../:{stubrunner_core_path}/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfigurationSpec.groovy[tags=wireMockHttpServerStubConfigurer] ----- -==== - -You can then reuse it with the `@AutoConfigureStubRunner` annotation, as follows: - -==== -[source,groovy,indent=0] ----- -include:../:{stubrunner_core_path}/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfigurationSpec.groovy[tags=annotation] ----- -==== - -Whenever an HTTPS port is found, it takes precedence over the HTTP port. - -[[features-stub-runner-running-stubs]] -== Running stubs - -This section describes how to run stubs. It contains the following topics: - -* xref:_project-features-stubrunner/stub-runner-core.adoc#features-stub-runner-http-stubs[HTTP Stubs] -* xref:_project-features-stubrunner/stub-runner-core.adoc#features-stub-runner-viewing[Viewing Registered Mappings] -* xref:_project-features-stubrunner/stub-runner-core.adoc#features-stub-runner-messaging[Messaging Stubs] - -[[features-stub-runner-http-stubs]] -=== HTTP Stubs - -Stubs are defined in JSON documents, whose syntax is defined in the http://wiremock.org/stubbing.html[WireMock documentation]. - -The following example defines a stub in JSON: - -==== -[source,javascript,indent=0] ----- -{ - "request": { - "method": "GET", - "url": "/ping" - }, - "response": { - "status": 200, - "body": "pong", - "headers": { - "Content-Type": "text/plain" - } - } -} ----- -==== - -[[features-stub-runner-viewing]] -=== Viewing Registered Mappings - -Every stubbed collaborator exposes a list of defined mappings under the `__/admin/` endpoint. - -You can also use the `mappingsOutputFolder` property to dump the mappings to files. -For the annotation-based approach, it would resembling the following example: - -==== -[source,java] ----- -@AutoConfigureStubRunner(ids="a.b.c:loanIssuance,a.b.c:fraudDetectionServer", -mappingsOutputFolder = "target/outputmappings/") ----- -==== - -For the JUnit approach, it resembles the following example: - -==== -[source,java] ----- -@ClassRule @Shared StubRunnerRule rule = new StubRunnerRule() - .repoRoot("https://some_url") - .downloadStub("a.b.c", "loanIssuance") - .downloadStub("a.b.c:fraudDetectionServer") - .withMappingsOutputFolder("target/outputmappings") ----- -==== - -Then, if you check out the `target/outputmappings` folder, you would see the following structure; - -==== -[source,bash] ----- -. -├── fraudDetectionServer_13705 -└── loanIssuance_12255 ----- -==== - -That means that there were two stubs registered. `fraudDetectionServer` was registered at port `13705` -and `loanIssuance` at port `12255`. If we take a look at one of the files, we would see (for WireMock) -the mappings available for the given server: - -==== -[source,json] ----- -[{ - "id" : "f9152eb9-bf77-4c38-8289-90be7d10d0d7", - "request" : { - "url" : "/name", - "method" : "GET" - }, - "response" : { - "status" : 200, - "body" : "fraudDetectionServer" - }, - "uuid" : "f9152eb9-bf77-4c38-8289-90be7d10d0d7" -}, -... -] ----- -==== - -[[features-stub-runner-messaging]] -=== Messaging Stubs - -Depending on the provided Stub Runner dependency and the DSL, the messaging routes are automatically set up. - diff --git a/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-fail-on-no-stubs.adoc b/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-fail-on-no-stubs.adoc deleted file mode 100644 index 3480c144f3..0000000000 --- a/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-fail-on-no-stubs.adoc +++ /dev/null @@ -1,39 +0,0 @@ -[[features-stub-runner-fail-on-no-stubs]] -= Fail On No Stubs - -By default, Stub Runner will fail if no stubs are found. In order to change that behavior, set the `failOnNoStubs` property to `false` in the annotation or call the `withFailOnNoStubs(false)` method on a JUnit Rule or Extension. The following example shows how to do so: - -==== -[source,java,indent=0,subs="verbatim,attributes",role="primary"] -.Annotation ----- -@AutoConfigureStubRunner( -stubsMode = StubRunnerProperties.StubsMode.REMOTE, - repositoryRoot = "stubs://file://location/to/the/contracts", - ids = "com.example:some-producer", - failOnNoStubs = false) ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.JUnit 4 Rule ----- -@Rule - public StubRunnerRule rule = new StubRunnerRule() - .downloadStub("com.example:some-producer") - .repoRoot("stubs://file://location/to/the/contracts") - .stubsMode(StubRunnerProperties.StubsMode.REMOTE) - .withFailOnNoStubs(false); ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.JUnit 5 Extension ----- -@RegisterExtension - public StubRunnerExtension stubRunnerExtension = new StubRunnerExtension() - .downloadStub("com.example:some-producer") - .repoRoot("stubs://file://location/to/the/contracts") - .stubsMode(StubRunnerProperties.StubsMode.REMOTE) - .withFailOnNoStubs(false); ----- -==== - diff --git a/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-generate-stubs-at-runtime.adoc b/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-generate-stubs-at-runtime.adoc deleted file mode 100644 index 66b064fd5f..0000000000 --- a/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-generate-stubs-at-runtime.adoc +++ /dev/null @@ -1,43 +0,0 @@ -[[features-stub-runner-generate-stubs-at-runtime]] -= Generating Stubs at Runtime - -As a consumer, you might not want to wait for the producer to finish its implementation and then publish their stubs. A solution to this problem can be generation of stubs at runtime. - -As a producer, when a contract is defined, you are required to make the generated tests pass in order for the stubs to be published. There are cases where you would like to unblock the consumers so that they can fetch the stubs before your tests actually pass. In this case, you should set such contracts as in-progress. You can read more about this under the xref:_project-features-contract/common-top-elements.adoc#contract-dsl-in-progress[Contracts in Progress] section. That way, your tests are not generated, but the stubs are generated. - -As a consumer, you can toggle a switch to generate stubs at runtime. Stub Runner ignores all the existing stub mappings and generates new ones for all the contract definitions. Another option is to pass the `stubrunner.generate-stubs` system property. The following example shows such a setup: - -==== -[source,java,indent=0,subs="verbatim,attributes",role="primary"] -.Annotation ----- -@AutoConfigureStubRunner( -stubsMode = StubRunnerProperties.StubsMode.REMOTE, - repositoryRoot = "stubs://file://location/to/the/contracts", - ids = "com.example:some-producer", - generateStubs = true) ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.JUnit 4 Rule ----- -@Rule - public StubRunnerRule rule = new StubRunnerRule() - .downloadStub("com.example:some-producer") - .repoRoot("stubs://file://location/to/the/contracts") - .stubsMode(StubRunnerProperties.StubsMode.REMOTE) - .withGenerateStubs(true); ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.JUnit 5 Extension ----- -@RegisterExtension - public StubRunnerExtension stubRunnerExtension = new StubRunnerExtension() - .downloadStub("com.example:some-producer") - .repoRoot("stubs://file://location/to/the/contracts") - .stubsMode(StubRunnerProperties.StubsMode.REMOTE) - .withGenerateStubs(true); ----- -==== - diff --git a/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-junit.adoc b/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-junit.adoc deleted file mode 100644 index 5c7ad331af..0000000000 --- a/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-junit.adoc +++ /dev/null @@ -1,167 +0,0 @@ -[[features-stub-runner-junit]] -= Stub Runner JUnit Rule and Stub Runner JUnit5 Extension - -Stub Runner comes with a JUnit rule that lets you can download and run stubs for a given -group and artifact ID, as the following example shows: - -==== -[source,java,indent=0] ----- -include:../:{stubrunner_core_path}/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleJUnitTest.java[tags=classrule] ----- -==== - -A `StubRunnerExtension` is also available for JUnit 5. `StubRunnerRule` and -`StubRunnerExtension` work in a very similar fashion. After the rule or extension is -called, Stub Runner connects to your Maven repository and, for the given list of -dependencies, tries to: - -- Download them -- Cache them locally -- Unzip them to a temporary folder -- Start a WireMock server for each Maven dependency on a random port from the provided -range of ports or the provided port -- Feed the WireMock server with all JSON files that are valid WireMock definitions -- Send messages (remember to pass an implementation of `MessageVerifierSender` interface) - -Stub Runner uses the https://wiki.eclipse.org/Aether[Eclipse Aether] mechanism to download the Maven dependencies. -Check their https://wiki.eclipse.org/Aether[docs] for more information. - -Since the `StubRunnerRule` and `StubRunnerExtension` implement the `StubFinder`, they let -you find the started stubs, as the following example shows: - -==== -[source,groovy,indent=0] ----- -include:../:{stubrunner_core_path}/src/main/java/org/springframework/cloud/contract/stubrunner/StubFinder.java[lines=16..-1] ----- -==== - -The following examples provide more detail about using Stub Runner: - -==== -[source,groovy,indent=0,subs="verbatim,attributes",role="primary"] -.Spock ----- -include:../:{stubrunner_core_path}/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleSpec.groovy[tags=classrule] ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Junit 4 ----- -include:../:{stubrunner_core_path}/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleJUnitTest.java[tags=test] ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.Junit 5 ----- -include:../:{stubrunner_core_path}/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionTests.java[tags=extension] ----- -==== - -See the xref:_project-features-stubrunner/stub-runner-common.adoc#features-stub-runner-common-properties-junit-spring[Common Properties for JUnit and Spring] for more information on -how to apply global configuration of Stub Runner. - -IMPORTANT: To use the JUnit rule or JUnit 5 extension together with messaging, you have to provide an implementation of the -`MessageVerifierSender` and `MessageVerifierReceiver` interface to the rule builder (for example, `rule.messageVerifierSender(new MyMessageVerifierSender())`). -If you do not do this, then, whenever you try to send a message, an exception is thrown. - -[[features-stub-runner-rule-maven-settings]] -== Maven Settings - -The stub downloader honors Maven settings for a different local repository folder. -Authentication details for repositories and profiles are currently not taken into account, -so you need to specify it by using the properties mentioned above. - -[[features-stub-runner-rule-fixed-ports]] -== Providing Fixed Ports - -You can also run your stubs on fixed ports. You can do it in two different ways. -One is to pass it in the properties, and the other is to use the fluent API of -JUnit rule. - -[[features-stub-runner-rule-fluent-api]] -== Fluent API - -When using the `StubRunnerRule` or `StubRunnerExtension`, you can add a stub to download -and then pass the port for the last downloaded stub. The following example shows how to do so: - -==== -[source,java,indent=0] ----- -include:../:{stubrunner_core_path}/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleCustomPortJUnitTest.java[tags=classrule_with_port] ----- -==== - -For the preceding example, the following test is valid: - -==== -[source,java,indent=0] ----- -include:../:{stubrunner_core_path}/src/test/groovy/org/springframework/cloud/contract/stubrunner/junit4/StubRunnerRuleCustomPortJUnitTest.java[tags=test_with_port] ----- -==== - -[[features-stub-runner-rule-spring]] -== Stub Runner with Spring - -Stub Runner with Spring sets up Spring configuration of the Stub Runner project. - -By providing a list of stubs inside your configuration file, Stub Runner automatically downloads -and registers in WireMock the selected stubs. - -If you want to find the URL of your stubbed dependency, you can autowire the `StubFinder` interface and use -its methods, as follows: - -==== -[source,groovy,indent=0] ----- -include:../:{stubrunner_core_path}/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfigurationSpec.groovy[tags=test] ----- -==== - -Doing so depends on the following configuration file: - -==== -[source,yml,indent=0] ----- -include:../:{stubrunner_core_path}/src/test/resources/application-test.yml[tags=test] ----- -==== - -Instead of using the properties, you can also use the properties inside the `@AutoConfigureStubRunner`. -The following example achieves the same result by setting values on the annotation: - -==== -[source,groovy,indent=0] ----- -include:../:{stubrunner_core_path}/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/consul/StubRunnerSpringCloudConsulAutoConfigurationSpec.groovy[tags=autoconfigure] ----- -==== - -Stub Runner Spring registers environment variables in the following manner -for every registered WireMock server. The following example shows Stub Runner IDs for -`com.example:thing1` and `com.example:thing2`: - -- `stubrunner.runningstubs.thing1.port` -- `stubrunner.runningstubs.com.example.thing1.port` -- `stubrunner.runningstubs.thing2.port` -- `stubrunner.runningstubs.com.example.thing2.port` - -You can reference these values in your code. - -You can also use the `@StubRunnerPort` annotation to inject the port of a running stub. -The value of the annotation can be the `groupid:artifactid` or only the `artifactid`. -The following example works shows Stub Runner IDs for -`com.example:thing1` and `com.example:thing2`. - -==== -[source,java,indent=0] ----- -@StubRunnerPort("thing1") -int thing1Port; -@StubRunnerPort("com.example:thing2") -int thing2Port; ----- -==== - diff --git a/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-publishing-stubs-as-jars.adoc b/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-publishing-stubs-as-jars.adoc deleted file mode 100644 index 3e12070ae2..0000000000 --- a/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-publishing-stubs-as-jars.adoc +++ /dev/null @@ -1,32 +0,0 @@ -[[features-stub-runner-publishing-stubs-as-jars]] -= Publishing Stubs as JARs - -The easiest approach to publishing stubs as jars is to centralize the way stubs are kept. -For example, you can keep them as jars in a Maven repository. - -TIP: For both Maven and Gradle, the setup comes ready to work. However, you can customize -it if you want to. - -The following example shows how to publish stubs as jars: - -==== -[source,xml,indent=0,subs="verbatim,attributes",role="primary"] -.Maven ----- - -include:../:{samples_url}/producer_with_restdocs/pom.xml[tags=skip_jar,indent=0] - - -include:../:{samples_url}/producer_with_restdocs/pom.xml[tags=assembly,indent=0] - - -include:../:{samples_url}/producer_with_restdocs/src/assembly/stub.xml[indent=0] ----- - -[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] -.Gradle ----- -include:../:{plugins_path}/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/scenarioProject/build.gradle[tags=jar_setup,indent=0] ----- -==== - diff --git a/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-snapshot-versions.adoc b/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-snapshot-versions.adoc deleted file mode 100644 index f1b2725e86..0000000000 --- a/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-snapshot-versions.adoc +++ /dev/null @@ -1,21 +0,0 @@ -[[features-stub-runner-snapshot-versions]] -= Snapshot Versions -:page-section-summary-toc: 1 - -You can add the additional snapshot repository to your build file to use snapshot -versions, which are automatically uploaded after every successful build, as follows: - -==== -[source,xml,indent=0,subs="verbatim,attributes",role="primary"] -.Maven ----- -include:../:{standalone_samples_path}/http-server/pom.xml[tags=repos,indent=0] ----- - -[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] -.Gradle (`settings.xml`) ----- -include:../:{standalone_samples_path}/http-server/settings.gradle[tags=repos,indent=0] ----- -==== - diff --git a/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-stubs-per-consumer.adoc b/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-stubs-per-consumer.adoc deleted file mode 100644 index 9b2cf5cc1e..0000000000 --- a/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-stubs-per-consumer.adoc +++ /dev/null @@ -1,98 +0,0 @@ -[[features-stub-runner-stubs-per-consumer]] -= Consumer-Driven Contracts: Stubs Per Consumer - -There are cases in which two consumers of the same endpoint want to have two different responses. - -TIP: This approach also lets you immediately know which consumer uses which part of your API. -You can remove part of a response that your API produces and see which of your autogenerated tests -fails. If none fails, you can safely delete that part of the response, because nobody uses it. - -Consider the following example of a contract defined for the producer called `producer`, -which has two consumers (`foo-consumer` and `bar-consumer`): - -==== -.Consumer `foo-service` -[source,groovy] ----- -request { - url '/foo' - method GET() -} -response { - status OK() - body( - foo: "foo" - } -} ----- - -.Consumer `bar-service` -[source,groovy] ----- -request { - url '/bar' - method GET() -} -response { - status OK() - body( - bar: "bar" - } -} ----- -==== - -You cannot produce two different responses for the same request. That is why you can properly package the -contracts and then profit from the `stubsPerConsumer` feature. - -On the producer side, the consumers can have a folder that contains contracts related only to them. -By setting the `stubrunner.stubs-per-consumer` flag to `true`, we no longer register all stubs but only those that -correspond to the consumer application's name. In other words, we scan the path of every stub and, -if it contains a subfolder with name of the consumer in the path, only then is it registered. - -On the `foo` producer side the contracts would look like this - -[source,bash] ----- -. -└── contracts - ├── bar-consumer - │   ├── bookReturnedForBar.groovy - │   └── shouldCallBar.groovy - └── foo-consumer - ├── bookReturnedForFoo.groovy - └── shouldCallFoo.groovy ----- - -The `bar-consumer` consumer can either set the `spring.application.name` or the `stubrunner.consumer-name` to `bar-consumer` -Alternatively, you can set the test as follows: - -==== -[source,groovy] ----- -include:../:{stubrunner_core_path}/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerStubsPerConsumerSpec.groovy[tags=test] -... -} ----- -==== - -Then only the stubs registered under a path that contains `bar-consumer` in its name (that is, those from the -`src/test/resources/contracts/bar-consumer/some/contracts/...` folder) are allowed to be referenced. - -You can also set the consumer name explicitly, as follows: - -==== -[source,groovy] ----- -include:../:{stubrunner_core_path}/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerStubsPerConsumerWithConsumerNameSpec.groovy[tags=test] -... -} ----- -==== - -Then only the stubs registered under a path that contains the `foo-consumer` in its name (that is, those from the -`src/test/resources/contracts/foo-consumer/some/contracts/...` folder) are allowed to be referenced. - -For more information about the reasons behind this change, -see https://github.com/spring-cloud/spring-cloud-contract/issues/224[issue 224]. - diff --git a/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-stubs-protocol.adoc b/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-stubs-protocol.adoc deleted file mode 100644 index c4085957a7..0000000000 --- a/docs/modules/ROOT/pages/_project-features-stubrunner/stub-runner-stubs-protocol.adoc +++ /dev/null @@ -1,121 +0,0 @@ -[[features-stub-runner-stubs-protocol]] -= Fetching Stubs or Contract Definitions From A Location - -Instead of picking the stubs or contract definitions from -Artifactory, Nexus, or Git, you can point to -a location on a drive or the classpath. Doing so can be especially useful in a multi-module project, where one module wants -to reuse stubs or contracts from another module without -the need to actually install those in a local maven -repository to commit those changes to Git. - -In order to achieve this, you can use the `stubs://` -protocol when the repository root parameter is set either -in Stub Runner or in a Spring Cloud Contract plugin. - -In this example, the `producer` project has been successfully -built and stubs were generated under the `target/stubs` folder. As a consumer, one can set up the Stub Runner to pick the stubs from that location by using the `stubs://` protocol. - -==== -[source,java,indent=0,subs="verbatim,attributes",role="primary"] -.Annotation ----- -@AutoConfigureStubRunner( -stubsMode = StubRunnerProperties.StubsMode.REMOTE, - repositoryRoot = "stubs://file://location/to/the/producer/target/stubs/", - ids = "com.example:some-producer") ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.JUnit 4 Rule ----- -@Rule - public StubRunnerRule rule = new StubRunnerRule() - .downloadStub("com.example:some-producer") - .repoRoot("stubs://file://location/to/the/producer/target/stubs/") - .stubsMode(StubRunnerProperties.StubsMode.REMOTE); ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.JUnit 5 Extension ----- -@RegisterExtension - public StubRunnerExtension stubRunnerExtension = new StubRunnerExtension() - .downloadStub("com.example:some-producer") - .repoRoot("stubs://file://location/to/the/producer/target/stubs/") - .stubsMode(StubRunnerProperties.StubsMode.REMOTE); ----- -==== - -Contracts and stubs may be stored in a location, where each producer has its own, dedicated folder for contracts and stub mappings. Under that folder, each consumer can have its own setup. To make Stub Runner find the dedicated folder from the provided IDs, you can pass the `stubs.find-producer=true` property or the `stubrunner.stubs.find-producer=true` system property. -The following listing shows an arrangement of contracts and stubs: - -==== -[source,bash,indent=0] ----- -└── com.example <1> - ├── some-artifact-id <2> - │   └── 0.0.1 - │   ├── contracts <3> - │   │   └── shouldReturnStuffForArtifactId.groovy - │   └── mappings <4> - │   └── shouldReturnStuffForArtifactId.json - └── some-other-artifact-id <5> - ├── contracts - │   └── shouldReturnStuffForOtherArtifactId.groovy - └── mappings - └── shouldReturnStuffForOtherArtifactId.json - ----- -<1> group ID of the consumers -<2> consumer with artifact id [some-artifact-id] -<3> contracts for the consumer with artifact id [some-artifact-id] -<4> mappings for the consumer with artifact id [some-artifact-id] -<5> consumer with artifact id [some-other-artifact-id] -==== - -==== -[source,java,indent=0,subs="verbatim,attributes",role="primary"] -.Annotation ----- -@AutoConfigureStubRunner( -stubsMode = StubRunnerProperties.StubsMode.REMOTE, - repositoryRoot = "stubs://file://location/to/the/contracts/directory", - ids = "com.example:some-producer", - properties="stubs.find-producer=true") ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.JUnit 4 Rule ----- - static Map contractProperties() { - Map map = new HashMap<>(); - map.put("stubs.find-producer", "true"); - return map; - } - -@Rule - public StubRunnerRule rule = new StubRunnerRule() - .downloadStub("com.example:some-producer") - .repoRoot("stubs://file://location/to/the/contracts/directory") - .stubsMode(StubRunnerProperties.StubsMode.REMOTE) - .properties(contractProperties()); ----- - -[source,java,indent=0,subs="verbatim,attributes",role="secondary"] -.JUnit 5 Extension ----- - static Map contractProperties() { - Map map = new HashMap<>(); - map.put("stubs.find-producer", "true"); - return map; - } - -@RegisterExtension - public StubRunnerExtension stubRunnerExtension = new StubRunnerExtension() - .downloadStub("com.example:some-producer") - .repoRoot("stubs://file://location/to/the/contracts/directory") - .stubsMode(StubRunnerProperties.StubsMode.REMOTE) - .properties(contractProperties()); ----- -==== - diff --git a/docs/modules/ROOT/pages/_project-features-wiremock.adoc b/docs/modules/ROOT/pages/_project-features-wiremock.adoc deleted file mode 100644 index fb4bfe4d0e..0000000000 --- a/docs/modules/ROOT/pages/_project-features-wiremock.adoc +++ /dev/null @@ -1,201 +0,0 @@ -[[features-wiremock]] -= Spring Cloud Contract WireMock - - -The Spring Cloud Contract WireMock modules let you use https://github.com/tomakehurst/wiremock[WireMock] in a -Spring Boot application. For more detail, check out the -https://github.com/spring-cloud/spring-cloud-contract/tree/{github-tag}/samples[samples]. - -If you have a Spring Boot application that uses Tomcat as an embedded server (which is -the default with `spring-boot-starter-web`), you can add -`spring-cloud-starter-contract-stub-runner` to your classpath and add `@AutoConfigureWireMock` -to use Wiremock in your tests. Wiremock runs as a stub server, and you -can register stub behavior by using a Java API or by using static JSON declarations as part of -your test. The following code shows an example: - -==== -[source,java,indent=0] ----- -include::{doc_samples_url}/src/test/java/com/example/WiremockForDocsTests.java[tags=wiremock_test1] -include::{doc_samples_url}/src/test/java/com/example/WiremockForDocsTests.java[tags=wiremock_test2] ----- -==== - -To start the stub server on a different port, use (for example), -`@AutoConfigureWireMock(port=9999)`. For a random port, use a value of `0`. The stub -server port can be bound in the test application context with the `wiremock.server.port` -property. Using `@AutoConfigureWireMock` adds a bean of type `WiremockConfiguration` to -your test application context, where it is cached between methods and classes -that have the same context. The same is true for Spring integration tests. Also, you can -inject a bean of type `WireMockServer` into your test. -The registered WireMock server is reset after each test class. -However, if you need to reset it after each test method, set the `wiremock.reset-mappings-after-each-test` property to `true`. - -[[features-wiremock-registering-stubs]] -== Registering Stubs Automatically - -If you use `@AutoConfigureWireMock`, it registers WireMock JSON stubs from the file -system or classpath (by default, from `file:src/test/resources/mappings`). You can -customize the locations by using the `stubs` attribute in the annotation, which can be an -Ant-style resource pattern or a directory. In the case of a directory, `**/*.json` is -appended. The following code shows an example: - -==== ----- -@RunWith(SpringRunner.class) -@SpringBootTest -@AutoConfigureWireMock(stubs="classpath:/stubs") -public class WiremockImportApplicationTests { - - @Autowired - private Service service; - - @Test - public void contextLoads() throws Exception { - assertThat(this.service.go()).isEqualTo("Hello World!"); - } - -} ----- -==== - -NOTE: Actually, WireMock always loads mappings from `src/test/resources/mappings` *as -well as* the custom locations in the `stubs` attribute. To change this behavior, you can -also specify a file root, as described in the xref:_project-features-wiremock.adoc#features-wiremock-using-files[next section of this document]. - -NOTE: Also, the mappings in the `stubs` location are not considered part of Wiremock's "default mappings" and calls -to `com.github.tomakehurst.wiremock.client.WireMock.resetToDefaultMappings` during a test do not result in the mappings -in the `stubs` location being included. However, the `org.springframework.cloud.contract.wiremock.WireMockTestExecutionListener` -does reset the mappings (including adding the ones from the stubs location) after every test class and, optionally, -after every test method (guarded by the `wiremock.reset-mappings-after-each-test` property). - -If you use Spring Cloud Contract's default stub jars, your -stubs are stored in the `/META-INF/group-id/artifact-id/versions/mappings/` folder. -If you want to register all stubs from that location, from all embedded JARs, you can use -the following syntax: - -==== -[source,java,indent=0] ----- -include::{wiremock_tests}/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockFilesApplicationWithUrlResourceTests.java[tags=load_all_stubs] ----- -==== - -[[features-wiremock-using-files]] -== Using Files to Specify the Stub Bodies - -WireMock can read response bodies from files on the classpath or the file system. In the -case of the file system, you can see in the JSON DSL that the response has a `bodyFileName` instead of a -(literal) `body`. The files are resolved relative to a root directory (by default, -`src/test/resources/\__files`). To customize this location, you can set the `files` -attribute in the `@AutoConfigureWireMock` annotation to the location of the parent -directory (in other words, `__files` is a subdirectory). You can use a Spring resource -notation to refer to `file:...` or `classpath:...` locations. Generic URLs are not -supported. A list of values can be given -- in which case, WireMock resolves the first file -that exists when it needs to find a response body. - -NOTE: When you configure the `files` root, it also affects the -automatic loading of stubs, because they come from the root location -in a subdirectory called `mappings`. - -NOTE: The value of `files` has no -effect on the stubs loaded explicitly from the `stubs` attribute. - -[[features-wiremock-junit-rule]] -== Alternative: Using JUnit Rules - -For a more conventional WireMock experience, you can use JUnit `@Rules` to start and stop -the server. To do so, use the `WireMockSpring` convenience class to obtain an `Options` -instance, as the following example shows: - -==== -[source,java,indent=0] ----- -include::{doc_samples_url}/src/test/java/com/example/WiremockForDocsClassRuleTests.java[tags=wiremock_test1] -include::{doc_samples_url}/src/test/java/com/example/WiremockForDocsClassRuleTests.java[tags=wiremock_test2] ----- -==== - -The `@ClassRule` means that the server shuts down after all the methods in this class -have been run. - -[[features-wiremock-relaxed-ssl]] -== Relaxed SSL Validation for Rest Template - -WireMock lets you stub a "`secure`" server with an `https` URL protocol. If your -application wants to contact that stub server in an integration test, it finds that -the SSL certificates are not valid (the usual problem with self-installed certificates). -The best option is often to re-configure the client to use `http`. If that is not an -option, you can ask Spring to configure an HTTP client that ignores SSL validation errors -(do so only for tests, of course). - -To make this work with minimum fuss, you need to use the Spring Boot -`RestTemplateBuilder` in your application, as the following example shows: - -==== -[source,java,indent=0] ----- - @Bean - public RestTemplate restTemplate(RestTemplateBuilder builder) { - return builder.build(); - } ----- -==== - -You need `RestTemplateBuilder` because the builder is passed through callbacks to -initialize it, so the SSL validation can be set up in the client at that point. This -happens automatically in your test if you use the `@AutoConfigureWireMock` -annotation or the stub runner. If you use the JUnit `@Rule` approach, you need to add the -`@AutoConfigureHttpClient` annotation as well, as the following example shows: - -==== -[source,java,indent=0] ----- -@RunWith(SpringRunner.class) -@SpringBootTest("app.baseUrl=https://localhost:6443") -@AutoConfigureHttpClient -public class WiremockHttpsServerApplicationTests { - - @ClassRule - public static WireMockClassRule wiremock = new WireMockClassRule( - WireMockSpring.options().httpsPort(6443)); -... -} ----- -==== - -If you use `spring-boot-starter-test`, you have the Apache HTTP client on the -classpath, and it is selected by the `RestTemplateBuilder` and configured to ignore SSL -errors. If you use the default `java.net` client, you do not need the annotation (but it -does no harm). There is currently no support for other clients, but it may be added -in future releases. - -To disable the custom `RestTemplateBuilder`, set the `wiremock.rest-template-ssl-enabled` -property to `false`. - -[[features-wiremock-spring-mvc-mocks]] -== WireMock and Spring MVC Mocks - -Spring Cloud Contract provides a convenience class that can load JSON WireMock stubs into -a Spring `MockRestServiceServer`. The following code shows an example: - -==== -[source,java,indent=0] ----- -include::{doc_samples_url}/src/test/java/com/example/WiremockForDocsMockServerApplicationTests.java[tags=wiremock_test] ----- -==== - -The `baseUrl` value is prepended to all mock calls, and the `stubs()` method takes a stub -path resource pattern as an argument. In the preceding example, the stub defined at -`/stubs/resource.json` is loaded into the mock server. If the `RestTemplate` is asked to -visit `https://example.org/`, it gets the responses as being declared at that URL. More -than one stub pattern can be specified, and each one can be a directory (for a recursive -list of all `.json`), a fixed filename (as in the preceding example), or an Ant-style -pattern. The JSON format is the normal WireMock format, which you can read about at the -https://wiremock.org/docs/stubbing/[WireMock website]. - -Currently, the Spring Cloud Contract Verifier supports Tomcat, Jetty, and Undertow as -Spring Boot embedded servers, and Wiremock itself has "`native`" support for a particular -version of Jetty (currently 9.2). To use the native Jetty, you need to add the native -Wiremock dependencies and exclude the Spring Boot container (if there is one). diff --git a/docs/modules/ROOT/pages/advanced.adoc b/docs/modules/ROOT/pages/advanced.adoc deleted file mode 100644 index b1b48e2166..0000000000 --- a/docs/modules/ROOT/pages/advanced.adoc +++ /dev/null @@ -1,462 +0,0 @@ -[[contract-customization]] -= Spring Cloud Contract customization - -In this section, we describe how to customize various parts of Spring Cloud Contract. - -[[customization-customization]] -== DSL Customization - -IMPORTANT: This section is valid only for the Groovy DSL - -You can customize the Spring Cloud Contract Verifier by extending the DSL, as shown in -the remainder of this section. - -[[customization-extending]] -=== Extending the DSL - -You can provide your own functions to the DSL. The key requirement for this feature is to -maintain the static compatibility. Later in this chapter, you can see examples of: - -* Creating a JAR with reusable classes. -* Referencing of these classes in the DSLs. - -You can find the full example -https://github.com/spring-cloud-samples/spring-cloud-contract-samples[here]. - -[[customization-extending-common-jar]] -=== Common JAR - -The following examples show three classes that can be reused in the DSLs. - -`PatternUtils` contains functions used by both the consumer and the producer. -The following listing shows the `PatternUtils` class: - -==== -[source,java] ----- -include::{samples_url}/common/src/main/java/com/example/PatternUtils.java[] ----- -==== - -`ConsumerUtils` contains functions used by the consumer. -The following listing shows the `ConsumerUtils` class: - -==== -[source,java] ----- -include::{samples_url}/common/src/main/java/com/example/ConsumerUtils.java[] ----- -==== - -`ProducerUtils` contains functions used by the producer. -The following listing shows the `ProducerUtils` class: - -==== -[source,java] ----- -include::{samples_url}/common/src/main/java/com/example/ProducerUtils.java[] ----- -==== - -[[customization-test-dep]] -=== Adding a Test Dependency in the Project's Dependencies - -To add a test dependency in the project's dependencies, you must first add the common jar -dependency as a test dependency. Because your contracts files -are available on the test resources path, the common jar classes automatically become -visible in your Groovy files. The following examples show how to test the dependency: - -==== -[source,xml,indent=0,subs="verbatim,attributes",role="primary"] -.Maven ----- -include::{samples_url}/producer/pom.xml[tags=test_dep,indent=0] ----- - -[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] -.Gradle ----- -include::{samples_url}/producer/build.gradle[tags=test_dep,indent=0] ----- -==== - -[[customization-plugin-dep]] -=== Adding a Test Dependency in the Plugin's Dependencies - -Now, you must add the dependency for the plugin to reuse at runtime, as the -following example shows: - -==== -[source,xml,indent=0,subs="verbatim,attributes",role="primary"] -.Maven ----- -include::{samples_url}/producer/pom.xml[tags=test_dep_in_plugin,indent=0] ----- - -[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] -.Gradle ----- -include::{samples_url}/producer/build.gradle[tags=test_dep_in_plugin,indent=0] ----- -==== - -[[customization-referencing]] -=== Referencing Classes in DSLs - -You can now reference your classes in your DSL, as the following example shows: - -==== -[source,groovy] ----- -include::{samples_url}/producer/src/test/resources/contracts/beer/rest/shouldGrantABeerIfOldEnough.groovy[indent=0] ----- -==== - -IMPORTANT: You can set the Spring Cloud Contract plugin up by setting `convertToYaml` to -`true`. That way, you do NOT have to add the dependency with the extended functionality -to the consumer side, since the consumer side uses YAML contracts instead of Groovy contracts. - -[[customization-wiremock]] -== WireMock Customization - -In this section, we show how to customize the way you work with https://wiremock.org[WireMock]. - -[[customization-wiremock-extension]] -=== Registering Your Own WireMock Extension - -WireMock lets you register custom extensions. By default, Spring Cloud Contract registers -the transformer, which lets you reference a request from a response. If you want to -provide your own extensions, you can register an implementation of the -`org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockExtensions` interface. -Since we use the `spring.factories` extension approach, you can create an entry similar to -the following in the `META-INF/spring.factories` file: - -==== -[source,groovy,indent=0] ----- -include::{stubrunner_core_path}/src/test/resources/META-INF/spring.factories[indent=0] ----- -==== - -The following example shows a custom extension: - -.TestWireMockExtensions.groovy -==== -[source,groovy,indent=0] ----- -include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/TestWireMockExtensions.groovy[indent=0] ----- -==== - -IMPORTANT: If you want the transformation to be applied only for a mapping that explicitly -requires it, override the `applyGlobally()` method and set it to `false` . - -[[customization-wiremock-configuration]] -=== Customization of WireMock Configuration - -You can register a bean of type `org.springframework.cloud.contract.wiremock.WireMockConfigurationCustomizer` -to customize the WireMock configuration (for example, to add custom transformers). -The following example shows how to do so: - -==== -[source,java,indent=0] ----- -include::{wiremock_tests}/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockConfigurationCustomizerTests.java[tags=customizer_1] -// perform your customization here -include::{wiremock_tests}/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockConfigurationCustomizerTests.java[tags=customizer_2] ----- -==== - -[[customization-wiremock-from-metadata]] -=== Customization of WireMock via Metadata - -With version 3.0.0 you're able to set `metadata` in your contracts. If you set an entry with key equal to `wiremock` and the value -will be a valid WireMock's `StubMapping` JSON / map or an actual `StubMapping` object, Spring Cloud Contract will patch the generated -stub with part of your customization. Let's look at the following example - -[source,yaml,indent=0] ----- -include::{standalone_samples_path}/http-server/src/test/resources/contracts/yml/fraud/shouldReturnFraudStats.yml[tags=metadata,indent=0] ----- - -In the `metadata` section we've set an entry with key `wiremock` and its value is a JSON `StubMapping` that sets a delay in the generated stub. Such code allowed us to get the following merged WireMock JSON stub. - -[source,json,indent=0] ----- -{ - "id" : "ebae49e2-a2a3-490c-a57f-ba28e26b81ea", - "request" : { - "url" : "/yamlfrauds", - "method" : "GET" - }, - "response" : { - "status" : 200, - "body" : "{\"count\":200}", - "headers" : { - "Content-Type" : "application/json" - }, - "fixedDelayMilliseconds" : 2000, - "transformers" : [ "response-template" ] - }, - "uuid" : "ebae49e2-a2a3-490c-a57f-ba28e26b81ea" -} ----- - -The current implementation allows to manipulate only the stub side (we don't change the generated test). Also, what does not get changed -are the whole request and body and headers of the response. - -[[customization-wiremock-from-metadata-custom-processor]] -==== Customization of WireMock via Metadata and a Custom Processor - -If you want to apply a custom WireMock `StubMapping` post processing, you can under `META-INF/spring.factories` under the -`org.springframework.cloud.contract.verifier.converter.StubProcessor` key register your own implementation of a stub processor. For your convenience we've created an interface called `org.springframework.cloud.contract.verifier.wiremock.WireMockStubPostProcessor` that is dedicated to WireMock. - -You'll have to implement methods to inform Spring Cloud Contract whether the post processor is applicable for a given contract and how should the post processing look like. - -IMPORTANT: On the consumer side, when using Stub Runner, remember to pass the custom `HttpServerStubConfigurer` implementation (e.g. the one that extends `WireMockHttpServerStubConfigurer`) where you'll register a custom extension of your choosing. If you don't do so, even you have a custom WireMock extension on the classpath, WireMock will not notice it, won't apply it and will print out a warning statement that the given extension was not found. - -[[customization-pluggable-architecture]] -== Using the Pluggable Architecture - -You may encounter cases where your contracts have been defined in other formats, -such as YAML, RAML, or PACT. In those cases, you still want to benefit from the automatic -generation of tests and stubs. You can add your own implementation for generating both -tests and stubs. Also, you can customize the way tests are generated (for example, you -can generate tests for other languages) and the way stubs are generated (for example, you -can generate stubs for other HTTP server implementations). - -[[customization-custom-contract-converter]] -=== Custom Contract Converter - -The `ContractConverter` interface lets you register your own implementation of a contract -structure converter. The following code listing shows the `ContractConverter` interface: - -==== -[source,java] ----- -include::{contract_spec_path}/src/main/java/org/springframework/cloud/contract/spec/ContractConverter.java[indent=0,lines=17..-1] ----- -==== - -Your implementation must define the condition on which it should start the -conversion. Also, you must define how to perform that conversion in both directions. - -IMPORTANT: Once you create your implementation, you must create a -`/META-INF/spring.factories` file in which you provide the fully qualified name of your -implementation. - -The following example shows a typical `spring.factories` file: - -==== -[source] ----- -org.springframework.cloud.contract.spec.ContractConverter=\ -org.springframework.cloud.contract.verifier.converter.YamlContractConverter ----- -==== - -[[customization-custom-test-generator]] -=== Using the Custom Test Generator - -If you want to generate tests for languages other than Java or you are not happy with the -way the verifier builds Java tests, you can register your own implementation. - -The `SingleTestGenerator` interface lets you register your own implementation. The -following code listing shows the `SingleTestGenerator` interface: - -==== -[source,groovy] ----- -include::{verifier_core_path}/src/main/java/org/springframework/cloud/contract/verifier/builder/SingleTestGenerator.java[indent=0,lines=17..-1] ----- -==== - -Again, you must provide a `spring.factories` file, such as the one shown in the following -example: - -==== -[source] ----- -org.springframework.cloud.contract.verifier.builder.SingleTestGenerator=/ -com.example.MyGenerator ----- -==== - -[[customization-custom-stub-generator]] -=== Using the Custom Stub Generator - -If you want to generate stubs for stub servers other than WireMock, you can plug in your -own implementation of the `StubGenerator` interface. The following code listing shows the -`StubGenerator` interface: - -==== -[source,groovy] ----- -include::{converters_path}/src/main/java/org/springframework/cloud/contract/verifier/converter/StubGenerator.java[indent=0,lines=16..-1] ----- -==== - -Again, you must provide a `spring.factories` file, such as the one shown in the following -example: - -==== -[source] ----- -include::{converters_path}/src/main/resources/META-INF/spring.factories[indent=0] ----- -==== - -The default implementation is the WireMock stub generation. - -TIP: You can provide multiple stub generator implementations. For example, from a single -DSL, you can produce both WireMock stubs and Pact files. - -[[customization-custom-stub-runner]] -=== Using the Custom Stub Runner - -If you decide to use custom stub generation, you also need a custom way of running -stubs with your different stub provider. - -Assume that you use https://github.com/dreamhead/moco[Moco] to build your stubs and that -you have written a stub generator and placed your stubs in a JAR file. - -In order for Stub Runner to know how to run your stubs, you have to define a custom -HTTP Stub server implementation, which might resemble the following example: - -==== -[source,groovy] ----- -include::{tests_path}/spring-cloud-contract-stub-runner-moco/src/test/groovy/org/springframework/cloud/contract/stubrunner/provider/moco/MocoHttpServerStub.groovy[indent=0,lines=16..-1] ----- -==== - -Then you can register it in your `spring.factories` file, as the following -example shows: - -==== -[source] ----- -org.springframework.cloud.contract.stubrunner.HttpServerStub=\ -org.springframework.cloud.contract.stubrunner.provider.moco.MocoHttpServerStub ----- -==== - -Now you can run stubs with Moco. - -IMPORTANT: If you do not provide any implementation, the default (WireMock) -implementation is used. If you provide more than one, the first one on the list is used. - -[[customization-custom-stub-downloader]] -=== Using the Custom Stub Downloader - -You can customize the way your stubs are downloaded by creating an implementation of the -`StubDownloaderBuilder` interface, as the following example shows: - -==== -[source,java] ----- -package com.example; - -class CustomStubDownloaderBuilder implements StubDownloaderBuilder { - - @Override - public StubDownloader build(final StubRunnerOptions stubRunnerOptions) { - return new StubDownloader() { - @Override - public Map.Entry downloadAndUnpackStubJar( - StubConfiguration config) { - File unpackedStubs = retrieveStubs(); - return new AbstractMap.SimpleEntry<>( - new StubConfiguration(config.getGroupId(), config.getArtifactId(), version, - config.getClassifier()), unpackedStubs); - } - - File retrieveStubs() { - // here goes your custom logic to provide a folder where all the stubs reside - } - } - } -} ----- -==== - -Then you can register it in your `spring.factories` file, as the following -example shows: - -==== -[source] ----- -# Example of a custom Stub Downloader Provider -org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder=\ -com.example.CustomStubDownloaderBuilder ----- -==== - -Now you can pick a folder with the source of your stubs. - -IMPORTANT: If you do not provide any implementation, the default (scanning the classpath) is used. -If you provide the `stubsMode = StubRunnerProperties.StubsMode.LOCAL` or -`stubsMode = StubRunnerProperties.StubsMode.REMOTE`, the Aether implementation is used -If you provide more than one, the first one on the list is used. - -[[scm-stub-downloader]] -=== Using the SCM Stub Downloader - -Whenever the `repositoryRoot` starts with a SCM protocol -(currently, we support only `git://`), the stub downloader tries -to clone the repository and use it as a source of contracts -to generate tests or stubs. - -Through environment variables, system properties, or properties set -inside the plugin or the contracts repository configuration, you can -tweak the downloader's behavior. The following table describes the available -properties: - -.SCM Stub Downloader properties -|==== -|Type of a property |Name of the property | Description -| -* `git.branch` (plugin prop) - -* `stubrunner.properties.git.branch` (system prop) - -* `STUBRUNNER_PROPERTIES_GIT_BRANCH` (env prop) -|master -|Which branch to checkout - -| -* `git.username` (plugin prop) - -* `stubrunner.properties.git.username` (system prop) - -* `STUBRUNNER_PROPERTIES_GIT_USERNAME` (env prop) -| -|Git clone username - -| -* `git.password` (plugin prop) - -* `stubrunner.properties.git.password` (system prop) - -* `STUBRUNNER_PROPERTIES_GIT_PASSWORD` (env prop) -| -|Git clone password - -| -* `git.no-of-attempts` (plugin prop) - -* `stubrunner.properties.git.no-of-attempts` (system prop) - -* `STUBRUNNER_PROPERTIES_GIT_NO_OF_ATTEMPTS` (env prop) -|10 -|Number of attempts to push the commits to `origin` - -| -* `git.wait-between-attempts` (Plugin prop) - -* `stubrunner.properties.git.wait-between-attempts` (system prop) - -* `STUBRUNNER_PROPERTIES_GIT_WAIT_BETWEEN_ATTEMPTS` (env prop) -|1000 -|Number of milliseconds to wait between attempts to push the commits to `origin` -|==== diff --git a/docs/modules/ROOT/pages/appendix.adoc b/docs/modules/ROOT/pages/appendix.adoc deleted file mode 100644 index e88632a567..0000000000 --- a/docs/modules/ROOT/pages/appendix.adoc +++ /dev/null @@ -1,20 +0,0 @@ -:numbered!: -[appendix] -[[common-application-properties]] -= Common application properties -:page-section-summary-toc: 1 - - -Various properties can be specified inside your `application.properties` file, inside your `application.yml` file, or as command line switches. -This appendix provides a list of common {project-full-name} properties and references to the underlying classes that consume them. - -NOTE: Property contributions can come from additional jar files on your classpath, so you should not consider this an exhaustive list. -Also, you can define your own properties. - -[[default-application-properties]] -== Default application properties - - -[[additional-application-properties]] -== Additional application properties - diff --git a/docs/modules/ROOT/pages/docker-project.adoc b/docs/modules/ROOT/pages/docker-project.adoc deleted file mode 100644 index fce6ad412c..0000000000 --- a/docs/modules/ROOT/pages/docker-project.adoc +++ /dev/null @@ -1,627 +0,0 @@ -[[docker]] -= Docker Project - -In this section, we publish a `springcloud/spring-cloud-contract` Docker image -that contains a project that generates tests and runs them in `EXPLICIT` mode -against a running application. - -TIP: The `EXPLICIT` mode means that the tests generated from contracts send -real requests and not mocked ones. - -We also publish a `spring-cloud/spring-cloud-contract-stub-runner` Docker image -that starts the standalone version of Stub Runner. - -[[docker-intro]] -== A Short Introduction to Maven, JARs, and Binary Storage - -Since non-JVM projects can use the Docker image, it is good to -explain the basic terms behind Spring Cloud Contract packaging defaults. - -Parts of the following definitions were taken from the https://maven.apache.org/glossary.html[Maven Glossary]: - -- `Project`: Maven thinks in terms of projects. Projects -are all you build. Those projects follow a well defined -"`Project Object Model`". Projects can depend on other projects -- -in that case, the latter are called "`dependencies`". A project may -consistent of several subprojects. However, these subprojects are still -treated equally as projects. -- `Artifact`: An artifact is something that is either produced or used -by a project. Examples of artifacts produced by Maven for a project -include JAR files and source and binary distributions. Each artifact -is uniquely identified by a group ID and an artifact ID that is -unique within a group. -- `JAR`: JAR stands for Java ARchive. Its format is based on -the ZIP file format. Spring Cloud Contract packages the contracts and generated -stubs in a JAR file. -- `GroupId`: A group ID is a universally unique identifier for a project. -While this is often just the project name (for example, `commons-collections`), -it is helpful to use a fully-qualified package name to distinguish it -from other projects with a similar name (for example, `org.apache.maven`). -Typically, when published to the Artifact Manager, the `GroupId` gets -slash separated and forms part of the URL. For example, for a group ID of `com.example` -and an artifact ID of `application`, the result would be `/com/example/application/`. -- `Classifier`: The Maven dependency notation looks as follows: -`groupId:artifactId:version:classifier`. The classifier is an additional suffix -passed to the dependency -- for example, `stubs` or `sources`. The same dependency -(for example, `com.example:application`) can produce multiple artifacts that -differ from each other with the classifier. -- `Artifact manager`: When you generate binaries, sources, or packages, you would -like them to be available for others to download, reference, or reuse. In the case -of the JVM world, those artifacts are generally JARs. For Ruby, those artifacts are gems. -For Docker, those artifacts are Docker images. You can store those artifacts -in a manager. Examples of such managers include https://jfrog.com/artifactory/[Artifactory] -and https://www.sonatype.org/nexus/[Nexus]. - -[[docker-how-it-works]] -== Generating Tests on the Producer Side - -The image searches for contracts under the `/contracts` folder. -The output from running the tests is available in the -`/spring-cloud-contract/build` folder (useful for debugging -purposes). - -You can mount your contracts and pass the environment variables. -The image then: - -- Generates the contract tests -- Runs the tests against the provided URL -- Generates the https://github.com/tomakehurst/wiremock[WireMock] stubs -- Publishes the stubs to a Artifact Manager (optional -- turned on by default) - -[[docker-env-vars]] -=== Environment Variables - -The Docker image requires some environment variables to point to -your running application, to the Artifact manager instance, and so on. -The following list describes the environment variables: - -// TODO: reenable -//include::{project-root}/docker/spring-cloud-contract-docker/target/adoc/props.adoc[indent=0] - -The following environment variables are used when tests are run: - -// TODO: reenable -//include::{project-root}/docker/spring-cloud-contract-docker/target/adoc/appProps.adoc[indent=0] - -### Customizing the gradle build - -You can provide a customized `gradle.build` to be run in the container by mounting your customized build file as a volume when running the container: - -==== -[source,bash] ----- -$ docker run -v :/spring-cloud-contract/build.gradle springcloud/spring-cloud-contract: ----- -==== - -[[docker-example-of-usage]] -=== Example of Usage via HTTP - -In this section, we explore a simple MVC application. To get started, clone the following -git repository and cd to the resulting directory, by running the following commands: - -==== -[source,bash] ----- -$ git clone https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs -$ cd bookstore ----- -==== - -The contracts are available in the `/contracts` folder. - -Since we want to run tests, we can run the following command: - -==== -[source,bash] ----- -$ npm test ----- -==== - -However, for learning purposes, we split it into pieces, as follows: - -==== -[source,bash] ----- -# Stop docker infra (nodejs, artifactory) -$ ./stop_infra.sh -# Start docker infra (nodejs, artifactory) -$ ./setup_infra.sh - -# Kill & Run app -$ pkill -f "node app" -$ nohup node app & - -# Prepare environment variables -$ SC_CONTRACT_DOCKER_VERSION="..." -$ APP_IP="192.168.0.100" -$ APP_PORT="3000" -$ ARTIFACTORY_PORT="8081" -$ APPLICATION_BASE_URL="http://${APP_IP}:${APP_PORT}" -$ ARTIFACTORY_URL="http://${APP_IP}:${ARTIFACTORY_PORT}/artifactory/libs-release-local" -$ CURRENT_DIR="$( pwd )" -$ CURRENT_FOLDER_NAME=${PWD##*/} -$ PROJECT_VERSION="0.0.1.RELEASE" - -# Run contract tests -$ docker run --rm -e "APPLICATION_BASE_URL=${APPLICATION_BASE_URL}" -e "PUBLISH_ARTIFACTS=true" -e "PROJECT_NAME=${CURRENT_FOLDER_NAME}" -e "REPO_WITH_BINARIES_URL=${ARTIFACTORY_URL}" -e "PROJECT_VERSION=${PROJECT_VERSION}" -v "${CURRENT_DIR}/contracts/:/contracts:ro" -v "${CURRENT_DIR}/node_modules/spring-cloud-contract/output:/spring-cloud-contract-output/" springcloud/spring-cloud-contract:"${SC_CONTRACT_DOCKER_VERSION}" - -# Kill app -$ pkill -f "node app" ----- -==== - -Through bash scripts, the following happens: - -- The infrastructure (MongoDb and Artifactory) is set up. -In a real-life scenario, you would run the NodeJS application -with a mocked database. In this example, we want to show how we can -benefit from Spring Cloud Contract in very little time. -- Due to those constraints, the contracts also represent the -stateful situation. -** The first request is a `POST` that causes data to get inserted into the database. -** The second request is a `GET` that returns a list of data with 1 previously inserted element. -- The NodeJS application is started (on port `3000`). -- The contract tests are generated through Docker, and tests -are run against the running application. -** The contracts are taken from `/contracts` folder. -** The output of the test is available under -`node_modules/spring-cloud-contract/output`. -- The stubs are uploaded to Artifactory. You can find them in -http://localhost:8081/artifactory/libs-release-local/com/example/bookstore/0.0.1.RELEASE/. -The stubs are at http://localhost:8081/artifactory/libs-release-local/com/example/bookstore/0.0.1.RELEASE/bookstore-0.0.1.RELEASE-stubs.jar. - -[[docker-example-of-usage-messaging]] -=== Example of Usage via Messaging - -If you want to use Spring Cloud Contract with messaging via the Docker images (e.g. -in case of polyglot applications) then you'll have to have the following prerequisites met: - -* Middleware (e.g. RabbitMQ or Kafka) must be running before generating tests -* Your contract needs to call a method `triggerMessage(...)` with a `String` parameter that is equal to the contract's `label`. -* Your application needs to have a HTTP endpoint via which we can trigger a message -** That endpoint should not be available on production (could be enabled via an environment variable) - -[[docker-example-of-usage-messaging-contract]] -==== Example of a Messaging Contract - -The contract needs to call a `triggerMessage(...)` method. That method is already provided in the base class for all tests in the docker image and will send out a request to the HTTP endpoint on the producer side. Below you can find examples of such contracts. - -==== -[source,groovy,indent=0,subs="verbatim,attributes",role="primary"] -.Groovy ----- -import org.springframework.cloud.contract.spec.Contract - -Contract.make { - description 'Send a pong message in response to a ping message' - label 'ping_pong' - input { - // You have to provide the `triggerMessage` method with the `label` - // as a String parameter of the method - triggeredBy('triggerMessage("ping_pong")') - } - outputMessage { - sentTo('output') - body([ - message: 'pong' - ]) - } - metadata( - [amqp: - [ - outputMessage: [ - connectToBroker: [ - declareQueueWithName: "queue" - ], - messageProperties: [ - receivedRoutingKey: '#' - ] - ] - ] - ]) -} ----- - -[source,yml,indent=0,subs="verbatim,attributes",role="secondary"] -.YAML ----- -description: 'Send a pong message in response to a ping message' -label: 'ping_pong' -input: - # You have to provide the `triggerMessage` method with the `label` - # as a String parameter of the method - triggeredBy: 'triggerMessage("ping_pong")' -outputMessage: - sentTo: 'output' - body: - message: 'pong' -metadata: - amqp: - outputMessage: - connectToBroker: - declareQueueWithName: "queue" - messageProperties: - receivedRoutingKey: '#' ----- -==== - -[[docker-example-of-usage-messaging-endpoint]] -==== HTTP Endpoint to Trigger a Message - -Why is there need to develop such an endpoint? Spring Cloud Contract -would have to generate code in various languages (as it does in Java) to make it possible to trigger production -code that sends a message to a broker. If such code is not generated then we need to be able to trigger the message anyways, and the way to do it is to provide an HTTP endpoint that the user will prepare in the language of their choosing. - -The endpoint must have the following configuration: - -- URL: `/springcloudcontract/{label}` where `label` can be any text -- Method: `POST` -- Basing on the `label` will generate a message that will be sent to a given destination according to the contract definition - -Below you have an example of such an endpoint. If you're interested in -providing an example in your language don't hesitate to file an issue in -the https://github.com/spring-cloud/spring-cloud-contract/issues/new?assignees=&labels=&template=feature_request.md&title=New+Polyglot+Sample+of+a+HTTP+controller[Spring Cloud Contract repository at Github]. - -==== -[source,python,indent=0,subs="verbatim,attributes"] -.Python ----- -#!/usr/bin/env python - -from flask import Flask -from flask import jsonify -import pika -import os - -app = Flask(__name__) - -# Production code that sends a message to RabbitMQ -def send_message(cmd): - connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) - channel = connection.channel() - channel.basic_publish( - exchange='output', - routing_key='#', - body=cmd, - properties=pika.BasicProperties( - delivery_mode=2, # make message persistent - )) - connection.close() - return " [x] Sent via Rabbit: %s" % cmd - -# This should be ran in tests (shouldn't be publicly available) -if 'CONTRACT_TEST' in os.environ: - @app.route('/springcloudcontract/+$C_ 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�P7>c8|nmWH@sJ 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%0Dv?AJbBFAdp6l%~@$e)!}LaZi$}Yob}O7q4}E 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