From 118b63c2a036440dd3c2f02823f0cbd0cd6c8b3b Mon Sep 17 00:00:00 2001 From: Denis Stepanov Date: Fri, 12 Jun 2015 11:47:15 +0200 Subject: [PATCH] Body matching by content type and client-side XML support --- .../DslToWiremockClientConverterSpec.groovy | 2 +- .../builder/SpockMethodBodyBuilder.groovy | 34 +- .../dsl/BaseWiremockStubStrategy.groovy | 70 ++- .../dsl/WiremockRequestStubStrategy.groovy | 94 ++- .../dsl/WiremockResponseStubStrategy.groovy | 15 +- .../accurest/dsl/internal/Body.groovy | 55 +- .../dsl/internal/MatchingStrategy.groovy | 45 +- .../dsl/internal/QueryParameters.groovy | 16 - .../accurest/dsl/internal/Request.groovy | 50 ++ .../codearte/accurest/util/ContentType.groovy | 5 + .../accurest/util/ContentUtils.groovy | 192 ++++++ .../accurest/dsl/WiremockGroovyDslSpec.groovy | 557 +++++++++++++++--- .../codearte/accurest/dsl/WiremockSpec.groovy | 2 +- .../plugin/BasicFunctionalSpec.groovy | 2 +- 14 files changed, 897 insertions(+), 242 deletions(-) create mode 100644 accurest-core/src/main/groovy/io/codearte/accurest/util/ContentType.groovy create mode 100644 accurest-core/src/main/groovy/io/codearte/accurest/util/ContentUtils.groovy diff --git a/accurest-converters/src/test/groovy/io/codearte/accurest/wiremock/DslToWiremockClientConverterSpec.groovy b/accurest-converters/src/test/groovy/io/codearte/accurest/wiremock/DslToWiremockClientConverterSpec.groovy index 2f20546014..edf11a256f 100755 --- a/accurest-converters/src/test/groovy/io/codearte/accurest/wiremock/DslToWiremockClientConverterSpec.groovy +++ b/accurest-converters/src/test/groovy/io/codearte/accurest/wiremock/DslToWiremockClientConverterSpec.groovy @@ -85,7 +85,7 @@ class DslToWiremockClientConverterSpec extends Specification { "method":"PUT", "url":"/api/12", "bodyPatterns": [ - { "equalTo": "[{\\"created_at\\":\\"Sat Jul 26 09:38:57 +0000 2014\\",\\"id\\":492967299297845248,\\"id_str\\":\\"492967299297845248\\",\\"place\\":{\\"attributes\\":{},\\"bounding_box\\":{\\"coordinates\\":[[[-77.119759,38.791645],[-76.909393,38.791645],[-76.909393,38.995548],[-77.119759,38.995548]]],\\"type\\":\\"Polygon\\"},\\"country\\":\\"United States\\",\\"country_code\\":\\"US\\",\\"full_name\\":\\"Washington, DC\\",\\"id\\":\\"01fbe706f872cb32\\",\\"name\\":\\"Washington\\",\\"place_type\\":\\"city\\",\\"url\\":\\"http://api.twitter.com/1/geo/id/01fbe706f872cb32.json\\"},\\"text\\":\\"Gonna see you at Warsaw\\"}]" } + { "equalToJson": "[{\\"created_at\\":\\"Sat Jul 26 09:38:57 +0000 2014\\",\\"id\\":492967299297845248,\\"id_str\\":\\"492967299297845248\\",\\"place\\":{\\"attributes\\":{},\\"bounding_box\\":{\\"coordinates\\":[[[-77.119759,38.791645],[-76.909393,38.791645],[-76.909393,38.995548],[-77.119759,38.995548]]],\\"type\\":\\"Polygon\\"},\\"country\\":\\"United States\\",\\"country_code\\":\\"US\\",\\"full_name\\":\\"Washington, DC\\",\\"id\\":\\"01fbe706f872cb32\\",\\"name\\":\\"Washington\\",\\"place_type\\":\\"city\\",\\"url\\":\\"http://api.twitter.com/1/geo/id/01fbe706f872cb32.json\\"},\\"text\\":\\"Gonna see you at Warsaw\\"}]" } ], "headers": { "Content-Type": { diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/builder/SpockMethodBodyBuilder.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/builder/SpockMethodBodyBuilder.groovy index 3d44123212..544abb98b1 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/builder/SpockMethodBodyBuilder.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/builder/SpockMethodBodyBuilder.groovy @@ -11,8 +11,14 @@ import io.codearte.accurest.dsl.internal.QueryParameter import io.codearte.accurest.dsl.internal.Request import io.codearte.accurest.dsl.internal.Response import io.codearte.accurest.dsl.internal.UrlPath +import io.codearte.accurest.util.ContentType import java.util.regex.Pattern + +import static io.codearte.accurest.util.ContentUtils.extractValue +import static io.codearte.accurest.util.ContentUtils.recognizeContentTypeFromHeader +import static io.codearte.accurest.util.ContentUtils.recognizeContentTypeFromContent + /** * @author Jakub Kubrynski */ @@ -36,7 +42,11 @@ class SpockMethodBodyBuilder { addLine(".header('${header.name}', '${header.serverValue}')") } if (request.body) { - String matches = new JsonOutput().toJson(request.body.serverValue) + Object bodyValue = request.body.serverValue + if (bodyValue instanceof GString) { + bodyValue = extractValue(bodyValue, {DslProperty dslProperty -> dslProperty.serverValue}) + } + String matches = new JsonOutput().toJson(bodyValue) addLine(".body('$matches')") } @@ -61,12 +71,24 @@ class SpockMethodBodyBuilder { if (response.body) { endBlock() addLine('and:').startBlock() - addLine('def responseBody = new JsonSlurper().parseText(response.body.asString())') def responseBody = response.body.serverValue - if (responseBody instanceof List) { - processArrayElements(responseBody, "", blockBuilder) - } else { - processMapElement(responseBody, blockBuilder, "") + ContentType contentType = recognizeContentTypeFromHeader(response.headers) + if (contentType == ContentType.UNKNOWN) { + contentType = recognizeContentTypeFromContent(responseBody) + } + if (responseBody instanceof GString) { + responseBody = extractValue(responseBody, contentType, { DslProperty dslProperty -> dslProperty.serverValue }) + } + if (contentType == ContentType.JSON) { + addLine('def responseBody = new JsonSlurper().parseText(response.body.asString())') + if (responseBody instanceof List) { + processArrayElements(responseBody, "", blockBuilder) + } else { + processMapElement(responseBody, blockBuilder, "") + } + } else if (contentType == ContentType.XML) { + addLine('def responseBody = new XmlSlurper().parseText(response.body.asString())') + // TODO xml validation } } endBlock() diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/BaseWiremockStubStrategy.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/BaseWiremockStubStrategy.groovy index 32bc831f1b..a5c100341b 100755 --- a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/BaseWiremockStubStrategy.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/BaseWiremockStubStrategy.groovy @@ -1,22 +1,22 @@ package io.codearte.accurest.dsl -import groovy.json.JsonOutput -import groovy.json.JsonSlurper + +import groovy.json.JsonBuilder import groovy.transform.TypeChecked -import groovy.xml.XmlUtil import io.codearte.accurest.dsl.internal.DslProperty import io.codearte.accurest.dsl.internal.Header import io.codearte.accurest.dsl.internal.Headers -import io.codearte.accurest.util.JsonConverter +import io.codearte.accurest.util.ContentType import java.util.regex.Pattern -import static groovy.json.StringEscapeUtils.escapeJava +import static io.codearte.accurest.util.ContentUtils.extractValue +import static io.codearte.accurest.util.JsonConverter.transformValues @TypeChecked abstract class BaseWiremockStubStrategy { private static Closure transform = { - it instanceof DslProperty ? JsonConverter.transformValues(it.clientValue, transform) : it + it instanceof DslProperty ? transformValues(it.clientValue, transform) : it } protected Map buildClientRequestHeadersSection(Headers headers) { @@ -33,43 +33,49 @@ abstract class BaseWiremockStubStrategy { return null } return headers.entries.collectEntries { Header entry -> - [(entry.name) : entry.clientValue] + [(entry.name): entry.clientValue] } } protected Map parseHeader(String entryKey, Object entry) { - return [(entryKey): [equalTo : entry]] + return [(entryKey): [equalTo: entry]] } protected Map parseHeader(String entryKey, String entry) { - return [(entryKey): [equalTo : entry]] + return [(entryKey): [equalTo: entry]] } protected Map parseHeader(String entryKey, Pattern entry) { - return [(entryKey): [matches : entry.pattern()]] + return [(entryKey): [matches: entry.pattern()]] } - protected String parseBody(Object body) { - String bodyAsString = body as String - try { - def json = new JsonSlurper().parseText(bodyAsString) - return escapeJava(JsonOutput.toJson(bodyAsString)) - } catch (Exception jsonException) { - try { - def xml = new XmlSlurper().parseText(bodyAsString) - return escapeJava(XmlUtil.serialize(bodyAsString)) - } catch (Exception xmlException) { - return escapeJava(bodyAsString) - } - } - } + public String parseBody(Object value, ContentType contentType) { + return parseBody(value.toString(), contentType) + } - protected String parseBody(List body) { - return JsonOutput.toJson(body) - } + public String parseBody(Map map, ContentType contentType) { + def transformedMap = transformValues(map, transform) + return parseBody(toJson(transformedMap), contentType) + } - protected String parseBody(Map body) { - def transformedMap = JsonConverter.transformValues(body, transform) - return JsonOutput.toJson(transformedMap) - } -} + public String parseBody(List list, ContentType contentType) { + return parseBody(toJson(list), contentType) + } + + public String parseBody(GString value, ContentType contentType) { + Object processedValue = extractValue(value, contentType, { DslProperty dslProperty -> dslProperty.clientValue }) + if (processedValue instanceof GString) { + return parseBody(processedValue.toString(), contentType) + } + return parseBody(processedValue, contentType) + } + + public String parseBody(String value, ContentType contentType) { + return value + } + + private static toJson(Object value) { + return new JsonBuilder(value).toString() + } + +} \ No newline at end of file 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..f9bc9bdc23 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 @@ -1,16 +1,23 @@ package io.codearte.accurest.dsl + import groovy.transform.PackageScope import groovy.transform.TypeChecked +import io.codearte.accurest.dsl.internal.Body import io.codearte.accurest.dsl.internal.ClientRequest +import io.codearte.accurest.dsl.internal.DslProperty import io.codearte.accurest.dsl.internal.MatchingStrategy import io.codearte.accurest.dsl.internal.QueryParameter import io.codearte.accurest.dsl.internal.QueryParameters import io.codearte.accurest.dsl.internal.Request +import io.codearte.accurest.util.ContentType import java.util.regex.Pattern -import static io.codearte.accurest.dsl.internal.JsonStructureConverter.TEMPORARY_PATTERN_HOLDER -import static io.codearte.accurest.dsl.internal.JsonStructureConverter.convertJsonStructureToObjectUnderstandingStructure +import static io.codearte.accurest.util.ContentUtils.extractValue +import static io.codearte.accurest.util.ContentUtils.recognizeContentTypeFromHeader +import static io.codearte.accurest.util.ContentUtils.getEqualsTypeFromContentType +import static io.codearte.accurest.util.ContentUtils.recognizeContentTypeFromContent +import static io.codearte.accurest.util.ContentUtils.recognizeContentTypeFromMatchingStrategy @TypeChecked @PackageScope @@ -29,7 +36,7 @@ class WiremockRequestStubStrategy extends BaseWiremockStubStrategy { private Map buildRequestContent(ClientRequest request) { return ([method : request?.method?.clientValue, - headers : buildClientRequestHeadersSection(request.headers) + headers : buildClientRequestHeadersSection(request.headers) ] << appendUrl(request) << appendQueryParameters(request) << appendBody(request)).findAll { it.value } } @@ -75,40 +82,69 @@ class WiremockRequestStubStrategy extends BaseWiremockStubStrategy { } private Map appendBody(ClientRequest clientRequest) { - Object body = clientRequest?.body?.clientValue - if (body == null) { - return [:] + return clientRequest.body? appendBody(clientRequest.body) : [:] + } + + private Map appendBody(Body body) { + return [bodyPatterns: (appendBodyPatterns(body.clientValue))] + } + + private List> appendBodyPatterns(MatchingStrategy matchingStrategy) { + return [appendBodyPattern(matchingStrategy)] + } + + private List> appendBodyPatterns(List matchingStrategies) { + return matchingStrategies.collect { appendBodyPattern(it) } + } + + private List> appendBodyPatterns(GString gString) { + if (containsPattern(gString)) { + Object value = extractValue(gString, { DslProperty dslProperty -> dslProperty.clientValue }) + return appendBodyPatterns(extractReqexpMatching(value)) } - 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() }) - } - ))]]] + return appendBodyPatterns(new MatchingStrategy(gString, getEqualsTypeFromContentTypeHeader())) + } + + private List> appendBodyPatterns(Object bodyValue) { + return appendBodyPatterns(new MatchingStrategy(bodyValue, MatchingStrategy.Type.EQUAL_TO)) + } + + private Map appendBodyPattern(MatchingStrategy matchingStrategy) { + MatchingStrategy.Type type = matchingStrategy.type + Object value= matchingStrategy.clientValue + ContentType contentType = recognizeContentTypeFromMatchingStrategy(type) + if (contentType == ContentType.UNKNOWN && type == MatchingStrategy.Type.EQUAL_TO) { + contentType = recognizeContentTypeFromContent(value) + type = getEqualsTypeFromContentType(contentType) } - return [bodyPatterns: [[equalTo: parseBody(body)]]] + Map result = [(type.name): parseBody(value, contentType)] + if (type == MatchingStrategy.Type.EQUAL_TO_JSON && matchingStrategy.jsonCompareMode) { + return result << [jsonCompareMode : (matchingStrategy.jsonCompareMode.toString())] + } + return result } - protected String parseBody(Object body) { - return body + private boolean containsPattern(GString bodyAsValue) { + return bodyAsValue.values.collect { it instanceof DslProperty ? it.clientValue : it } + .find { it instanceof Pattern } } - boolean containsRegex(Object bodyObject) { - String bodyString = bodyObject as String - return (bodyString =~ /\^.*\$/).find() + private List extractReqexpMatching(Object responseBodyObject) { + def matchingStrategies = new ArrayList() + responseBodyObject.each { k, v -> + if (v instanceof List) { + v.each { + matchingStrategies.addAll(extractReqexpMatching((Map)it)) + } + } else { + matchingStrategies.add(new MatchingStrategy(/.*${k}":.?"?${v}"?.*/, MatchingStrategy.Type.MATCHING)) + } + } + return matchingStrategies } - boolean containsRegex(Map map) { - return map.values().any { it instanceof Pattern } + private MatchingStrategy.Type getEqualsTypeFromContentTypeHeader() { + return getEqualsTypeFromContentType(recognizeContentTypeFromHeader(request.headers)) } } 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 b517150236..a17dad9420 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 @@ -2,16 +2,23 @@ package io.codearte.accurest.dsl import groovy.transform.PackageScope import groovy.transform.TypeChecked import io.codearte.accurest.dsl.internal.ClientResponse +import io.codearte.accurest.dsl.internal.Request import io.codearte.accurest.dsl.internal.Response +import io.codearte.accurest.util.ContentType + +import static io.codearte.accurest.util.ContentUtils.recognizeContentTypeFromContent +import static io.codearte.accurest.util.ContentUtils.recognizeContentTypeFromHeader @TypeChecked @PackageScope class WiremockResponseStubStrategy extends BaseWiremockStubStrategy { + private final Request request private final Response response WiremockResponseStubStrategy(GroovyDsl groovyDsl) { this.response = groovyDsl.response + this.request = groovyDsl.request } @PackageScope @@ -27,6 +34,12 @@ class WiremockResponseStubStrategy extends BaseWiremockStubStrategy { private Map appendBody(ClientResponse response) { Object body = response?.body?.clientValue - return body != null ? [body: parseBody(body)] : [:] + ContentType contentType = recognizeContentTypeFromHeader(response.headers) + if (contentType == ContentType.UNKNOWN) { + contentType = recognizeContentTypeFromContent(body) + } + return body != null ? [body: parseBody(body, contentType)] : [:] } + + } 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..df799d87f8 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,23 +1,16 @@ package io.codearte.accurest.dsl.internal -import groovy.json.JsonSlurper +import groovy.transform.CompileStatic 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) +@CompileStatic 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})) + super(extractValue(body, { DslProperty p -> p.clientValue}), extractValue(body, {DslProperty p -> p.serverValue})) } private static Map extractValue(Map body, Closure valueProvider) { @@ -26,8 +19,8 @@ class Body extends DslProperty { } as Map } - Body(List bodyAsList) { - super(bodyAsList.collect { it.clientValue }, bodyAsList.collect { it.serverValue }) + Body(List bodyAsList) { + super(bodyAsList.collect { DslProperty p -> p.clientValue }, bodyAsList.collect { DslProperty p -> p.serverValue }) } Body(Object bodyAsValue) { @@ -35,48 +28,16 @@ class Body extends DslProperty { } Body(GString bodyAsValue) { - super(extractValue(bodyAsValue, {it.clientValue}), extractValue(bodyAsValue, {it.serverValue})) + super(bodyAsValue, bodyAsValue) } Body(DslProperty bodyAsValue) { super(bodyAsValue.clientValue, bodyAsValue.serverValue) } - /** - * 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. - * - * In order to preserve the original JSON structure we need to convert the passed Regex patterns - * to a temporary string, then convert all to a legitimate JSON structure and then finally - * convert it back from string to a pattern. - * - * @param bodyAsValue - GString with passed values - * @param valueProvider - provider of values either for server or client side - * @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)) - return convertAllTemporaryRegexPlaceholdersBackToPatterns(parsedJson) + Body(MatchingStrategy matchingStrategy) { + super(matchingStrategy, matchingStrategy) } - 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/dsl/internal/MatchingStrategy.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/MatchingStrategy.groovy index c385bb1939..e9093dc9aa 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/MatchingStrategy.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/MatchingStrategy.groovy @@ -9,26 +9,39 @@ import groovy.transform.ToString; @CompileStatic class MatchingStrategy extends DslProperty { - Type type + Type type + JSONCompareMode jsonCompareMode - MatchingStrategy(Object value, Type type) { - super(value) - this.type = type - } + MatchingStrategy(Object value, Type type) { + this(value, type, null) + } - MatchingStrategy(DslProperty value, Type type) { - super(value.clientValue, value.serverValue) - this.type = type - } + MatchingStrategy(Object value, Type type, JSONCompareMode jsonCompareMode) { + super(value) + this.type = type + this.jsonCompareMode = jsonCompareMode + } - enum Type { - EQUAL_TO("equalTo"), CONTAINS("contains"), MATCHING("matches"), NOT_MATCHING("doesNotMatch") + MatchingStrategy(DslProperty value, Type type) { + this(value, type, null) + } - final String name + MatchingStrategy(DslProperty value, Type type, JSONCompareMode jsonCompareMode) { + super(value.clientValue, value.serverValue) + this.type = type + this.jsonCompareMode = jsonCompareMode + } - Type(name) { - this.name = name - } - } + enum Type { + + EQUAL_TO("equalTo"), CONTAINS("contains"), MATCHING("matches"), NOT_MATCHING("doesNotMatch"), + EQUAL_TO_JSON("equalToJson"), EQUAL_TO_XML("equalToXml") + + final String name + + Type(name) { + this.name = name + } + } } \ No newline at end of file diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/QueryParameters.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/QueryParameters.groovy index eedaf5654b..0a5d6233f2 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/QueryParameters.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/QueryParameters.groovy @@ -20,20 +20,4 @@ class QueryParameters { parameters << new QueryParameter(parameterName, parameterValue) } - MatchingStrategy equalTo(Object value) { - return new MatchingStrategy(value, MatchingStrategy.Type.EQUAL_TO) - } - - MatchingStrategy containing(Object value) { - return new MatchingStrategy(value, MatchingStrategy.Type.CONTAINS) - } - - MatchingStrategy matching(Object value) { - return new MatchingStrategy(value, MatchingStrategy.Type.MATCHING) - } - - MatchingStrategy notMatching(Object value) { - return new MatchingStrategy(value, MatchingStrategy.Type.NOT_MATCHING) - } - } diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Request.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Request.groovy index dab8f873f2..67b9dde09f 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Request.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Request.groovy @@ -3,6 +3,7 @@ import groovy.transform.CompileStatic import groovy.transform.EqualsAndHashCode import groovy.transform.ToString import groovy.transform.TypeChecked +import groovy.xml.MarkupBuilder @TypeChecked @EqualsAndHashCode @@ -88,6 +89,10 @@ class Request extends Common { this.body = new Body(convertObjectsToDslProperties(body)) } + void body(DslProperty dslProperty) { + this.body = new Body(dslProperty) + } + void body(Object bodyAsValue) { this.body = new Body(bodyAsValue) } @@ -95,6 +100,51 @@ class Request extends Common { Body getBody() { return body } + + MatchingStrategy equalTo(Object value) { + return new MatchingStrategy(value, MatchingStrategy.Type.EQUAL_TO) + } + + MatchingStrategy containing(Object value) { + return new MatchingStrategy(value, MatchingStrategy.Type.CONTAINS) + } + + MatchingStrategy matching(Object value) { + return new MatchingStrategy(value, MatchingStrategy.Type.MATCHING) + } + + MatchingStrategy notMatching(Object value) { + return new MatchingStrategy(value, MatchingStrategy.Type.NOT_MATCHING) + } + + MatchingStrategy equalToXml(Object value) { + return new MatchingStrategy(value, MatchingStrategy.Type.EQUAL_TO_XML) + } + + MatchingStrategy equalToJson(Object value) { + return new MatchingStrategy(value, MatchingStrategy.Type.EQUAL_TO_JSON) + } + + MatchingStrategy equalToJson(Object value, JSONCompareMode jsonCompareMode) { + return new MatchingStrategy(value, MatchingStrategy.Type.EQUAL_TO_JSON) + } + + MatchingStrategy equalToJsonStrictly(Object value) { + return new MatchingStrategy(value, MatchingStrategy.Type.EQUAL_TO_JSON, JSONCompareMode.STRICT) + } + + MatchingStrategy equalToJsonLeniently(Object value) { + return new MatchingStrategy(value, MatchingStrategy.Type.EQUAL_TO_JSON, JSONCompareMode.LENIENT) + } + + MatchingStrategy equalToJsonNonExtensibly(Object value) { + return new MatchingStrategy(value, MatchingStrategy.Type.EQUAL_TO_JSON, JSONCompareMode.NON_EXTENSIBLE) + } + + MatchingStrategy equalToJsonWithStrictOrder(Object value) { + return new MatchingStrategy(value, MatchingStrategy.Type.EQUAL_TO_JSON, JSONCompareMode.STRICT_ORDER) + } + } @CompileStatic diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/util/ContentType.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/util/ContentType.groovy new file mode 100644 index 0000000000..142c93a945 --- /dev/null +++ b/accurest-core/src/main/groovy/io/codearte/accurest/util/ContentType.groovy @@ -0,0 +1,5 @@ +package io.codearte.accurest.util + +enum ContentType { + JSON, XML, UNKNOWN +} \ No newline at end of file diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/util/ContentUtils.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/util/ContentUtils.groovy new file mode 100644 index 0000000000..1a187595b9 --- /dev/null +++ b/accurest-core/src/main/groovy/io/codearte/accurest/util/ContentUtils.groovy @@ -0,0 +1,192 @@ +package io.codearte.accurest.util +import groovy.json.JsonException +import groovy.json.JsonSlurper +import groovy.transform.TypeChecked +import io.codearte.accurest.dsl.internal.DslProperty +import io.codearte.accurest.dsl.internal.Headers +import io.codearte.accurest.dsl.internal.MatchingStrategy +import org.codehaus.groovy.runtime.GStringImpl + +import java.util.regex.Matcher +import java.util.regex.Pattern + +import static org.apache.commons.lang3.StringEscapeUtils.escapeJson +import static org.apache.commons.lang3.StringEscapeUtils.escapeXml11 + +@TypeChecked +class ContentUtils { + + private static final Pattern TEMPORARY_PATTERN_HOLDER = Pattern.compile('REGEXP>>(.*)<<') + private static final String JSON_VALUE_PATTERN_FOR_REGEX = 'REGEXP>>%s<<' + + /** + * 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. + * + * In order to preserve the original JSON structure we need to convert the passed Regex patterns + * to a temporary string, then convert all to a legitimate JSON structure and then finally + * convert it back from string to a pattern. + * + * @param bodyAsValue - GString with passed values + * @param valueProvider - provider of values either for server or client side + * @return JSON structure with replaced client / server side parts + */ + public static Object extractValue(GString bodyAsValue, ContentType contentType, Closure valueProvider) { + if (contentType == ContentType.JSON) { + return extractValueForJSON(bodyAsValue, valueProvider) + } + if (contentType == ContentType.XML) { + return extractValueForXML(bodyAsValue, valueProvider) + } + // else Brute force :( + try { + return extractValueForJSON(bodyAsValue, valueProvider) + } catch(JsonException e) { + // Not a JSON format + return extractValueForXML(bodyAsValue, valueProvider) + } + return bodyAsValue + } + + public static Object extractValue(GString bodyAsValue, Closure valueProvider) { + return extractValue(bodyAsValue, ContentType.UNKNOWN, valueProvider) + } + + private static Object extractValueForJSON(GString bodyAsValue, Closure valueProvider) { + GString transformedString = new GStringImpl( + bodyAsValue.values.collect { transformJSONStringValue(it, valueProvider) } as String[], + bodyAsValue.strings.clone() as String[] + ) + def parsedJson = new JsonSlurper().parseText(transformedString.toString()) + return convertAllTemporaryRegexPlaceholdersBackToPatterns(parsedJson) + } + + private static GStringImpl extractValueForXML(GString bodyAsValue, Closure valueProvider) { + return new GStringImpl( + bodyAsValue.values.collect { transformXMLStringValue(it, valueProvider) } as String[], + bodyAsValue.strings.clone() as String[] + ) + } + + 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) { + String string = (String) value + Matcher matcher = TEMPORARY_PATTERN_HOLDER.matcher(string) + if (matcher.matches()) { + List val = matcher[0] as List + String pattern = val[1] + return Pattern.compile(pattern) + } + return value + } + return value + }) + } + + public static ContentType recognizeContentTypeFromHeader(Headers headers) { + String content = headers?.entries.find { it.name == "Content-Type" } ?.clientValue?.toString() + if (content?.endsWith("json")) { + return ContentType.JSON + } + if (content?.endsWith("xml")) { + return ContentType.XML + } + return ContentType.UNKNOWN + } + + public static MatchingStrategy.Type getEqualsTypeFromContentType(ContentType contentType) { + switch (contentType) { + case ContentType.JSON: + return MatchingStrategy.Type.EQUAL_TO_JSON + case ContentType.XML: + return MatchingStrategy.Type.EQUAL_TO_XML + } + return MatchingStrategy.Type.EQUAL_TO + } + + public static ContentType recognizeContentTypeFromContent(GString gstring) { + if (isJsonType(gstring)) { + return ContentType.JSON + } + if (isXmlType(gstring)) { + return ContentType.XML + } + return ContentType.UNKNOWN + } + + public static ContentType recognizeContentTypeFromContent(Map jsonMap) { + return ContentType.JSON + } + + public static ContentType recognizeContentTypeFromContent(List jsonList) { + return ContentType.JSON + } + + public static ContentType recognizeContentTypeFromContent(Object gstring) { + return ContentType.UNKNOWN + } + + public static boolean isJsonType(GString gstring) { + GString stringWithoutValues = new GStringImpl( + gstring.values.collect({ + it instanceof String || it instanceof GString ? it.toString() : escapeJson(it.toString()) + }) as Object[], + gstring.strings.clone() as String[] + ) + try { + new JsonSlurper().parseText(stringWithoutValues.toString()) + return true + } catch (JsonException e) { + // Not JSON + } + return false + } + + public static boolean isXmlType(GString gstring) { + GString stringWithoutValues = new GStringImpl( + gstring.values.collect({ + it instanceof String || it instanceof GString ? it.toString() : escapeXml11(it.toString()) + }) as Object[], + gstring.strings.clone() as String[] + ) + try { + new XmlSlurper().parseText(stringWithoutValues.toString()) + return true + } catch (Exception e) { + // Not XML + } + return false + } + + public static ContentType recognizeContentTypeFromMatchingStrategy(MatchingStrategy.Type type) { + switch (type) { + case MatchingStrategy.Type.EQUAL_TO_XML: + return ContentType.XML + case MatchingStrategy.Type.EQUAL_TO_JSON: + return ContentType.JSON + } + return ContentType.UNKNOWN + } + +} 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 c8767551b4..5f6cb74fab 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 @@ -181,7 +181,7 @@ class WiremockGroovyDslSpec extends WiremockSpec { "urlPattern": "/[0-9]{2}", "bodyPatterns": [ { - "equalTo":"{\\"name\\":\\"Jan\\"}" + "equalToJson":"{\\"name\\":\\"Jan\\"}" } ] }, @@ -198,6 +198,314 @@ class WiremockGroovyDslSpec extends WiremockSpec { stubMappingIsValidWiremockStub(wiremockStub) } + def 'should use equalToJson when body match is defined as map'() { + given: + GroovyDsl groovyDsl = GroovyDsl.make { + request { + method('GET') + url $(client(~/\/[0-9]{2}/), server('/12')) + body( + id: value( + client('123'), + server({ regex('[0-9]+') }) + ), + surname: $( + client('Kowalsky'), + server('Lewandowski') + ), + name: 'Jan', + created: $(client('2014-02-02 12:23:43'), server({ currentDate(it) })) + ) + } + response { + status 200 + } + } + when: + String wiremockStub = new WiremockStubStrategy(groovyDsl).toWiremockClientStub() + then: + new JsonSlurper().parseText(wiremockStub) == new JsonSlurper().parseText(''' + { + "request": { + "method": "GET", + "urlPattern": "/[0-9]{2}", + "bodyPatterns": [ + { + "equalToJson": "{\\"id\\":\\"123\\",\\"surname\\":\\"Kowalsky\\",\\"name\\":\\"Jan\\",\\"created\\":\\"2014-02-02 12:23:43\\"}" + } + ] + }, + "response": { + "status": 200, + } + } + ''') + and: + 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 use equalToXml when content type is parsable xml'() { + given: + GroovyDsl groovyDsl = GroovyDsl.make { + request { + method 'GET' + url "/users" + 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", + "bodyPatterns": [ + { + "equalToXml":"Jozo<test>" + } + ] + }, + "response": { + "status": 200 + } + } + ''') + and: + stubMappingIsValidWiremockStub(json) + } + + def 'should support xml as a response body'() { + given: + GroovyDsl groovyDsl = GroovyDsl.make { + request { + method 'GET' + url "/users" + } + response { + status 200 + body """${value(client('Jozo'), server('Denis'))}${value(client(""), server('1234567890'))}""" + } + } + when: + String json = toWiremockClientJsonStub(groovyDsl) + then: + parseJson(json) == parseJson(''' + { + "request": { + "method": "GET", + "url": "/users" + }, + "response": { + "status": 200, + "body":"Jozo<test>" + } + } + ''') + and: + stubMappingIsValidWiremockStub(json) + } + + def 'should use equalToJson compare mode'() { + given: + GroovyDsl groovyDsl = GroovyDsl.make { + request { + method 'GET' + url "/users" + body equalToJsonWithStrictOrder('''{"name":"Jan"}''') + } + response { + status 200 + } + } + when: + String json = toWiremockClientJsonStub(groovyDsl) + then: + parseJson(json) == parseJson(''' + { + "request": { + "method": "GET", + "url": "/users", + "bodyPatterns": [ + { + "equalToJson":"{\\"name\\":\\"Jan\\"}", + "jsonCompareMode":"STRICT_ORDER" + } + ] + }, + "response": { + "status": 200 + } + } + ''') + and: + stubMappingIsValidWiremockStub(json) + } + + def 'should use equalToJson'() { + given: + GroovyDsl groovyDsl = GroovyDsl.make { + request { + method 'GET' + url "/users" + body equalToJson('''{"name":"Jan"}''') + } + response { + status 200 + } + } + when: + String json = toWiremockClientJsonStub(groovyDsl) + then: + parseJson(json) == parseJson(''' + { + "request": { + "method": "GET", + "url": "/users", + "bodyPatterns": [ + { + "equalToJson":"{\\"name\\":\\"Jan\\"}" + } + ] + }, + "response": { + "status": 200 + } + } + ''') + and: + stubMappingIsValidWiremockStub(json) + } + + def 'should use equalToXml'() { + given: + GroovyDsl groovyDsl = GroovyDsl.make { + request { + method 'GET' + url "/users" + body equalToXml("""${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", + "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 { @@ -232,9 +540,7 @@ class WiremockGroovyDslSpec extends WiremockSpec { "method": "GET", "urlPattern": "/[0-9]{2}", "bodyPatterns": [ - { - "matches":"\\\\{\\"personalId\\":\\"^[0-9]{11}$\\"\\\\}" - } + {"matches": ".*personalId\\":.?\\"?^[0-9]{11}$\\"?.*"} ] }, "response": { @@ -294,9 +600,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": { @@ -427,78 +732,78 @@ class WiremockGroovyDslSpec extends WiremockSpec { def "should generate request with urlPath for client side"() { given: - GroovyDsl groovyDsl = GroovyDsl.make { - request { - method 'GET' - urlPath $(client("boxes"), server("items")) - } - response { - status 200 - } - } - when: - def json = toWiremockClientJsonStub(groovyDsl) - then: - parseJson(json) == parseJson(''' - { - "request": { - "method": "GET", - "urlPath": "boxes" - }, - "response": { - "status": 200, + GroovyDsl groovyDsl = GroovyDsl.make { + request { + method 'GET' + urlPath $(client("boxes"), server("items")) + } + response { + status 200 } } - ''') + when: + def json = toWiremockClientJsonStub(groovyDsl) + then: + parseJson(json) == parseJson(''' + { + "request": { + "method": "GET", + "urlPath": "boxes" + }, + "response": { + "status": 200, + } + } + ''') and: - stubMappingIsValidWiremockStub(json) + stubMappingIsValidWiremockStub(json) } def "should generate simple request with urlPath for client side"() { given: - GroovyDsl groovyDsl = GroovyDsl.make { - request { - method 'GET' - urlPath "boxes" - } - response { - status 200 - } - } - when: - def json = toWiremockClientJsonStub(groovyDsl) - then: - parseJson(json) == parseJson(''' - { - "request": { - "method": "GET", - "urlPath": "boxes" - }, - "response": { - "status": 200, + GroovyDsl groovyDsl = GroovyDsl.make { + request { + method 'GET' + urlPath "boxes" + } + response { + status 200 } } - ''') + when: + def json = toWiremockClientJsonStub(groovyDsl) + then: + parseJson(json) == parseJson(''' + { + "request": { + "method": "GET", + "urlPath": "boxes" + }, + "response": { + "status": 200, + } + } + ''') and: - stubMappingIsValidWiremockStub(json) + stubMappingIsValidWiremockStub(json) } def "should not allow regexp in url for server value"() { when: - GroovyDsl.make { - request { - method 'GET' - url(regex(/users\/[0-9]*/)) { - queryParameters { - parameter 'age': notMatching("^\\w*\$") - parameter 'name': matching("Denis.*") + GroovyDsl.make { + request { + method 'GET' + url(regex(/users\/[0-9]*/)) { + queryParameters { + parameter 'age': notMatching("^\\w*\$") + parameter 'name': matching("Denis.*") + } } } + response { + status 200 + } } - response { - status 200 - } - } then: def e = thrown(IllegalStateException) e.message.contains "Url can't be a pattern for the server side" @@ -547,44 +852,44 @@ class WiremockGroovyDslSpec extends WiremockSpec { def "should generate request with url and queryParameters for client side"() { given: - GroovyDsl groovyDsl = GroovyDsl.make { - request { - method 'GET' - url($(client(regex(/users\/[0-9]*/)), server("users/123"))) { - queryParameters { - parameter 'age': $(client(notMatching("^\\w*\$")), server(10)) - parameter 'name': $(client(matching("Denis.*")), server("Denis")) + GroovyDsl groovyDsl = GroovyDsl.make { + request { + method 'GET' + url($(client(regex(/users\/[0-9]*/)), server("users/123"))) { + queryParameters { + parameter 'age': $(client(notMatching("^\\w*\$")), server(10)) + parameter 'name': $(client(matching("Denis.*")), server("Denis")) + } } } + response { + status 200 + } } - response { - status 200 - } - } when: - def json = toWiremockClientJsonStub(groovyDsl) + def json = toWiremockClientJsonStub(groovyDsl) then: - parseJson(json) == parseJson(''' - { - "request": { - "method": "GET", - "urlPattern": "users/[0-9]*", - "queryParameters": { - "age": { - "doesNotMatch": "^\\\\w*$" - }, - "name": { - "matches": "Denis.*" - } + parseJson(json) == parseJson(''' + { + "request": { + "method": "GET", + "urlPattern": "users/[0-9]*", + "queryParameters": { + "age": { + "doesNotMatch": "^\\\\w*$" + }, + "name": { + "matches": "Denis.*" + } + } + }, + "response": { + "status": 200, } - }, - "response": { - "status": 200, } - } - ''') + ''') and: - stubMappingIsValidWiremockStub(json) + stubMappingIsValidWiremockStub(json) } def "should generate stub with some headers section for client side"() { @@ -622,6 +927,74 @@ class WiremockGroovyDslSpec extends WiremockSpec { ''') } + 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) { new JsonBuilder(value).toPrettyString() } 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) diff --git a/accurest-gradle-plugin/src/test/groovy/io/codearte/accurest/plugin/BasicFunctionalSpec.groovy b/accurest-gradle-plugin/src/test/groovy/io/codearte/accurest/plugin/BasicFunctionalSpec.groovy index e2ee36959d..96cabca538 100755 --- a/accurest-gradle-plugin/src/test/groovy/io/codearte/accurest/plugin/BasicFunctionalSpec.groovy +++ b/accurest-gradle-plugin/src/test/groovy/io/codearte/accurest/plugin/BasicFunctionalSpec.groovy @@ -52,7 +52,7 @@ class BasicFunctionalSpec extends IntegrationSpec { }, "url": "/api/12", "bodyPatterns": [ - { "equalTo": "[{\\"text\\":\\"Gonna see you at Warsaw\\"}]" } + { "equalToJson": "[{\\"text\\":\\"Gonna see you at Warsaw\\"}]" } ] }, "response": {