Body matching by content type and client-side XML support
This commit is contained in:
@@ -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": {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<String, Object> 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<String, Object> appendBody(ClientRequest clientRequest) {
|
||||
Object body = clientRequest?.body?.clientValue
|
||||
if (body == null) {
|
||||
return [:]
|
||||
return clientRequest.body? appendBody(clientRequest.body) : [:]
|
||||
}
|
||||
|
||||
private Map<String, Object> appendBody(Body body) {
|
||||
return [bodyPatterns: (appendBodyPatterns(body.clientValue))]
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> appendBodyPatterns(MatchingStrategy matchingStrategy) {
|
||||
return [appendBodyPattern(matchingStrategy)]
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> appendBodyPatterns(List<MatchingStrategy> matchingStrategies) {
|
||||
return matchingStrategies.collect { appendBodyPattern(it) }
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> 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<Map<String, Object>> appendBodyPatterns(Object bodyValue) {
|
||||
return appendBodyPatterns(new MatchingStrategy(bodyValue, MatchingStrategy.Type.EQUAL_TO))
|
||||
}
|
||||
|
||||
private Map<String, Object> 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<String, ? extends Object> 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<MatchingStrategy> extractReqexpMatching(Object responseBodyObject) {
|
||||
def matchingStrategies = new ArrayList<MatchingStrategy>()
|
||||
responseBodyObject.each { k, v ->
|
||||
if (v instanceof List) {
|
||||
v.each {
|
||||
matchingStrategies.addAll(extractReqexpMatching((Map<String, Object>)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))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<String, Object> 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)] : [:]
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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<String, DslProperty> 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<String, Object> extractValue(Map<String, DslProperty> body, Closure valueProvider) {
|
||||
@@ -26,8 +19,8 @@ class Body extends DslProperty {
|
||||
} as Map<String, Object>
|
||||
}
|
||||
|
||||
Body(List bodyAsList) {
|
||||
super(bodyAsList.collect { it.clientValue }, bodyAsList.collect { it.serverValue })
|
||||
Body(List<DslProperty> 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
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package io.codearte.accurest.util
|
||||
|
||||
enum ContentType {
|
||||
JSON, XML, UNKNOWN
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 """<name>${value(client('Jozo'), server('Denis'))}</name><jobId>${value(client("<test>"), server('1234567890'))}</jobId>"""
|
||||
}
|
||||
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":"<name>Jozo</name><jobId><test></jobId>"
|
||||
}
|
||||
]
|
||||
},
|
||||
"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 """<user><name>${value(client('Jozo'), server('Denis'))}</name><jobId>${value(client("<test>"), server('1234567890'))}</jobId></user>"""
|
||||
}
|
||||
response {
|
||||
status 200
|
||||
}
|
||||
}
|
||||
when:
|
||||
String json = toWiremockClientJsonStub(groovyDsl)
|
||||
then:
|
||||
parseJson(json) == parseJson('''
|
||||
{
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"url": "/users",
|
||||
"bodyPatterns": [
|
||||
{
|
||||
"equalToXml":"<user><name>Jozo</name><jobId><test></jobId></user>"
|
||||
}
|
||||
]
|
||||
},
|
||||
"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 """<user><name>${value(client('Jozo'), server('Denis'))}</name><jobId>${value(client("<test>"), server('1234567890'))}</jobId></user>"""
|
||||
}
|
||||
}
|
||||
when:
|
||||
String json = toWiremockClientJsonStub(groovyDsl)
|
||||
then:
|
||||
parseJson(json) == parseJson('''
|
||||
{
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"url": "/users"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"body":"<user><name>Jozo</name><jobId><test></jobId></user>"
|
||||
}
|
||||
}
|
||||
''')
|
||||
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("""<name>${value(client('Jozo'), server('Denis'))}</name><jobId>${value(client("<test>"), server('1234567890'))}</jobId>""")
|
||||
}
|
||||
response {
|
||||
status 200
|
||||
}
|
||||
}
|
||||
when:
|
||||
String json = toWiremockClientJsonStub(groovyDsl)
|
||||
then:
|
||||
parseJson(json) == parseJson('''
|
||||
{
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"url": "/users",
|
||||
"bodyPatterns": [
|
||||
{
|
||||
"equalToXml":"<name>Jozo</name><jobId><test></jobId>"
|
||||
}
|
||||
]
|
||||
},
|
||||
"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()
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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": {
|
||||
|
||||
Reference in New Issue
Block a user