Fixed escaping of headers; fixes gh-892

This commit is contained in:
Marcin Grzejszczak
2019-02-19 14:56:33 +01:00
parent fbe999be55
commit dc9a6589e1
4 changed files with 49 additions and 8 deletions

View File

@@ -34,6 +34,7 @@ import org.springframework.cloud.contract.verifier.config.ContractVerifierConfig
import org.springframework.cloud.contract.verifier.util.RegexpBuilders
import static groovy.json.StringEscapeUtils.escapeJava
import static org.apache.commons.text.StringEscapeUtils.escapeJava
import static org.springframework.cloud.contract.verifier.config.TestFramework.JUNIT
import static org.springframework.cloud.contract.verifier.config.TestFramework.JUNIT5
import static org.springframework.cloud.contract.verifier.util.ContentUtils.getJavaMultipartFileParameterContent
@@ -214,7 +215,7 @@ abstract class JUnitMethodBodyBuilder extends RequestProcessingMethodBodyBuilder
}
protected String createHeaderComparison(Pattern headerValue) {
return buildEscapedMatchesMethod(headerValue) + ";"
return createMatchesMethod(escapeJava(headerValue.pattern())) + ";"
}
protected String createBodyComparison(Pattern bodyValue) {
@@ -229,7 +230,7 @@ abstract class JUnitMethodBodyBuilder extends RequestProcessingMethodBodyBuilder
}
protected String createCookieComparison(Pattern cookieValue) {
return buildEscapedMatchesMethod(cookieValue) + ";"
return createMatchesMethod(escapeJava(cookieValue.pattern())) + ";"
}
private String buildEscapedMatchesMethod(Pattern escapedValue) {

View File

@@ -198,11 +198,11 @@ abstract class SpockMethodRequestProcessingBodyBuilder extends RequestProcessing
}
protected String convertHeaderComparison(Pattern headerValue) {
return patternComparison(headerValue)
return patternComparisonWithMatchesCheck(escapeJava(headerValue.pattern()))
}
protected String convertHeaderComparison(RegexProperty headerValue) {
return convertHeaderComparison(headerValue.pattern)
return patternComparisonWithMatchesCheck(escapeJava(headerValue.pattern.pattern()))
}
protected String convertCookieComparison(String cookieValue) {
@@ -220,7 +220,7 @@ abstract class SpockMethodRequestProcessingBodyBuilder extends RequestProcessing
}
protected String convertCookieComparison(Pattern cookieValue) {
return patternComparison(cookieValue)
return patternComparisonWithMatchesCheck(convertUnicodeEscapesIfRequired(cookieValue.pattern()))
}
protected String patternComparison(Pattern pattern) {
@@ -229,6 +229,10 @@ abstract class SpockMethodRequestProcessingBodyBuilder extends RequestProcessing
protected String patternComparison(String pattern) {
String converted = escapeJava(convertUnicodeEscapesIfRequired(pattern))
return patternComparisonWithMatchesCheck(converted)
}
private String patternComparisonWithMatchesCheck(String converted) {
return "==~ java.util.regex.Pattern.compile('${converted}')"
}
}

View File

@@ -1284,4 +1284,40 @@ DocumentContext parsedJson = JsonPath.parse(json);
"JaxRsClientJUnitMethodBodyBuilder" | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) }
}
@Issue("#892")
def "should not unnecessarily escape non json body [#methodBuilderName]"() {
given:
Contract contractDsl = Contract.make {
request {
method GET()
url $(consumer(regex("/api/v1/files/" + uuid())),
producer("/api/v1/files/b0683f29-741a-4178-b5c6-6e62202e3cf1"))
}
response {
status OK()
body($(consumer("some-content"), producer(regex(nonBlank()))))
headers {
header(contentLength(), $(consumer(2647691), producer(regex(positiveInt()))))
header(contentType(), $(consumer(applicationOctetStream()), producer(regex(nonBlank()))))
}
}
}
MethodBodyBuilder builder = methodBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.appendTo(blockBuilder)
then:
String test = blockBuilder.toString()
SyntaxChecker.tryToCompile(methodBuilderName, test)
asserter(test)
and:
stubMappingIsValidWireMockStub(contractDsl)
where:
methodBuilderName | methodBuilder | asserter
"MockMvcSpockMethodBuilder" | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } | { String testContent -> assert testContent.contains('''response.header('Content-Length') ==~ java.util.regex.Pattern.compile('([1-9]\\\\d*)')''') && testContent.contains('''response.header('Content-Type') ==~ java.util.regex.Pattern.compile('^\\\\s*\\\\S[\\\\S\\\\s]*')'''); return true }
"MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } | { String testContent -> assert testContent.contains('''assertThat(response.header("Content-Type")).matches("^\\\\s*\\\\S[\\\\S\\\\s]*")''') && testContent.contains('''assertThat(response.header("Content-Length")).matches("([1-9]\\\\d*)")'''); return true }
"JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } | { String testContent -> assert testContent.contains('''response.getHeaderString('Content-Length') ==~ java.util.regex.Pattern.compile('([1-9]\\\\d*)')''') && testContent.contains('''response.getHeaderString('Content-Type') ==~ java.util.regex.Pattern.compile('^\\\\s*\\\\S[\\\\S\\\\s]*')'''); return true }
"JaxRsClientJUnitMethodBodyBuilder" | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } | { String testContent -> assert testContent.contains('''assertThat(response.getHeaderString("Content-Type")).matches("^\\\\s*\\\\S[\\\\S\\\\s]*")''') && testContent.contains('''assertThat(response.getHeaderString("Content-Length")).matches("([1-9]\\\\d*)")'''); return true }
}
}

View File

@@ -898,9 +898,9 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock
SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString())
where:
methodBuilderName | methodBuilder | headerEvaluationString
HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '''response.header('Location') ==~ java.util.regex.Pattern.compile('^((http[s]?|ftp):/)/?([^:/s]+)(:[0-9]{1,5})?/partners/[0-9]+/users/[0-9]+')'''
MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | 'assertThat(response.header("Location")).matches("^((http[s]?|ftp):/)/?([^:/s]+)(:[0-9]{1,5})?/partners/[0-9]+/users/[0-9]+");'
WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | 'assertThat(response.header("Location")).matches("^((http[s]?|ftp):/)/?([^:/s]+)(:[0-9]{1,5})?/partners/[0-9]+/users/[0-9]+");'
HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '''response.header('Location') ==~ java.util.regex.Pattern.compile('^((http[s]?|ftp):/)/?([^:/\\\\s]+)(:[0-9]{1,5})?/partners/[0-9]+/users/[0-9]+')'''
MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | 'assertThat(response.header("Location")).matches("^((http[s]?|ftp):/)/?([^:/\\\\s]+)(:[0-9]{1,5})?/partners/[0-9]+/users/[0-9]+");'
WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | 'assertThat(response.header("Location")).matches("^((http[s]?|ftp):/)/?([^:/\\\\s]+)(:[0-9]{1,5})?/partners/[0-9]+/users/[0-9]+");'
}
def 'should work with more complex stuff and jsonpaths with #methodBuilderName'() {