Added documentation to the new features
This commit is contained in:
@@ -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.
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<SingleTestGenerator> 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()
|
||||
}
|
||||
|
||||
@@ -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<ContractMetadata> 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<ParsedDsl, TestType> 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<ParsedDsl, TestType> mapContractsToTheirTestTypes(Collection<ContractMetadata> 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<ContractMetadata> 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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<ContractMetadata> 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<ParsedDsl, TestType> 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<ParsedDsl, TestType> mapContractsToTheirTestTypes(Collection<ContractMetadata> 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<ContractMetadata> 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<ContractMetadata> listOfFiles,
|
||||
String className, String classPackage, String includedDirectoryRelativePath)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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<Path, ContractMetadata> result, File[] files, File file,
|
||||
int index, Contract convertedContract = null) {
|
||||
int index, Contract convertedContract) {
|
||||
Path path = file.toPath()
|
||||
Integer order = null
|
||||
if (hasScenarioFilenamePattern(path)) {
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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) }
|
||||
|
||||
@@ -82,7 +82,7 @@ class ContractFileScannerSpec extends Specification {
|
||||
ListMultimap<Path, ContractMetadata> 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" }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user