diff --git a/README.adoc b/README.adoc index a5b3a780a8..2cf991def5 100644 --- a/README.adoc +++ b/README.adoc @@ -1350,6 +1350,11 @@ started will be attached. Yes! With version 1.1.0 we've added such a possibility. On the HTTP stub server side we're providing support for this for WireMock. In case of other HTTP server stubs you'll have to implement the approach yourself. +==== Can I reference text from file? + +Yes! With version 1.2.0 we've added such a possibility. It's enough to call `file(...)` method in the +DSL and provide a path relative to where the contract lays. + === Links Here you can find interesting links related to Spring Cloud Contract Verifier: diff --git a/docs/src/main/asciidoc/verifier/contract.adoc b/docs/src/main/asciidoc/verifier/contract.adoc index 7d675d369b..c3691e87cc 100644 --- a/docs/src/main/asciidoc/verifier/contract.adoc +++ b/docs/src/main/asciidoc/verifier/contract.adoc @@ -67,6 +67,48 @@ or just set the `ignored` property on the contract itself: include::{contract_spec_path}/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy[tags=ignored,indent=0] ---- +===== Passing values from files + +Starting with version `1.2.0` it's possible to pass values from files. Let's assume that we have +the following resources in our project. + +[source,bash,indent=0] +---- +└── src +    └── test +       └── resources +          └── contracts +    ├── readFromFile.groovy +    ├── request.json +    └── response.json +---- + +And our contract looks like this: + +[source,groovy,indent=0] +---- +include::{verifier_core_path}/src/test/resources/classpath/readFromFile.groovy[indent=0] +---- + +and the json files look like this: + +*request.json* +[source,json,indent=0] +---- +include::{verifier_core_path}/src/test/resources/classpath/request.json[indent=0] +---- + +*response.json* +[source,json,indent=0] +---- +include::{verifier_core_path}/src/test/resources/classpath/response.json[indent=0] +---- + +When test / stub generation takes place then the contents of the file will be +passed to the body of request / response. All thanks to the `file(...)` method. +The argument of that method needs to be a file with location relative to the +folder in which the contract lays. + ==== HTTP Top-Level Elements Following methods can be called in the top-level closure of a contract definition. Request and response are mandatory, priority is optional. diff --git a/docs/src/main/asciidoc/verifier/introduction.adoc b/docs/src/main/asciidoc/verifier/introduction.adoc index 66d62d56a8..5135fd9c2b 100644 --- a/docs/src/main/asciidoc/verifier/introduction.adoc +++ b/docs/src/main/asciidoc/verifier/introduction.adoc @@ -878,3 +878,8 @@ started will be attached. Yes! With version 1.1.0 we've added such a possibility. On the HTTP stub server side we're providing support for this for WireMock. In case of other HTTP server stubs you'll have to implement the approach yourself. + +==== Can I reference text from file? + +Yes! With version 1.2.0 we've added such a possibility. It's enough to call `file(...)` method in the +DSL and provide a path relative to where the contract lays. diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Common.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Common.groovy index 7db6aca4b9..122d042ef0 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Common.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Common.groovy @@ -161,6 +161,14 @@ class Common { return new ServerDslProperty(serverValue) } + String file(String relativePath) { + URL resource = Thread.currentThread().getContextClassLoader().getResource(relativePath) + if (resource == null) { + throw new IllegalStateException("File [${relativePath}] is not present") + } + return new File(resource.toURI()).text + } + /** * Helper method to provide a better name for the producer side */ diff --git a/spring-cloud-contract-stub-runner/README.adoc b/spring-cloud-contract-stub-runner/README.adoc index 7604bdd8b6..6b48b23f65 100644 --- a/spring-cloud-contract-stub-runner/README.adoc +++ b/spring-cloud-contract-stub-runner/README.adoc @@ -248,7 +248,7 @@ That means that there were two stubs registered. `fraudDetectionServer` was regi and `loanIssuance` at port `12255`. If we take a look at one of the files we would see (for WireMock) mappings available for the given server: -[souce,json] +[source,json] ---- [{ "id" : "f9152eb9-bf77-4c38-8289-90be7d10d0d7", 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 index b92923a88e..8e4ee733b2 100644 --- 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 @@ -155,7 +155,7 @@ class StubRepository { } @SuppressWarnings("unchecked") - private Collection collectContractDescriptors(File descriptorsDirectory) { + private Collection collectContractDescriptors(final File descriptorsDirectory) { final List contractDescriptors = new ArrayList<>(); try { Files.walkFileTree(Paths.get(descriptorsDirectory.toURI()), @@ -167,7 +167,7 @@ class StubRepository { ContractConverter converter = contractConverter(file); if (isContractDescriptor(file) && isStubPerConsumerPathMatching(file)) { contractDescriptors - .addAll(ContractVerifierDslConverter.convertAsCollection(file)); + .addAll(ContractVerifierDslConverter.convertAsCollection(file.getParentFile(), file)); } else if (converter != null && isStubPerConsumerPathMatching(file)) { contractDescriptors.addAll(converter.convertFrom(file)); } diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockConverter.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockConverter.groovy index 910a96c4b7..d34c9fa5e6 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockConverter.groovy +++ b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockConverter.groovy @@ -17,10 +17,8 @@ package org.springframework.cloud.contract.verifier.wiremock import groovy.transform.CompileStatic -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.converter.StubGenerator -import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter +import org.springframework.cloud.contract.verifier.converter.StubGenerator /** * WireMock implementation of the {@link StubGenerator} * @@ -46,8 +44,4 @@ abstract class DslToWireMockConverter implements StubGenerator { } return "" } - - protected Collection createGroovyDSLFromStringContent(String groovyDslAsString) { - return ContractVerifierDslConverter.convertAsCollection(groovyDslAsString) - } } 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 index f848ad78bd..092f6a5bc3 100755 --- 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 @@ -65,7 +65,7 @@ class DslToWireMockClientConverterSpec extends Specification { """) when: String json = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null, - ContractVerifierDslConverter.convertAsCollection(file))).values().first() + ContractVerifierDslConverter.convertAsCollection(new File("/"),file))).values().first() then: JSONAssert.assertEquals(''' {"request":{"method":"PUT","urlPattern":"/[0-9]{2}"},"response":{"status":200}} @@ -101,7 +101,7 @@ class DslToWireMockClientConverterSpec extends Specification { ''') when: Map convertedContents = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null, - ContractVerifierDslConverter.convertAsCollection(file))) + ContractVerifierDslConverter.convertAsCollection(new File("/"),file))) then: convertedContents.size() == 2 JSONAssert.assertEquals(jsonResponse(1), convertedContents.values().first(), false) @@ -142,7 +142,7 @@ class DslToWireMockClientConverterSpec extends Specification { when: Map convertedContents = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null, - ContractVerifierDslConverter.convertAsCollection(file))) + ContractVerifierDslConverter.convertAsCollection(new File("/"),file))) then: convertedContents.isEmpty() } @@ -167,7 +167,7 @@ class DslToWireMockClientConverterSpec extends Specification { """) when: String json = converter.convertContents("test", new ContractMetadata(file.toPath(), false, 0, null, - ContractVerifierDslConverter.convertAsCollection(file))).values().first() + ContractVerifierDslConverter.convertAsCollection(new File("/"),file))).values().first() then: JSONAssert.assertEquals(''' {"request":{ @@ -236,7 +236,7 @@ class DslToWireMockClientConverterSpec extends Specification { """) when: String json = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null, - ContractVerifierDslConverter.convertAsCollection(file))).values().first() + ContractVerifierDslConverter.convertAsCollection(new File("/"),file))).values().first() then: JSONAssert.assertEquals(''' { @@ -354,7 +354,7 @@ class DslToWireMockClientConverterSpec extends Specification { """) when: String json = converter.convertContents("test", new ContractMetadata(file.toPath(), false, 0, null, - ContractVerifierDslConverter.convertAsCollection(file))).values().first() + ContractVerifierDslConverter.convertAsCollection(new File("/"),file))).values().first() then: JSONAssert.assertEquals(''' {"request":{"urlPath":"/foos","method":"GET"},"response":{"body":"[{\\"id\\":\\"123\\"},{\\"id\\":\\"567\\"}]"}} @@ -393,7 +393,7 @@ class DslToWireMockClientConverterSpec extends Specification { """) when: String json = converter.convertContents("test", new ContractMetadata(file.toPath(), false, 0, null, - ContractVerifierDslConverter.convertAsCollection(file))).values().first() + ContractVerifierDslConverter.convertAsCollection(new File("/"),file))).values().first() then: noExceptionThrown() and: @@ -440,7 +440,7 @@ class DslToWireMockClientConverterSpec extends Specification { ''') when: String json = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null, - ContractVerifierDslConverter.convertAsCollection(file))).values().first() + ContractVerifierDslConverter.convertAsCollection(new File("/"),file))).values().first() then: JSONAssert.assertEquals( // tag::wiremock[] ''' @@ -595,7 +595,7 @@ class DslToWireMockClientConverterSpec extends Specification { ''') when: String json = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null, - ContractVerifierDslConverter.convertAsCollection(file))).values().first() + ContractVerifierDslConverter.convertAsCollection(new File("/"),file))).values().first() then: JSONAssert.assertEquals(//tag::matchers[] ''' @@ -749,7 +749,7 @@ class DslToWireMockClientConverterSpec extends Specification { ''') when: String json = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null, - ContractVerifierDslConverter.convertAsCollection(file))).values().first() + ContractVerifierDslConverter.convertAsCollection(new File("/"),file))).values().first() then: JSONAssert.assertEquals( ''' 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 index 0c6d6f3c2c..095091af0e 100755 --- 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 @@ -88,7 +88,7 @@ class WireMockToDslConverterSpec extends Specification { when: String groovyDsl = WireMockToDslConverter.fromWireMockStub(wireMockStub) then: - def a = ContractVerifierDslConverter.convertAsCollection( + def a = ContractVerifierDslConverter.convertAsCollection(new File("/"), """org.springframework.cloud.contract.spec.Contract.make { $groovyDsl }""") @@ -143,7 +143,7 @@ class WireMockToDslConverterSpec extends Specification { when: String groovyDsl = WireMockToDslConverter.fromWireMockStub(wireMockStub) then: - def a = ContractVerifierDslConverter.convertAsCollection( + def a = ContractVerifierDslConverter.convertAsCollection(new File("/"), """org.springframework.cloud.contract.spec.Contract.make { $groovyDsl }""") @@ -196,7 +196,7 @@ class WireMockToDslConverterSpec extends Specification { when: String groovyDsl = WireMockToDslConverter.fromWireMockStub(wireMockStub) then: - ContractVerifierDslConverter.convertAsCollection( + ContractVerifierDslConverter.convertAsCollection(new File("/"), """org.springframework.cloud.contract.spec.Contract.make { $groovyDsl }""").first() == expectedGroovyDsl @@ -253,7 +253,7 @@ class WireMockToDslConverterSpec extends Specification { when: String groovyDsl = WireMockToDslConverter.fromWireMockStub(wireMockStub) then: - ContractVerifierDslConverter.convertAsCollection( + ContractVerifierDslConverter.convertAsCollection(new File("/"), """org.springframework.cloud.contract.spec.Contract.make { $groovyDsl }""").first() == expectedGroovyDsl @@ -318,7 +318,7 @@ class WireMockToDslConverterSpec extends Specification { when: String groovyDsl = WireMockToDslConverter.fromWireMockStub(wireMockStub) then: - ContractVerifierDslConverter.convertAsCollection( + ContractVerifierDslConverter.convertAsCollection(new File("/"), """org.springframework.cloud.contract.spec.Contract.make { $groovyDsl }""").first() == expectedGroovyDsl @@ -356,7 +356,7 @@ class WireMockToDslConverterSpec extends Specification { when: String groovyDsl = WireMockToDslConverter.fromWireMockStub(wireMockStub) then: - Contract evaluatedGroovyDsl = ContractVerifierDslConverter.convertAsCollection( + Contract evaluatedGroovyDsl = ContractVerifierDslConverter.convertAsCollection(new File("/"), """org.springframework.cloud.contract.spec.Contract.make { $groovyDsl }""").first() @@ -396,7 +396,7 @@ class WireMockToDslConverterSpec extends Specification { when: String groovyDsl = WireMockToDslConverter.fromWireMockStub(wireMockStub) then: - Contract evaluatedGroovyDsl = ContractVerifierDslConverter.convertAsCollection( + Contract evaluatedGroovyDsl = ContractVerifierDslConverter.convertAsCollection(new File("/"), """org.springframework.cloud.contract.spec.Contract.make { $groovyDsl }""").first() @@ -437,7 +437,7 @@ class WireMockToDslConverterSpec extends Specification { when: String groovyDsl = WireMockToDslConverter.fromWireMockStub(wireMockStub) then: - Contract evaluatedGroovyDsl = ContractVerifierDslConverter.convertAsCollection( + Contract evaluatedGroovyDsl = ContractVerifierDslConverter.convertAsCollection(new File("/"), """org.springframework.cloud.contract.spec.Contract.make { $groovyDsl }""").first() @@ -477,7 +477,7 @@ class WireMockToDslConverterSpec extends Specification { when: String groovyDsl = WireMockToDslConverter.fromWireMockStub(wireMockStub) then: - Contract evaluatedGroovyDsl = ContractVerifierDslConverter.convertAsCollection( + Contract evaluatedGroovyDsl = ContractVerifierDslConverter.convertAsCollection(new File("/"), """org.springframework.cloud.contract.spec.Contract.make { $groovyDsl }""").first() @@ -517,7 +517,7 @@ class WireMockToDslConverterSpec extends Specification { when: String groovyDsl = WireMockToDslConverter.fromWireMockStub(wireMockStub) then: - Contract evaluatedGroovyDsl = ContractVerifierDslConverter.convertAsCollection( + Contract evaluatedGroovyDsl = ContractVerifierDslConverter.convertAsCollection(new File("/"), """org.springframework.cloud.contract.spec.Contract.make { $groovyDsl }""").first() @@ -555,7 +555,7 @@ class WireMockToDslConverterSpec extends Specification { when: String groovyDsl = WireMockToDslConverter.fromWireMockStub(wireMockStub) then: - Contract evaluatedGroovyDsl = ContractVerifierDslConverter.convertAsCollection( + Contract evaluatedGroovyDsl = ContractVerifierDslConverter.convertAsCollection(new File("/"), """org.springframework.cloud.contract.spec.Contract.make { $groovyDsl }""").first() 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 index 40636a5adb..351ebddf15 100755 --- 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 @@ -31,7 +31,7 @@ class WiremockScenarioConverterSpec extends Specification { 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(dsl.toFile()))).values().first() + ContractVerifierDslConverter.convertAsCollection(new File("/"), dsl.toFile()))).values().first() then: content.contains('"requiredScenarioState" : "Started"') content.contains('"newScenarioState" : "Step1"') @@ -44,7 +44,7 @@ class WiremockScenarioConverterSpec extends Specification { 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(dsl.toFile()))).values().first() + ContractVerifierDslConverter.convertAsCollection(new File("/"), dsl.toFile()))).values().first() then: content.contains('"requiredScenarioState" : "Step1"') content.contains('"newScenarioState" : "Step2"') @@ -57,7 +57,7 @@ class WiremockScenarioConverterSpec extends Specification { 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(dsl.toFile()))).values().first() + ContractVerifierDslConverter.convertAsCollection(new File("/"), dsl.toFile()))).values().first() then: content.contains('"requiredScenarioState" : "Step2"') !content.contains('"newScenarioState"') 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 index f467d080ce..545ce367a8 100644 --- 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 @@ -16,6 +16,8 @@ package org.springframework.cloud.contract.maven.verifier; import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -191,23 +193,7 @@ public class GenerateTestsMojo extends AbstractMojo { this.contractsPath, this.contractsRepositoryUrl, this.contractsWorkOffline, getLog(), this.aetherStubDownloaderFactory, this.repoSession).downloadAndUnpackContractsIfRequired(config, this.contractsDirectory); getLog().info("Directory with contract is present at [" + contractsDirectory + "]"); - config.setContractsDslDir(contractsDirectory); - config.setGeneratedTestSourcesDir(this.generatedTestSourcesDir); - config.setTargetFramework(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.setAssertJsonSize(this.assertJsonSize); - config.setPackageWithBaseClasses(this.packageWithBaseClasses); - if (this.baseClassMappings != null) { - config.setBaseClassMappings(mappingsToMap()); - } + setupConfig(config, contractsDirectory); this.project.addTestCompileSourceRoot(this.generatedTestSourcesDir.getAbsolutePath()); if (getLog().isInfoEnabled()) { getLog().info( @@ -228,6 +214,35 @@ public class GenerateTestsMojo extends AbstractMojo { } } + private void setupConfig(ContractVerifierConfigProperties config, + File contractsDirectory) { + config.setContractsDslDir(contractsDirectory); + config.setGeneratedTestSourcesDir(this.generatedTestSourcesDir); + config.setTargetFramework(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.setAssertJsonSize(this.assertJsonSize); + config.setPackageWithBaseClasses(this.packageWithBaseClasses); + if (this.baseClassMappings != null) { + config.setBaseClassMappings(mappingsToMap()); + } + } + + private URL fileToUrl(File contractsDirectory) { + try { + return contractsDirectory.toURI().toURL(); + } catch (MalformedURLException e) { + throw new IllegalStateException(e); + } + } + public Map mappingsToMap() { Map map = new HashMap<>(); if (this.baseClassMappings == null) { diff --git a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/groovy/org/springframework/cloud/contract/verifier/spec/pact/PactContractConverterSpec.groovy b/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/groovy/org/springframework/cloud/contract/verifier/spec/pact/PactContractConverterSpec.groovy index bc3f6375df..741e4d80e7 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/groovy/org/springframework/cloud/contract/verifier/spec/pact/PactContractConverterSpec.groovy +++ b/spring-cloud-contract-tools/spring-cloud-contract-spec-pact/src/test/groovy/org/springframework/cloud/contract/verifier/spec/pact/PactContractConverterSpec.groovy @@ -266,7 +266,7 @@ class PactContractConverterSpec extends Specification { given: Resource[] contractResources = new PathMatchingResourcePatternResolver().getResources("contracts/*.groovy") Resource[] pactResources = new PathMatchingResourcePatternResolver().getResources("contracts/*.json") - Map> contracts = contractResources.collectEntries { [(it.filename) : ContractVerifierDslConverter.convertAsCollection(it.file)] } + Map> contracts = contractResources.collectEntries { [(it.filename) : ContractVerifierDslConverter.convertAsCollection(new File("/"), it.file)] } Map jsonPacts = pactResources.collectEntries { [(it.filename) : it.file.text] } when: Map pacts = contracts.entrySet().collectEntries { [(it.key) : converter.convertTo(it.value)] } diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScanner.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScanner.groovy index 0fe41a86ef..dd29460a25 100755 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScanner.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScanner.groovy @@ -99,7 +99,7 @@ class ContractFileScanner { boolean contractFile = isContractFile(file) boolean included = includeMatcher ? file.absolutePath.matches(includeMatcher) : true if (contractFile && included) { - addContractToTestGeneration(result, files, file, i, ContractVerifierDslConverter.convertAsCollection(file)) + addContractToTestGeneration(result, files, file, i, ContractVerifierDslConverter.convertAsCollection(baseDir, file)) } else if (!contractFile && included) { addContractToTestGeneration(converters, result, files, file, i) } else { diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/ContractVerifierDslConverter.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/ContractVerifierDslConverter.groovy index c1de53f32f..5a3f43eae5 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/ContractVerifierDslConverter.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/ContractVerifierDslConverter.groovy @@ -32,6 +32,10 @@ import org.springframework.cloud.contract.spec.Contract @Slf4j class ContractVerifierDslConverter { + /** + * @deprecated - use {@link ContractVerifierDslConverter#convertAsCollection(java.io.File, java.lang.String)} + */ + @Deprecated static Collection convertAsCollection(String dsl) { try { Object object = groovyShell().evaluate(dsl) @@ -44,6 +48,26 @@ class ContractVerifierDslConverter { } } + static Collection convertAsCollection(File rootFolder, String dsl) { + ClassLoader classLoader = ContractVerifierDslConverter.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) + } + } + + /** + * @deprecated - use {@link ContractVerifierDslConverter#convertAsCollection(java.io.File, java.io.File)} + */ + @Deprecated static Collection convertAsCollection(File dsl) { try { Object object = groovyShell().evaluate(dsl) @@ -56,8 +80,37 @@ class ContractVerifierDslConverter { } } + static Collection convertAsCollection(File rootFolder, File dsl) { + ClassLoader classLoader = ContractVerifierDslConverter.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 at path [${dsl.path}]", e) + throw new DslParseException(e) + } finally { + Thread.currentThread().setContextClassLoader(classLoader) + } + } + + private static ClassLoader updatedClassLoader(File rootFolder, ClassLoader classLoader) { + ClassLoader urlCl = URLClassLoader + .newInstance([rootFolder.toURI().toURL()] as URL[], classLoader) + Thread.currentThread().setContextClassLoader(urlCl) + return urlCl + } + private static GroovyShell groovyShell() { - return new GroovyShell(ContractVerifierDslConverter.classLoader, new Binding(), new CompilerConfiguration(sourceEncoding: 'UTF-8')) + return new GroovyShell(ContractVerifierDslConverter.classLoader, new CompilerConfiguration(sourceEncoding: 'UTF-8')) + } + + private static GroovyShell groovyShell(ClassLoader cl, File rootFolder) { + return new GroovyShell(cl, + new CompilerConfiguration(sourceEncoding: 'UTF-8', + classpathList: [rootFolder.absolutePath])) } private static Collection listOfContracts(object) { 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 index 3fa371c63e..8ea2a2c906 100644 --- 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 @@ -134,7 +134,7 @@ class SingleTestGeneratorSpec extends Specification { ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() properties.targetFramework = testFramework properties.testMode = mode - ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2, convertAsCollection(file)) + ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2, convertAsCollection(new File("/"),file)) contract.ignored >> true contract.order >> 2 JavaTestGenerator testGenerator = new JavaTestGenerator() @@ -187,7 +187,7 @@ class SingleTestGeneratorSpec extends Specification { properties.targetFramework = testFramework properties.testMode = mode ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2, - convertAsCollection(file) ) + convertAsCollection(new File("/"),file) ) contract.ignored >> true contract.order >> 2 JavaTestGenerator testGenerator = new JavaTestGenerator(checker: new ClassPresenceChecker() { @@ -258,11 +258,11 @@ class SingleTestGeneratorSpec extends Specification { ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() properties.targetFramework = testFramework ContractMetadata contract = new ContractMetadata(file.toPath(), false, 1, null, - convertAsCollection(file) ) + convertAsCollection(new File("/"),file) ) contract.ignored >> false and: ContractMetadata contract2 = new ContractMetadata(file2.toPath(), false, 1, null, - convertAsCollection(file2) ) + convertAsCollection(new File("/"),file2) ) contract2.ignored >> false and: JavaTestGenerator testGenerator = new JavaTestGenerator() @@ -289,7 +289,7 @@ class SingleTestGeneratorSpec extends Specification { ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() properties.testMode = TestMode.JAXRSCLIENT properties.targetFramework = testFramework - ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2, convertAsCollection(file)) + ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2, convertAsCollection(new File("/"),file)) contract.ignored >> true contract.order >> 2 JavaTestGenerator testGenerator = new JavaTestGenerator() @@ -331,11 +331,11 @@ class SingleTestGeneratorSpec extends Specification { and: ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() properties.targetFramework = testFramework - ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2, convertAsCollection(file)) + ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2, convertAsCollection(new File("/"),file)) contract.ignored >> true contract.order >> 2 and: - ContractMetadata contract2 = new ContractMetadata(secondFile.toPath(), true, 1, 2, convertAsCollection(secondFile)) + ContractMetadata contract2 = new ContractMetadata(secondFile.toPath(), true, 1, 2, convertAsCollection(new File("/"),secondFile)) contract2.ignored >> true contract2.order >> 2 and: @@ -377,7 +377,7 @@ class SingleTestGeneratorSpec extends Specification { ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() properties.targetFramework = testFramework and: - ContractMetadata contract2 = new ContractMetadata(secondFile.toPath(), true, 1, 2, convertAsCollection(file)) + ContractMetadata contract2 = new ContractMetadata(secondFile.toPath(), true, 1, 2, convertAsCollection(new File("/"),file)) contract2.ignored >> false contract2.order >> 2 and: @@ -445,7 +445,7 @@ class SingleTestGeneratorSpec extends Specification { properties.baseClassForTests = "test.ContextPathTestingBaseClass" and: ContractMetadata contract = new ContractMetadata(file.toPath(), false, 1, - null, convertAsCollection(file)) + null, convertAsCollection(new File("/"),file)) and: SingleTestGenerator testGenerator = new JavaTestGenerator() when: @@ -473,7 +473,7 @@ class SingleTestGeneratorSpec extends Specification { and: ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties(); properties.targetFramework = testFramework - ContractMetadata contract = new ContractMetadata(secondFile.toPath(), false, 1, null, convertAsCollection(secondFile)) + ContractMetadata contract = new ContractMetadata(secondFile.toPath(), false, 1, null, convertAsCollection(new File("/"),secondFile)) JavaTestGenerator testGenerator = new JavaTestGenerator() when: String clazz = testGenerator.buildClass(properties, [contract], "test", "test", 'com/foo') @@ -505,7 +505,7 @@ class SingleTestGeneratorSpec extends Specification { and: ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties(); properties.targetFramework = testFramework - ContractMetadata contract = new ContractMetadata(secondFile.toPath(), false, 1, null, convertAsCollection(secondFile)) + ContractMetadata contract = new ContractMetadata(secondFile.toPath(), false, 1, null, convertAsCollection(new File("/"),secondFile)) JavaTestGenerator testGenerator = new JavaTestGenerator() when: String clazz = testGenerator.buildClass(properties, [contract], "test", "test", 'com/foo') @@ -537,7 +537,7 @@ class SingleTestGeneratorSpec extends Specification { and: ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties(); properties.targetFramework = testFramework - ContractMetadata contract = new ContractMetadata(secondFile.toPath(), false, 1, null, convertAsCollection(secondFile)) + ContractMetadata contract = new ContractMetadata(secondFile.toPath(), false, 1, null, convertAsCollection(new File("/"),secondFile)) JavaTestGenerator testGenerator = new JavaTestGenerator() when: String clazz = testGenerator.buildClass(properties, [contract], "test", "test", 'com/foo') @@ -548,6 +548,30 @@ class SingleTestGeneratorSpec extends Specification { testFramework << [JUNIT, SPOCK] } + @Issue("#359") + def "should generate tests from a contract that references a file for [#testFramework]"() { + given: + File contractLocation = new File(SingleTestGeneratorSpec.class.getResource("/classpath/readFromFile.groovy").toURI()) + File temp = tmpFolder.newFolder() + and: + ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties( + targetFramework: testFramework, contractsDslDir: contractLocation.parentFile, + basePackageForTests: "a.b", + generatedTestSourcesDir: temp + ) + TestGenerator testGenerator = new TestGenerator(properties) + when: + int count = testGenerator.generate() + then: + count == 1 + and: + String test = new File(temp, "a/b/ContractVerifier" + (testFramework == JUNIT ? "Test.java" : "Spec.groovy")).text + test.contains("REQUEST") + test.contains("RESPONSE") + where: + testFramework << [JUNIT, SPOCK] + } + 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 index 371cd656e1..8f39cb115b 100644 --- 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 @@ -71,28 +71,28 @@ class ContractVerifierDslConverterSpec extends Specification { def "should convert file to a list of Contracts"() { when: - List contract = ContractVerifierDslConverter.convertAsCollection(multipleContracts) + List contract = ContractVerifierDslConverter.convertAsCollection(new File("/"),multipleContracts) then: contract == expectedMultipleContracts } def "should convert text to a list of Contracts"() { when: - Collection contract = ContractVerifierDslConverter.convertAsCollection(multipleContracts.text) + Collection contract = ContractVerifierDslConverter.convertAsCollection(new File("/"),multipleContracts.text) then: contract == expectedMultipleContracts } def "should throw an exception when an invalid file is parsed"() { when: - ContractVerifierDslConverter.convertAsCollection(invalidContract.text) + 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(invalidContract) + ContractVerifierDslConverter.convertAsCollection(new File("/"),invalidContract) then: DslParseException e = thrown(DslParseException) e.toString().contains("contract.yml") @@ -100,7 +100,7 @@ class ContractVerifierDslConverterSpec extends Specification { def "should throw an exception when a non existent file is parsed"() { when: - ContractVerifierDslConverter.convertAsCollection(new File("/foo/bar/baz.foo")) + ContractVerifierDslConverter.convertAsCollection(new File("/"),new File("/foo/bar/baz.foo")) then: DslParseException e = thrown(DslParseException) e.cause instanceof FileNotFoundException @@ -108,14 +108,14 @@ class ContractVerifierDslConverterSpec extends Specification { def "should convert file to a list of Contracts when there's only one declared contract"() { when: - Collection contract = ContractVerifierDslConverter.convertAsCollection(singleContract) + Collection contract = ContractVerifierDslConverter.convertAsCollection(new File("/"),singleContract) then: contract == [expectedSingleContract] } def "should convert text to a list of Contracts when there's only one declared contract"() { when: - Collection contract = ContractVerifierDslConverter.convertAsCollection(singleContract.text) + Collection contract = ContractVerifierDslConverter.convertAsCollection(new File("/"),singleContract.text) then: contract == [expectedSingleContract] } diff --git a/spring-cloud-contract-verifier/src/test/resources/classpath/readFromFile.groovy b/spring-cloud-contract-verifier/src/test/resources/classpath/readFromFile.groovy new file mode 100644 index 0000000000..e245d4b877 --- /dev/null +++ b/spring-cloud-contract-verifier/src/test/resources/classpath/readFromFile.groovy @@ -0,0 +1,19 @@ +import org.springframework.cloud.contract.spec.Contract + +Contract.make { + request { + method('PUT') + headers { + contentType(applicationJson()) + } + body(file("request.json")) + url("/1") + } + response { + status 200 + body(file("response.json")) + headers { + contentType(textPlain()) + } + } +} diff --git a/spring-cloud-contract-verifier/src/test/resources/classpath/request.json b/spring-cloud-contract-verifier/src/test/resources/classpath/request.json new file mode 100644 index 0000000000..51674161be --- /dev/null +++ b/spring-cloud-contract-verifier/src/test/resources/classpath/request.json @@ -0,0 +1 @@ +{ "status" : "REQUEST" } \ 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 new file mode 100644 index 0000000000..b7561f66d1 --- /dev/null +++ b/spring-cloud-contract-verifier/src/test/resources/classpath/response.json @@ -0,0 +1 @@ +{ "status" : "RESPONSE" } \ No newline at end of file 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 index f60ddc9510..0c54f79533 100644 --- 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 @@ -1,10 +1,7 @@ package org.springframework.cloud.contract.wiremock.restdocs; import java.io.File; -import java.io.IOException; import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; import java.util.Collection; import java.util.HashSet; import java.util.Set; @@ -82,7 +79,7 @@ public class ContractDslSnippetTests { then(file("/contracts/index.groovy")).exists(); then(file("/index/dsl-contract.adoc")).exists(); - Collection parsedContracts = ContractVerifierDslConverter.convertAsCollection(file("/contracts/index.groovy")); + 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 @@ -105,7 +102,7 @@ public class ContractDslSnippetTests { then(file("/contracts/empty.groovy")).exists(); then(file("/empty/dsl-contract.adoc")).exists(); - Collection parsedContracts = ContractVerifierDslConverter.convertAsCollection(file("/contracts/empty.groovy")); + 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();