From 4631ab6ea8d81a006ef3107963c4c724c22a7fa0 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Thu, 1 Jun 2017 17:50:10 +0200 Subject: [PATCH] Adds support for execute in request body fixes #313 --- docs/src/main/asciidoc/verifier/contract.adoc | 31 ++++++++++++++++- .../JUnitMessagingMethodBodyBuilder.groovy | 2 +- .../builder/JUnitMethodBodyBuilder.groovy | 10 ++++-- .../JaxRsClientJUnitMethodBodyBuilder.groovy | 4 ++- ...kMethodRequestProcessingBodyBuilder.groovy | 6 ++-- .../verifier/builder/MethodBodyBuilder.groovy | 2 +- .../RequestProcessingMethodBodyBuilder.groovy | 4 ++- .../SpockMessagingMethodBodyBuilder.groovy | 2 +- ...kMethodRequestProcessingBodyBuilder.groovy | 10 ++++-- .../builder/MethodBodyBuilderSpec.groovy | 33 +++++++++++++++++++ 10 files changed, 92 insertions(+), 12 deletions(-) diff --git a/docs/src/main/asciidoc/verifier/contract.adoc b/docs/src/main/asciidoc/verifier/contract.adoc index d778b91aa5..7d675d369b 100644 --- a/docs/src/main/asciidoc/verifier/contract.adoc +++ b/docs/src/main/asciidoc/verifier/contract.adoc @@ -283,7 +283,6 @@ include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract include::{plugins_path}/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/src/test/groovy/org/springframework/cloud/contract/verifier/twitter/places/BaseMockMvcSpec.groovy[tags=base_class,indent=0] ---- - IMPORTANT: You can't use both a String and `execute` to perform concatenation. E.g. calling `header('Authorization', 'Bearer ' + execute('authToken()'))` will lead to improper results. To make this work just call `header('Authorization', execute('authToken()'))` and ensure that @@ -298,6 +297,36 @@ JSON path: - proper `Number` if you point to `Integer`, `Double` etc. in a JSON - `Boolean` if you point to a `Boolean` in a JSON +In the request part of the contract you can specify that the `body` should be +taken from a method. + +IMPORTANT: You have to provide both the consumer and the producer side +and the `execute` part can be applied for the whole body. Not for parts of it! + +Example: + +[source,groovy,indent=0] +---- +include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilderSpec.groovy[tags=body_execute,indent=0] +---- + +This will result in calling the `hashCode()` method in the request body. +It would more or less like this: + +[source,java,indent=0] +---- + // given: + MockMvcRequestSpecification request = given() + .body(hashCode()); + + // when: + ResponseOptions response = given().spec(request) + .get("/something"); + + // then: + assertThat(response.statusCode()).isEqualTo(200); +---- + ===== Referencing request from response The best situation is to provide fixed values but sometimes you need to reference a request in your response. diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JUnitMessagingMethodBodyBuilder.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JUnitMessagingMethodBodyBuilder.groovy index fdf1979381..ded05264a7 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JUnitMessagingMethodBodyBuilder.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JUnitMessagingMethodBodyBuilder.groovy @@ -175,7 +175,7 @@ class JUnitMessagingMethodBodyBuilder extends MessagingMethodBodyBuilder { } @Override - protected String getBodyString(String bodyAsString) { + protected String getBodyString(Object body) { return "" } diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JUnitMethodBodyBuilder.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JUnitMethodBodyBuilder.groovy index dfa25d9124..3c35d00f63 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JUnitMethodBodyBuilder.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JUnitMethodBodyBuilder.groovy @@ -152,8 +152,14 @@ abstract class JUnitMethodBodyBuilder extends RequestProcessingMethodBodyBuilder } @Override - protected String getBodyString(String bodyAsString) { - return ".body(\"$bodyAsString\")" + protected String getBodyString(Object body) { + String value + if (body instanceof ExecutionProperty) { + value = body.toString() + } else { + value = "\"$body\"" + } + return ".body($value)" } @Override diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientJUnitMethodBodyBuilder.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientJUnitMethodBodyBuilder.groovy index 0d7ce51442..c79c698ff7 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientJUnitMethodBodyBuilder.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientJUnitMethodBodyBuilder.groovy @@ -104,7 +104,9 @@ class JaxRsClientJUnitMethodBodyBuilder extends JUnitMethodBodyBuilder { String method = request.method.serverValue.toString().toLowerCase() if (request.body) { String contentType = getHeader('Content-Type') ?: getRequestContentType().mimeType - bb.addLine(".method(\"${method.toUpperCase()}\", entity(\"$bodyAsString\", \"$contentType\"))") + String body = request.body?.serverValue instanceof ExecutionProperty ? + request.body?.serverValue?.toString() : "\"${bodyAsString}\"" + bb.addLine(".method(\"${method.toUpperCase()}\", entity(${body}, \"$contentType\"))") } else { bb.addLine(".method(\"${method.toUpperCase()}\")") } diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientSpockMethodRequestProcessingBodyBuilder.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientSpockMethodRequestProcessingBodyBuilder.groovy index 41caff1368..d1fd85da40 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientSpockMethodRequestProcessingBodyBuilder.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientSpockMethodRequestProcessingBodyBuilder.groovy @@ -109,7 +109,9 @@ class JaxRsClientSpockMethodRequestProcessingBodyBuilder extends SpockMethodRequ String method = request.method.serverValue.toString().toLowerCase() if (request.body) { String contentType = getHeader('Content-Type') ?: getRequestContentType().mimeType - bb.addLine(".method('${method.toUpperCase()}', entity('$bodyAsString', '$contentType'))") + String body = request.body?.serverValue instanceof ExecutionProperty ? + request.body?.serverValue?.toString() : "'${bodyAsString}'" + bb.addLine(".method('${method.toUpperCase()}', entity(${body}, '$contentType'))") } else { bb.addLine(".method('${method.toUpperCase()}')") } @@ -123,7 +125,7 @@ class JaxRsClientSpockMethodRequestProcessingBodyBuilder extends SpockMethodRequ } protected String getHeader(String name) { - return request.headers?.entries.find { it.name == name }?.serverValue + return request.headers?.entries?.find { it.name == name }?.serverValue } @Override diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilder.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilder.groovy index c5c69e761a..7a8ad2eaa7 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilder.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilder.groovy @@ -197,7 +197,7 @@ abstract class MethodBodyBuilder { /** * Builds the code to append body to the request / message */ - protected abstract String getBodyString(String bodyAsString) + protected abstract String getBodyString(Object body) /** * Builds the code to append multipart content to the request. diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/RequestProcessingMethodBodyBuilder.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/RequestProcessingMethodBodyBuilder.groovy index 0492aa4023..5da2c0c139 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/RequestProcessingMethodBodyBuilder.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/RequestProcessingMethodBodyBuilder.groovy @@ -98,7 +98,9 @@ abstract class RequestProcessingMethodBodyBuilder extends MethodBodyBuilder { bb.addLine(getHeaderString(header)) } if (request.body) { - bb.addLine(getBodyString(bodyAsString)) + Object body = request.body?.serverValue instanceof ExecutionProperty ? + request.body?.serverValue : bodyAsString + bb.addLine(getBodyString(body)) } if (request.multipart) { multipartParameters?.each { Map.Entry entry -> bb.addLine(getMultipartParameterLine(entry)) } diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SpockMessagingMethodBodyBuilder.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SpockMessagingMethodBodyBuilder.groovy index d9cbb47f43..6782af0463 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SpockMessagingMethodBodyBuilder.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SpockMessagingMethodBodyBuilder.groovy @@ -169,7 +169,7 @@ class SpockMessagingMethodBodyBuilder extends MessagingMethodBodyBuilder { } @Override - protected String getBodyString(String bodyAsString) { + protected String getBodyString(Object body) { return '' } diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SpockMethodRequestProcessingBodyBuilder.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SpockMethodRequestProcessingBodyBuilder.groovy index 669eb35643..0ec9622e38 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SpockMethodRequestProcessingBodyBuilder.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SpockMethodRequestProcessingBodyBuilder.groovy @@ -127,8 +127,14 @@ abstract class SpockMethodRequestProcessingBodyBuilder extends RequestProcessing } @Override - protected String getBodyString(String bodyAsString) { - return ".body('''$bodyAsString''')" + protected String getBodyString(Object body) { + String value + if (body instanceof ExecutionProperty) { + value = body.toString() + } else { + value = "'''$body'''" + } + return ".body($value)" } @Override diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilderSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilderSpec.groovy index cd0c1c9c55..a27f3ddff9 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilderSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilderSpec.groovy @@ -207,4 +207,37 @@ DocumentContext parsedJson = JsonPath.parse(json); "JaxRsClientJUnitMethodBodyBuilder" | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } } + @Issue('#313') + def "should allow to use execute in request body [#methodBuilderName]"() { + given: + //tag::body_execute[] + Contract contractDsl = Contract.make { + request { + method 'GET' + url '/something' + body( + $(c("foo"), p(execute("hashCode()"))) + ) + } + response { + status 200 + } + } + //end::body_execute[] + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + def test = blockBuilder.toString() + then: + SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) + !test.contains("executionCommand") + where: + methodBuilderName | methodBuilder + "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) } + } + }