Using factories
This commit is contained in:
6
pom.xml
6
pom.xml
@@ -136,6 +136,12 @@
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<!-- TODO: Why isn't the version taken from boot bom? -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>4.3.4.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-dependencies</artifactId>
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package org.springframework.cloud.contract.spec;
|
||||
|
||||
import java.io.File;
|
||||
package org.springframework.cloud.contract.spec
|
||||
|
||||
/**
|
||||
* Converter to be used to convert FROM {@link File} TO {@link Contract}
|
||||
* and from {@link Contract} to {@link T}
|
||||
* and from {@link Contract} to {@code T}
|
||||
*
|
||||
* @param <T> - type to which we want to convert the contract
|
||||
*
|
||||
@@ -20,7 +18,7 @@ public interface ContractConverter<T> {
|
||||
* @param file - file to be considered for conversion
|
||||
* @return - {@code true} if the given implementation can convert the file
|
||||
*/
|
||||
boolean isAccepted(File file);
|
||||
boolean isAccepted(File file)
|
||||
|
||||
/**
|
||||
* Converts the given {@link File} to its {@link Contract} representation
|
||||
@@ -28,7 +26,7 @@ public interface ContractConverter<T> {
|
||||
* @param file - file to convert
|
||||
* @return - {@link Contract} representation of the file
|
||||
*/
|
||||
Contract convertFrom(File file);
|
||||
Contract convertFrom(File file)
|
||||
|
||||
/**
|
||||
* Converts the given {@link Contract} to a {@link T} representation
|
||||
@@ -36,5 +34,5 @@ public interface ContractConverter<T> {
|
||||
* @param contract - the parsed contract
|
||||
* @return - {@link T} the type to which we do the conversion
|
||||
*/
|
||||
T convertTo(Contract contract);
|
||||
T convertTo(Contract contract)
|
||||
}
|
||||
@@ -38,11 +38,6 @@
|
||||
<groupId>com.github.tomakehurst</groupId>
|
||||
<artifactId>wiremock</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<scope>optional</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spockframework</groupId>
|
||||
<artifactId>spock-core</artifactId>
|
||||
|
||||
@@ -45,6 +45,11 @@
|
||||
<artifactId>spring-rabbit</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<scope>optional</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.inject</groupId>
|
||||
<artifactId>javax.inject</artifactId>
|
||||
|
||||
@@ -123,7 +123,7 @@ class SingleTestGenerator {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Stub content from file [${stubsFile.text}]")
|
||||
}
|
||||
Contract stubContent = ContractVerifierDslConverter.convert(stubsFile)
|
||||
Contract stubContent = it.convertedContract ?: ContractVerifierDslConverter.convert(stubsFile)
|
||||
TestType testType = (stubContent.input || stubContent.outputMessage) ? TestType.MESSAGING : TestType.HTTP
|
||||
return [(new ParsedDsl(it, stubContent, stubsFile)): testType]
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.springframework.cloud.contract.verifier.dsl;
|
||||
package org.springframework.cloud.contract.verifier.converter;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.springframework.cloud.contract.verifier.dsl
|
||||
package org.springframework.cloud.contract.verifier.converter
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import org.springframework.cloud.contract.spec.Contract
|
||||
@@ -27,23 +27,23 @@ class YamlContractConverter implements ContractConverter<YamlContract> {
|
||||
YamlContract yamlContract = new Yaml().loadAs(new FileInputStream(file), YamlContract.class)
|
||||
return Contract.make {
|
||||
request {
|
||||
method(yamlContract.request.method)
|
||||
url(yamlContract.request.url)
|
||||
method(yamlContract?.request?.method)
|
||||
url(yamlContract?.request?.url)
|
||||
headers {
|
||||
yamlContract.request.headers.each { String key, Object value ->
|
||||
yamlContract?.request?.headers?.each { String key, Object value ->
|
||||
header(key, value)
|
||||
}
|
||||
}
|
||||
body(yamlContract.request.body)
|
||||
body(yamlContract?.request?.body)
|
||||
}
|
||||
response {
|
||||
status(yamlContract.response.status)
|
||||
status(yamlContract?.response?.status)
|
||||
headers {
|
||||
yamlContract.response.headers.each { String key, Object value ->
|
||||
yamlContract?.response?.headers?.each { String key, Object value ->
|
||||
header(key, value)
|
||||
}
|
||||
}
|
||||
body(yamlContract.response.body)
|
||||
body(yamlContract?.response?.body)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -57,15 +57,15 @@ class YamlContractConverter implements ContractConverter<YamlContract> {
|
||||
// TODO: Pick one of the sides - consumer / producer
|
||||
YamlContract yamlContract = new YamlContract()
|
||||
yamlContract.request.with {
|
||||
method = contract.request.method.clientValue
|
||||
url = contract.request.url.clientValue
|
||||
headers = (contract.request.headers as Headers).asStubSideMap()
|
||||
body = contract.request.body.clientValue as Map
|
||||
method = contract?.request?.method?.clientValue
|
||||
url = contract?.request?.url?.clientValue
|
||||
headers = (contract?.request?.headers as Headers)?.asStubSideMap()
|
||||
body = contract?.request?.body?.clientValue as Map
|
||||
}
|
||||
yamlContract.response.with {
|
||||
status = contract.response.status.clientValue as Integer
|
||||
headers = (contract.response.headers as Headers).asStubSideMap()
|
||||
body = contract.response.body.clientValue as Map
|
||||
status = contract?.response?.status?.clientValue as Integer
|
||||
headers = (contract?.response?.headers as Headers)?.asStubSideMap()
|
||||
body = contract?.response?.body?.clientValue as Map
|
||||
}
|
||||
return yamlContract
|
||||
}
|
||||
@@ -21,6 +21,9 @@ import com.google.common.collect.ListMultimap
|
||||
import groovy.transform.CompileStatic
|
||||
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.core.io.support.SpringFactoriesLoader
|
||||
|
||||
import java.nio.file.FileSystem
|
||||
import java.nio.file.FileSystems
|
||||
@@ -74,7 +77,12 @@ class ContractFileScanner {
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* We iterate over found contracts, filter out those that should be excluded
|
||||
* and try to convert via pluggable Contract Converters any possible contracts
|
||||
*/
|
||||
private void appendRecursively(File baseDir, ListMultimap<Path, ContractMetadata> result) {
|
||||
List<ContractConverter> converters = SpringFactoriesLoader.loadFactories(ContractConverter, null)
|
||||
File[] files = baseDir.listFiles()
|
||||
if (!files) {
|
||||
return;
|
||||
@@ -85,12 +93,9 @@ class ContractFileScanner {
|
||||
boolean contractFile = isContractFile(file)
|
||||
boolean included = includeMatcher ? file.absolutePath.matches(includeMatcher) : true
|
||||
if (contractFile && included) {
|
||||
Path path = file.toPath()
|
||||
Integer order = null
|
||||
if (hasScenarioFilenamePattern(path)) {
|
||||
order = index
|
||||
}
|
||||
result.put(file.parentFile.toPath(), new ContractMetadata(path, matchesPattern(file, ignoreMatchers), files.size(), order))
|
||||
addContractToTestGeneration(result, files, file, index)
|
||||
} else if (!contractFile && included) {
|
||||
addContractToTestGeneration(converters, result, files, file, index)
|
||||
} else {
|
||||
appendRecursively(file, result)
|
||||
if (log.isDebugEnabled()) {
|
||||
@@ -105,6 +110,35 @@ class ContractFileScanner {
|
||||
}
|
||||
}
|
||||
|
||||
private void addContractToTestGeneration(List<ContractConverter> converters, ListMultimap<Path, ContractMetadata> result,
|
||||
File[] files, File file, int index) {
|
||||
boolean converted = false
|
||||
for (ContractConverter converter : converters) {
|
||||
if (converter.isAccepted(file)) {
|
||||
addContractToTestGeneration(result, files, file, index, converter.convertFrom(file))
|
||||
converted = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!converted) {
|
||||
appendRecursively(file, result)
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("File [$file] wasn't ignored but no converter was applicable.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addContractToTestGeneration(ListMultimap<Path, ContractMetadata> result, File[] files, File file,
|
||||
int index, Contract convertedContract = null) {
|
||||
Path path = file.toPath()
|
||||
Integer order = null
|
||||
if (hasScenarioFilenamePattern(path)) {
|
||||
order = index
|
||||
}
|
||||
result.put(file.parentFile.toPath(), new ContractMetadata(path, matchesPattern(file, ignoreMatchers),
|
||||
files.size(), order, convertedContract))
|
||||
}
|
||||
|
||||
private boolean hasScenarioFilenamePattern(Path path) {
|
||||
return SCENARIO_STEP_FILENAME_PATTERN.matcher(path.fileName.toString()).matches()
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
package org.springframework.cloud.contract.verifier.file
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import org.springframework.cloud.contract.spec.Contract
|
||||
|
||||
import java.nio.file.Path
|
||||
|
||||
/**
|
||||
* Contains metadata for a particular file with a DSL
|
||||
*
|
||||
@@ -33,12 +33,14 @@ class ContractMetadata {
|
||||
final boolean ignored
|
||||
final int groupSize
|
||||
final Integer order
|
||||
final Contract convertedContract
|
||||
|
||||
ContractMetadata(Path path, boolean ignored, int groupSize, Integer order) {
|
||||
ContractMetadata(Path path, boolean ignored, int groupSize, Integer order, Contract convertedContract = null) {
|
||||
this.groupSize = groupSize
|
||||
this.path = path
|
||||
this.ignored = ignored
|
||||
this.order = order
|
||||
this.convertedContract = convertedContract
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -48,6 +50,7 @@ class ContractMetadata {
|
||||
", ignored=" + ignored +
|
||||
", groupSize=" + groupSize +
|
||||
", order=" + order +
|
||||
", convertedContract=" + convertedContract +
|
||||
'}'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,4 +5,8 @@ org.springframework.cloud.contract.verifier.messaging.integration.ContractVerifi
|
||||
org.springframework.cloud.contract.verifier.messaging.amqp.ContractVerifierAmqpAutoConfiguration,\
|
||||
org.springframework.cloud.contract.verifier.messaging.amqp.RabbitMockConnectionFactoryAutoConfiguration,\
|
||||
org.springframework.cloud.contract.verifier.messaging.camel.ContractVerifierCamelConfiguration,\
|
||||
org.springframework.cloud.contract.verifier.messaging.noop.NoOpContractVerifierAutoConfiguration
|
||||
org.springframework.cloud.contract.verifier.messaging.noop.NoOpContractVerifierAutoConfiguration
|
||||
|
||||
# Converters
|
||||
org.springframework.cloud.contract.spec.ContractConverter=\
|
||||
org.springframework.cloud.contract.verifier.converter.YamlContractConverter
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.springframework.cloud.contract.verifier.dsl
|
||||
package org.springframework.cloud.contract.verifier.converter
|
||||
|
||||
import org.springframework.cloud.contract.spec.Contract
|
||||
import spock.lang.Specification
|
||||
@@ -59,4 +59,4 @@ class YamlContractConverterSpec extends Specification {
|
||||
yamlContract.response.headers.find { it.key == "foo2" && it.value == "bar" }
|
||||
yamlContract.response.body == [foo2: "bar"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,4 +73,16 @@ class ContractFileScannerSpec extends Specification {
|
||||
contracts.values().find { it.path.fileName.toString().startsWith('02') }.order == 1
|
||||
contracts.values().find { it.path.fileName.toString().startsWith('03') }.order == 2
|
||||
}
|
||||
|
||||
def "should find contract files with converters"() {
|
||||
given:
|
||||
File baseDir = new File(this.getClass().getResource("/directory/with/mixed").toURI())
|
||||
ContractFileScanner scanner = new ContractFileScanner(baseDir, null, null)
|
||||
when:
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
request:
|
||||
url: /foo
|
||||
method: PUT
|
||||
headers:
|
||||
foo: bar
|
||||
body:
|
||||
foo: bar
|
||||
response:
|
||||
status: 200
|
||||
headers:
|
||||
foo2: bar
|
||||
body:
|
||||
foo2: bar
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user