Merge branch '2.0.x'
This commit is contained in:
@@ -1,20 +1,20 @@
|
||||
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.dataformat.yaml.YAMLMapper
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.PackageScope
|
||||
import org.yaml.snakeyaml.Yaml
|
||||
|
||||
import org.springframework.cloud.contract.spec.Contract
|
||||
import org.springframework.cloud.contract.spec.internal.DslProperty
|
||||
import org.springframework.cloud.contract.spec.internal.ExecutionProperty
|
||||
import org.springframework.cloud.contract.spec.internal.MatchingTypeValue
|
||||
import org.springframework.cloud.contract.spec.internal.NamedProperty
|
||||
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
|
||||
@@ -86,10 +86,10 @@ class YamlToContracts {
|
||||
yamlContract.request.queryParameters.each { String key, Object value ->
|
||||
if (value instanceof List) {
|
||||
((List) value).each {
|
||||
parameter(key, it)
|
||||
parameter(key, queryParamValue(yamlContract, key, it))
|
||||
}
|
||||
} else {
|
||||
parameter(key, value)
|
||||
parameter(key, queryParamValue(yamlContract, key, value))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -202,8 +202,15 @@ class YamlToContracts {
|
||||
case YamlContract.StubMatcherType.by_equality:
|
||||
value = byEquality()
|
||||
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:
|
||||
value = byNull()
|
||||
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) {
|
||||
jsonPath(testMatcher.path, value)
|
||||
@@ -451,6 +460,33 @@ class YamlToContracts {
|
||||
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) {
|
||||
Object serverValue = value
|
||||
if (matcher?.command) {
|
||||
@@ -499,6 +535,8 @@ class YamlToContracts {
|
||||
return patterns.nonEmpty()
|
||||
case YamlContract.PredefinedRegex.non_blank:
|
||||
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
|
||||
|
||||
import org.springframework.cloud.contract.spec.internal.MatchingStrategy
|
||||
import org.springframework.cloud.contract.spec.internal.QueryParameters
|
||||
import spock.lang.Issue
|
||||
|
||||
import java.util.regex.Pattern
|
||||
@@ -187,6 +189,22 @@ class YamlContractConverterSpec extends Specification {
|
||||
RegexPatterns patterns = new RegexPatterns()
|
||||
contract.request.headers.entries.find { it.name == "Content-Type" &&
|
||||
((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].matchingType() == MatchingType.REGEX
|
||||
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)')
|
||||
}
|
||||
|
||||
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")
|
||||
def "should convert YAML with Message matchers to DSL"() {
|
||||
given:
|
||||
|
||||
@@ -209,5 +209,10 @@ class WireMockResponseStubStrategySpec extends Specification {
|
||||
subject.buildClientRequestContent()
|
||||
then:
|
||||
noExceptionThrown()
|
||||
when:
|
||||
def response = new WireMockResponseStubStrategy(contract)
|
||||
response.buildClientResponseContent()
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,19 @@
|
||||
request:
|
||||
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:
|
||||
duck: 123
|
||||
alpha: "abc"
|
||||
@@ -15,6 +28,35 @@ request:
|
||||
"complex.key": 'foo'
|
||||
nullValue: null
|
||||
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:
|
||||
- key: Content-Type
|
||||
regex: "application/json.*"
|
||||
@@ -45,8 +87,6 @@ request:
|
||||
type: by_equality
|
||||
- path: $.nullvalue
|
||||
type: by_null
|
||||
headers:
|
||||
Content-Type: application/json
|
||||
response:
|
||||
status: 200
|
||||
body:
|
||||
|
||||
Reference in New Issue
Block a user