Merge branch '2.0.x'
This commit is contained in:
@@ -1,20 +1,20 @@
|
|||||||
package org.springframework.cloud.contract.verifier.converter
|
package org.springframework.cloud.contract.verifier.converter
|
||||||
|
|
||||||
import java.nio.file.Files
|
|
||||||
import java.util.regex.Pattern
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper
|
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper
|
||||||
import groovy.transform.CompileStatic
|
import groovy.transform.CompileStatic
|
||||||
import groovy.transform.PackageScope
|
import groovy.transform.PackageScope
|
||||||
import org.yaml.snakeyaml.Yaml
|
|
||||||
|
|
||||||
import org.springframework.cloud.contract.spec.Contract
|
import org.springframework.cloud.contract.spec.Contract
|
||||||
import org.springframework.cloud.contract.spec.internal.DslProperty
|
import org.springframework.cloud.contract.spec.internal.DslProperty
|
||||||
import org.springframework.cloud.contract.spec.internal.ExecutionProperty
|
import org.springframework.cloud.contract.spec.internal.ExecutionProperty
|
||||||
import org.springframework.cloud.contract.spec.internal.MatchingTypeValue
|
import org.springframework.cloud.contract.spec.internal.MatchingTypeValue
|
||||||
import org.springframework.cloud.contract.spec.internal.NamedProperty
|
import org.springframework.cloud.contract.spec.internal.NamedProperty
|
||||||
import org.springframework.cloud.contract.spec.internal.RegexPatterns
|
import org.springframework.cloud.contract.spec.internal.RegexPatterns
|
||||||
|
import org.springframework.cloud.contract.spec.internal.Request
|
||||||
|
import org.yaml.snakeyaml.Yaml
|
||||||
|
|
||||||
|
import java.nio.file.Files
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Marcin Grzejszczak
|
* @author Marcin Grzejszczak
|
||||||
@@ -86,10 +86,10 @@ class YamlToContracts {
|
|||||||
yamlContract.request.queryParameters.each { String key, Object value ->
|
yamlContract.request.queryParameters.each { String key, Object value ->
|
||||||
if (value instanceof List) {
|
if (value instanceof List) {
|
||||||
((List) value).each {
|
((List) value).each {
|
||||||
parameter(key, it)
|
parameter(key, queryParamValue(yamlContract, key, it))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
parameter(key, value)
|
parameter(key, queryParamValue(yamlContract, key, value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,8 +202,15 @@ class YamlToContracts {
|
|||||||
case YamlContract.StubMatcherType.by_equality:
|
case YamlContract.StubMatcherType.by_equality:
|
||||||
value = byEquality()
|
value = byEquality()
|
||||||
break
|
break
|
||||||
|
case YamlContract.StubMatcherType.by_null:
|
||||||
|
// do nothing
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
throw new UnsupportedOperationException("The type [" + matcher.type + "] is unsupported. Hint: If you're using <predefined> remember to pass <type: by_regex>")
|
||||||
|
}
|
||||||
|
if (value) {
|
||||||
|
jsonPath(matcher.path, value)
|
||||||
}
|
}
|
||||||
jsonPath(matcher.path, value)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -282,6 +289,8 @@ class YamlToContracts {
|
|||||||
case YamlContract.TestMatcherType.by_null:
|
case YamlContract.TestMatcherType.by_null:
|
||||||
value = byNull()
|
value = byNull()
|
||||||
break
|
break
|
||||||
|
default:
|
||||||
|
throw new UnsupportedOperationException("The type [" + testMatcher.type + "] is unsupported. Hint: If you're using <predefined> remember to pass <type: by_regex>")
|
||||||
}
|
}
|
||||||
if (testMatcher.path) {
|
if (testMatcher.path) {
|
||||||
jsonPath(testMatcher.path, value)
|
jsonPath(testMatcher.path, value)
|
||||||
@@ -451,6 +460,33 @@ class YamlToContracts {
|
|||||||
return clientValue
|
return clientValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Object queryParamValue(YamlContract yamlContract, String key, Object value) {
|
||||||
|
Request request = new Request()
|
||||||
|
YamlContract.QueryParameterMatcher matcher = yamlContract.request.
|
||||||
|
matchers.queryParameters.find { it.key == key}
|
||||||
|
if (!matcher) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
switch (matcher.type) {
|
||||||
|
case YamlContract.MatchingType.equal_to:
|
||||||
|
return new DslProperty(request.equalTo(matcher.value), value)
|
||||||
|
case YamlContract.MatchingType.containing:
|
||||||
|
return new DslProperty(request.containing(matcher.value), value)
|
||||||
|
case YamlContract.MatchingType.matching:
|
||||||
|
return new DslProperty(request.matching(matcher.value), value)
|
||||||
|
case YamlContract.MatchingType.not_matching:
|
||||||
|
return new DslProperty(request.notMatching(matcher.value), value)
|
||||||
|
case YamlContract.MatchingType.equal_to_json:
|
||||||
|
return new DslProperty(request.equalToJson(matcher.value), value)
|
||||||
|
case YamlContract.MatchingType.equal_to_xml:
|
||||||
|
return new DslProperty(request.equalToXml(matcher.value), value)
|
||||||
|
case YamlContract.MatchingType.absent:
|
||||||
|
return new DslProperty(request.absent(), null)
|
||||||
|
default:
|
||||||
|
throw new UnsupportedOperationException("The provided matching type [" + matcher + "] is unsupported. Use on of " + YamlContract.MatchingType.values())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected Object serverValue(Object value, YamlContract.KeyValueMatcher matcher) {
|
protected Object serverValue(Object value, YamlContract.KeyValueMatcher matcher) {
|
||||||
Object serverValue = value
|
Object serverValue = value
|
||||||
if (matcher?.command) {
|
if (matcher?.command) {
|
||||||
@@ -499,6 +535,8 @@ class YamlToContracts {
|
|||||||
return patterns.nonEmpty()
|
return patterns.nonEmpty()
|
||||||
case YamlContract.PredefinedRegex.non_blank:
|
case YamlContract.PredefinedRegex.non_blank:
|
||||||
return patterns.nonBlank()
|
return patterns.nonBlank()
|
||||||
|
default:
|
||||||
|
throw new UnsupportedOperationException("The predefined regex [" + predefinedRegex + "] is unsupported. Use on of " + YamlContract.PredefinedRegex.values())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package org.springframework.cloud.contract.verifier.converter
|
package org.springframework.cloud.contract.verifier.converter
|
||||||
|
|
||||||
|
import org.springframework.cloud.contract.spec.internal.MatchingStrategy
|
||||||
|
import org.springframework.cloud.contract.spec.internal.QueryParameters
|
||||||
import spock.lang.Issue
|
import spock.lang.Issue
|
||||||
|
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
@@ -187,6 +189,22 @@ class YamlContractConverterSpec extends Specification {
|
|||||||
RegexPatterns patterns = new RegexPatterns()
|
RegexPatterns patterns = new RegexPatterns()
|
||||||
contract.request.headers.entries.find { it.name == "Content-Type" &&
|
contract.request.headers.entries.find { it.name == "Content-Type" &&
|
||||||
((Pattern) it.clientValue).pattern == "application/json.*" && it.serverValue == "application/json" }
|
((Pattern) it.clientValue).pattern == "application/json.*" && it.serverValue == "application/json" }
|
||||||
|
contract.request.urlPath.queryParameters.parameters.size() == 8
|
||||||
|
QueryParameters queryParameters = contract.request.urlPath.queryParameters
|
||||||
|
assertQueryParam(queryParameters, "limit", 10,
|
||||||
|
MatchingStrategy.Type.EQUAL_TO, 20)
|
||||||
|
assertQueryParam(queryParameters, "offset", 20,
|
||||||
|
MatchingStrategy.Type.CONTAINS, 20)
|
||||||
|
assertQueryParam(queryParameters, "sort", "name",
|
||||||
|
MatchingStrategy.Type.EQUAL_TO, "name")
|
||||||
|
assertQueryParam(queryParameters, "search", 55,
|
||||||
|
MatchingStrategy.Type.NOT_MATCHING, (~/^[0-9]{2}$/).pattern())
|
||||||
|
assertQueryParam(queryParameters, "age", 99,
|
||||||
|
MatchingStrategy.Type.NOT_MATCHING, "^\\\\w*\$")
|
||||||
|
assertQueryParam(queryParameters, "name", "John.Doe",
|
||||||
|
MatchingStrategy.Type.MATCHING, "John.*")
|
||||||
|
assertQueryParam(queryParameters, "hello", true,
|
||||||
|
MatchingStrategy.Type.ABSENT, null)
|
||||||
contract.request.bodyMatchers.jsonPathRegexMatchers[0].path() == '$.duck'
|
contract.request.bodyMatchers.jsonPathRegexMatchers[0].path() == '$.duck'
|
||||||
contract.request.bodyMatchers.jsonPathRegexMatchers[0].matchingType() == MatchingType.REGEX
|
contract.request.bodyMatchers.jsonPathRegexMatchers[0].matchingType() == MatchingType.REGEX
|
||||||
contract.request.bodyMatchers.jsonPathRegexMatchers[0].value() == '[0-9]{3}'
|
contract.request.bodyMatchers.jsonPathRegexMatchers[0].value() == '[0-9]{3}'
|
||||||
@@ -264,6 +282,17 @@ class YamlContractConverterSpec extends Specification {
|
|||||||
contract.response.bodyMatchers.jsonPathRegexMatchers[15].value() == new ExecutionProperty('assertThatValueIsANumber($it)')
|
contract.response.bodyMatchers.jsonPathRegexMatchers[15].value() == new ExecutionProperty('assertThatValueIsANumber($it)')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Object assertQueryParam(QueryParameters queryParameters, String queryParamName, Object serverValue,
|
||||||
|
MatchingStrategy.Type clientType, Object clientValue) {
|
||||||
|
if (clientType == MatchingStrategy.Type.ABSENT) {
|
||||||
|
return ! queryParameters.parameters.find { it.name == queryParamName}
|
||||||
|
}
|
||||||
|
return queryParameters.parameters.find { it.name == queryParamName &&
|
||||||
|
it.serverValue == serverValue &&
|
||||||
|
((MatchingStrategy) it.clientValue).type == clientType &&
|
||||||
|
((MatchingStrategy) it.clientValue).clientValue == clientValue }
|
||||||
|
}
|
||||||
|
|
||||||
@Issue("#604")
|
@Issue("#604")
|
||||||
def "should convert YAML with Message matchers to DSL"() {
|
def "should convert YAML with Message matchers to DSL"() {
|
||||||
given:
|
given:
|
||||||
|
|||||||
@@ -209,5 +209,10 @@ class WireMockResponseStubStrategySpec extends Specification {
|
|||||||
subject.buildClientRequestContent()
|
subject.buildClientRequestContent()
|
||||||
then:
|
then:
|
||||||
noExceptionThrown()
|
noExceptionThrown()
|
||||||
|
when:
|
||||||
|
def response = new WireMockResponseStubStrategy(contract)
|
||||||
|
response.buildClientResponseContent()
|
||||||
|
then:
|
||||||
|
noExceptionThrown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,19 @@
|
|||||||
request:
|
request:
|
||||||
method: GET
|
method: GET
|
||||||
urlPath: /get
|
urlPath: /get/1
|
||||||
|
headers:
|
||||||
|
Content-Type: application/json
|
||||||
|
cookies:
|
||||||
|
foo: 2
|
||||||
|
queryParameters:
|
||||||
|
limit: 10
|
||||||
|
offset: 20
|
||||||
|
filter: 'email'
|
||||||
|
sort: name
|
||||||
|
search: 55
|
||||||
|
age: 99
|
||||||
|
name: John.Doe
|
||||||
|
email: 'bob@email.com'
|
||||||
body:
|
body:
|
||||||
duck: 123
|
duck: 123
|
||||||
alpha: "abc"
|
alpha: "abc"
|
||||||
@@ -15,6 +28,35 @@ request:
|
|||||||
"complex.key": 'foo'
|
"complex.key": 'foo'
|
||||||
nullValue: null
|
nullValue: null
|
||||||
matchers:
|
matchers:
|
||||||
|
url:
|
||||||
|
regex: /get/[0-9]
|
||||||
|
# predefined:
|
||||||
|
# execute a method
|
||||||
|
# command:
|
||||||
|
queryParameters:
|
||||||
|
- key: limit
|
||||||
|
type: equal_to
|
||||||
|
value: 20
|
||||||
|
- key: offset
|
||||||
|
type: containing
|
||||||
|
value: 20
|
||||||
|
- key: sort
|
||||||
|
type: equal_to
|
||||||
|
value: name
|
||||||
|
- key: search
|
||||||
|
type: not_matching
|
||||||
|
value: '^[0-9]{2}$'
|
||||||
|
- key: age
|
||||||
|
type: not_matching
|
||||||
|
value: '^\\w*$'
|
||||||
|
- key: name
|
||||||
|
type: matching
|
||||||
|
value: 'John.*'
|
||||||
|
- key: hello
|
||||||
|
type: absent
|
||||||
|
cookies:
|
||||||
|
- key: foo
|
||||||
|
regex: '[0-9]'
|
||||||
headers:
|
headers:
|
||||||
- key: Content-Type
|
- key: Content-Type
|
||||||
regex: "application/json.*"
|
regex: "application/json.*"
|
||||||
@@ -45,8 +87,6 @@ request:
|
|||||||
type: by_equality
|
type: by_equality
|
||||||
- path: $.nullvalue
|
- path: $.nullvalue
|
||||||
type: by_null
|
type: by_null
|
||||||
headers:
|
|
||||||
Content-Type: application/json
|
|
||||||
response:
|
response:
|
||||||
status: 200
|
status: 200
|
||||||
body:
|
body:
|
||||||
|
|||||||
Reference in New Issue
Block a user