Fixed resolution of content type when working with WireMock stubs
This commit is contained in:
@@ -41,7 +41,7 @@ import org.springframework.cloud.contract.verifier.util.JsonToJsonPathsConverter
|
||||
import org.springframework.cloud.contract.verifier.util.MapConverter
|
||||
|
||||
import static org.springframework.cloud.contract.verifier.util.ContentType.XML
|
||||
import static org.springframework.cloud.contract.verifier.util.ContentUtils.evaluateContentType
|
||||
import static org.springframework.cloud.contract.verifier.util.ContentUtils.evaluateClientSideContentType
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
@@ -72,7 +72,7 @@ class ContractsToYaml {
|
||||
if (!contract.outputMessage) {
|
||||
return
|
||||
}
|
||||
ContentType contentType = evaluateContentType(contract.response?.headers,
|
||||
ContentType contentType = evaluateClientSideContentType(contract.response?.headers,
|
||||
contract.response?.body)
|
||||
yamlContract.outputMessage = new YamlContract.OutputMessage()
|
||||
yamlContract.outputMessage.sentTo = MapConverter.
|
||||
@@ -102,7 +102,7 @@ class ContractsToYaml {
|
||||
if (!contract.input) {
|
||||
return
|
||||
}
|
||||
ContentType contentType = evaluateContentType(contract.input?.messageHeaders,
|
||||
ContentType contentType = evaluateClientSideContentType(contract.input?.messageHeaders,
|
||||
contract.input?.messageBody)
|
||||
yamlContract.input = new YamlContract.Input()
|
||||
yamlContract.input.assertThat = MapConverter.
|
||||
@@ -132,7 +132,7 @@ class ContractsToYaml {
|
||||
if (!contract.request) {
|
||||
return
|
||||
}
|
||||
ContentType requestContentType = evaluateContentType(contract.request.headers,
|
||||
ContentType requestContentType = evaluateClientSideContentType(contract.request.headers,
|
||||
contract.request.body)
|
||||
yamlContract.request = new YamlContract.Request()
|
||||
yamlContract.request.with { YamlContract.Request request ->
|
||||
@@ -336,7 +336,7 @@ class ContractsToYaml {
|
||||
if (!contract.response) {
|
||||
return
|
||||
}
|
||||
ContentType contentType = evaluateContentType(contract.response?.headers,
|
||||
ContentType contentType = evaluateClientSideContentType(contract.response?.headers,
|
||||
contract.response?.body)
|
||||
yamlContract.response = new YamlContract.Response()
|
||||
yamlContract.response.with { YamlContract.Response response ->
|
||||
|
||||
@@ -39,7 +39,7 @@ import org.springframework.util.StringUtils
|
||||
|
||||
import static java.util.stream.Collectors.toSet
|
||||
import static org.springframework.cloud.contract.verifier.util.ContentType.XML
|
||||
import static org.springframework.cloud.contract.verifier.util.ContentUtils.evaluateContentType
|
||||
import static org.springframework.cloud.contract.verifier.util.ContentUtils.evaluateClientSideContentType
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Olga Maciaszek-Sharma
|
||||
@@ -250,7 +250,7 @@ class YamlToContracts {
|
||||
yamlContract.request.matchers?.body?.
|
||||
each { YamlContract.BodyStubMatcher matcher ->
|
||||
ContentType contentType =
|
||||
evaluateContentType(
|
||||
evaluateClientSideContentType(
|
||||
yamlHeadersToContractHeaders(yamlContract.request?.headers),
|
||||
yamlContract.request?.body)
|
||||
MatchingTypeValue value = null
|
||||
@@ -367,7 +367,7 @@ class YamlToContracts {
|
||||
yamlContract.response?.matchers?.body?.
|
||||
each { YamlContract.BodyTestMatcher testMatcher ->
|
||||
ContentType contentType =
|
||||
evaluateContentType(
|
||||
evaluateClientSideContentType(
|
||||
yamlHeadersToContractHeaders(yamlContract.response?.headers),
|
||||
yamlContract.response?.body)
|
||||
MatchingTypeValue value = null
|
||||
@@ -457,7 +457,7 @@ class YamlToContracts {
|
||||
yamlContract.input.matchers.body?.
|
||||
each { YamlContract.BodyStubMatcher matcher ->
|
||||
ContentType contentType =
|
||||
evaluateContentType(
|
||||
evaluateClientSideContentType(
|
||||
yamlHeadersToContractHeaders(yamlContract.input?.messageHeaders),
|
||||
yamlContract.input?.messageBody)
|
||||
MatchingTypeValue value = null
|
||||
@@ -527,7 +527,7 @@ class YamlToContracts {
|
||||
yamlContract.outputMessage?.matchers?.body?.
|
||||
each { YamlContract.BodyTestMatcher testMatcher ->
|
||||
ContentType contentType =
|
||||
evaluateContentType(
|
||||
evaluateClientSideContentType(
|
||||
yamlHeadersToContractHeaders(yamlContract.outputMessage?.headers),
|
||||
yamlContract.outputMessage?.body)
|
||||
MatchingTypeValue value = null
|
||||
|
||||
@@ -29,7 +29,6 @@ import groovy.json.JsonOutput
|
||||
import groovy.json.StringEscapeUtils
|
||||
import groovy.transform.PackageScope
|
||||
import groovy.transform.TypeChecked
|
||||
import groovy.transform.TypeCheckingMode
|
||||
import groovy.util.logging.Commons
|
||||
|
||||
import org.springframework.cloud.contract.spec.Contract
|
||||
@@ -60,6 +59,7 @@ import static org.springframework.cloud.contract.spec.internal.MatchingType.EQUA
|
||||
import static org.springframework.cloud.contract.spec.internal.MatchingType.NULL
|
||||
import static org.springframework.cloud.contract.spec.internal.MatchingType.TYPE
|
||||
import static org.springframework.cloud.contract.verifier.util.ContentType.FORM
|
||||
import static org.springframework.cloud.contract.verifier.util.ContentType.JSON
|
||||
import static org.springframework.cloud.contract.verifier.util.ContentUtils.getEqualsTypeFromContentType
|
||||
import static org.springframework.cloud.contract.verifier.util.RegexpBuilders.buildGStringRegexpForStubSide
|
||||
import static org.springframework.cloud.contract.verifier.util.RegexpBuilders.buildJSONRegexpMatch
|
||||
@@ -315,38 +315,42 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
@TypeChecked(TypeCheckingMode.SKIP)
|
||||
protected ContentPattern convertToValuePattern(Object object) {
|
||||
switch (object) {
|
||||
case Pattern:
|
||||
case RegexProperty:
|
||||
return WireMock.matching(new RegexProperty(object).pattern())
|
||||
case OptionalProperty:
|
||||
OptionalProperty value = object as OptionalProperty
|
||||
return WireMock.matching(value.optionalPattern())
|
||||
case MatchingStrategy:
|
||||
MatchingStrategy value = object as MatchingStrategy
|
||||
switch (value.type) {
|
||||
case MatchingStrategy.Type.NOT_MATCHING:
|
||||
return WireMock.notMatching(value.clientValue.toString())
|
||||
case MatchingStrategy.Type.ABSENT:
|
||||
return WireMock.absent()
|
||||
default:
|
||||
try {
|
||||
return WireMock."${value.type.name}"(
|
||||
clientBody(value.clientValue, contentType))
|
||||
}
|
||||
catch (Throwable t) {
|
||||
log.error("Exception occurred while trying to call WireMock.${value.type.name}(${value.clientValue})", t)
|
||||
throw t
|
||||
}
|
||||
}
|
||||
case Pattern:
|
||||
case RegexProperty:
|
||||
return WireMock.matching(new RegexProperty(object).pattern())
|
||||
case OptionalProperty:
|
||||
OptionalProperty value = object as OptionalProperty
|
||||
return WireMock.matching(value.optionalPattern())
|
||||
case MatchingStrategy:
|
||||
MatchingStrategy value = object as MatchingStrategy
|
||||
switch (value.type) {
|
||||
case MatchingStrategy.Type.NOT_MATCHING:
|
||||
return WireMock.notMatching(value.clientValue.toString())
|
||||
case MatchingStrategy.Type.ABSENT:
|
||||
return WireMock.absent()
|
||||
case MatchingStrategy.Type.EQUAL_TO:
|
||||
return WireMock.equalTo(clientBody(value.clientValue, contentType).toString())
|
||||
case MatchingStrategy.Type.CONTAINS:
|
||||
return WireMock.containing(clientBody(value.clientValue, contentType).toString())
|
||||
case MatchingStrategy.Type.MATCHING:
|
||||
return WireMock.matching(clientBody(value.clientValue, contentType).toString())
|
||||
case MatchingStrategy.Type.EQUAL_TO_JSON:
|
||||
return WireMock.equalToJson(clientBody(value.clientValue, contentType).toString())
|
||||
case MatchingStrategy.Type.EQUAL_TO_XML:
|
||||
return WireMock.equalToXml(clientBody(value.clientValue, contentType).toString())
|
||||
case MatchingStrategy.Type.BINARY_EQUAL_TO:
|
||||
return WireMock.binaryEqualTo(clientBody(value.clientValue, contentType) as byte[])
|
||||
default:
|
||||
return WireMock.equalTo(object.toString())
|
||||
throw new UnsupportedOperationException("Unknown matching strategy " + value.type)
|
||||
}
|
||||
default:
|
||||
return WireMock.equalTo(clientBody(object, contentType).toString())
|
||||
}
|
||||
}
|
||||
|
||||
protected static Object clientBody(Object bodyValue, ContentType contentType) {
|
||||
protected Object clientBody(Object bodyValue, ContentType contentType) {
|
||||
if (FORM == contentType) {
|
||||
if (bodyValue instanceof Map) {
|
||||
// [a:3, b:4] == "a=3&b=4"
|
||||
@@ -365,6 +369,9 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy {
|
||||
else if (bodyValue instanceof FromFileProperty) {
|
||||
return bodyValue.isByte() ? bodyValue.asBytes() : bodyValue.asString()
|
||||
}
|
||||
else if (JSON == contentType) {
|
||||
return parseBody(bodyValue, contentType)
|
||||
}
|
||||
return bodyValue
|
||||
}
|
||||
|
||||
@@ -421,14 +428,14 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy {
|
||||
|
||||
private MatchingStrategy appendBodyRegexpMatchPattern(Object value, ContentType contentType) {
|
||||
switch (contentType) {
|
||||
case ContentType.JSON:
|
||||
return new MatchingStrategy(
|
||||
buildJSONRegexpMatch(value), MatchingStrategy.Type.MATCHING)
|
||||
case ContentType.UNKNOWN:
|
||||
return new MatchingStrategy(
|
||||
buildGStringRegexpForStubSide(value), MatchingStrategy.Type.MATCHING)
|
||||
case ContentType.XML:
|
||||
throw new IllegalStateException("XML pattern matching is not implemented yet")
|
||||
case ContentType.JSON:
|
||||
return new MatchingStrategy(
|
||||
buildJSONRegexpMatch(value), MatchingStrategy.Type.MATCHING)
|
||||
case ContentType.UNKNOWN:
|
||||
return new MatchingStrategy(
|
||||
buildGStringRegexpForStubSide(value), MatchingStrategy.Type.MATCHING)
|
||||
case ContentType.XML:
|
||||
throw new IllegalStateException("XML pattern matching is not implemented yet")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -117,19 +117,37 @@ class SingleContractMetadata {
|
||||
DslProperty inputBody = inputBody(currentContract)
|
||||
Headers outputHeaders = outputHeaders(currentContract)
|
||||
DslProperty outputBody = outputBody(currentContract)
|
||||
this.evaluatedInputTestContentType = ContentUtils.evaluateContentType(inputHeaders, inputBody?.getServerValue())
|
||||
this.evaluatedInputTestContentType = tryToEvaluateTestContentType(inputHeaders, inputBody)
|
||||
this.inputTestContentType = inputBody != null ? this.evaluatedInputTestContentType : ContentType.UNKNOWN
|
||||
this.evaluatedOutputTestContentType = ContentUtils.evaluateContentType(outputHeaders, outputBody?.getServerValue())
|
||||
this.evaluatedOutputTestContentType = tryToEvaluateTestContentType(outputHeaders, outputBody)
|
||||
this.outputTestContentType = outputBody != null ? this.evaluatedOutputTestContentType : ContentType.UNKNOWN
|
||||
this.evaluatedInputStubContentType = ContentUtils.evaluateContentType(inputHeaders, inputBody?.getClientValue())
|
||||
this.evaluatedInputStubContentType = tryToEvaluateStubContentType(inputHeaders, inputBody)
|
||||
this.inputStubContentType = inputBody != null ? this.evaluatedInputStubContentType : ContentType.UNKNOWN
|
||||
this.evaluatedOutputStubContentType = ContentUtils.evaluateContentType(outputHeaders, outputBody?.getClientValue())
|
||||
this.evaluatedOutputStubContentType = tryToEvaluateStubContentType(outputHeaders, outputBody)
|
||||
this.outputStubContentType = outputBody != null ? this.evaluatedOutputStubContentType : ContentType.UNKNOWN
|
||||
this.http = currentContract.request != null
|
||||
this.contractMetadata = contractMetadata
|
||||
this.stubsFile = contractMetadata.getPath() != null ? contractMetadata.getPath().toFile() : null
|
||||
}
|
||||
|
||||
private ContentType tryToEvaluateStubContentType(Headers mainHeaders, DslProperty body) {
|
||||
ContentType contentType = ContentUtils.evaluateClientSideContentType(mainHeaders, body?.getClientValue())
|
||||
if (contentType == ContentType.DEFINED || contentType == ContentType.UNKNOWN) {
|
||||
// try to retrieve from the other side (e.g. stub side was a regex, but test side is concrete)
|
||||
return ContentUtils.evaluateServerSideContentType(mainHeaders, body?.getServerValue())
|
||||
}
|
||||
return contentType
|
||||
}
|
||||
|
||||
private ContentType tryToEvaluateTestContentType(Headers mainHeaders, DslProperty body) {
|
||||
ContentType contentType = ContentUtils.evaluateClientSideContentType(mainHeaders, body?.getServerValue())
|
||||
if (contentType == ContentType.DEFINED || contentType == ContentType.UNKNOWN) {
|
||||
// try to retrieve from the other side (e.g. stub side was a regex, but test side is concrete)
|
||||
return ContentUtils.evaluateServerSideContentType(mainHeaders, body?.getClientValue())
|
||||
}
|
||||
return contentType
|
||||
}
|
||||
|
||||
boolean isJson() {
|
||||
return this.inputTestContentType == ContentType.JSON ||
|
||||
this.outputTestContentType == ContentType.JSON ||
|
||||
|
||||
@@ -650,7 +650,7 @@ class ContentUtils {
|
||||
escapeJava(property.value.serverValue.toString()) + quote + ".getBytes()"
|
||||
}
|
||||
|
||||
static ContentType evaluateContentType(Headers contractHeaders, Object body) {
|
||||
static ContentType evaluateClientSideContentType(Headers contractHeaders, Object body) {
|
||||
ContentType contentType = recognizeContentTypeFromHeader(contractHeaders)
|
||||
if (UNKNOWN == contentType) {
|
||||
contentType = recognizeContentTypeFromContent(body)
|
||||
@@ -658,6 +658,14 @@ class ContentUtils {
|
||||
return contentType
|
||||
}
|
||||
|
||||
static ContentType evaluateServerSideContentType(Headers contractHeaders, Object body) {
|
||||
ContentType contentType = recognizeContentTypeFromTestHeader(contractHeaders)
|
||||
if (UNKNOWN == contentType) {
|
||||
contentType = recognizeContentTypeFromContent(body)
|
||||
}
|
||||
return contentType
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link XmlSlurper} with default error handler.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user