Assert size of collections on the request side; fixes gh-824

This commit is contained in:
Marcin Grzejszczak
2018-12-20 14:53:38 +01:00
parent 6969d233b8
commit 9c7c896115
21 changed files with 202 additions and 117 deletions

View File

@@ -128,7 +128,9 @@ class ContractsToYaml {
request.matchers.body << new YamlContract.BodyStubMatcher(
path: matcher.path(),
type: stubMatcherType(matcher.matchingType()),
value: matcher.value()?.toString()
value: matcher.value()?.toString(),
minOccurrence: matcher.minTypeOccurrence(),
maxOccurrence: matcher.maxTypeOccurrence(),
)
}
Object url = contract.request.url?.clientValue

View File

@@ -104,6 +104,8 @@ class YamlContract {
public StubMatcherType type
public String value
public PredefinedRegex predefined
public Integer minOccurrence
public Integer maxOccurrence
}
@CompileStatic
@@ -199,7 +201,7 @@ class YamlContract {
@CompileStatic
static enum StubMatcherType {
by_date, by_time, by_timestamp, by_regex, by_equality, by_null
by_date, by_time, by_timestamp, by_regex, by_equality, by_type, by_null
}
@CompileStatic

View File

@@ -199,6 +199,12 @@ class YamlToContracts {
case YamlContract.StubMatcherType.by_equality:
value = byEquality()
break
case YamlContract.StubMatcherType.by_type:
value = byType {
if (matcher.minOccurrence != null) minOccurrence(matcher.minOccurrence)
if (matcher.maxOccurrence != null) maxOccurrence(matcher.maxOccurrence)
}
break
case YamlContract.StubMatcherType.by_null:
// do nothing
break

View File

@@ -142,14 +142,16 @@ class JsonToJsonPathsConverter {
static String convertJsonPathAndRegexToAJsonPath(BodyMatcher bodyMatcher, def body = null) {
String path = bodyMatcher.path()
Object value = bodyMatcher.value()
if (value == null && bodyMatcher.matchingType() != MatchingType.EQUALITY) {
if (value == null && bodyMatcher.matchingType() != MatchingType.EQUALITY &&
bodyMatcher.matchingType() != MatchingType.TYPE) {
return path
}
int lastIndexOfDot = lastIndexOfDot(path)
String toLastDot = path.substring(0, lastIndexOfDot)
String fromLastDot = path.substring(lastIndexOfDot + 1)
String comparison = createComparison(bodyMatcher, value, body)
return "${toLastDot}[?(@.${fromLastDot} ${comparison})]"
String propertyName = "@.${fromLastDot}"
String comparison = createComparison(propertyName, bodyMatcher, value, body)
return "${toLastDot}[?(${comparison})]"
}
private static int lastIndexOfDot(String path) {
@@ -173,7 +175,7 @@ class JsonToJsonPathsConverter {
return value
}
private static String createComparison(BodyMatcher bodyMatcher, Object value, def body) {
private static String createComparison(String propertyName, BodyMatcher bodyMatcher, Object value, def body) {
if (bodyMatcher.matchingType() == MatchingType.EQUALITY) {
Object convertedBody = body
if (!body) {
@@ -185,13 +187,25 @@ class JsonToJsonPathsConverter {
}
Object retrievedValue = JsonPath.parse(convertedBody).read(bodyMatcher.path())
String wrappedValue = retrievedValue instanceof Number ? retrievedValue : "'${retrievedValue.toString()}'"
return "== ${wrappedValue}"
return "${propertyName} == ${wrappedValue}"
} catch (PathNotFoundException e) {
throw new IllegalStateException("Value [${bodyMatcher.path()}] not found in JSON [${JsonOutput.toJson(convertedBody)}]", e)
}
} else if (bodyMatcher.matchingType() == MatchingType.TYPE) {
Integer min = bodyMatcher.minTypeOccurrence()
Integer max = bodyMatcher.maxTypeOccurrence()
String result = ""
if (min != null) {
result = "${propertyName}.size() >= ${min}"
}
if (max != null) {
String maxResult = "${propertyName}.size() <= ${max}"
result = result ? "${result} && ${maxResult}" : maxResult
}
return result
} else {
String convertedValue = value.toString().replace('/', '\\\\/')
return "=~ /(${convertedValue})/"
return "${propertyName} =~ /(${convertedValue})/"
}
}

View File

@@ -1192,7 +1192,7 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub
where:
methodBuilderName | methodBuilder | endOfLineRegexSymbol
"JaxRsClientSpockMethodRequestProcessingBodyBuilder"| { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '\\$'
"JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '$'
"JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) }| '$'
}
private String stripped(String string) {

View File

@@ -475,7 +475,7 @@ class MockMvcMethodBodyBuilderWithMatchersSpec extends Specification implements
bodyMatchers {
jsonPath('$.items[*].id', byRegex(nonBlank()))
jsonPath('$.items[*].title', byRegex(nonBlank()))
jsonPath('$.items[*]', byType { minOccurrence(2); maxOccurrence(2) })
jsonPath('$.items[*]', byType { occurrence(2) })
}
headers { header 'content-type', 'application/...json;charset=UTF-8' }
}

View File

@@ -239,6 +239,16 @@ class YamlContractConverterSpec extends Specification {
contract.request.bodyMatchers.jsonPathRegexMatchers[8].value() == patterns.isoTime()
contract.request.bodyMatchers.jsonPathRegexMatchers[9].path() == "\$.['key'].['complex.key']"
contract.request.bodyMatchers.jsonPathRegexMatchers[9].matchingType() == MatchingType.EQUALITY
contract.request.bodyMatchers.jsonPathRegexMatchers[10].path() == '$.valueWithMin'
contract.request.bodyMatchers.jsonPathRegexMatchers[10].matchingType() == MatchingType.TYPE
contract.request.bodyMatchers.jsonPathRegexMatchers[10].minTypeOccurrence() == 1
contract.request.bodyMatchers.jsonPathRegexMatchers[11].path() == '$.valueWithMax'
contract.request.bodyMatchers.jsonPathRegexMatchers[11].matchingType() == MatchingType.TYPE
contract.request.bodyMatchers.jsonPathRegexMatchers[11].maxTypeOccurrence() == 3
contract.request.bodyMatchers.jsonPathRegexMatchers[12].path() == '$.valueWithMinMax'
contract.request.bodyMatchers.jsonPathRegexMatchers[12].matchingType() == MatchingType.TYPE
contract.request.bodyMatchers.jsonPathRegexMatchers[12].minTypeOccurrence() == 1
contract.request.bodyMatchers.jsonPathRegexMatchers[12].maxTypeOccurrence() == 3
contract.request.cookies.entries.find { it.key == "foo" }.clientValue instanceof Pattern
contract.request.cookies.entries.find { it.key == "bar" }.serverValue == new ExecutionProperty('equals($it)')
and:

View File

@@ -28,6 +28,20 @@ request:
key:
"complex.key": 'foo'
nullValue: null
valueWithMin:
- 1
- 2
- 3
valueWithMax:
- 1
- 2
- 3
valueWithMinMax:
- 1
- 2
- 3
valueWithMinEmpty: []
valueWithMaxEmpty: []
matchers:
url:
regex: /get/[0-9]
@@ -90,6 +104,16 @@ request:
type: by_equality
- path: $.nullvalue
type: by_null
- path: $.valueWithMin
type: by_type
minOccurrence: 1
- path: $.valueWithMax
type: by_type
maxOccurrence: 3
- path: $.valueWithMinMax
type: by_type
minOccurrence: 1
maxOccurrence: 3
response:
status: 200
cookies: