Fixed missing support for execute method in URL

without this change the execute method in URL is quoted and treated as string
with this change we're supporting it OOB

fixes #11
This commit is contained in:
Marcin Grzejszczak
2017-01-17 13:46:26 +01:00
parent 9be467ed51
commit 4d82abc52d
8 changed files with 208 additions and 155 deletions

View File

@@ -44,7 +44,7 @@ class ExecutionProperty {
}
@Override
public String toString() {
String toString() {
return executionCommand
}
}

View File

@@ -19,11 +19,13 @@ package org.springframework.cloud.contract.verifier.builder
import groovy.transform.PackageScope
import groovy.transform.TypeChecked
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.spec.internal.DslProperty
import org.springframework.cloud.contract.spec.internal.Header
import org.springframework.cloud.contract.spec.internal.QueryParameter
import org.springframework.cloud.contract.spec.internal.ExecutionProperty
import org.springframework.cloud.contract.spec.internal.QueryParameters
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
import org.springframework.cloud.contract.verifier.util.MapConverter
import java.util.regex.Pattern
@@ -73,14 +75,22 @@ class JaxRsClientJUnitMethodBodyBuilder extends JUnitMethodBodyBuilder {
protected void appendUrlPathAndQueryParameters(BlockBuilder bb) {
if (request.url) {
bb.addLine(".path(\"$request.url.serverValue\")")
bb.addLine(".path(${concreteUrl(request.url)})")
appendQueryParams(request.url.queryParameters, bb)
} else if (request.urlPath) {
bb.addLine(".path(\"$request.urlPath.serverValue\")")
bb.addLine(".path(${concreteUrl(request.urlPath)})")
appendQueryParams(request.urlPath.queryParameters, bb)
}
}
protected String concreteUrl(DslProperty url) {
Object testSideUrl = MapConverter.getTestSideValues(url)
if (!(testSideUrl instanceof ExecutionProperty)) {
return '"' + testSideUrl.toString() + '"'
}
return testSideUrl.toString()
}
private void appendQueryParams(QueryParameters queryParameters, BlockBuilder bb) {
if (!queryParameters?.parameters) {
return

View File

@@ -19,11 +19,13 @@ package org.springframework.cloud.contract.verifier.builder
import groovy.transform.PackageScope
import groovy.transform.TypeChecked
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.spec.internal.DslProperty
import org.springframework.cloud.contract.spec.internal.Header
import org.springframework.cloud.contract.spec.internal.QueryParameter
import org.springframework.cloud.contract.spec.internal.QueryParameters
import org.springframework.cloud.contract.spec.internal.ExecutionProperty
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
import org.springframework.cloud.contract.verifier.util.MapConverter
import java.util.regex.Pattern
@@ -78,14 +80,22 @@ class JaxRsClientSpockMethodRequestProcessingBodyBuilder extends SpockMethodRequ
protected void appendUrlPathAndQueryParameters(BlockBuilder bb) {
if (request.url) {
bb.addLine(".path('$request.url.serverValue')")
bb.addLine(".path(${concreteUrl(request.url)})")
appendQueryParams(request.url.queryParameters, bb)
} else if (request.urlPath) {
bb.addLine(".path('$request.urlPath.serverValue')")
bb.addLine(".path(${concreteUrl(request.urlPath)})")
appendQueryParams(request.urlPath.queryParameters, bb)
}
}
protected String concreteUrl(DslProperty url) {
Object testSideUrl = MapConverter.getTestSideValues(url)
if (!(testSideUrl instanceof ExecutionProperty)) {
return "'" + testSideUrl.toString() + "'"
}
return testSideUrl.toString()
}
private void appendQueryParams(QueryParameters queryParameters, BlockBuilder bb) {
if (!queryParameters?.parameters) {
return

View File

@@ -21,6 +21,7 @@ import groovy.transform.PackageScope
import groovy.transform.TypeChecked
import groovy.transform.TypeCheckingMode
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.spec.internal.ExecutionProperty
import org.springframework.cloud.contract.spec.internal.Request
import org.springframework.cloud.contract.spec.internal.Header
import org.springframework.cloud.contract.spec.internal.MatchingStrategy
@@ -131,9 +132,13 @@ abstract class RequestProcessingMethodBodyBuilder extends MethodBodyBuilder {
}
protected addUrl(Url buildUrl, BlockBuilder bb){
String url =MapConverter.getTestSideValues(buildUrl)
Object testSideUrl = MapConverter.getTestSideValues(buildUrl)
String method = request.method.serverValue.toString().toLowerCase()
bb.addLine(/.${method}(${DOUBLE_QUOTE}${url}${DOUBLE_QUOTE})/)
String url = testSideUrl.toString()
if (!(testSideUrl instanceof ExecutionProperty)) {
url = "${DOUBLE_QUOTE}${testSideUrl.toString()}${DOUBLE_QUOTE}"
}
bb.addLine(/.${method}(${url})/)
}
@Override

View File

@@ -678,11 +678,11 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub
and:
stubMappingIsValidWireMockStub(contractDsl)
and:
SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString())
SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, blockBuilder.toString())
where:
methodBuilderName | methodBuilder | methodString
methodBuilderName | methodBuilder | methodString
"JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | ".method('GET')"
"JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | 'method("GET")'
"JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | 'method("GET")'
}
def "should generate a call with an url path and query parameters with JUnit - we'll put it into docs"() {
@@ -882,7 +882,7 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub
MethodBodyBuilder builder = new JaxRsClientSpockMethodRequestProcessingBodyBuilder(contractDsl, properties)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.then(blockBuilder)
builder.appendTo(blockBuilder)
def test = blockBuilder.toString()
then:
test.contains("responseBody ==~ java.util.regex.Pattern.compile('.*')")
@@ -930,12 +930,13 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub
MethodBodyBuilder builder = new JaxRsClientSpockMethodRequestProcessingBodyBuilder(contractDsl, properties)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.then(blockBuilder)
builder.appendTo(blockBuilder)
def test = blockBuilder.toString()
then:
test.contains("foo(responseBody)")
and:
SyntaxChecker.tryToCompileGroovy(blockBuilder.toString())
// no static compilation due to bug in Groovy https://issues.apache.org/jira/browse/GROOVY-8055
SyntaxChecker.tryToCompileGroovy(blockBuilder.toString(), false)
}
def "should allow c/p version of consumer producer"() {

View File

@@ -16,6 +16,9 @@
package org.springframework.cloud.contract.verifier.builder
import org.codehaus.groovy.control.MultipleCompilationErrorsException
import org.junit.Rule
import org.springframework.boot.test.rule.OutputCapture
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
import org.springframework.cloud.contract.verifier.dsl.WireMockStubVerifier
@@ -23,20 +26,21 @@ import org.springframework.cloud.contract.verifier.util.SyntaxChecker
import spock.lang.Issue
import spock.lang.Shared
import spock.lang.Specification
import spock.lang.Unroll
import spock.util.environment.RestoreSystemProperties
import java.util.regex.Pattern
/**
* @author Jakub Kubrynski, codearte.io
*/
class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStubVerifier {
@Rule OutputCapture capture = new OutputCapture()
@Shared ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties(
assertJsonSize: true
)
@Shared
// tag::contract_with_regex[]
Contract dslWithOptionalsInString = Contract.make {
@@ -103,8 +107,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub
}
}
@Unroll
def "should generate assertions for simple response body with #methodBuilderName"() {
def "should generate assertions for simple response body with #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -137,8 +140,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub
}
@Issue("#187")
@Unroll
def "should generate assertions for null and boolean values with #methodBuilderName"() {
def "should generate assertions for null and boolean values with #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -173,8 +175,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub
}
@Issue("#79")
@Unroll
def "should generate assertions for simple response body constructed from map with a list with #methodBuilderName"() {
def "should generate assertions for simple response body constructed from map with a list with #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -212,8 +213,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub
@Issue("#79")
@RestoreSystemProperties
@Unroll
def "should generate assertions for simple response body constructed from map with a list with #methodBuilderName with array size check"() {
def "should generate assertions for simple response body constructed from map with a list with #methodBuilderName with array size check"() {
given:
System.setProperty('spring.cloud.contract.verifier.assert.size', 'true')
Contract contractDsl = Contract.make {
@@ -252,8 +252,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub
}
@Issue("#82")
@Unroll
def "should generate proper request when body constructed from map with a list #methodBuilderName"() {
def "should generate proper request when body constructed from map with a list #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -284,8 +283,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub
}
@Issue("#88")
@Unroll
def "should generate proper request when body constructed from GString with #methodBuilderName"() {
def "should generate proper request when body constructed from GString with #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -316,8 +314,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub
}
@Issue("185")
@Unroll
def "should generate assertions for a response body containing map with integers as keys with #methodBuilderName"() {
def "should generate assertions for a response body containing map with integers as keys with #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -351,8 +348,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub
"MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) }
}
@Unroll
def "should generate assertions for array in response body with #methodBuilderName"() {
def "should generate assertions for array in response body with #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -387,8 +383,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub
"MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) }
}
@Unroll
def "should generate assertions for array inside response body element with #methodBuilderName"() {
def "should generate assertions for array inside response body element with #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -422,8 +417,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub
"MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) }
}
@Unroll
def "should generate assertions for nested objects in response body with #methodBuilderName"() {
def "should generate assertions for nested objects in response body with #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -457,8 +451,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub
"MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) }
}
@Unroll
def "should generate regex assertions for map objects in response body with #methodBuilderName"() {
def "should generate regex assertions for map objects in response body with #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -496,8 +489,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub
"MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) }
}
@Unroll
def "should generate regex assertions for string objects in response body with #methodBuilderName"() {
def "should generate regex assertions for string objects in response body with #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -532,8 +524,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub
}
@Issue(["#126", "#143"])
@Unroll
def "should generate escaped regex assertions for string objects in response body with #methodBuilderName"() {
def "should generate escaped regex assertions for string objects in response body with #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -566,8 +557,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub
"MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) }
}
@Unroll
def "should generate a call with an url path and query parameters with #methodBuilderName"() {
def "should generate a call with an url path and query parameters with #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -625,8 +615,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub
}
@Issue('#169')
@Unroll
def "should generate a call with an url path and query parameters with url containing a pattern with #methodBuilderName"() {
def "should generate a call with an url path and query parameters with url containing a pattern with #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -683,8 +672,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub
"MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) }
}
@Unroll
def "should generate test for empty body with #methodBuilderName"() {
def "should generate test for empty body with #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -713,8 +701,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub
"MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | ".body(\"\\\"\\\"\")"
}
@Unroll
def "should generate test for String in response body with #methodBuilderName"() {
def "should generate test for String in response body with #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -745,8 +732,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub
}
@Issue('113')
@Unroll
def "should generate regex test for String in response header with #methodBuilderName"() {
def "should generate regex test for String in response header with #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -787,8 +773,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub
}
@Issue('115')
@Unroll
def "should generate regex with helper method with #methodBuilderName"() {
def "should generate regex with helper method with #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -828,8 +813,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub
"MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | 'assertThat(response.header("Location")).matches("^((http[s]?|ftp):/)/?([^:/s]+)(:[0-9]{1,5})?/partners/[0-9]+/users/[0-9]+");'
}
@Unroll
def "should work with more complex stuff and jsonpaths with #methodBuilderName"() {
def "should work with more complex stuff and jsonpaths with #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
priority 10
@@ -872,82 +856,81 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub
"MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) }
}
@Unroll
def "should work properly with GString url with #methodBuilderName"() {
def "should work properly with GString url with #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
Contract contractDsl = Contract.make {
request {
method PUT()
url "/partners/${value(consumer(regex('^[0-9]*$')), producer('11'))}/agents/11/customers/09665703Z"
headers {
contentType(applicationJson())
request {
method PUT()
url "/partners/${value(consumer(regex('^[0-9]*$')), producer('11'))}/agents/11/customers/09665703Z"
headers {
contentType(applicationJson())
}
body(
first_name: 'Josef',
)
}
response {
status 422
}
body(
first_name: 'Josef',
)
}
response {
status 422
}
}
MethodBodyBuilder builder = methodBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
MethodBodyBuilder builder = methodBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.appendTo(blockBuilder)
def test = blockBuilder.toString()
builder.appendTo(blockBuilder)
def test = blockBuilder.toString()
then:
test.contains('''/partners/11/agents/11/customers/09665703Z''')
test.contains('''/partners/11/agents/11/customers/09665703Z''')
and:
stubMappingIsValidWireMockStub(contractDsl)
stubMappingIsValidWireMockStub(contractDsl)
and:
SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString())
SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString())
where:
methodBuilderName | methodBuilder
"MockMvcSpockMethodBuilder" | { Contract dsl -> new MockMvcSpockMethodRequestProcessingBodyBuilder(dsl, properties) }
"MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) }
methodBuilderName | methodBuilder
"MockMvcSpockMethodBuilder" | { Contract dsl -> new MockMvcSpockMethodRequestProcessingBodyBuilder(dsl, properties) }
"MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) }
}
@Unroll
def "should resolve properties in GString with regular expression with #methodBuilderName"() {
def "should resolve properties in GString with regular expression with #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
priority 1
request {
method POST()
url '/users/password'
headers {
contentType(applicationJson())
Contract contractDsl = Contract.make {
priority 1
request {
method POST()
url '/users/password'
headers {
contentType(applicationJson())
}
body(
email: $(consumer(regex(email())), producer('not.existing@user.com')),
callback_url: $(consumer(regex(hostname())), producer('http://partners.com'))
)
}
body(
email: $(consumer(regex(email())), producer('not.existing@user.com')),
callback_url: $(consumer(regex(hostname())), producer('http://partners.com'))
)
}
response {
status 404
headers {
contentType(applicationJson())
response {
status 404
headers {
contentType(applicationJson())
}
body(
code: 4,
message: "User not found by email = [${value(producer(regex(email())), consumer('not.existing@user.com'))}]"
)
}
body(
code: 4,
message: "User not found by email = [${value(producer(regex(email())), consumer('not.existing@user.com'))}]"
)
}
}
MethodBodyBuilder builder = methodBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
MethodBodyBuilder builder = methodBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.appendTo(blockBuilder)
def test = blockBuilder.toString()
builder.appendTo(blockBuilder)
def test = blockBuilder.toString()
then:
test.contains("""assertThatJson(parsedJson).field("message").matches("User not found by email = \\\\\\\\[[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\\\\\.[a-zA-Z]{2,4}\\\\\\\\]")""")
test.contains("""assertThatJson(parsedJson).field("message").matches("User not found by email = \\\\\\\\[[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\\\\\.[a-zA-Z]{2,4}\\\\\\\\]")""")
and:
SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString())
// no static compilation due to bug in Groovy https://issues.apache.org/jira/browse/GROOVY-8055
SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, blockBuilder.toString())
where:
methodBuilderName | methodBuilder
"MockMvcSpockMethodBuilder" | { Contract dsl -> new MockMvcSpockMethodRequestProcessingBodyBuilder(dsl, properties) }
"MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) }
methodBuilderName | methodBuilder
"MockMvcSpockMethodBuilder" | { Contract dsl -> new MockMvcSpockMethodRequestProcessingBodyBuilder(dsl, properties) }
"MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) }
}
@Issue('42')
@@ -991,8 +974,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub
}
@Issue('72')
@Unroll
def "should make the execute method work with #methodBuilderName"() {
def "should make the execute method work with #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -1044,8 +1026,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub
"MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | ['''assertThatRejectionReasonIsNull(parsedJson.read("$.rejectionReason"))''', '''assertThatLocationIsNull(response.header("Location"))''']
}
@Unroll
def "should support inner map and list definitions with #methodBuilderName"() {
def "should support inner map and list definitions with #methodBuilderName"() {
given:
Pattern PHONE_NUMBER = Pattern.compile(/[+\w]*/)
@@ -1115,8 +1096,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub
}
@Unroll
def "shouldn't generate unicode escape characters with #methodBuilderName"() {
def "shouldn't generate unicode escape characters with #methodBuilderName"() {
given:
Pattern ONLY_ALPHA_UNICODE = Pattern.compile(/[\p{L}]*/)
@@ -1157,8 +1137,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub
}
@Issue('177')
@Unroll
def "should generate proper test code when having multiline body with #methodBuilderName"() {
def "should generate proper test code when having multiline body with #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -1188,8 +1167,7 @@ World.'''"""
}
@Issue('180')
@Unroll
def "should generate proper test code when having multipart parameters with #methodBuilderName"() {
def "should generate proper test code when having multipart parameters with #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -1232,8 +1210,7 @@ World.'''"""
}
@Issue('180')
@Unroll
def "should generate proper test code when having multipart parameters with named as map with #methodBuilderName"() {
def "should generate proper test code when having multipart parameters with named as map with #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -1338,8 +1315,7 @@ World.'''"""
SyntaxChecker.tryToCompileJava(blockBuilder.toString())
}
@Unroll
def "should work with execution property with #methodBuilderName"() {
def "should work with execution property with #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -1394,7 +1370,7 @@ World.'''"""
MethodBodyBuilder builder = new MockMvcSpockMethodRequestProcessingBodyBuilder(contractDsl, properties)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.then(blockBuilder)
builder.appendTo(blockBuilder)
def test = blockBuilder.toString()
then:
test.contains('assertThatJson(parsedJson).array().contains("id").matches("[0-9]+")')
@@ -1403,8 +1379,7 @@ World.'''"""
}
@Issue('266')
@Unroll
def "should generate proper test code with top level array using #methodBuilderName"() {
def "should generate proper test code with top level array using #methodBuilderName"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -1440,8 +1415,7 @@ World.'''"""
@Issue('266')
@RestoreSystemProperties
@Unroll
def "should generate proper test code with top level array using #methodBuilderName with array size check"() {
def "should generate proper test code with top level array using #methodBuilderName with array size check"() {
given:
System.setProperty('spring.cloud.contract.verifier.assert.size', 'true')
Contract contractDsl = Contract.make {
@@ -1597,7 +1571,7 @@ World.'''"""
then:
test.contains('assertThatJson(parsedJson).field("message").matches("^(?!\\\\s*\\$).+")')
and:
SyntaxChecker.tryToCompileGroovy(blockBuilder.toString())
SyntaxChecker.tryToCompileGroovy(blockBuilder.toString(), false)
}
Contract dslForDocs =
@@ -1717,8 +1691,11 @@ World.'''"""
def test = blockBuilder.toString()
then:
test.contains('assertThatRejectionReasonIsNull(parsedJson.read(\'$.rejectionReason.title\'))')
and:
when:
SyntaxChecker.tryToCompileGroovy(blockBuilder.toString())
then:
def e = thrown(MultipleCompilationErrorsException)
e.message.contains("Cannot find matching method Script1#assertThatRejectionReasonIsNull")
}
@Issue('#85')
@@ -1809,8 +1786,11 @@ World.'''"""
def test = blockBuilder.toString()
then:
test.contains('.header("authorization", getOAuthTokenHeader())')
and:
when:
SyntaxChecker.tryToCompileGroovy(blockBuilder.toString())
then:
def e = thrown(MultipleCompilationErrorsException)
e.message.contains("Cannot find matching method Script1#getOAuthTokenHeader")
}
@Issue('#150')
@@ -1822,7 +1802,6 @@ World.'''"""
url '/get'
}
response {
status 200
status 200
body(value(stub("HELLO FROM STUB"), server(regex(".*"))))
}
@@ -1830,7 +1809,7 @@ World.'''"""
MethodBodyBuilder builder = new MockMvcSpockMethodRequestProcessingBodyBuilder(contractDsl, properties)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.then(blockBuilder)
builder.appendTo(blockBuilder)
def test = blockBuilder.toString()
then:
test.contains("responseBody ==~ java.util.regex.Pattern.compile('.*')")
@@ -1847,7 +1826,6 @@ World.'''"""
url '/get'
}
response {
status 200
status 200
body(value(stub("HELLO FROM STUB"), server(execute('foo($it)'))))
}
@@ -1855,12 +1833,15 @@ World.'''"""
MethodBodyBuilder builder = new MockMvcSpockMethodRequestProcessingBodyBuilder(contractDsl, properties)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.then(blockBuilder)
builder.appendTo(blockBuilder)
def test = blockBuilder.toString()
then:
test.contains("foo(responseBody)")
and:
when:
SyntaxChecker.tryToCompileGroovy(blockBuilder.toString())
then:
def e = thrown(MultipleCompilationErrorsException)
e.message.contains("Cannot find matching method Script1#foo")
}
@Issue('#149')
@@ -1891,13 +1872,15 @@ World.'''"""
def test = blockBuilder.toString()
then:
test.contains('.header("authorization", getOAuthTokenHeader())')
and:
when:
SyntaxChecker.tryToCompileGroovy(blockBuilder.toString())
then:
def e = thrown(MultipleCompilationErrorsException)
e.message.contains("Cannot find matching method Script1#getOAuthTokenHeader()")
}
@Issue('#149')
@Unroll
def "should allow easier way of providing dynamic values for [#methodBuilderName]"() {
def "should allow easier way of providing dynamic values for [#methodBuilderName]"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -1969,8 +1952,7 @@ World.'''"""
}
@Issue('#162')
@Unroll
def "should escape regex properly for content type"() {
def "should escape regex properly for content type"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -2003,8 +1985,7 @@ World.'''"""
}
@Issue('#173')
@Unroll
def "should resolve Optional object when used in query parameters"() {
def "should resolve Optional object when used in query parameters"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -2041,8 +2022,7 @@ World.'''"""
}
@Issue('#172')
@Unroll
def "should resolve plain text properly via headers"() {
def "should resolve plain text properly via headers"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -2109,4 +2089,38 @@ World.'''"""
"MockMvcSpockMethodBuilder" | { Contract dsl -> new MockMvcSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '''responseBody == "{\\"a\\":1}\\n{\\"a\\":2}"'''
"MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}'''
}
@Issue('#169')
def "should make the execute method work in a url for [#methodBuilderName]"() {
given:
Contract contractDsl = Contract.make {
request {
method 'POST'
url $(c("foo"), p(execute("executedMethod()")))
}
response {
status 200
}
}
MethodBodyBuilder builder = methodBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
and:
builder.appendTo(blockBuilder)
String test = blockBuilder.toString()
when:
SyntaxChecker.tryToCompile(methodBuilderName, test)
then:
def e = thrown(Throwable)
missingMethodAssertion(e, capture)
and:
test.contains("executedMethod()")
!test.contains("\"executedMethod()\"")
!test.contains("'executedMethod()'")
where:
methodBuilderName | methodBuilder | missingMethodAssertion
"MockMvcSpockMethodBuilder" | { Contract dsl -> new MockMvcSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | { Throwable t, OutputCapture capture -> t.message.contains("Cannot find matching method Script1#executedMethod") }
"MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | { Throwable t, OutputCapture capture -> t.message.contains("Truncated class file") && capture.toString().contains("post(executedMethod())") }
"JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | { Throwable t, OutputCapture capture -> t.message.contains("Cannot find matching method Script1#executedMethod") }
"JaxRsClientJUnitMethodBodyBuilder" | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | { Throwable t, OutputCapture capture -> t.message.contains("Truncated class file") && capture.toString().contains("path(executedMethod())") }
}
}

View File

@@ -146,11 +146,11 @@ class MockMvcMethodBodyBuilderWithMatchersSpec extends Specification implements
test.contains('assertThat(parsedJson.read("' + rootElement + '.valueWithMinMax", java.util.Collection.class).size()).isStrictlyBetween(1, 3)')
!test.contains('cursor')
and:
SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString())
SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, blockBuilder.toString())
where:
methodBuilderName | methodBuilder | rootElement
"MockMvcSpockMethodBuilder" | { Contract dsl -> new MockMvcSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '\\$'
"MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '$'
methodBuilderName | methodBuilder | rootElement
"MockMvcSpockMethodBuilder" | { Contract dsl -> new MockMvcSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '\\$'
"MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '$'
"JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '\\$'
"JaxRsClientJUnitMethodBodyBuilder" | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | '$'
}

View File

@@ -2,6 +2,7 @@ package org.springframework.cloud.contract.verifier.util
import groovy.transform.CompileStatic
import org.codehaus.groovy.control.CompilerConfiguration
import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
import org.codehaus.groovy.control.customizers.ImportCustomizer
import org.mdkt.compiler.InMemoryJavaCompiler
@@ -42,7 +43,6 @@ class SyntaxChecker {
"org.assertj.core.api.Assertions.assertThat"
].collect { "import static ${it};"}.join("\n")
static void tryToCompile(String builderName, String test) {
if (builderName.toLowerCase().contains("spock")) {
tryToCompileGroovy(test)
@@ -51,11 +51,24 @@ class SyntaxChecker {
}
}
static void tryToCompileGroovy(String test) {
// no static compilation due to bug in Groovy https://issues.apache.org/jira/browse/GROOVY-8055
static void tryToCompileWithoutCompileStatic(String builderName, String test) {
if (builderName.toLowerCase().contains("spock")) {
tryToCompileGroovy(test, false)
} else {
tryToCompileJava(test)
}
}
static void tryToCompileGroovy(String test, boolean compileStatic = true) {
def imports = new ImportCustomizer()
CompilerConfiguration configuration = new CompilerConfiguration()
if (compileStatic) {
configuration.addCompilationCustomizers(
new ASTTransformationCustomizer(CompileStatic))
}
configuration.addCompilationCustomizers(imports)
StringBuffer sourceCode = new StringBuffer()
StringBuilder sourceCode = new StringBuilder()
sourceCode.append("${DEFAULT_IMPORTS_AS_STRING}\n")
sourceCode.append("${STATIC_IMPORTS}\n")
sourceCode.append("\n")