From 58b47fd6b4da6641503e34fac41840f22084ad89 Mon Sep 17 00:00:00 2001 From: Denis Stepanov Date: Thu, 11 Jun 2015 13:13:15 +0200 Subject: [PATCH 1/8] Implement selecting compare method by content type --- .../dsl/WiremockRequestStubStrategy.groovy | 15 +++- .../accurest/dsl/internal/Body.groovy | 51 +++++++++-- .../accurest/dsl/WiremockGroovyDslSpec.groovy | 90 +++++++++++++++++++ 3 files changed, 149 insertions(+), 7 deletions(-) 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 298cc1b2ec..3390b6456b 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 @@ -2,6 +2,7 @@ package io.codearte.accurest.dsl import groovy.transform.PackageScope import groovy.transform.TypeChecked import io.codearte.accurest.dsl.internal.ClientRequest +import io.codearte.accurest.dsl.internal.Header import io.codearte.accurest.dsl.internal.MatchingStrategy import io.codearte.accurest.dsl.internal.QueryParameter import io.codearte.accurest.dsl.internal.QueryParameters @@ -95,7 +96,19 @@ class WiremockRequestStubStrategy extends BaseWiremockStubStrategy { } ))]]] } - return [bodyPatterns: [[equalTo: parseBody(body)]]] + + return [bodyPatterns: [[(getCompareType()): parseBody(body)]]] + } + + private String getCompareType() { + Header contentType = request.headers?.entries.find { it.name == "Content-Type" } + if (contentType && contentType.clientValue.toString().endsWith("json")) { + return "equalToJson" + } + if (contentType && contentType.clientValue.toString().endsWith("xml")) { + return "equalToXml" + } + return "equalTo" } protected String parseBody(Object 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 315135d939..c68380f0f2 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 @@ -1,5 +1,6 @@ package io.codearte.accurest.dsl.internal +import groovy.json.JsonException import groovy.json.JsonSlurper import groovy.transform.EqualsAndHashCode import groovy.transform.ToString @@ -9,6 +10,8 @@ import org.codehaus.groovy.runtime.GStringImpl import java.util.regex.Matcher import java.util.regex.Pattern +import static org.apache.commons.lang3.StringEscapeUtils.escapeXml11 + @ToString(includePackage = false, includeFields = true, includeNames = true) @EqualsAndHashCode(includeFields = true) class Body extends DslProperty { @@ -55,15 +58,51 @@ class Body extends DslProperty { * @return JSON structure with replaced client / server side parts */ private static Object extractValue(GString bodyAsValue, Closure valueProvider) { - 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)) + try { + return extractValueForJSON(bodyAsValue, valueProvider) + } catch(JsonException e) { + // Not a JSON format + return extractValueForXML(bodyAsValue, valueProvider) + } + return bodyAsValue + } + + private static Object extractValueForJSON(GString bodyAsValue, Closure valueProvider) { + GString transformedString = new GStringImpl( + bodyAsValue.values.collect { transformJSONStringValue(it, valueProvider) } as Object[], + bodyAsValue.strings.clone() + ) + def parsedJson = new JsonSlurper().parseText(transformedString) return convertAllTemporaryRegexPlaceholdersBackToPatterns(parsedJson) } + private static GStringImpl extractValueForXML(GString bodyAsValue, Closure valueProvider) { + return new GStringImpl( + bodyAsValue.values.collect { transformXMLStringValue(it, valueProvider) } as Object[], + bodyAsValue.strings.clone() + ) + } + + private static String transformJSONStringValue(Object obj, Closure valueProvider) { + return obj.toString() + } + + private static String transformJSONStringValue(DslProperty dslProperty, Closure valueProvider) { + return transformJSONStringValue(valueProvider(dslProperty), valueProvider) + } + + private static String transformJSONStringValue(Pattern pattern, Closure valueProvider) { + return String.format(JSON_VALUE_PATTERN_FOR_REGEX, pattern.pattern()) + } + + private static String transformXMLStringValue(Object obj, Closure valueProvider) { + return escapeXml11(obj.toString()) + } + + private static String transformXMLStringValue(DslProperty dslProperty, Closure valueProvider) { + return transformXMLStringValue(valueProvider(dslProperty), valueProvider) + } + private static Object convertAllTemporaryRegexPlaceholdersBackToPatterns(parsedJson) { JsonConverter.transformValues(parsedJson, { Object value -> if (value instanceof String) { diff --git a/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockGroovyDslSpec.groovy b/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockGroovyDslSpec.groovy index 7d8e5f1d49..4674441a09 100755 --- a/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockGroovyDslSpec.groovy +++ b/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockGroovyDslSpec.groovy @@ -150,6 +150,96 @@ class WiremockGroovyDslSpec extends WiremockSpec { stubMappingIsValidWiremockStub(wiremockStub) } + def 'should use equalToJson when content type ends with json'() { + given: + GroovyDsl groovyDsl = GroovyDsl.make { + request { + method 'GET' + url "/users" + headers { + header "Content-Type", "customtype/json" + } + body """ + { + "name": "Jan" + } + """ + } + response { + status 200 + } + } + when: + String json = toWiremockClientJsonStub(groovyDsl) + then: + parseJson(json) == parseJson(''' + { + "request": { + "method": "GET", + "url": "/users", + "headers": { + "Content-Type": { + "equalTo": "customtype/json" + } + }, + "bodyPatterns": [ + { + "equalToJson":"{\\"name\\":\\"Jan\\"}" + } + ] + }, + "response": { + "status": 200 + } + } + ''') + and: + stubMappingIsValidWiremockStub(json) + } + + def 'should use equalToXml when content type ends with xml'() { + given: + GroovyDsl groovyDsl = GroovyDsl.make { + request { + method 'GET' + url "/users" + headers { + header "Content-Type", "customtype/xml" + } + body """${value(client('Jozo'), server('Denis'))}${value(client(""), server('1234567890'))}""" + } + response { + status 200 + } + } + when: + String json = toWiremockClientJsonStub(groovyDsl) + then: + parseJson(json) == parseJson(''' + { + "request": { + "method": "GET", + "url": "/users", + "headers": { + "Content-Type": { + "equalTo": "customtype/xml" + } + }, + "bodyPatterns": [ + { + "equalToXml":"Jozo<test>" + } + ] + }, + "response": { + "status": 200 + } + } + ''') + and: + stubMappingIsValidWiremockStub(json) + } + def 'should convert groovy dsl stub with regexp Body as String to wiremock stub for the client side'() { given: GroovyDsl groovyDsl = GroovyDsl.make { From a5502b35e27dffdf814b3e364a57023bc314ef75 Mon Sep 17 00:00:00 2001 From: Denis Stepanov Date: Thu, 11 Jun 2015 13:37:14 +0200 Subject: [PATCH 2/8] Implement selecting compare method by content type --- .../dsl/WiremockRequestStubStrategy.groovy | 55 ++++++++----------- .../accurest/dsl/internal/Body.groovy | 8 +++ 2 files changed, 32 insertions(+), 31 deletions(-) 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 3390b6456b..31eb05300a 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 @@ -2,7 +2,6 @@ package io.codearte.accurest.dsl import groovy.transform.PackageScope import groovy.transform.TypeChecked import io.codearte.accurest.dsl.internal.ClientRequest -import io.codearte.accurest.dsl.internal.Header import io.codearte.accurest.dsl.internal.MatchingStrategy import io.codearte.accurest.dsl.internal.QueryParameter import io.codearte.accurest.dsl.internal.QueryParameters @@ -80,32 +79,35 @@ class WiremockRequestStubStrategy extends BaseWiremockStubStrategy { if (body == null) { return [:] } - if (containsRegex(body)) { - return [bodyPatterns: [[matches: parseBody(convertJsonStructureToObjectUnderstandingStructure(body, - { it instanceof Pattern }, - { String json -> json.collect { - switch(it) { - case ('{'): return '\\{' - case ('}'): return '\\}' - default: return it - } - } .join('') - }, - { LinkedList list, String json -> - return json.replaceAll(TEMPORARY_PATTERN_HOLDER, { String a, String[] b -> list.pop() }) - } - ))]]] + if (clientRequest.body?.containsPattern) { + return [bodyPatterns: [[matches: escapeBodyForJson(body)]]] } - - return [bodyPatterns: [[(getCompareType()): parseBody(body)]]] + return [bodyPatterns: [[(getMatchType()): parseBody(body)]]] } - private String getCompareType() { - Header contentType = request.headers?.entries.find { it.name == "Content-Type" } - if (contentType && contentType.clientValue.toString().endsWith("json")) { + private Object escapeBodyForJson(Object body) { + return parseBody(convertJsonStructureToObjectUnderstandingStructure(body, + { it instanceof Pattern }, + { String json -> json.collect { + switch(it) { + case ('{'): return '\\{' + case ('}'): return '\\}' + default: return it + } + } .join('') + }, + { LinkedList list, String json -> + return json.replaceAll(TEMPORARY_PATTERN_HOLDER, { String a, String[] b -> list.pop() }) + } + )) + } + + private String getMatchType() { + String content = request.headers?.entries.find { it.name == "Content-Type" } ?.clientValue?.toString() + if (content?.endsWith("json")) { return "equalToJson" } - if (contentType && contentType.clientValue.toString().endsWith("xml")) { + if (content?.endsWith("xml")) { return "equalToXml" } return "equalTo" @@ -115,13 +117,4 @@ class WiremockRequestStubStrategy extends BaseWiremockStubStrategy { return body } - boolean containsRegex(Object bodyObject) { - String bodyString = bodyObject as String - 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/internal/Body.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Body.groovy index c68380f0f2..78813a74a8 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 @@ -19,6 +19,8 @@ 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<<' + boolean containsPattern + Body(Map body) { super(extractValue(body, {it.clientValue}), extractValue(body, {it.serverValue})) } @@ -39,12 +41,18 @@ class Body extends DslProperty { Body(GString bodyAsValue) { super(extractValue(bodyAsValue, {it.clientValue}), extractValue(bodyAsValue, {it.serverValue})) + containsPattern = containsPattern(bodyAsValue) } Body(DslProperty bodyAsValue) { super(bodyAsValue.clientValue, bodyAsValue.serverValue) } + private boolean containsPattern(GString bodyAsValue) { + return bodyAsValue.values.collect { it instanceof DslProperty ? it.clientValue : it } + .find { it instanceof Pattern } + } + /** * Due to the fact that we allow users to have a body with GString and different values inside * we need to be prepared that they pass regexps around both on client and server side. From b5e1799468d40bf65b43f028726a7ab9990f0dbf Mon Sep 17 00:00:00 2001 From: "Jozef.Najman" Date: Thu, 11 Jun 2015 15:27:20 +0200 Subject: [PATCH 3/8] Fixed generating stubs from regex - one matcher for one regex --- .../dsl/WiremockRequestStubStrategy.groovy | 28 ++--- .../accurest/dsl/WiremockGroovyDslSpec.groovy | 113 ++++++++++++++---- .../codearte/accurest/dsl/WiremockSpec.groovy | 2 +- 3 files changed, 103 insertions(+), 40 deletions(-) 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 31eb05300a..3c726f66d2 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 @@ -80,26 +80,24 @@ class WiremockRequestStubStrategy extends BaseWiremockStubStrategy { return [:] } if (clientRequest.body?.containsPattern) { - return [bodyPatterns: [[matches: escapeBodyForJson(body)]]] + return [bodyPatterns: parseMatchesBody(body)] } return [bodyPatterns: [[(getMatchType()): parseBody(body)]]] } - private Object escapeBodyForJson(Object body) { - return parseBody(convertJsonStructureToObjectUnderstandingStructure(body, - { it instanceof Pattern }, - { String json -> json.collect { - switch(it) { - case ('{'): return '\\{' - case ('}'): return '\\}' - default: return it - } - } .join('') - }, - { LinkedList list, String json -> - return json.replaceAll(TEMPORARY_PATTERN_HOLDER, { String a, String[] b -> list.pop() }) + private Object parseMatchesBody(def responseBodyObject) { + def regexList = new ArrayList<>() + responseBodyObject.each { k, v -> + if (v instanceof List) { + v.each { + regexList.addAll(parseMatchesBody((Map)it)) } - )) + } else { + String regex = ".*${k}\":.?\"${v}\".*" + regexList.add([matches: regex]); + } + } + return regexList } private String getMatchType() { diff --git a/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockGroovyDslSpec.groovy b/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockGroovyDslSpec.groovy index 4674441a09..452cc758ed 100755 --- a/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockGroovyDslSpec.groovy +++ b/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockGroovyDslSpec.groovy @@ -161,7 +161,7 @@ class WiremockGroovyDslSpec extends WiremockSpec { } body """ { - "name": "Jan" + "name": "${value(client('Jan'), server('Honza'))}" } """ } @@ -270,22 +270,20 @@ class WiremockGroovyDslSpec extends WiremockSpec { then: new JsonSlurper().parseText(wiremockStub) == new JsonSlurper().parseText(''' { - "request": { - "method": "GET", - "urlPattern": "/[0-9]{2}", - "bodyPatterns": [ - { - "matches":"\\\\{\\"personalId\\":\\"^[0-9]{11}$\\"\\\\}" - } - ] - }, - "response": { - "status": 200, - "body": "{\\"name\\":\\"Jan\\"}", - "headers": { - "Content-Type": "text/plain" - } - } + "request": { + "method": "GET", + "urlPattern": "/[0-9]{2}", + "bodyPatterns": [ + {"matches": ".*personalId\\":.?\\"^[0-9]{11}$\\".*"} + ] + }, + "response": { + "status": 200, + "body": "{\\"name\\":\\"Jan\\"}", + "headers": { + "Content-Type": "text/plain" + } + } } ''') and: @@ -336,9 +334,8 @@ class WiremockGroovyDslSpec extends WiremockSpec { }, "url": "/fraudcheck", "bodyPatterns": [ - { - "matches": "\\\\{\\"clientPesel\\":\\"[0-9]{10}\\",\\"loanAmount\\":123.123\\\\}" - } + {"matches": ".*clientPesel\\":.?\\"[0-9]{10}\\".*"}, + {"matches": ".*loanAmount\\":.?\\"123.123\\".*"} ] }, "response": { @@ -658,10 +655,78 @@ class WiremockGroovyDslSpec extends WiremockSpec { }, "X-Custom-Header": { "matches": "^.*2134.*$" - } - } - } - ''') + } + } + } + ''') + } + + def 'should convert groovy dsl stub with rich tree Body as String to wiremock stub for the client side'() { + given: + GroovyDsl groovyDsl = GroovyDsl.make { + request { + method('GET') + url $(client(~/\/[0-9]{2}/), server('/12')) + body """\ + { + "personalId": "${value(client(regex('[0-9]{11}')), server('57593728525'))}", + "firstName": "${value(client(regex('.*')), server('Bruce'))}", + "lastName": "${value(client(regex('.*')), server('Lee'))}", + "birthDate": "${value(client(regex('[0-9]{4}-[0-9]{2}-[0-9]{2}')), server('1985-12-12'))}", + "errors": [ + { + "propertyName": "${value(client(regex('[0-9]{2}')), server('04'))}", + "providerValue": "Test" + }, + { + "propertyName": "${value(client(regex('[0-9]{2}')), server('08'))}", + "providerValue": "Test" + } + ] + } + """ + } + response { + status 200 + body("""\ + { + "name": "Jan" + } + """ + ) + headers { + header 'Content-Type': 'text/plain' + } + } + } + when: + String wiremockStub = new WiremockStubStrategy(groovyDsl).toWiremockClientStub() + then: + new JsonSlurper().parseText(wiremockStub) == new JsonSlurper().parseText(''' + { + "request": { + "method": "GET", + "urlPattern": "/[0-9]{2}", + "bodyPatterns": [ + {"matches": ".*birthDate\\":.?\\"[0-9]{4}-[0-9]{2}-[0-9]{2}\\".*"}, + {"matches": ".*propertyName\\":.?\\"[0-9]{2}\\".*"}, + {"matches": ".*providerValue\\":.?\\"Test\\".*"}, + {"matches": ".*propertyName\\":.?\\"[0-9]{2}\\".*"}, + {"matches": ".*providerValue\\":.?\\"Test\\".*"}, + {"matches": ".*firstName\\":.?\\".*\\".*"}, + {"matches": ".*lastName\\":.?\\".*\\".*"}, + {"matches": ".*personalId\\":.?\\"[0-9]{11}\\".*"} + ] + }, + "response": { + "status": 200, + "body": "{\\"name\\":\\"Jan\\"}", + "headers": { + "Content-Type": "text/plain" + } + } + } + ''') } String toJsonString(value) { diff --git a/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockSpec.groovy b/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockSpec.groovy index 796e603c11..ab1133c9ae 100644 --- a/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockSpec.groovy +++ b/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockSpec.groovy @@ -5,7 +5,7 @@ import spock.lang.Specification import java.util.regex.Pattern -class WiremockSpec extends Specification { +abstract class WiremockSpec extends Specification { void stubMappingIsValidWiremockStub(String mappingDefinition) { StubMapping stubMapping = StubMapping.buildFrom(mappingDefinition) From 254a67cdb58b0285d6d41fa1156bacf422fe5aac Mon Sep 17 00:00:00 2001 From: "Jozef.Najman" Date: Thu, 11 Jun 2015 17:14:12 +0200 Subject: [PATCH 4/8] Reverted generating stubs from regex - one matcher for one regex --- .../dsl/WiremockRequestStubStrategy.groovy | 28 +++-- .../accurest/dsl/WiremockGroovyDslSpec.groovy | 113 ++++-------------- 2 files changed, 39 insertions(+), 102 deletions(-) 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 3c726f66d2..31eb05300a 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 @@ -80,24 +80,26 @@ class WiremockRequestStubStrategy extends BaseWiremockStubStrategy { return [:] } if (clientRequest.body?.containsPattern) { - return [bodyPatterns: parseMatchesBody(body)] + return [bodyPatterns: [[matches: escapeBodyForJson(body)]]] } return [bodyPatterns: [[(getMatchType()): parseBody(body)]]] } - private Object parseMatchesBody(def responseBodyObject) { - def regexList = new ArrayList<>() - responseBodyObject.each { k, v -> - if (v instanceof List) { - v.each { - regexList.addAll(parseMatchesBody((Map)it)) + private Object escapeBodyForJson(Object body) { + return parseBody(convertJsonStructureToObjectUnderstandingStructure(body, + { it instanceof Pattern }, + { String json -> json.collect { + switch(it) { + case ('{'): return '\\{' + case ('}'): return '\\}' + default: return it + } + } .join('') + }, + { LinkedList list, String json -> + return json.replaceAll(TEMPORARY_PATTERN_HOLDER, { String a, String[] b -> list.pop() }) } - } else { - String regex = ".*${k}\":.?\"${v}\".*" - regexList.add([matches: regex]); - } - } - return regexList + )) } private String getMatchType() { diff --git a/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockGroovyDslSpec.groovy b/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockGroovyDslSpec.groovy index 452cc758ed..4674441a09 100755 --- a/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockGroovyDslSpec.groovy +++ b/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockGroovyDslSpec.groovy @@ -161,7 +161,7 @@ class WiremockGroovyDslSpec extends WiremockSpec { } body """ { - "name": "${value(client('Jan'), server('Honza'))}" + "name": "Jan" } """ } @@ -270,20 +270,22 @@ class WiremockGroovyDslSpec extends WiremockSpec { then: new JsonSlurper().parseText(wiremockStub) == new JsonSlurper().parseText(''' { - "request": { - "method": "GET", - "urlPattern": "/[0-9]{2}", - "bodyPatterns": [ - {"matches": ".*personalId\\":.?\\"^[0-9]{11}$\\".*"} - ] - }, - "response": { - "status": 200, - "body": "{\\"name\\":\\"Jan\\"}", - "headers": { - "Content-Type": "text/plain" - } - } + "request": { + "method": "GET", + "urlPattern": "/[0-9]{2}", + "bodyPatterns": [ + { + "matches":"\\\\{\\"personalId\\":\\"^[0-9]{11}$\\"\\\\}" + } + ] + }, + "response": { + "status": 200, + "body": "{\\"name\\":\\"Jan\\"}", + "headers": { + "Content-Type": "text/plain" + } + } } ''') and: @@ -334,8 +336,9 @@ class WiremockGroovyDslSpec extends WiremockSpec { }, "url": "/fraudcheck", "bodyPatterns": [ - {"matches": ".*clientPesel\\":.?\\"[0-9]{10}\\".*"}, - {"matches": ".*loanAmount\\":.?\\"123.123\\".*"} + { + "matches": "\\\\{\\"clientPesel\\":\\"[0-9]{10}\\",\\"loanAmount\\":123.123\\\\}" + } ] }, "response": { @@ -655,78 +658,10 @@ class WiremockGroovyDslSpec extends WiremockSpec { }, "X-Custom-Header": { "matches": "^.*2134.*$" - } - } - } - ''') - } - - def 'should convert groovy dsl stub with rich tree Body as String to wiremock stub for the client side'() { - given: - GroovyDsl groovyDsl = GroovyDsl.make { - request { - method('GET') - url $(client(~/\/[0-9]{2}/), server('/12')) - body """\ - { - "personalId": "${value(client(regex('[0-9]{11}')), server('57593728525'))}", - "firstName": "${value(client(regex('.*')), server('Bruce'))}", - "lastName": "${value(client(regex('.*')), server('Lee'))}", - "birthDate": "${value(client(regex('[0-9]{4}-[0-9]{2}-[0-9]{2}')), server('1985-12-12'))}", - "errors": [ - { - "propertyName": "${value(client(regex('[0-9]{2}')), server('04'))}", - "providerValue": "Test" - }, - { - "propertyName": "${value(client(regex('[0-9]{2}')), server('08'))}", - "providerValue": "Test" - } - ] - } - """ - } - response { - status 200 - body("""\ - { - "name": "Jan" - } - """ - ) - headers { - header 'Content-Type': 'text/plain' - } - } - } - when: - String wiremockStub = new WiremockStubStrategy(groovyDsl).toWiremockClientStub() - then: - new JsonSlurper().parseText(wiremockStub) == new JsonSlurper().parseText(''' - { - "request": { - "method": "GET", - "urlPattern": "/[0-9]{2}", - "bodyPatterns": [ - {"matches": ".*birthDate\\":.?\\"[0-9]{4}-[0-9]{2}-[0-9]{2}\\".*"}, - {"matches": ".*propertyName\\":.?\\"[0-9]{2}\\".*"}, - {"matches": ".*providerValue\\":.?\\"Test\\".*"}, - {"matches": ".*propertyName\\":.?\\"[0-9]{2}\\".*"}, - {"matches": ".*providerValue\\":.?\\"Test\\".*"}, - {"matches": ".*firstName\\":.?\\".*\\".*"}, - {"matches": ".*lastName\\":.?\\".*\\".*"}, - {"matches": ".*personalId\\":.?\\"[0-9]{11}\\".*"} - ] - }, - "response": { - "status": 200, - "body": "{\\"name\\":\\"Jan\\"}", - "headers": { - "Content-Type": "text/plain" - } - } - } - ''') + } + } + } + ''') } String toJsonString(value) { From a0c6f7959c7391230c74cc8acc4cb3ee43fda69b Mon Sep 17 00:00:00 2001 From: Denis Stepanov Date: Fri, 12 Jun 2015 15:20:16 +0200 Subject: [PATCH 5/8] Revert "Implement selecting compare method by content type" This reverts commit a5502b35e27dffdf814b3e364a57023bc314ef75. --- .../dsl/WiremockRequestStubStrategy.groovy | 55 +++++++++++-------- .../accurest/dsl/internal/Body.groovy | 8 --- 2 files changed, 31 insertions(+), 32 deletions(-) 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 31eb05300a..3390b6456b 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 @@ -2,6 +2,7 @@ package io.codearte.accurest.dsl import groovy.transform.PackageScope import groovy.transform.TypeChecked import io.codearte.accurest.dsl.internal.ClientRequest +import io.codearte.accurest.dsl.internal.Header import io.codearte.accurest.dsl.internal.MatchingStrategy import io.codearte.accurest.dsl.internal.QueryParameter import io.codearte.accurest.dsl.internal.QueryParameters @@ -79,35 +80,32 @@ class WiremockRequestStubStrategy extends BaseWiremockStubStrategy { if (body == null) { return [:] } - if (clientRequest.body?.containsPattern) { - return [bodyPatterns: [[matches: escapeBodyForJson(body)]]] - } - return [bodyPatterns: [[(getMatchType()): parseBody(body)]]] - } - - private Object escapeBodyForJson(Object body) { - return parseBody(convertJsonStructureToObjectUnderstandingStructure(body, - { it instanceof Pattern }, - { String json -> json.collect { - switch(it) { - case ('{'): return '\\{' - case ('}'): return '\\}' - default: return it + if (containsRegex(body)) { + return [bodyPatterns: [[matches: parseBody(convertJsonStructureToObjectUnderstandingStructure(body, + { it instanceof Pattern }, + { String json -> json.collect { + switch(it) { + case ('{'): return '\\{' + case ('}'): return '\\}' + default: return it + } + } .join('') + }, + { LinkedList list, String json -> + return json.replaceAll(TEMPORARY_PATTERN_HOLDER, { String a, String[] b -> list.pop() }) } - } .join('') - }, - { LinkedList list, String json -> - return json.replaceAll(TEMPORARY_PATTERN_HOLDER, { String a, String[] b -> list.pop() }) - } - )) + ))]]] + } + + return [bodyPatterns: [[(getCompareType()): parseBody(body)]]] } - private String getMatchType() { - String content = request.headers?.entries.find { it.name == "Content-Type" } ?.clientValue?.toString() - if (content?.endsWith("json")) { + private String getCompareType() { + Header contentType = request.headers?.entries.find { it.name == "Content-Type" } + if (contentType && contentType.clientValue.toString().endsWith("json")) { return "equalToJson" } - if (content?.endsWith("xml")) { + if (contentType && contentType.clientValue.toString().endsWith("xml")) { return "equalToXml" } return "equalTo" @@ -117,4 +115,13 @@ class WiremockRequestStubStrategy extends BaseWiremockStubStrategy { return body } + boolean containsRegex(Object bodyObject) { + String bodyString = bodyObject as String + 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/internal/Body.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Body.groovy index 78813a74a8..c68380f0f2 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 @@ -19,8 +19,6 @@ 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<<' - boolean containsPattern - Body(Map body) { super(extractValue(body, {it.clientValue}), extractValue(body, {it.serverValue})) } @@ -41,18 +39,12 @@ class Body extends DslProperty { Body(GString bodyAsValue) { super(extractValue(bodyAsValue, {it.clientValue}), extractValue(bodyAsValue, {it.serverValue})) - containsPattern = containsPattern(bodyAsValue) } Body(DslProperty bodyAsValue) { super(bodyAsValue.clientValue, bodyAsValue.serverValue) } - private boolean containsPattern(GString bodyAsValue) { - return bodyAsValue.values.collect { it instanceof DslProperty ? it.clientValue : it } - .find { it instanceof Pattern } - } - /** * Due to the fact that we allow users to have a body with GString and different values inside * we need to be prepared that they pass regexps around both on client and server side. From 080aae6060be1202d92deabdddf11baf97a1b3a3 Mon Sep 17 00:00:00 2001 From: Denis Stepanov Date: Fri, 12 Jun 2015 15:20:49 +0200 Subject: [PATCH 6/8] Revert "Implement selecting compare method by content type" This reverts commit 58b47fd6b4da6641503e34fac41840f22084ad89. --- .../dsl/WiremockRequestStubStrategy.groovy | 15 +--- .../accurest/dsl/internal/Body.groovy | 51 ++--------- .../accurest/dsl/WiremockGroovyDslSpec.groovy | 90 ------------------- 3 files changed, 7 insertions(+), 149 deletions(-) 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 3390b6456b..298cc1b2ec 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 @@ -2,7 +2,6 @@ package io.codearte.accurest.dsl import groovy.transform.PackageScope import groovy.transform.TypeChecked import io.codearte.accurest.dsl.internal.ClientRequest -import io.codearte.accurest.dsl.internal.Header import io.codearte.accurest.dsl.internal.MatchingStrategy import io.codearte.accurest.dsl.internal.QueryParameter import io.codearte.accurest.dsl.internal.QueryParameters @@ -96,19 +95,7 @@ class WiremockRequestStubStrategy extends BaseWiremockStubStrategy { } ))]]] } - - return [bodyPatterns: [[(getCompareType()): parseBody(body)]]] - } - - private String getCompareType() { - Header contentType = request.headers?.entries.find { it.name == "Content-Type" } - if (contentType && contentType.clientValue.toString().endsWith("json")) { - return "equalToJson" - } - if (contentType && contentType.clientValue.toString().endsWith("xml")) { - return "equalToXml" - } - return "equalTo" + return [bodyPatterns: [[equalTo: parseBody(body)]]] } protected String parseBody(Object 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 c68380f0f2..315135d939 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 @@ -1,6 +1,5 @@ package io.codearte.accurest.dsl.internal -import groovy.json.JsonException import groovy.json.JsonSlurper import groovy.transform.EqualsAndHashCode import groovy.transform.ToString @@ -10,8 +9,6 @@ import org.codehaus.groovy.runtime.GStringImpl import java.util.regex.Matcher import java.util.regex.Pattern -import static org.apache.commons.lang3.StringEscapeUtils.escapeXml11 - @ToString(includePackage = false, includeFields = true, includeNames = true) @EqualsAndHashCode(includeFields = true) class Body extends DslProperty { @@ -58,51 +55,15 @@ class Body extends DslProperty { * @return JSON structure with replaced client / server side parts */ private static Object extractValue(GString bodyAsValue, Closure valueProvider) { - try { - return extractValueForJSON(bodyAsValue, valueProvider) - } catch(JsonException e) { - // Not a JSON format - return extractValueForXML(bodyAsValue, valueProvider) - } - return bodyAsValue - } - - private static Object extractValueForJSON(GString bodyAsValue, Closure valueProvider) { - GString transformedString = new GStringImpl( - bodyAsValue.values.collect { transformJSONStringValue(it, valueProvider) } as Object[], - bodyAsValue.strings.clone() - ) - def parsedJson = new JsonSlurper().parseText(transformedString) + 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 GStringImpl extractValueForXML(GString bodyAsValue, Closure valueProvider) { - return new GStringImpl( - bodyAsValue.values.collect { transformXMLStringValue(it, valueProvider) } as Object[], - bodyAsValue.strings.clone() - ) - } - - private static String transformJSONStringValue(Object obj, Closure valueProvider) { - return obj.toString() - } - - private static String transformJSONStringValue(DslProperty dslProperty, Closure valueProvider) { - return transformJSONStringValue(valueProvider(dslProperty), valueProvider) - } - - private static String transformJSONStringValue(Pattern pattern, Closure valueProvider) { - return String.format(JSON_VALUE_PATTERN_FOR_REGEX, pattern.pattern()) - } - - private static String transformXMLStringValue(Object obj, Closure valueProvider) { - return escapeXml11(obj.toString()) - } - - private static String transformXMLStringValue(DslProperty dslProperty, Closure valueProvider) { - return transformXMLStringValue(valueProvider(dslProperty), valueProvider) - } - private static Object convertAllTemporaryRegexPlaceholdersBackToPatterns(parsedJson) { JsonConverter.transformValues(parsedJson, { Object value -> if (value instanceof String) { diff --git a/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockGroovyDslSpec.groovy b/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockGroovyDslSpec.groovy index 4674441a09..7d8e5f1d49 100755 --- a/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockGroovyDslSpec.groovy +++ b/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockGroovyDslSpec.groovy @@ -150,96 +150,6 @@ class WiremockGroovyDslSpec extends WiremockSpec { stubMappingIsValidWiremockStub(wiremockStub) } - def 'should use equalToJson when content type ends with json'() { - given: - GroovyDsl groovyDsl = GroovyDsl.make { - request { - method 'GET' - url "/users" - headers { - header "Content-Type", "customtype/json" - } - body """ - { - "name": "Jan" - } - """ - } - response { - status 200 - } - } - when: - String json = toWiremockClientJsonStub(groovyDsl) - then: - parseJson(json) == parseJson(''' - { - "request": { - "method": "GET", - "url": "/users", - "headers": { - "Content-Type": { - "equalTo": "customtype/json" - } - }, - "bodyPatterns": [ - { - "equalToJson":"{\\"name\\":\\"Jan\\"}" - } - ] - }, - "response": { - "status": 200 - } - } - ''') - and: - stubMappingIsValidWiremockStub(json) - } - - def 'should use equalToXml when content type ends with xml'() { - given: - GroovyDsl groovyDsl = GroovyDsl.make { - request { - method 'GET' - url "/users" - headers { - header "Content-Type", "customtype/xml" - } - body """${value(client('Jozo'), server('Denis'))}${value(client(""), server('1234567890'))}""" - } - response { - status 200 - } - } - when: - String json = toWiremockClientJsonStub(groovyDsl) - then: - parseJson(json) == parseJson(''' - { - "request": { - "method": "GET", - "url": "/users", - "headers": { - "Content-Type": { - "equalTo": "customtype/xml" - } - }, - "bodyPatterns": [ - { - "equalToXml":"Jozo<test>" - } - ] - }, - "response": { - "status": 200 - } - } - ''') - and: - stubMappingIsValidWiremockStub(json) - } - def 'should convert groovy dsl stub with regexp Body as String to wiremock stub for the client side'() { given: GroovyDsl groovyDsl = GroovyDsl.make { From b2887e9588ca82826c05a111bcf3ad9a6f1928f5 Mon Sep 17 00:00:00 2001 From: Denis Stepanov Date: Fri, 12 Jun 2015 15:23:02 +0200 Subject: [PATCH 7/8] Revert changes --- .../test/groovy/io/codearte/accurest/dsl/WiremockSpec.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockSpec.groovy b/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockSpec.groovy index ab1133c9ae..796e603c11 100644 --- a/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockSpec.groovy +++ b/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockSpec.groovy @@ -5,7 +5,7 @@ import spock.lang.Specification import java.util.regex.Pattern -abstract class WiremockSpec extends Specification { +class WiremockSpec extends Specification { void stubMappingIsValidWiremockStub(String mappingDefinition) { StubMapping stubMapping = StubMapping.buildFrom(mappingDefinition) From 1cca744b56cf8a786969704d063369d1162dffbd Mon Sep 17 00:00:00 2001 From: Denis Stepanov Date: Fri, 12 Jun 2015 15:25:46 +0200 Subject: [PATCH 8/8] Fix windows bug --- .../src/main/groovy/io/codearte/accurest/util/NamesUtil.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/util/NamesUtil.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/util/NamesUtil.groovy index 4817cc4816..a15bd1b5dc 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/util/NamesUtil.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/util/NamesUtil.groovy @@ -40,6 +40,6 @@ class NamesUtil { } static String packageToDirectory(String packageName) { - return packageName.replaceAll('\\.', File.separator) + return packageName.replace('.' as char, File.separatorChar) } }