Merge branch '2.2.x'

This commit is contained in:
Marcin Grzejszczak
2020-11-17 08:42:01 +01:00
4 changed files with 155 additions and 8 deletions

View File

@@ -320,13 +320,15 @@ class JsonToJsonPathsConverter {
}
JsonPaths transformToJsonPathWithTestsSideValues(def json,
Closure parsingClosure = MapConverter.JSON_PARSING_CLOSURE) {
return transformToJsonPathWithValues(json, SERVER_SIDE, parsingClosure)
Closure parsingClosure = MapConverter.JSON_PARSING_CLOSURE,
boolean includeEmptyCheck = false) {
return transformToJsonPathWithValues(json, SERVER_SIDE, parsingClosure, includeEmptyCheck)
}
JsonPaths transformToJsonPathWithStubsSideValues(def json,
Closure parsingClosure = MapConverter.JSON_PARSING_CLOSURE) {
return transformToJsonPathWithValues(json, CLIENT_SIDE, parsingClosure)
Closure parsingClosure = MapConverter.JSON_PARSING_CLOSURE,
boolean includeEmptyCheck = false) {
return transformToJsonPathWithValues(json, CLIENT_SIDE, parsingClosure, includeEmptyCheck)
}
static JsonPaths transformToJsonPathWithStubsSideValuesAndNoArraySizeCheck(def json,
@@ -336,11 +338,11 @@ class JsonToJsonPathsConverter {
}
private JsonPaths transformToJsonPathWithValues(def json, boolean clientSide,
Closure parsingClosure = MapConverter.JSON_PARSING_CLOSURE) {
if (!json) {
Closure parsingClosure = MapConverter.JSON_PARSING_CLOSURE,
boolean includeEmptyCheck = false) {
if (json == null || (!json && !includeEmptyCheck)) {
return new JsonPaths()
}
JsonPaths pathsAndValues = [] as Set
Object convertedJson = MapConverter.
getClientOrServerSideValues(json, clientSide, parsingClosure)
Object jsonWithPatterns = ContentUtils.
@@ -349,6 +351,11 @@ class JsonToJsonPathsConverter {
new DelegatingJsonVerifiable(JsonAssertion.
assertThat(JsonOutput.toJson(jsonWithPatterns))
.withoutThrowingException())
JsonPaths pathsAndValues = [] as Set
if (isRootElement(methodBufferingJsonPathVerifiable) && !json) {
pathsAndValues.add(methodBufferingJsonPathVerifiable.isEmpty())
return pathsAndValues
}
traverseRecursivelyForKey(jsonWithPatterns, methodBufferingJsonPathVerifiable,
{ MethodBufferingJsonVerifiable key, Object value ->
if (value instanceof ExecutionProperty || !(key instanceof FinishedDelegatingJsonVerifiable)) {

View File

@@ -17,6 +17,7 @@
package org.springframework.cloud.contract.verifier.builder;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
@@ -98,13 +99,19 @@ class JsonBodyVerificationBuilder implements BodyMethodGeneration, ClassVerifier
}
Object copiedBody = cloneBody(convertedResponseBody);
convertedResponseBody = JsonToJsonPathsConverter.removeMatchingJsonPaths(convertedResponseBody, bodyMatchers);
// If it was a map or list where all elements covered by matchers - json paths
// should not include empty check
boolean includeEmptyCheck = !mapOrListBodyReducedToEmpty(copiedBody, convertedResponseBody);
// remove quotes from fromRequest objects before picking json paths
TestSideRequestTemplateModel templateModel = hasRequestBody()
? TestSideRequestTemplateModel.from(contract.getRequest()) : null;
convertedResponseBody = MapConverter.transformValues(convertedResponseBody,
returnReferencedEntries(templateModel), parsingClosure);
JsonPaths jsonPaths = new JsonToJsonPathsConverter(assertJsonSize)
.transformToJsonPathWithTestsSideValues(convertedResponseBody, parsingClosure);
.transformToJsonPathWithTestsSideValues(convertedResponseBody, parsingClosure, includeEmptyCheck);
DocumentContext finalParsedRequestBody = parsedRequestBody;
jsonPaths.forEach(it -> {
String method = it.method();
@@ -118,6 +125,17 @@ class JsonBodyVerificationBuilder implements BodyMethodGeneration, ClassVerifier
return convertedResponseBody;
}
private boolean mapOrListBodyReducedToEmpty(Object originalBody, Object convertedBody) {
int origSize = originalBody instanceof Map ? ((Map) originalBody).size() : -1;
int convertedSize = convertedBody instanceof Map ? ((Map) convertedBody).size() : -1;
if (origSize > 0 && convertedSize == 0) {
return true;
}
origSize = originalBody instanceof List ? ((List) originalBody).size() : -1;
convertedSize = convertedBody instanceof List ? ((List) convertedBody).size() : -1;
return (origSize > 0 && convertedSize == 0);
}
private boolean hasRequestBody() {
return contract.getRequest() != null && contract.getRequest().getBody() != null;
}

View File

@@ -579,6 +579,66 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock
"webclient" | { configProperties.testMode = TestMode.WEBTESTCLIENT }
}
@Issue('#1423')
def 'should generate assertions for a response body containing an empty list with #methodBuilderName'() {
given:
Contract contractDsl = Contract.make {
request {
method "GET"
url "/url"
}
response {
status OK()
body("[]")
}
}
methodBuilder()
when:
String test = singleTestGenerator(contractDsl)
then:
test.contains("""assertThatJson(parsedJson).isEmpty()""")
and:
stubMappingIsValidWireMockStub(contractDsl)
and:
SyntaxChecker.tryToCompile(methodBuilderName, test)
where:
methodBuilderName | methodBuilder
"spock" | { properties.testFramework = TestFramework.SPOCK }
"testng" | { properties.testFramework = TestFramework.TESTNG }
"mockmvc" | { properties.testMode = TestMode.MOCKMVC }
"webclient" | { properties.testMode = TestMode.WEBTESTCLIENT }
}
@Issue('#1423')
def 'should generate assertions for a response body containing an empty map with #methodBuilderName'() {
given:
Contract contractDsl = Contract.make {
request {
method "GET"
url "/url"
}
response {
status OK()
body("{}")
}
}
methodBuilder()
when:
String test = singleTestGenerator(contractDsl)
then:
test.contains("""assertThatJson(parsedJson).isEmpty()""")
and:
stubMappingIsValidWireMockStub(contractDsl)
and:
SyntaxChecker.tryToCompile(methodBuilderName, test)
where:
methodBuilderName | methodBuilder
"spock" | { properties.testFramework = TestFramework.SPOCK }
"testng" | { properties.testFramework = TestFramework.TESTNG }
"mockmvc" | { properties.testMode = TestMode.MOCKMVC }
"webclient" | { properties.testMode = TestMode.WEBTESTCLIENT }
}
def 'should generate regex assertions for map objects in response body with #methodBuilderName'() {
given:
Contract contractDsl = Contract.make {

View File

@@ -446,6 +446,68 @@ response:
"custom" | { properties.testMode = TestMode.CUSTOM }
}
@Issue('#1423')
def 'should generate assertions for a response body containing an empty list with #methodBuilderName'() {
given:
String contract = """\
---
description: Returns an empty collection
request:
method: GET
urlPath: /url
response:
status: 200
body: []
"""
Contract contractDsl = fromYaml(contract)
methodBuilder()
when:
String test = singleTestGenerator(contractDsl)
then:
test.contains("""assertThatJson(parsedJson).isEmpty()""")
and:
stubMappingIsValidWireMockStub(contractDsl)
and:
SyntaxChecker.tryToCompile(methodBuilderName, test)
where:
methodBuilderName | methodBuilder
"spock" | { properties.testFramework = TestFramework.SPOCK }
"testng" | { properties.testFramework = TestFramework.TESTNG }
"mockmvc" | { properties.testMode = TestMode.MOCKMVC }
"webclient" | { properties.testMode = TestMode.WEBTESTCLIENT }
}
@Issue('#1423')
def 'should generate assertions for a response body containing an empty map with #methodBuilderName'() {
given:
String contract = """\
---
description: Returns an empty map
request:
method: GET
urlPath: /url
response:
status: 200
body: {}
"""
Contract contractDsl = fromYaml(contract)
methodBuilder()
when:
String test = singleTestGenerator(contractDsl)
then:
test.contains("""assertThatJson(parsedJson).isEmpty()""")
and:
stubMappingIsValidWireMockStub(contractDsl)
and:
SyntaxChecker.tryToCompile(methodBuilderName, test)
where:
methodBuilderName | methodBuilder
"spock" | { properties.testFramework = TestFramework.SPOCK }
"testng" | { properties.testFramework = TestFramework.TESTNG }
"mockmvc" | { properties.testMode = TestMode.MOCKMVC }
"webclient" | { properties.testMode = TestMode.WEBTESTCLIENT }
}
def 'should generate regex assertions for map objects in response body with #methodBuilderName'() {
given:
String contract = '''\