From 7e7e3ff003c3da920ca24765f8d653cdbc0e91b7 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Tue, 12 May 2015 16:14:46 +0200 Subject: [PATCH] [#49] Fixed missing conversion of request body --- .../dsl/WiremockRequestStubStrategy.groovy | 8 ++- .../dsl/WiremockResponseStubStrategy.groovy | 12 ++-- .../accurest/dsl/internal/Body.groovy | 34 +++++++++-- .../accurest/util/JsonConverter.groovy | 38 ++++++++++++ .../accurest/util/StubMappingConverter.groovy | 53 ----------------- .../builder/SpockMethodBuilderSpec.groovy | 59 +++++++++++++++++++ 6 files changed, 139 insertions(+), 65 deletions(-) create mode 100644 accurest-core/src/main/groovy/io/codearte/accurest/util/JsonConverter.groovy delete mode 100644 accurest-core/src/main/groovy/io/codearte/accurest/util/StubMappingConverter.groovy diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/WiremockRequestStubStrategy.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/WiremockRequestStubStrategy.groovy index 36f7ec1ab5..97a7e942ba 100755 --- a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/WiremockRequestStubStrategy.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/WiremockRequestStubStrategy.groovy @@ -3,6 +3,7 @@ import groovy.transform.PackageScope import groovy.transform.TypeChecked import io.codearte.accurest.dsl.internal.ClientRequest import io.codearte.accurest.dsl.internal.Request +import io.codearte.accurest.util.JsonConverter import java.util.regex.Pattern @@ -38,9 +39,8 @@ class WiremockRequestStubStrategy extends BaseWiremockStubStrategy { return [:] } if (containsRegex(body)) { - return [bodyPatterns: [[matches: parseBody(body)]]] + return [bodyPatterns: [[matches: parseBody(JsonConverter.transformValues(body, { it.toString() }))]]] } - return [bodyPatterns: [[equalTo: parseBody(body)]]] } @@ -49,4 +49,8 @@ class WiremockRequestStubStrategy extends BaseWiremockStubStrategy { return (bodyString =~ /\^.*\$/).find() } + boolean containsRegex(Map map) { + return map.values().any { it instanceof Pattern } + } + } diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/WiremockResponseStubStrategy.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/WiremockResponseStubStrategy.groovy index e0b7556547..b517150236 100755 --- a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/WiremockResponseStubStrategy.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/WiremockResponseStubStrategy.groovy @@ -21,12 +21,12 @@ class WiremockResponseStubStrategy extends BaseWiremockStubStrategy { private Map buildResponseContent(ClientResponse response) { return ([status : response?.status?.clientValue, - headers: buildClientResponseHeadersSection(response.headers) - ] << appendBody(response)).findAll { it.value } + headers: buildClientResponseHeadersSection(response.headers) + ] << appendBody(response)).findAll { it.value } } - private Map appendBody(ClientResponse response) { - Object body = response?.body?.clientValue - return body != null ? [body: parseBody(body)] : [:] - } + private Map appendBody(ClientResponse response) { + Object body = response?.body?.clientValue + return body != null ? [body: parseBody(body)] : [:] + } } diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Body.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Body.groovy index 5e8d46ed98..da602b5ebc 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Body.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Body.groovy @@ -3,12 +3,19 @@ package io.codearte.accurest.dsl.internal import groovy.json.JsonSlurper import groovy.transform.EqualsAndHashCode import groovy.transform.ToString +import io.codearte.accurest.util.JsonConverter import org.codehaus.groovy.runtime.GStringImpl +import java.util.regex.Matcher +import java.util.regex.Pattern + @ToString(includePackage = false, includeFields = true, includeNames = true) @EqualsAndHashCode(includeFields = true) class Body extends DslProperty { + private static final Pattern TEMPORARY_PATTERN_HOLDER = Pattern.compile('REGEXP>>(.*)<<') + private static final String JSON_VALUE_PATTERN_FOR_REGEX = 'REGEXP>>%s<<' + Body(Map body) { super(extractValue(body, {it.clientValue}), extractValue(body, {it.serverValue})) } @@ -36,9 +43,28 @@ class Body extends DslProperty { } private static Object extractValue(GString bodyAsValue, Closure valueProvider) { - GString clientGString = new GStringImpl(bodyAsValue.values.clone(), bodyAsValue.strings.clone()) - Object[] clientValues = bodyAsValue.values.collect { it instanceof DslProperty ? valueProvider(it) : it } as Object[] - return new JsonSlurper().parseText(new GStringImpl(clientValues, clientGString.strings).toString()) + GString gString = new GStringImpl(bodyAsValue.values.clone(), bodyAsValue.strings.clone()) + Object[] values = bodyAsValue.values.collect { it instanceof DslProperty ? valueProvider(it) : it } as Object[] + Object[] valuesWithRegexpsAsTransformedStrings = values.collect { + it instanceof Pattern ? String.format(JSON_VALUE_PATTERN_FOR_REGEX, it.toString()) : it + } as Object[] + def parsedJson = new JsonSlurper().parseText(new GStringImpl(valuesWithRegexpsAsTransformedStrings, gString.strings)) + return convertAllTemporaryRegexPlaceholdersBackToPatterns(parsedJson) } - + + private static Object convertAllTemporaryRegexPlaceholdersBackToPatterns(parsedJson) { + JsonConverter.transformValues(parsedJson, { Object value -> + if (value instanceof String) { + String string = (String) value + Matcher matcher = TEMPORARY_PATTERN_HOLDER.matcher(string) + if (matcher.matches()) { + String pattern = matcher[0][1] + return Pattern.compile(pattern) + } + return value + } + return value + }) + } + } diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/util/JsonConverter.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/util/JsonConverter.groovy new file mode 100644 index 0000000000..208a3aefa3 --- /dev/null +++ b/accurest-core/src/main/groovy/io/codearte/accurest/util/JsonConverter.groovy @@ -0,0 +1,38 @@ +package io.codearte.accurest.util + +import groovy.json.JsonSlurper +/** + * @author Marcin Grzejszczak + */ +class JsonConverter { + + private static Map convert(Map map, Closure closure) { + return map.collectEntries { + key, value -> + [key, transformValues(value, closure)] + } + } + + static def transformValues(def value, Closure closure) { + if (value instanceof String && value) { + try { + def json = new JsonSlurper().parseText(value) + if (json instanceof Map) { + return convert(json, closure) + } + } catch (Exception ignore) { + return closure(value) + } + } else if (value instanceof Map) { + return convert(value as Map, closure) + } else if (value instanceof List) { + return value.collect({ transformValues(it, closure) }) + } + try { + return closure(value) + } catch (Exception ignore) { + return value + } + } + +} diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/util/StubMappingConverter.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/util/StubMappingConverter.groovy deleted file mode 100644 index f1ce59959f..0000000000 --- a/accurest-core/src/main/groovy/io/codearte/accurest/util/StubMappingConverter.groovy +++ /dev/null @@ -1,53 +0,0 @@ -package io.codearte.accurest.util - -import groovy.json.JsonException -import groovy.json.JsonSlurper - -import java.util.regex.Pattern - -/** - * @author Marcin Grzejszczak - */ -class StubMappingConverter { - - private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile(/^\$\{(.*):(.*)\}$/) - public static final int SERVER_SIDE_GROUP = 2 - - static Map toStubMappingOnServerSide(File stubMapping) { - def json = new JsonSlurper().parse(stubMapping) - return convertPlaceholders(json as Map, { String value -> - getGroupFromMatchingPattern(value) - }) - } - - private static Map convertPlaceholders(Map map, Closure closure) { - return map.collectEntries { - key, value -> - [key, transformValue(value, closure)] - } - } - - static def transformValue(def value, Closure closure) { - if (value instanceof String && value) { - try { - def json = new JsonSlurper().parseText(value) - if (json instanceof Map) { - return convertPlaceholders(json, closure) - } - } catch (JsonException ignore) { - return closure(value) - } - } else if (value instanceof Map) { - return convertPlaceholders(value as Map, closure) - } else if (value instanceof List) { - return value.collect({ transformValue(it, closure) }) - } - - return value - } - - private static Object getGroupFromMatchingPattern(String value) { - return value.matches(PLACEHOLDER_PATTERN) ? PLACEHOLDER_PATTERN.matcher(value)[0][SERVER_SIDE_GROUP] : value - } - -} diff --git a/accurest-core/src/test/groovy/io/codearte/accurest/builder/SpockMethodBuilderSpec.groovy b/accurest-core/src/test/groovy/io/codearte/accurest/builder/SpockMethodBuilderSpec.groovy index c68a96a1e6..39f2b4762f 100644 --- a/accurest-core/src/test/groovy/io/codearte/accurest/builder/SpockMethodBuilderSpec.groovy +++ b/accurest-core/src/test/groovy/io/codearte/accurest/builder/SpockMethodBuilderSpec.groovy @@ -110,4 +110,63 @@ class SpockMethodBuilderSpec extends Specification { blockBuilder.toString().contains("responseBody.property1 == \"a\"") blockBuilder.toString().contains("responseBody.property2.property3 == \"b\"") } + + def "should generate regex assertions for map objects in response body"() { + given: + GroovyDsl contractDsl = GroovyDsl.make { + request { + method "GET" + url "test" + } + response { + status 200 + body( + property1: "a", + property2: value( + client(''), + server(regex('\\\\d{3}')) + ) + ) + headers { + header('Content-Type': 'application/json') + + } + + } + } + SpockMethodBodyBuilder builder = new SpockMethodBodyBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + then: + blockBuilder.toString().contains("responseBody.property1 == \"a\"") + blockBuilder.toString().contains("responseBody.property2 ==~ java.util.regex.Pattern.compile('\\\\d{3}')") + } + + def "should generate regex assertions for string objects in response body"() { + given: + GroovyDsl contractDsl = GroovyDsl.make { + request { + method "GET" + url "test" + } + response { + status 200 + body( """{"property1":"a","property2":"${value(client('123'), server(regex('[0-9]{3}')))}"}""") + headers { + header('Content-Type': 'application/json') + + } + + } + } + SpockMethodBodyBuilder builder = new SpockMethodBodyBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + then: + blockBuilder.toString().contains("responseBody.property1 == \"a\"") + blockBuilder.toString().contains("responseBody.property2 ==~ java.util.regex.Pattern.compile('[0-9]{3}')") + } + }