From 148dc4effc640810d09e0d2d471ec2c35a2284bf Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Mon, 5 Dec 2016 18:24:13 +0100 Subject: [PATCH] Added documentation to the new features --- docs/src/main/asciidoc/verifier/contract.adoc | 102 ++++++++++- .../spring-cloud-contract-verifier.adoc | 1 + .../cloud/contract/verifier/FileSaver.groovy | 1 - .../contract/verifier/TestGenerator.groovy | 14 +- .../verifier/builder/JavaTestGenerator.groovy | 169 ++++++++++++++++++ .../builder/SingleTestGenerator.groovy | 169 ++---------------- .../converter/YamlContractConverter.groovy | 3 +- .../verifier/file/ContractFileScanner.groovy | 5 +- .../verifier/GeneratorScannerSpec.groovy | 12 +- .../builder/SingleTestGeneratorSpec.groovy | 27 +-- .../file/ContractFileScannerSpec.groovy | 4 +- .../resources/directory/with/mixed/dsl.groovy | 32 ++++ 12 files changed, 353 insertions(+), 186 deletions(-) create mode 100644 spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JavaTestGenerator.groovy diff --git a/docs/src/main/asciidoc/verifier/contract.adoc b/docs/src/main/asciidoc/verifier/contract.adoc index 4aece20bef..f532f683b4 100644 --- a/docs/src/main/asciidoc/verifier/contract.adoc +++ b/docs/src/main/asciidoc/verifier/contract.adoc @@ -319,7 +319,9 @@ as presented below (note you can use either `$` or `value` methods to provide `c include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy[tags=consumer_producer] ---- -=== Extending the DSL +=== Cutomization + +==== Extending the DSL It is possible to provide your own functions to the DSL. The key requirement for this feature was to maintain the static compatibility. Below you will be able to see an example @@ -330,7 +332,7 @@ of: The full example can be found https://github.com/spring-cloud-samples/spring-cloud-contract-samples[here]. -==== Common JAR +===== Common JAR Below you can find three classes that we will reuse in the DSLs. @@ -355,12 +357,12 @@ include::{samples_url}/common/src/main/java/com/example/ConsumerUtils.java[] include::{samples_url}/common/src/main/java/com/example/ProducerUtils.java[] ---- -==== Adding the dependency to project +===== Adding the dependency to project In order for the plugins and IDE to be able to reference the common JAR classes you need to pass the dependency to your project. -===== Test dependency in project's dependencies +====== Test dependency in project's dependencies First add the common jar dependency as a test dependency. That way since your contracts files are available at test resources path, automatically the @@ -378,7 +380,7 @@ include::{samples_url}/producer/pom.xml[tags=test_dep,indent=0] include::{samples_url}/producer/build.gradle[tags=test_dep,indent=0] ---- -===== Test dependency in plugin's dependencies +====== Test dependency in plugin's dependencies Now you have to add the dependency for the plugin to reuse at runtime. @@ -394,7 +396,7 @@ include::{samples_url}/producer/pom.xml[tags=test_dep_in_plugin,indent=0] include::{samples_url}/producer/build.gradle[tags=test_dep_in_plugin,indent=0] ---- -===== Referencing classes in DSLs +====== Referencing classes in DSLs Now you can reference your classes in your DSL. Example: @@ -402,3 +404,91 @@ Now you can reference your classes in your DSL. Example: ---- include::{samples_url}/producer/src/test/resources/contracts/beer/rest/shouldGrantABeerIfOldEnough.groovy[indent=0] ---- + +=== Pluggable architecture + +There are cases where you have your contracts defined in other formats +like YAML, RAML or PACT. On the other hand you'd like to profit from +the test and stubs generation. It's really easy to add your own implementation +of either of those. Also you can customize the way tests are generated (for example you can generate +tests for other languages) and you can do the same for stubs generation (you can generate +stubs for other stub http server implementations). + +==== Custom contract converter + +Let's assume that your contract is written in a YAML file like this: + +[source,yml] +---- +include::{verifier_core_path}/src/test/resources/contract.yml[indent=0] +---- + +Thanks to the interface + +[source,groovy] +---- +include::{contract_spec_path}/src/main/groovy/org/springframework/cloud/contract/spec/ContractConverter.groovy[indent=0] +---- + +you can register your own implementation of a contract structure converter. +Your implementation needs to state the condition on which it should start the +conversion. Also you have to define how to perform that conversion in both ways. + +IMPORTANT: Once you create your implementation you have to create a `/META-INF/spring.factories` +file in which you provide the fully qualified name of your implementation. + +Example of a `spring.factories` file + +[source] +---- +include::{verifier_core_path}/src/main/resources/META-INF/spring.factories[indent=0] +---- + +and the YAML implementation + +[source,groovy] +---- +include::{verifier_core_path}/src/main/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.groovy[indent=0] +---- + +==== Custom test generator + +If you want to generate tests for different languages than Java or you're +not happy with the way we're building Java tests for you then you can register +your own implementation to do that. + +Thanks to the interface + +[source,groovy] +---- +include::{verifier_core_path}/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGenerator.groovy[indent=0] +---- + +you can register your own implementation that generates a test. Again, it's enough to provide +a proper `spring.factories` file. Example: + +[source] +---- +org.springframework.cloud.contract.verifier.builder.SingleTestGenerator=/ +com.example.MyGenerator +---- + +==== Custom stub generator + +If you want to generate stubs for other stub server than WireMock it's enough to + plug in your own implementation of this interface: + +[source,groovy] +---- +include::{converters_path}/src/main/groovy/org/springframework/cloud/contract/verifier/converter/SingleFileConverter.groovy[indent=0] +---- + +you can register your own implementation that generate Stubs. Again, it's enough to provide +a proper `spring.factories` file. Example: + +[source] +---- +include::{converters_path}/src/main/resources/META-INF/spring.factories[indent=0] +---- + +The default implementation is the WireMock stub generation. \ No newline at end of file diff --git a/docs/src/main/asciidoc/verifier/spring-cloud-contract-verifier.adoc b/docs/src/main/asciidoc/verifier/spring-cloud-contract-verifier.adoc index 1d46d7a178..2a256b8fa1 100644 --- a/docs/src/main/asciidoc/verifier/spring-cloud-contract-verifier.adoc +++ b/docs/src/main/asciidoc/verifier/spring-cloud-contract-verifier.adoc @@ -1,5 +1,6 @@ :core_path: ../../../../.. :plugins_path: ../../../../../spring-cloud-contract-tools +:converters_path: {plugins_path}/spring-cloud-contract-converters :verifier_root_path: {core_path}/spring-cloud-contract-verifier :contract_spec_path: {core_path}/spring-cloud-contract-spec :samples_path: {core_path}/samples diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/FileSaver.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/FileSaver.groovy index 6b350b34e3..14852174c6 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/FileSaver.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/FileSaver.groovy @@ -42,7 +42,6 @@ class FileSaver { } void saveClassFile(String fileName, String basePackageClass, String includedDirectoryRelativePath, byte[] classBytes) { - Path testBaseDir = Paths.get(targetDirectory.absolutePath, packageToDirectory(basePackageClass), beforeLast(includedDirectoryRelativePath, File.separator)) Files.createDirectories(testBaseDir) diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/TestGenerator.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/TestGenerator.groovy index 60ad94a94a..59e63c8c0e 100755 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/TestGenerator.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/TestGenerator.groovy @@ -20,10 +20,12 @@ import com.google.common.collect.ListMultimap import groovy.transform.PackageScope import org.apache.commons.lang3.StringUtils 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 java.nio.charset.StandardCharsets import java.nio.file.Path @@ -45,10 +47,18 @@ class TestGenerator { private ContractFileScanner contractFileScanner TestGenerator(ContractVerifierConfigProperties configProperties) { - this(configProperties, new SingleTestGenerator(configProperties), + this(configProperties, singleTestGenerator(), new FileSaver(configProperties.generatedTestSourcesDir, configProperties.targetFramework)) } + private static SingleTestGenerator singleTestGenerator() { + List factories = SpringFactoriesLoader.loadFactories(SingleTestGenerator, null) + if (factories.empty) { + return new JavaTestGenerator() + } + return factories.first() + } + TestGenerator(ContractVerifierConfigProperties configProperties, SingleTestGenerator generator, FileSaver saver) { this.configProperties = configProperties if (configProperties.contractsDslDir == null) { @@ -88,7 +98,7 @@ class TestGenerator { if (contracts.size()) { def className = afterLast(includedDirectoryRelativePath.toString(), File.separator) + resolveNameSuffix() def packageName = buildPackage(basePackageNameForClass, includedDirectoryRelativePath) - def classBytes = generator.buildClass(contracts, className, packageName, includedDirectoryRelativePath).getBytes(StandardCharsets.UTF_8) + def classBytes = generator.buildClass(configProperties, contracts, className, packageName, includedDirectoryRelativePath).getBytes(StandardCharsets.UTF_8) saver.saveClassFile(className, basePackageNameForClass, convertIllegalPackageChars(includedDirectoryRelativePath.toString()), classBytes) counter.incrementAndGet() } diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JavaTestGenerator.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JavaTestGenerator.groovy new file mode 100644 index 0000000000..b1accfa9c2 --- /dev/null +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JavaTestGenerator.groovy @@ -0,0 +1,169 @@ +/* + * Copyright 2013-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.contract.verifier.builder + +import groovy.transform.Canonical +import groovy.transform.EqualsAndHashCode +import groovy.util.logging.Slf4j +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 static org.springframework.cloud.contract.verifier.util.NamesUtil.capitalize +/** + * Builds a single test for the given {@link ContractVerifierConfigProperties properties} + * + * @since 1.0.0 + */ +@Slf4j +class JavaTestGenerator implements SingleTestGenerator { + + private static final String JSON_ASSERT_STATIC_IMPORT = 'com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson' + private static final String JSON_ASSERT_CLASS = 'com.toomuchcoding.jsonassert.JsonAssertion' + + @Override + String buildClass(ContractVerifierConfigProperties configProperties, Collection listOfFiles, String className, String classPackage, String includedDirectoryRelativePath) { + ClassBuilder clazz = ClassBuilder.createClass(capitalize(className), classPackage, configProperties, includedDirectoryRelativePath) + + if (configProperties.imports) { + configProperties.imports.each { + clazz.addImport(it) + } + } + + if (configProperties.staticImports) { + configProperties.staticImports.each { + clazz.addStaticImport(it) + } + } + + if (isScenarioClass(listOfFiles)) { + clazz.addImport(configProperties.targetFramework.getOrderAnnotationImport()) + clazz.addClassLevelAnnotation(configProperties.targetFramework.getOrderAnnotation()) + } + + addJsonPathRelatedImports(clazz) + + Map contracts = mapContractsToTheirTestTypes(listOfFiles) + + boolean conditionalImportsAdded = false + boolean toIgnore = listOfFiles.ignored.find { it } + contracts.each { ParsedDsl key, TestType value -> + if (!conditionalImportsAdded) { + if (contracts.values().contains(TestType.HTTP)) { + if (configProperties.testMode == TestMode.JAXRSCLIENT) { + clazz.addStaticImport('javax.ws.rs.client.Entity.*') + if (configProperties.targetFramework == TestFramework.JUNIT) { + clazz.addImport('javax.ws.rs.core.Response') + } + } else if (configProperties.testMode == TestMode.MOCKMVC) { + clazz.addStaticImport('com.jayway.restassured.module.mockmvc.RestAssuredMockMvc.*') + } else { + clazz.addStaticImport('com.jayway.restassured.RestAssured.*') + } + } + if (configProperties.targetFramework == TestFramework.JUNIT) { + if (contracts.values().contains(TestType.HTTP) && configProperties.testMode == TestMode.MOCKMVC) { + clazz.addImport('com.jayway.restassured.module.mockmvc.specification.MockMvcRequestSpecification') + clazz.addImport('com.jayway.restassured.response.ResponseOptions') + } + clazz.addImport('org.junit.Test') + clazz.addStaticImport('org.assertj.core.api.Assertions.assertThat') + } + if (configProperties.ruleClassForTests) { + clazz.addImport('org.junit.Rule').addRule(configProperties.ruleClassForTests) + } + if (contracts.values().contains(TestType.MESSAGING)) { + addMessagingRelatedEntries(clazz) + } + conditionalImportsAdded = true + toIgnore = toIgnore ? true: key.groovyDsl.ignored + } + clazz.addMethod(MethodBuilder.createTestMethod(key.contract, key.stubsFile, key.groovyDsl, configProperties)) + } + + if (toIgnore) { + clazz.addImport(configProperties.targetFramework.getIgnoreClass()) + } + + return clazz.build() + } + + private Map mapContractsToTheirTestTypes(Collection listOfFiles) { + return listOfFiles.collectEntries { + File stubsFile = it.path.toFile() + if (log.isDebugEnabled()) { + log.debug("Stub content from file [${stubsFile.text}]") + } + Contract stubContent = it.convertedContract + TestType testType = (stubContent.input || stubContent.outputMessage) ? TestType.MESSAGING : TestType.HTTP + return [(new ParsedDsl(it, stubContent, stubsFile)): testType] + } + } + + @Canonical + @EqualsAndHashCode + private static class ParsedDsl { + ContractMetadata contract + Contract groovyDsl + File stubsFile + } + + private static enum TestType { + MESSAGING, HTTP + } + + private boolean isScenarioClass(Collection listOfFiles) { + return listOfFiles.find({ it.order != null }) != null + } + + private void addJsonPathRelatedImports(ClassBuilder clazz) { + clazz.addImport(['com.jayway.jsonpath.DocumentContext', + 'com.jayway.jsonpath.JsonPath', + ]) + if (jsonAssertPresent()) { + clazz.addStaticImport(JSON_ASSERT_STATIC_IMPORT) + } + } + + private void addMessagingRelatedEntries(ClassBuilder clazz) { + clazz.addField(['@Inject ContractVerifierMessaging contractVerifierMessaging', + '@Inject ContractVerifierObjectMapper contractVerifierObjectMapper' + ]) + clazz.addImport([ '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', + ]) + clazz.addStaticImport('org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers') + } + + private static boolean jsonAssertPresent() { + try { + Class.forName(JSON_ASSERT_CLASS) + return true + } catch (ClassNotFoundException e) { + if (log.isDebugEnabled()) { + log.debug("JsonAssert is not present on classpath. Will not add a static import.") + } + return false + } + } + +} diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGenerator.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGenerator.groovy index 70a61e458b..4bfee7f97d 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGenerator.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGenerator.groovy @@ -16,166 +16,29 @@ package org.springframework.cloud.contract.verifier.builder -import groovy.transform.Canonical -import groovy.transform.EqualsAndHashCode -import groovy.transform.PackageScope -import groovy.util.logging.Slf4j -import org.springframework.cloud.contract.spec.Contract +import groovy.transform.CompileStatic 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.ContractVerifierDslConverter -import static org.springframework.cloud.contract.verifier.util.NamesUtil.capitalize /** - * Builds a single test for the given {@link ContractVerifierConfigProperties properties} + * Builds a single test. * - * @since 1.0.0 + * @since 1.0.3 */ -@Slf4j -class SingleTestGenerator { - - private static final String JSON_ASSERT_STATIC_IMPORT = 'com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson' - private static final String JSON_ASSERT_CLASS = 'com.toomuchcoding.jsonassert.JsonAssertion' - - private final ContractVerifierConfigProperties configProperties - - SingleTestGenerator(ContractVerifierConfigProperties configProperties) { - this.configProperties = configProperties - } +@CompileStatic +interface SingleTestGenerator { /** - * Returns String code representing a test class with test methods for - * each {@link ContractMetadata} + * 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 className - the name of the generated test class + * @param classPackage - the name of the package in which the test class should be stored + * @param includedDirectoryRelativePath - relative path to the included directory + * @return contents of a single test class */ - @PackageScope - String buildClass(Collection listOfFiles, String className, String classPackage, String includedDirectoryRelativePath) { - ClassBuilder clazz = ClassBuilder.createClass(capitalize(className), classPackage, configProperties, includedDirectoryRelativePath) - - if (configProperties.imports) { - configProperties.imports.each { - clazz.addImport(it) - } - } - - if (configProperties.staticImports) { - configProperties.staticImports.each { - clazz.addStaticImport(it) - } - } - - if (isScenarioClass(listOfFiles)) { - clazz.addImport(configProperties.targetFramework.getOrderAnnotationImport()) - clazz.addClassLevelAnnotation(configProperties.targetFramework.getOrderAnnotation()) - } - - addJsonPathRelatedImports(clazz) - - Map contracts = mapContractsToTheirTestTypes(listOfFiles) - - boolean conditionalImportsAdded = false - boolean toIgnore = listOfFiles.ignored.find { it } - contracts.each { ParsedDsl key, TestType value -> - if (!conditionalImportsAdded) { - if (contracts.values().contains(TestType.HTTP)) { - if (configProperties.testMode == TestMode.JAXRSCLIENT) { - clazz.addStaticImport('javax.ws.rs.client.Entity.*') - if (configProperties.targetFramework == TestFramework.JUNIT) { - clazz.addImport('javax.ws.rs.core.Response') - } - } else if (configProperties.testMode == TestMode.MOCKMVC) { - clazz.addStaticImport('com.jayway.restassured.module.mockmvc.RestAssuredMockMvc.*') - } else { - clazz.addStaticImport('com.jayway.restassured.RestAssured.*') - } - } - if (configProperties.targetFramework == TestFramework.JUNIT) { - if (contracts.values().contains(TestType.HTTP) && configProperties.testMode == TestMode.MOCKMVC) { - clazz.addImport('com.jayway.restassured.module.mockmvc.specification.MockMvcRequestSpecification') - clazz.addImport('com.jayway.restassured.response.ResponseOptions') - } - clazz.addImport('org.junit.Test') - clazz.addStaticImport('org.assertj.core.api.Assertions.assertThat') - } - if (configProperties.ruleClassForTests) { - clazz.addImport('org.junit.Rule').addRule(configProperties.ruleClassForTests) - } - if (contracts.values().contains(TestType.MESSAGING)) { - addMessagingRelatedEntries(clazz) - } - conditionalImportsAdded = true - toIgnore = toIgnore ? true: key.groovyDsl.ignored - } - clazz.addMethod(MethodBuilder.createTestMethod(key.contract, key.stubsFile, key.groovyDsl, configProperties)) - } - - if (toIgnore) { - clazz.addImport(configProperties.targetFramework.getIgnoreClass()) - } - - return clazz.build() - } - - private Map mapContractsToTheirTestTypes(Collection listOfFiles) { - return listOfFiles.collectEntries { - File stubsFile = it.path.toFile() - if (log.isDebugEnabled()) { - log.debug("Stub content from file [${stubsFile.text}]") - } - Contract stubContent = it.convertedContract ?: ContractVerifierDslConverter.convert(stubsFile) - TestType testType = (stubContent.input || stubContent.outputMessage) ? TestType.MESSAGING : TestType.HTTP - return [(new ParsedDsl(it, stubContent, stubsFile)): testType] - } - } - - @Canonical - @EqualsAndHashCode - private static class ParsedDsl { - ContractMetadata contract - Contract groovyDsl - File stubsFile - } - - private static enum TestType { - MESSAGING, HTTP - } - - private boolean isScenarioClass(Collection listOfFiles) { - return listOfFiles.find({ it.order != null }) != null - } - - private void addJsonPathRelatedImports(ClassBuilder clazz) { - clazz.addImport(['com.jayway.jsonpath.DocumentContext', - 'com.jayway.jsonpath.JsonPath', - ]) - if (jsonAssertPresent()) { - clazz.addStaticImport(JSON_ASSERT_STATIC_IMPORT) - } - } - - private void addMessagingRelatedEntries(ClassBuilder clazz) { - clazz.addField(['@Inject ContractVerifierMessaging contractVerifierMessaging', - '@Inject ContractVerifierObjectMapper contractVerifierObjectMapper' - ]) - clazz.addImport([ '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', - ]) - clazz.addStaticImport('org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers') - } - - private static boolean jsonAssertPresent() { - try { - Class.forName(JSON_ASSERT_CLASS) - return true - } catch (ClassNotFoundException e) { - if (log.isDebugEnabled()) { - log.debug("JsonAssert is not present on classpath. Will not add a static import.") - } - return false - } - } - + String buildClass(ContractVerifierConfigProperties properties, Collection listOfFiles, + String className, String classPackage, String includedDirectoryRelativePath) } diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.groovy index c9b6aed109..b477e099c9 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.groovy @@ -7,7 +7,8 @@ import org.springframework.cloud.contract.spec.internal.Headers import org.yaml.snakeyaml.Yaml /** - * Converter from and to a {@link YamlContract} to a + * Converter from and to a {@link YamlContract} to a {@link Contract} + * * @author Marcin Grzejszczak * @since 1.0.3 */ 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 31c8d06434..7a9f303b51 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 @@ -23,6 +23,7 @@ import groovy.util.logging.Slf4j import org.apache.commons.lang3.SystemUtils 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 import java.nio.file.FileSystem @@ -93,7 +94,7 @@ class ContractFileScanner { boolean contractFile = isContractFile(file) boolean included = includeMatcher ? file.absolutePath.matches(includeMatcher) : true if (contractFile && included) { - addContractToTestGeneration(result, files, file, index) + addContractToTestGeneration(result, files, file, index, ContractVerifierDslConverter.convert(file)) } else if (!contractFile && included) { addContractToTestGeneration(converters, result, files, file, index) } else { @@ -129,7 +130,7 @@ class ContractFileScanner { } private void addContractToTestGeneration(ListMultimap result, File[] files, File file, - int index, Contract convertedContract = null) { + int index, Contract convertedContract) { Path path = file.toPath() Integer order = null if (hasScenarioFilenamePattern(path)) { 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 index 0444d49ef0..ba9fa80632 100644 --- 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 @@ -16,14 +16,14 @@ package org.springframework.cloud.contract.verifier -import org.springframework.cloud.contract.verifier.builder.SingleTestGenerator +import org.springframework.cloud.contract.verifier.builder.JavaTestGenerator import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties import org.springframework.cloud.contract.verifier.config.TestFramework import spock.lang.Specification class GeneratorScannerSpec extends Specification { - private SingleTestGenerator classGenerator = Mock(SingleTestGenerator) + private JavaTestGenerator classGenerator = Mock(JavaTestGenerator) def "should find all .json files and generate 6 classes for them"() { given: @@ -34,7 +34,7 @@ class GeneratorScannerSpec extends Specification { when: testGenerator.generateTestClasses("org.springframework.cloud.contract.verifier") then: - 6 * classGenerator.buildClass(_, _, _, _) >> "qwerty" + 6 * classGenerator.buildClass(_, _, _, _, _) >> "qwerty" } def "should create class with full package"() { @@ -45,9 +45,9 @@ class GeneratorScannerSpec extends Specification { when: testGenerator.generateTestClasses("org.springframework.cloud.contract.verifier") then: - 1 * classGenerator.buildClass(_, 'exceptionsSpec', 'org.springframework.cloud.contract.verifier', _) >> "spec" - 1 * classGenerator.buildClass(_, 'exceptionsSpec', 'org.springframework.cloud.contract.verifier.v1', _) >> "spec1" - 1 * classGenerator.buildClass(_, 'exceptionsSpec', 'org.springframework.cloud.contract.verifier.v2', _) >> "spec2" + 1 * classGenerator.buildClass(_, _, 'exceptionsSpec', 'org.springframework.cloud.contract.verifier', _) >> "spec" + 1 * classGenerator.buildClass(_, _, 'exceptionsSpec', 'org.springframework.cloud.contract.verifier.v1', _) >> "spec1" + 1 * classGenerator.buildClass(_, _, 'exceptionsSpec', 'org.springframework.cloud.contract.verifier.v2', _) >> "spec2" } } 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 8db73be660..b0b3a0dd8a 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 @@ -26,6 +26,7 @@ import spock.lang.Specification import static org.springframework.cloud.contract.verifier.config.TestFramework.JUNIT import static org.springframework.cloud.contract.verifier.config.TestFramework.SPOCK +import static org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter.convert class SingleTestGeneratorSpec extends Specification { @@ -63,13 +64,13 @@ class SingleTestGeneratorSpec extends Specification { given: ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties(); properties.targetFramework = testFramework - ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2) + ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2, convert(file)) contract.ignored >> true contract.order >> 2 - SingleTestGenerator testGenerator = new SingleTestGenerator(properties) + JavaTestGenerator testGenerator = new JavaTestGenerator() when: - String clazz = testGenerator.buildClass([contract], "test", "test", 'com/foo') + String clazz = testGenerator.buildClass(properties, [contract], "test", "test", 'com/foo') then: classStrings.each { clazz.contains(it) } @@ -85,13 +86,13 @@ class SingleTestGeneratorSpec extends Specification { ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties(); properties.testMode = TestMode.JAXRSCLIENT properties.targetFramework = testFramework - ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2) + ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2, convert(file)) contract.ignored >> true contract.order >> 2 - SingleTestGenerator testGenerator = new SingleTestGenerator(properties) + JavaTestGenerator testGenerator = new JavaTestGenerator() when: - String clazz = testGenerator.buildClass([contract], "test", "test", 'com/foo') + String clazz = testGenerator.buildClass(properties, [contract], "test", "test", 'com/foo') then: classStrings.each { clazz.contains(it) } @@ -123,18 +124,18 @@ class SingleTestGeneratorSpec extends Specification { and: ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties(); properties.targetFramework = testFramework - ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2) + ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2, convert(file)) contract.ignored >> true contract.order >> 2 and: - ContractMetadata contract2 = new ContractMetadata(secondFile.toPath(), true, 1, 2) + ContractMetadata contract2 = new ContractMetadata(secondFile.toPath(), true, 1, 2, convert(secondFile)) contract2.ignored >> true contract2.order >> 2 and: - SingleTestGenerator testGenerator = new SingleTestGenerator(properties) + JavaTestGenerator testGenerator = new JavaTestGenerator() when: - String clazz = testGenerator.buildClass([contract, contract2], "test", "test", 'com/foo') + String clazz = testGenerator.buildClass(properties, [contract, contract2], "test", "test", 'com/foo') then: classStrings.each { clazz.contains(it) } @@ -166,14 +167,14 @@ class SingleTestGeneratorSpec extends Specification { ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties(); properties.targetFramework = testFramework and: - ContractMetadata contract2 = new ContractMetadata(secondFile.toPath(), true, 1, 2) + ContractMetadata contract2 = new ContractMetadata(secondFile.toPath(), true, 1, 2, convert(file)) contract2.ignored >> false contract2.order >> 2 and: - SingleTestGenerator testGenerator = new SingleTestGenerator(properties) + JavaTestGenerator testGenerator = new JavaTestGenerator() when: - String clazz = testGenerator.buildClass([contract2], "test", "test", 'com/foo') + String clazz = testGenerator.buildClass(properties, [contract2], "test", "test", 'com/foo') then: classStrings.each { clazz.contains(it) } diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScannerSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScannerSpec.groovy index e501184cbf..541a387c56 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScannerSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/file/ContractFileScannerSpec.groovy @@ -82,7 +82,7 @@ class ContractFileScannerSpec extends Specification { ListMultimap result = scanner.findContracts() then: result.keySet().size() == 1 - result.entries().find { it.value.convertedContract && it.value.convertedContract.request.method.clientValue == "PUT" } - result.entries().find { !it.value.convertedContract && !it.value.ignored } + result.entries().every { it.value.convertedContract } + result.entries().find { it.value.convertedContract.request.method.clientValue == "PUT" } } } diff --git a/spring-cloud-contract-verifier/src/test/resources/directory/with/mixed/dsl.groovy b/spring-cloud-contract-verifier/src/test/resources/directory/with/mixed/dsl.groovy index 958ccd0673..067e0f7d19 100644 --- a/spring-cloud-contract-verifier/src/test/resources/directory/with/mixed/dsl.groovy +++ b/spring-cloud-contract-verifier/src/test/resources/directory/with/mixed/dsl.groovy @@ -1,3 +1,5 @@ +import org.springframework.cloud.contract.spec.Contract + /* * Copyright 2013-2016 the original author or authors. * @@ -14,3 +16,33 @@ * limitations under the License. */ +Contract.make { + request { + method('PUT') + headers { + contentType(applicationJson()) + } + body("""\ + { + "name": "Jan", + "id": "${value(consumer('abc'), producer('def'))}", + } + """ + ) + url $(consumer('/[0-9]{2}'), producer('/12')) + } + response { + status 200 + body("""\ + { + "name": "Jan", + "id": "${value(consumer('123'), producer('321'))}", + "surname": "${value(consumer('Kowalsky'), producer('$checkIfSurnameValid($value)'))}" + } + """ + ) + headers { + contentType(textPlain()) + } + } +}