Added Contract converter + Yaml example

This commit is contained in:
Marcin Grzejszczak
2016-12-05 12:34:59 +01:00
parent 21458deefc
commit d63a557a29
8 changed files with 230 additions and 1 deletions

View File

@@ -0,0 +1,40 @@
package org.springframework.cloud.contract.spec;
import java.io.File;
/**
* Converter to be used to convert FROM {@link File} TO {@link Contract}
* and from {@link Contract} to {@link T}
*
* @param <T> - type to which we want to convert the contract
*
* @author Marcin Grzejszczak
* @since 1.0.3
*/
public interface ContractConverter<T> {
/**
* Should this file be accepted by the converter. Can use the file extension
* to check if the conversion is possible.
*
* @param file - file to be considered for conversion
* @return - {@code true} if the given implementation can convert the file
*/
boolean isAccepted(File file);
/**
* Converts the given {@link File} to its {@link Contract} representation
*
* @param file - file to convert
* @return - {@link Contract} representation of the file
*/
Contract convertFrom(File file);
/**
* Converts the given {@link Contract} to a {@link T} representation
*
* @param contract - the parsed contract
* @return - {@link T} the type to which we do the conversion
*/
T convertTo(Contract contract);
}

View File

@@ -18,6 +18,10 @@
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-spec</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-verifier</artifactId>
@@ -34,6 +38,11 @@
<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>

View File

@@ -0,0 +1,29 @@
package org.springframework.cloud.contract.verifier.dsl;
import java.util.HashMap;
import java.util.Map;
/**
* Yaml representation of a {@link org.springframework.cloud.contract.spec.Contract}
*
* @author Marcin Grzejszczak
* @since 1.0.3
*/
//TODO: Perform full conversion
public 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 = new HashMap<>();
public Map<String, Object> body = new HashMap<>();
}
static class Response {
public int status;
public Map<String, Object> headers = new HashMap<>();
public Map<String, Object> body = new HashMap<>();
}
}

View File

@@ -0,0 +1,72 @@
package org.springframework.cloud.contract.verifier.dsl
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
* @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

@@ -0,0 +1,62 @@
package org.springframework.cloud.contract.verifier.dsl
import org.springframework.cloud.contract.spec.Contract
import spock.lang.Specification
/**
* @author Marcin Grzejszczak
*/
class YamlContractConverterSpec extends Specification {
URL ymlUrl = YamlContractConverterSpec.getResource("/contract.yml")
File yml = new File(ymlUrl.toURI())
YamlContractConverter converter = new YamlContractConverter()
def "should convert YAML to DSL"() {
given:
assert converter.isAccepted(yml)
when:
Contract contract = converter.convertFrom(yml)
then:
contract.request.url.clientValue == "/foo"
contract.request.method.clientValue == "PUT"
contract.request.headers.entries.find { it.name == "foo" && it.clientValue == "bar" }
contract.request.body.clientValue == [foo: "bar"]
contract.response.status.clientValue == 200
contract.response.headers.entries.find { it.name == "foo2" && it.clientValue == "bar" }
contract.response.body.clientValue == [foo2: "bar"]
}
def "should convert DSL to YAML"() {
given:
assert converter.isAccepted(yml)
and:
Contract contract = Contract.make {
request {
url("/foo")
method("PUT")
headers {
header("foo", "bar")
}
body([foo: "bar"])
}
response {
status(200)
headers {
header("foo2", "bar")
}
body([foo2: "bar"])
}
}
when:
YamlContract yamlContract = converter.convertTo(contract)
then:
yamlContract.request.url == "/foo"
yamlContract.request.method == "PUT"
yamlContract.request.headers.find { it.key == "foo" && it.value == "bar" }
yamlContract.request.body == [foo: "bar"]
yamlContract.response.status == 200
yamlContract.response.headers.find { it.key == "foo2" && it.value == "bar" }
yamlContract.response.body == [foo2: "bar"]
}
}

View File

@@ -0,0 +1,13 @@
request:
url: /foo
method: PUT
headers:
foo: bar
body:
foo: bar
response:
status: 200
headers:
foo2: bar
body:
foo2: bar

View File

@@ -17,6 +17,10 @@
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-spec</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test-autoconfigure</artifactId>

View File

@@ -82,7 +82,7 @@ class ContractFileScanner {
files.sort().eachWithIndex { File file, int index ->
boolean excluded = matchesPattern(file, excludeMatchers)
if (!excluded) {
boolean contractFile = isContractFile(file);
boolean contractFile = isContractFile(file)
boolean included = includeMatcher ? file.absolutePath.matches(includeMatcher) : true
if (contractFile && included) {
Path path = file.toPath()