WireMock done

This commit is contained in:
Marcin Grzejszczak
2016-12-06 14:32:01 +01:00
parent 7558fb183e
commit a328130418
32 changed files with 655 additions and 181 deletions

View File

@@ -427,7 +427,7 @@ Thanks to the interface
[source,groovy]
----
include::{contract_spec_path}/src/main/groovy/org/springframework/cloud/contract/spec/ContractConverter.groovy[indent=0]
include::{contract_spec_path}/src/main/groovy/org/springframework/cloud/contract/spec/ContractConverter.groovy[indent=0,lines=17..-1]
----
you can register your own implementation of a contract structure converter.
@@ -441,14 +441,14 @@ Example of a `spring.factories` file
[source]
----
include::{verifier_core_path}/src/main/resources/META-INF/spring.factories[indent=0]
include::{verifier_core_path}/src/test/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]
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.groovy[indent=0,lines=16..-1]
----
==== Custom test generator
@@ -461,7 +461,7 @@ Thanks to the interface
[source,groovy]
----
include::{verifier_core_path}/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGenerator.groovy[indent=0]
include::{verifier_core_path}/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGenerator.groovy[indent=0,lines=17..-1]
----
you can register your own implementation that generates a test. Again, it's enough to provide
@@ -480,7 +480,7 @@ If you want to generate stubs for other stub server than WireMock it's enough to
[source,groovy]
----
include::{converters_path}/src/main/groovy/org/springframework/cloud/contract/verifier/converter/SingleFileConverter.groovy[indent=0]
include::{converters_path}/src/main/groovy/org/springframework/cloud/contract/verifier/converter/SingleFileConverter.groovy[indent=0,lines=16..-1]
----
you can register your own implementation that generate Stubs. Again, it's enough to provide

View File

@@ -15,7 +15,7 @@ To trigger a message it's enough to use the `StubTrigger` interface:
[source,groovy]
----
include::{stubrunner_core_path}/src/main/java/org/springframework/cloud/contract/stubrunner/StubTrigger.java[]
include::{stubrunner_core_path}/src/main/java/org/springframework/cloud/contract/stubrunner/StubTrigger.java[lines=16..-1]
----
For convenience the `StubFinder` interface extends `StubTrigger` so it's enough to use only one in your tests.

View File

@@ -1,3 +1,19 @@
/*
* 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.spec
/**
@@ -26,7 +42,7 @@ public interface ContractConverter<T> {
* @param file - file to convert
* @return - {@link Contract} representation of the file
*/
Contract convertFrom(File file)
Collection<Contract> convertFrom(File file)
/**
* Converts the given {@link Contract} to a {@link T} representation
@@ -34,5 +50,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(Collection<Contract> contract)
}

View File

@@ -100,7 +100,7 @@ Since the `StubRunnerRule` implements the `StubFinder` it allows you to find the
[source,groovy,indent=0]
----
include::src/main/java/org/springframework/cloud/contract/stubrunner/StubFinder.java[]
include::src/main/java/org/springframework/cloud/contract/stubrunner/StubFinder.java[lines=16..-1]
----
Example of usage in Spock tests:

View File

@@ -33,12 +33,24 @@ interface SingleFileConverter {
boolean canHandleFileName(String fileName)
/**
* Returns the content of the converted file. The content will be the stub.
* Returns the content of the converted file. The content will be a single stub.
*/
@Deprecated
String convertContent(String rootName, ContractMetadata content)
/**
* Returns the name of the converted stub file.
* Returns the collection of converted contracts into stubs. One contract can
* result in multiple stubs.
*/
Collection<String> convertContents(String rootName, ContractMetadata content)
/**
* Returns the name of the converted stub file. If you have multiple contracts
* in a single file then a prefix will be added to the generated file.
*
* Example: name of file with 2 contracts is {@code foo.groovy}, it will be
* converted by the implementation to {@code foo.json}. The recursive file
* converter will create two files {@code 0_foo.json} and {@code 1_foo.json}
*/
String generateOutputFileNameForInput(String inputFileName)
}

View File

@@ -17,6 +17,7 @@
package org.springframework.cloud.contract.verifier.wiremock
import groovy.transform.CompileStatic
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockStubStrategy
import org.springframework.cloud.contract.verifier.file.ContractMetadata
@@ -31,10 +32,26 @@ import java.nio.charset.StandardCharsets
class DslToWireMockClientConverter extends DslToWireMockConverter {
@Override
@Deprecated
String convertContent(String rootName, ContractMetadata contract) {
return new WireMockStubStrategy(rootName, contract,
contract.convertedContract ?: createGroovyDSLFromStringContent(
contract.path.getText(StandardCharsets.UTF_8.toString()))
).toWireMockClientStub()
return convertASingleContract(rootName, contract, contract.convertedContract.first() ?: createGroovyDSLFromStringContent(
contract.path.getText(StandardCharsets.UTF_8.toString())).first())
}
private String convertASingleContract(String rootName, ContractMetadata contract, Contract dsl) {
return new WireMockStubStrategy(rootName, contract, dsl).toWireMockClientStub()
}
@Override
Collection<String> convertContents(String rootName, ContractMetadata contract) {
if (contract.convertedContract.size() == 1) {
return [convertASingleContract(rootName, contract, contract.convertedContract.first())]
}
List<String> convertedContracts = []
contract.convertedContract.eachWithIndex { Contract dsl, int index ->
String name = "${rootName}_${index}"
convertedContracts << convertASingleContract(name, contract, dsl)
}
return convertedContracts
}
}

View File

@@ -47,7 +47,7 @@ abstract class DslToWireMockConverter implements SingleFileConverter {
return ""
}
protected Contract createGroovyDSLFromStringContent(String groovyDslAsString) {
return ContractVerifierDslConverter.convert(groovyDslAsString)
protected List<Contract> createGroovyDSLFromStringContent(String groovyDslAsString) {
return ContractVerifierDslConverter.convertAsCollection(groovyDslAsString)
}
}

View File

@@ -19,6 +19,7 @@ package org.springframework.cloud.contract.verifier.wiremock
import com.google.common.collect.ListMultimap
import groovy.transform.CompileStatic
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.converter.SingleFileConverter
import org.springframework.cloud.contract.verifier.converter.SingleFileConvertersHolder
@@ -85,13 +86,17 @@ class RecursiveFilesConverter {
if (!contract.convertedContract && !singleFileConverter) {
return
}
String convertedContent = singleFileConverter.convertContent(entry.key.last().toString(), contract)
if (!convertedContent) {
return
int contractsSize = contract.convertedContract.size()
contract.convertedContract.eachWithIndex { Contract dsl, int index ->
String convertedContent = singleFileConverter.convertContent(entry.key.last().toString(), contract)
if (!convertedContent) {
return
}
Path absoluteTargetPath = createAndReturnTargetDirectory(sourceFile)
File newJsonFile = createTargetFileWithProperName(singleFileConverter, absoluteTargetPath,
sourceFile, contractsSize, index)
newJsonFile.setText(convertedContent, StandardCharsets.UTF_8.toString())
}
Path absoluteTargetPath = createAndReturnTargetDirectory(sourceFile)
File newJsonFile = createTargetFileWithProperName(singleFileConverter, absoluteTargetPath, sourceFile)
newJsonFile.setText(convertedContent, StandardCharsets.UTF_8.toString())
} catch (Exception e) {
throw new ConversionContractVerifierException("Unable to make conversion of ${sourceFile.name}", e)
}
@@ -106,8 +111,11 @@ class RecursiveFilesConverter {
return absoluteTargetPath
}
private File createTargetFileWithProperName(SingleFileConverter singleFileConverter, Path absoluteTargetPath, File sourceFile) {
File newJsonFile = new File(absoluteTargetPath.toFile(), singleFileConverter.generateOutputFileNameForInput(sourceFile.name))
private File createTargetFileWithProperName(SingleFileConverter singleFileConverter, Path absoluteTargetPath,
File sourceFile, int contractsSize, int index) {
String generatedName = singleFileConverter.generateOutputFileNameForInput(sourceFile.name)
String name = contractsSize == 1 ? generatedName : "${index}_${generatedName}"
File newJsonFile = new File(absoluteTargetPath.toFile(), name)
log.info("Creating new json [$newJsonFile.path]")
return newJsonFile
}

View File

@@ -27,7 +27,7 @@ import spock.lang.Specification
class DslToWireMockClientConverterSpec extends Specification {
@Rule
public TemporaryFolder tmpFolder = new TemporaryFolder();
public TemporaryFolder tmpFolder = new TemporaryFolder()
def "should convert DSL file to WireMock JSON"() {
given:
@@ -53,6 +53,39 @@ class DslToWireMockClientConverterSpec extends Specification {
''', json, false)
}
def "should convert DSL file with list of contracts to WireMock JSONs"() {
given:
def converter = new DslToWireMockClientConverter()
and:
File file = tmpFolder.newFile("dsl1_list.groovy")
file.write('''
(1..2).collect { int index ->
org.springframework.cloud.contract.spec.Contract.make {
request {
method(PUT())
headers {
contentType(applicationJson())
}
url "/${index}"
}
response {
status 200
}
}
}
''')
when:
List<String> json = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null))
then:
json.size() == 2
JSONAssert.assertEquals(jsonResponse(1), json.first(), false)
JSONAssert.assertEquals(jsonResponse(2), json.last(), false)
}
private String jsonResponse(int index) {
return """{"request":{"method":"PUT","url":"/${index}"},"response":{"status":200}}"""
}
@Issue("196")
def "should creation of delayed stub responses be possible"() {
given:

View File

@@ -33,7 +33,9 @@ import spock.lang.Specification
class RecursiveFilesConverterSpec extends Specification {
private static
final Set<Path> EXPECTED_TARGET_FILES = [Paths.get("dslRoot.json"), Paths.get("dir1/dsl1.json"), Paths.get("dir1/dsl1b.json"), Paths.get("dir2/dsl2.json")]
final Set<Path> EXPECTED_TARGET_FILES = [Paths.get("dslRoot.json"), Paths.get("dir1/dsl1.json"),
Paths.get("dir1/dsl1b.json"), Paths.get("dir2/dsl2.json"),
Paths.get("dir1/0_dsl1_list.json"), Paths.get("dir1/1_dsl1_list.json")]
@Rule
public TemporaryFolder tmpFolder = new TemporaryFolder();

View File

@@ -0,0 +1,32 @@
import org.springframework.cloud.contract.spec.Contract
/*
* 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.
*/
(1..2).collect { int index ->
Contract.make {
request {
method(PUT())
headers {
contentType(applicationJson())
}
url "/${index}"
}
response {
status 200
}
}
}

View File

@@ -45,12 +45,6 @@
<artifactId>spring-rabbit</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<!-- TODO: If I make this optional Groovy can't compile -->
<!--<scope>optional</scope>-->
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
@@ -111,6 +105,11 @@
<artifactId>slf4j-simple</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>

View File

@@ -106,15 +106,19 @@ class JavaTestGenerator implements SingleTestGenerator {
}
private Map<ParsedDsl, TestType> mapContractsToTheirTestTypes(Collection<ContractMetadata> listOfFiles) {
return listOfFiles.collectEntries {
File stubsFile = it.path.toFile()
Map<ParsedDsl, TestType> dsls = [:]
listOfFiles.each { ContractMetadata metadata ->
File stubsFile = metadata.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]
List<Contract> stubContents = metadata.convertedContract
dsls << stubContents.collectEntries { Contract stubContent ->
TestType testType = (stubContent.input || stubContent.outputMessage) ? TestType.MESSAGING : TestType.HTTP
return [(new ParsedDsl(metadata, stubContent, stubsFile)): testType]
}
}
return dsls
}
@Canonical

View File

@@ -1,26 +0,0 @@
package org.springframework.cloud.contract.verifier.converter
/**
* Yaml representation of a {@link org.springframework.cloud.contract.spec.Contract}
*
* @author Marcin Grzejszczak
* @since 1.0.3
*/
//TODO: Perform full conversion
class YamlContract {
public Request request = new Request()
public Response response = new Response()
static class Request {
public String method
public String url
public Map<String, Object> headers = [:]
public Map<String, Object> body = [:]
}
static class Response {
public int status
public Map<String, Object> headers = [:]
public Map<String, Object> body = [:]
}
}

View File

@@ -1,73 +0,0 @@
package org.springframework.cloud.contract.verifier.converter
import groovy.transform.CompileStatic
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.spec.ContractConverter
import org.springframework.cloud.contract.spec.internal.Headers
import org.yaml.snakeyaml.Yaml
/**
* Converter from and to a {@link YamlContract} to a {@link Contract}
*
* @author Marcin Grzejszczak
* @since 1.0.3
*/
//TODO: Perform full conversion
@CompileStatic
class YamlContractConverter implements ContractConverter<YamlContract> {
@Override
public boolean isAccepted(File file) {
String name = file.getName()
return name.endsWith(".yml") || name.endsWith(".yaml")
}
@Override
public Contract convertFrom(File file) {
try {
YamlContract yamlContract = new Yaml().loadAs(new FileInputStream(file), YamlContract.class)
return Contract.make {
request {
method(yamlContract?.request?.method)
url(yamlContract?.request?.url)
headers {
yamlContract?.request?.headers?.each { String key, Object value ->
header(key, value)
}
}
body(yamlContract?.request?.body)
}
response {
status(yamlContract?.response?.status)
headers {
yamlContract?.response?.headers?.each { String key, Object value ->
header(key, value)
}
}
body(yamlContract?.response?.body)
}
}
}
catch (FileNotFoundException e) {
throw new IllegalStateException(e)
}
}
@Override
public YamlContract convertTo(Contract contract) {
// 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
}
yamlContract.response.with {
status = contract?.response?.status?.clientValue as Integer
headers = (contract?.response?.headers as Headers)?.asStubSideMap()
body = contract?.response?.body?.clientValue as Map
}
return yamlContract
}
}

View File

@@ -94,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, ContractVerifierDslConverter.convert(file))
addContractToTestGeneration(result, files, file, index, ContractVerifierDslConverter.convertAsCollection(file))
} else if (!contractFile && included) {
addContractToTestGeneration(converters, result, files, file, index)
} else {
@@ -130,7 +130,7 @@ class ContractFileScanner {
}
private void addContractToTestGeneration(ListMultimap<Path, ContractMetadata> result, File[] files, File file,
int index, Contract convertedContract) {
int index, Collection<Contract> convertedContract) {
Path path = file.toPath()
Integer order = null
if (hasScenarioFilenamePattern(path)) {

View File

@@ -19,6 +19,7 @@ package org.springframework.cloud.contract.verifier.file
import groovy.transform.CompileStatic
import groovy.transform.ToString
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter
import java.nio.file.Path
/**
@@ -44,20 +45,28 @@ class ContractMetadata {
*/
final int groupSize
/**
* If scenario related will
* If scenario related will contain an order of execution
*/
final Integer order
/**
* When we have already converted a contract via a converter this
* field will be set
* The list of contracts for the given file
*/
final Contract convertedContract
final Collection<Contract> convertedContract = []
ContractMetadata(Path path, boolean ignored, int groupSize, Integer order, Contract convertedContract = null) {
@Deprecated
ContractMetadata(Path path, boolean ignored, int groupSize, Integer order) {
this(path, ignored, groupSize, order, ContractVerifierDslConverter.convertAsCollection(path.toFile()))
}
ContractMetadata(Path path, boolean ignored, int groupSize, Integer order, Contract convertedContract) {
this(path, ignored, groupSize, order, [convertedContract])
}
ContractMetadata(Path path, boolean ignored, int groupSize, Integer order, Collection<Contract> convertedContract) {
this.groupSize = groupSize
this.path = path
this.ignored = ignored
this.order = order
this.convertedContract = convertedContract
this.convertedContract.addAll(convertedContract)
}
}

View File

@@ -17,6 +17,7 @@
package org.springframework.cloud.contract.verifier.util
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
import org.codehaus.groovy.control.CompilerConfiguration
import org.springframework.cloud.contract.spec.Contract
@@ -28,17 +29,63 @@ import org.springframework.cloud.contract.spec.Contract
* @since 1.0.0
*/
@CompileStatic
@Slf4j
class ContractVerifierDslConverter {
@Deprecated
static Contract convert(String dsl) {
return groovyShell().evaluate(dsl) as Contract
try {
return groovyShell().evaluate(dsl) as Contract
} catch (Exception e) {
log.error("Exception occurred while trying to evaluate the contract", e)
throw new DslParseException(e)
}
}
@Deprecated
static Contract convert(File dsl) {
return groovyShell().evaluate(dsl) as Contract
try {
return groovyShell().evaluate(dsl) as Contract
} catch (Exception e) {
log.error("Exception occurred while trying to evaluate the contract", e)
throw new DslParseException(e)
}
}
static Collection<Contract> convertAsCollection(String dsl) {
try {
Object object = groovyShell().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)
}
}
static Collection<Contract> convertAsCollection(File dsl) {
try {
Object object = groovyShell().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)
}
}
private static GroovyShell groovyShell() {
return new GroovyShell(ContractVerifierDslConverter.classLoader, new Binding(), new CompilerConfiguration(sourceEncoding: 'UTF-8'))
}
private static List<Contract> listOfContracts(object) {
if (object instanceof Collection) {
return object as Collection<Contract>
} else if (!object instanceof Contract) {
throw new DslParseException("Contract is not returning a Contract or list of Contracts")
}
return [object] as Collection<Contract>
}
}

View File

@@ -0,0 +1,29 @@
/*
* 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.util
import groovy.transform.InheritConstructors
/**
* Exception occurring when we're trying to parse the DSL
*
* @author Marcin Grzejszczak
* @since 1.0.3
*/
@InheritConstructors
class DslParseException extends RuntimeException {
}

View File

@@ -5,8 +5,4 @@ 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
# Converters
org.springframework.cloud.contract.spec.ContractConverter=\
org.springframework.cloud.contract.verifier.converter.YamlContractConverter
org.springframework.cloud.contract.verifier.messaging.noop.NoOpContractVerifierAutoConfiguration

View File

@@ -86,7 +86,7 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub
blockBuilder.toString().contains("""assertThatJson(parsedJson).field("property2").isNull()""")
blockBuilder.toString().contains("""assertThatJson(parsedJson).field("property1").isEqualTo("true")""")
and:
stubMappingIsValidWireMockStub(new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null), contractDsl).toWireMockClientStub())
stubMappingIsValidWireMockStub(new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, contractDsl), contractDsl).toWireMockClientStub())
where:
methodBuilderName | methodBuilder
"JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) }
@@ -121,7 +121,7 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub
blockBuilder.toString().contains("""assertThatJson(parsedJson).array("property2").contains("a").isEqualTo("sth")""")
blockBuilder.toString().contains("""assertThatJson(parsedJson).array("property2").contains("b").isEqualTo("sthElse")""")
and:
stubMappingIsValidWireMockStub(new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null), contractDsl).toWireMockClientStub())
stubMappingIsValidWireMockStub(new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, contractDsl), contractDsl).toWireMockClientStub())
where:
methodBuilderName | methodBuilder
"JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) }
@@ -159,7 +159,7 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub
blockBuilder.toString().contains("""assertThatJson(parsedJson).array("property2").hasSize(2)""")
blockBuilder.toString().contains("""assertThatJson(parsedJson).array("property2").contains("b").isEqualTo("sthElse")""")
and:
stubMappingIsValidWireMockStub(new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null), contractDsl).toWireMockClientStub())
stubMappingIsValidWireMockStub(new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, contractDsl), contractDsl).toWireMockClientStub())
where:
methodBuilderName | methodBuilder
"JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) }

View File

@@ -0,0 +1,38 @@
/*
* 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.converter
/**
* Yaml representation of a {@link org.springframework.cloud.contract.spec.Contract}
*/
class YamlContract {
public Request request = new Request()
public Response response = new Response()
static class Request {
public String method
public String url
public Map<String, Object> headers = [:]
public Map<String, Object> body = [:]
}
static class Response {
public int status
public Map<String, Object> headers = [:]
public Map<String, Object> body = [:]
}
}

View File

@@ -0,0 +1,86 @@
/*
* 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.converter
import groovy.transform.CompileStatic
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.spec.ContractConverter
import org.springframework.cloud.contract.spec.internal.Headers
import org.yaml.snakeyaml.Yaml
/**
* Simple converter from and to a {@link YamlContract} to a collection of {@link Contract}
*/
@CompileStatic
class YamlContractConverter implements ContractConverter<List<YamlContract>> {
@Override
public boolean isAccepted(File file) {
String name = file.getName()
return name.endsWith(".yml") || name.endsWith(".yaml")
}
@Override
public Collection<Contract> convertFrom(File file) {
try {
YamlContract yamlContract = new Yaml().loadAs(new FileInputStream(file), YamlContract.class)
return [Contract.make {
request {
method(yamlContract?.request?.method)
url(yamlContract?.request?.url)
headers {
yamlContract?.request?.headers?.each { String key, Object value ->
header(key, value)
}
}
body(yamlContract?.request?.body)
}
response {
status(yamlContract?.response?.status)
headers {
yamlContract?.response?.headers?.each { String key, Object value ->
header(key, value)
}
}
body(yamlContract?.response?.body)
}
}]
}
catch (FileNotFoundException e) {
throw new IllegalStateException(e)
}
}
@Override
public List<YamlContract> convertTo(Collection<Contract> contracts) {
return contracts.collect { Contract contract ->
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
}
yamlContract.response.with {
status = contract?.response?.status?.clientValue as Integer
headers = (contract?.response?.headers as Headers)?.asStubSideMap()
body = contract?.response?.body?.clientValue as Map
}
return yamlContract
}
}
}

View File

@@ -1,3 +1,19 @@
/*
* 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.converter
import org.springframework.cloud.contract.spec.Contract
@@ -16,8 +32,10 @@ class YamlContractConverterSpec extends Specification {
given:
assert converter.isAccepted(yml)
when:
Contract contract = converter.convertFrom(yml)
Collection<Contract> contracts = converter.convertFrom(yml)
then:
contracts.size() == 1
Contract contract = contracts.first()
contract.request.url.clientValue == "/foo"
contract.request.method.clientValue == "PUT"
contract.request.headers.entries.find { it.name == "foo" && it.clientValue == "bar" }
@@ -31,7 +49,7 @@ class YamlContractConverterSpec extends Specification {
given:
assert converter.isAccepted(yml)
and:
Contract contract = Contract.make {
List<Contract> contracts = [Contract.make {
request {
url("/foo")
method("PUT")
@@ -47,10 +65,12 @@ class YamlContractConverterSpec extends Specification {
}
body([foo2: "bar"])
}
}
}]
when:
YamlContract yamlContract = converter.convertTo(contract)
Collection<YamlContract> yamlContracts = converter.convertTo(contracts)
then:
yamlContracts.size() == 1
YamlContract yamlContract = yamlContracts.first()
yamlContract.request.url == "/foo"
yamlContract.request.method == "PUT"
yamlContract.request.headers.find { it.key == "foo" && it.value == "bar" }

View File

@@ -45,7 +45,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
producer(regex('[a-zA-Z]+'))
),
name: 'Jan',
created: $(consumer('2014-02-02 12:23:43'), producer({ currentDate(it) }))
created: $(consumer('2014-02-02 12:23:43'), producer(execute('currentDate($it)')))
)
headers {
header 'Content-Type': 'text/plain'
@@ -53,7 +53,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
}
}
when:
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null), groovyDsl).toWireMockClientStub()
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl).toWireMockClientStub()
then:
AssertionUtil.assertThatJsonsAreEqual('''
{
@@ -98,7 +98,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
}
}
when:
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null), groovyDsl).toWireMockClientStub()
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl).toWireMockClientStub()
then:
AssertionUtil.assertThatJsonsAreEqual('''
{
@@ -146,7 +146,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
}
}
when:
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null), groovyDsl).toWireMockClientStub()
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl).toWireMockClientStub()
then:
AssertionUtil.assertThatJsonsAreEqual('''
{
@@ -198,7 +198,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
}
}
when:
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null), groovyDsl).toWireMockClientStub()
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl).toWireMockClientStub()
then:
AssertionUtil.assertThatJsonsAreEqual(('''
{
@@ -245,7 +245,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
}
}
when:
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null), groovyDsl).toWireMockClientStub()
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl).toWireMockClientStub()
then:
AssertionUtil.assertThatJsonsAreEqual('''
{
@@ -293,7 +293,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
}
}
when:
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null), groovyDsl).toWireMockClientStub()
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl).toWireMockClientStub()
then:
AssertionUtil.assertThatJsonsAreEqual(('''
{
@@ -577,7 +577,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
}
}
when:
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null), groovyDsl).toWireMockClientStub()
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl).toWireMockClientStub()
then:
AssertionUtil.assertThatJsonsAreEqual(('''
{
@@ -632,7 +632,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
}
when:
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null), groovyDsl).toWireMockClientStub()
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl).toWireMockClientStub()
then:
AssertionUtil.assertThatJsonsAreEqual(('''
{
@@ -1020,7 +1020,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
}
}
when:
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null), groovyDsl).toWireMockClientStub()
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl).toWireMockClientStub()
then:
AssertionUtil.assertThatJsonsAreEqual(('''
{
@@ -1190,7 +1190,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
}
}
when:
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null), groovyDsl).toWireMockClientStub()
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl).toWireMockClientStub()
then:
AssertionUtil.assertThatJsonsAreEqual(('''
{
@@ -1225,7 +1225,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
}
}
when:
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null), groovyDsl).toWireMockClientStub()
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl).toWireMockClientStub()
then:
AssertionUtil.assertThatJsonsAreEqual(('''
{
@@ -1273,7 +1273,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
}
}
when:
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null), groovyDsl).toWireMockClientStub()
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl).toWireMockClientStub()
then:
AssertionUtil.assertThatJsonsAreEqual(('''
{
@@ -1324,7 +1324,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
}
}
when:
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null), groovyDsl).toWireMockClientStub()
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl).toWireMockClientStub()
then:
AssertionUtil.assertThatJsonsAreEqual(('''
{
@@ -1352,7 +1352,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
@Issue('42')
def 'should generate stub without optional parameters'() {
when:
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null), contractDsl).toWireMockClientStub()
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, contractDsl), contractDsl).toWireMockClientStub()
then:
AssertionUtil.assertThatJsonsAreEqual(('''
{
@@ -1450,7 +1450,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
}
String toWireMockClientJsonStub(groovyDsl) {
new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null), groovyDsl).toWireMockClientStub()
new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, groovyDsl), groovyDsl).toWireMockClientStub()
}
@Issue('180')
@@ -1473,7 +1473,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
}
}
when:
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null), contractDsl).toWireMockClientStub()
String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, contractDsl), contractDsl).toWireMockClientStub()
then:
println wireMockStub
AssertionUtil.assertThatJsonsAreEqual(('''
@@ -1624,7 +1624,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
}
}
when:
def json = new WireMockStubStrategy("Test", new ContractMetadata(null, true, 0, null), groovyDsl).toWireMockClientStub()
def json = new WireMockStubStrategy("Test", new ContractMetadata(null, true, 0, null, groovyDsl), groovyDsl).toWireMockClientStub()
then:
json == ''
}

View File

@@ -18,6 +18,7 @@ package org.springframework.cloud.contract.verifier.dsl
import com.github.tomakehurst.wiremock.matching.RegexPattern
import com.github.tomakehurst.wiremock.stubbing.StubMapping
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockStubStrategy
import org.springframework.cloud.contract.verifier.file.ContractMetadata
@@ -33,8 +34,8 @@ trait WireMockStubVerifier {
assert !mappingDefinition.contains('org.springframework.cloud.contract.spec.internal')
}
void stubMappingIsValidWireMockStub(org.springframework.cloud.contract.spec.Contract contractDsl) {
stubMappingIsValidWireMockStub(new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null), contractDsl).toWireMockClientStub())
void stubMappingIsValidWireMockStub(Contract contractDsl) {
stubMappingIsValidWireMockStub(new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, contractDsl), contractDsl).toWireMockClientStub())
}
}

View File

@@ -83,6 +83,6 @@ class ContractFileScannerSpec extends Specification {
then:
result.keySet().size() == 1
result.entries().every { it.value.convertedContract }
result.entries().find { it.value.convertedContract.request.method.clientValue == "PUT" }
result.entries().find { it.value.convertedContract.any { it.request.method.clientValue == "PUT" } }
}
}

View File

@@ -0,0 +1,150 @@
/*
* 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.util
import org.springframework.cloud.contract.spec.Contract
import spock.lang.Specification
/**
* @author Marcin Grzejszczak
*/
class ContractVerifierDslConverterSpec extends Specification {
URL single = ContractVerifierDslConverterSpec.getResource("/contract.groovy")
File singleContract = new File(single.toURI())
URL multiple = ContractVerifierDslConverterSpec.getResource("/multiple_contracts.groovy")
File multipleContracts = new File(multiple.toURI())
URL invalid = ContractVerifierDslConverterSpec.getResource("/contract.yml")
File invalidContract = new File(invalid.toURI())
Contract expectedSingleContract = Contract.make {
request {
method('PUT')
headers {
contentType(applicationJson())
}
body(""" { "status" : "OK" } """)
url("/1")
}
response {
status 200
body(""" { "status" : "OK" } """)
headers {
contentType(textPlain())
}
}
}
List<Contract> expectedMultipleContracts = (1..2).collect { int index ->
Contract.make {
request {
method('PUT')
headers {
contentType(applicationJson())
}
body(""" { "status" : "OK" } """)
url("/${index}")
}
response {
status 200
body(""" { "status" : "OK" } """)
headers {
contentType(textPlain())
}
}
}
}
def "should convert file to a Contract"() {
when:
Contract contract = ContractVerifierDslConverter.convert(singleContract)
then:
contract == expectedSingleContract
}
def "should throw exception when invalid file is parsed"() {
when:
ContractVerifierDslConverter.convert(invalidContract)
then:
thrown(DslParseException)
}
def "should convert file to a list of Contracts"() {
when:
List<Contract> contract = ContractVerifierDslConverter.convertAsCollection(multipleContracts)
then:
contract == expectedMultipleContracts
}
def "should throw exception when invalid text is parsed"() {
when:
ContractVerifierDslConverter.convert(invalidContract.text)
then:
thrown(DslParseException)
}
def "should convert text to a Contract"() {
when:
Contract contract = ContractVerifierDslConverter.convert(singleContract.text)
then:
contract == expectedSingleContract
}
def "should convert text to a list of Contracts"() {
when:
Collection<Contract> contract = ContractVerifierDslConverter.convertAsCollection(multipleContracts.text)
then:
contract == expectedMultipleContracts
}
def "should throw an exception when an invalid file is parsed"() {
when:
ContractVerifierDslConverter.convertAsCollection(invalidContract.text)
then:
thrown(DslParseException)
}
def "should throw an exception with file path when an invalid file is parsed"() {
when:
ContractVerifierDslConverter.convertAsCollection(invalidContract)
then:
DslParseException e = thrown(DslParseException)
e.toString().contains("contract.yml")
}
def "should throw an exception when a non existent file is parsed"() {
when:
ContractVerifierDslConverter.convertAsCollection(new File("/foo/bar/baz.foo"))
then:
DslParseException e = thrown(DslParseException)
e.cause instanceof FileNotFoundException
}
def "should convert file to a list of Contracts when there's only one declared contract"() {
when:
Collection<Contract> contract = ContractVerifierDslConverter.convertAsCollection(singleContract)
then:
contract == [expectedSingleContract]
}
def "should convert text to a list of Contracts when there's only one declared contract"() {
when:
Collection<Contract> contract = ContractVerifierDslConverter.convertAsCollection(singleContract.text)
then:
contract == [expectedSingleContract]
}
}

View File

@@ -0,0 +1,3 @@
# Converters
org.springframework.cloud.contract.spec.ContractConverter=\
org.springframework.cloud.contract.verifier.converter.YamlContractConverter

View File

@@ -0,0 +1,35 @@
import org.springframework.cloud.contract.spec.Contract
/*
* 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.
*/
Contract.make {
request {
method('PUT')
headers {
contentType(applicationJson())
}
body(""" { "status" : "OK" } """)
url("/1")
}
response {
status 200
body(""" { "status" : "OK" } """)
headers {
contentType(textPlain())
}
}
}

View File

@@ -0,0 +1,36 @@
import org.springframework.cloud.contract.spec.Contract
/*
* 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.
*/
(1..2).collect { int index ->
Contract.make {
request {
method('PUT')
headers {
contentType(applicationJson())
}
body(""" { "status" : "OK" } """)
url("/${index}")
}
response {
status 200
body(""" { "status" : "OK" } """)
headers {
contentType(textPlain())
}
}
}
}

View File

@@ -67,7 +67,7 @@ and the following Spring Integration Route:
[source,xml]
----
include::src/test/resources/integration-context.xml[]
include::src/test/resources/integration-context.xml[lines=1;18..-1]
----