Merge pull request #133 from Codearte/issues/123-cleaner-assertions-squashed

[#121] Introduced full JSONPath support
This commit is contained in:
Marcin Grzejszczak
2015-09-02 23:37:43 +02:00
25 changed files with 1093 additions and 599 deletions

View File

@@ -1,9 +1,15 @@
language: java
sudo: false
jdk:
- oraclejdk7
- openjdk7
- oraclejdk8
cache:
directories:
- $HOME/.gradle
- $HOME/.m2
install: ./gradlew assemble
script: ./gradlew check --stacktrace --info --continue

View File

@@ -1,6 +1,6 @@
package io.codearte.accurest.wiremock
import groovy.json.JsonSlurper
import org.skyscreamer.jsonassert.JSONAssert
import spock.lang.Specification
class DslToWireMockClientConverterSpec extends Specification {
@@ -23,8 +23,9 @@ class DslToWireMockClientConverterSpec extends Specification {
when:
String json = converter.convertContent(dslBody)
then:
new JsonSlurper().parseText(json) == new JsonSlurper().parseText("""
{"request":{"method":"PUT","urlPattern":"/[0-9]{2}"},"response":{"status":200}}""")
JSONAssert.assertEquals('''
{"request":{"method":"PUT","urlPattern":"/[0-9]{2}"},"response":{"status":200}}
''', json, false)
}
@@ -80,22 +81,62 @@ class DslToWireMockClientConverterSpec extends Specification {
when:
String json = converter.convertContent(dslBody)
then:
new JsonSlurper().parseText(json) == new JsonSlurper().parseText("""{
"request":{
"method":"PUT",
"url":"/api/12",
"bodyPatterns": [
{ "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": {
"equalTo": "application/vnd.com.ofg.twitter-places-analyzer.v1+json"
}
}
},
"response":{
"status":200}
}
""")
JSONAssert.assertEquals('''
{
"request" : {
"url" : "/api/12",
"method" : "PUT",
"bodyPatterns" : [ {
"matchesJsonPath" : "$[*].place.bounding_box.coordinates[*][*][?(@ == 38.995548)]"
}, {
"matchesJsonPath" : "$[*].place[?(@.country == 'United States')]"
}, {
"matchesJsonPath" : "$[*].place.bounding_box.coordinates[*][*][?(@ == -77.119759)]"
}, {
"matchesJsonPath" : "$[*].place[?(@.name == 'Washington')]"
}, {
"matchesJsonPath" : "$[*].place.bounding_box[?(@.type == 'Polygon')]"
}, {
"matchesJsonPath" : "$[*][?(@.id_str == '492967299297845248')]"
}, {
"matchesJsonPath" : "$[*].place[?(@.country_code == 'US')]"
}, {
"matchesJsonPath" : "$[*][?(@.id == 492967299297845248)]"
}, {
"matchesJsonPath" : "$[*].place.bounding_box.coordinates[*][*][?(@ == -76.909393)]"
}, {
"matchesJsonPath" : "$[*].place.bounding_box.coordinates[*][*][?(@ == 38.791645)]"
}, {
"matchesJsonPath" : "$[*].place[?(@.id == '01fbe706f872cb32')]"
}, {
"matchesJsonPath" : "$[*].place[?(@.url == 'http://api.twitter.com/1/geo/id/01fbe706f872cb32.json')]"
}, {
"matchesJsonPath" : "$[*].place.bounding_box.coordinates[*][*][?(@ == -77.119759)]"
}, {
"matchesJsonPath" : "$[*].place.bounding_box.coordinates[*][*][?(@ == -76.909393)]"
}, {
"matchesJsonPath" : "$[*].place.bounding_box.coordinates[*][*][?(@ == 38.995548)]"
}, {
"matchesJsonPath" : "$[*][?(@.text == 'Gonna see you at Warsaw')]"
}, {
"matchesJsonPath" : "$[*].place[?(@.place_type == 'city')]"
}, {
"matchesJsonPath" : "$[*][?(@.created_at == 'Sat Jul 26 09:38:57 +0000 2014')]"
}, {
"matchesJsonPath" : "$[*].place[?(@.full_name == 'Washington, DC')]"
}, {
"matchesJsonPath" : "$[*].place.bounding_box.coordinates[*][*][?(@ == 38.791645)]"
} ],
"headers" : {
"Content-Type" : {
"equalTo" : "application/vnd.com.ofg.twitter-places-analyzer.v1+json"
}
}
},
"response" : {
"status" : 200
}
}
''', json, false)
}
}

View File

@@ -50,14 +50,23 @@ class SingleTestGenerator {
}
if (configProperties.ruleClassForTests) {
clazz.addImport('org.junit.Rule')
.addRule(configProperties.ruleClassForTests)
.addRule(configProperties.ruleClassForTests)
}
addJsonPathRelatedImports(clazz)
listOfFiles.each {
clazz.addMethod(createTestMethod(it, configProperties))
}
return clazz.build()
}
private ClassBuilder addJsonPathRelatedImports(ClassBuilder clazz) {
clazz.addImport(['com.jayway.jsonpath.DocumentContext',
'com.jayway.jsonpath.JsonPath',
'net.minidev.json.JSONArray'])
}
}

View File

@@ -43,6 +43,11 @@ class ClassBuilder {
return this
}
ClassBuilder addImport(List<String> importsToAdd) {
imports.addAll(importsToAdd)
return this
}
ClassBuilder addStaticImport(String importToAdd) {
staticImports << importToAdd
return this

View File

@@ -3,21 +3,13 @@ import groovy.json.JsonOutput
import groovy.transform.PackageScope
import groovy.transform.TypeChecked
import io.codearte.accurest.dsl.GroovyDsl
import io.codearte.accurest.dsl.internal.DslProperty
import io.codearte.accurest.dsl.internal.ExecutionProperty
import io.codearte.accurest.dsl.internal.MatchingStrategy
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.*
import io.codearte.accurest.util.ContentType
import io.codearte.accurest.util.JsonConverter
import java.util.regex.Pattern
import static io.codearte.accurest.util.ContentUtils.extractValue
import static io.codearte.accurest.util.ContentUtils.recognizeContentTypeFromContent
import static io.codearte.accurest.util.ContentUtils.recognizeContentTypeFromHeader
import io.codearte.accurest.util.MapConverter
import io.codearte.accurest.util.JsonPathJsonConverter
import io.codearte.accurest.util.JsonPaths
import static io.codearte.accurest.util.ContentUtils.*
/**
* @author Jakub Kubrynski
*/
@@ -93,17 +85,34 @@ abstract class SpockMethodBodyBuilder {
responseBody = extractValue(responseBody, contentType, { DslProperty dslProperty -> dslProperty.serverValue })
}
if (contentType == ContentType.JSON) {
bb.addLine("def responseBody = new JsonSlurper().parseText($responseAsString)")
appendJsonPath(bb, responseAsString)
JsonPaths jsonPaths = JsonPathJsonConverter.transformToJsonPathWithTestsSideValues(responseBody)
jsonPaths.each {
it.buildJsonPathComparison('parsedJson').each {
bb.addLine(it)
}
}
processBodyElement(bb, "", responseBody)
} else if (contentType == ContentType.XML) {
bb.addLine("def responseBody = new XmlSlurper().parseText($responseAsString)")
// TODO xml validation
} else {
bb.addLine("def responseBody = ($responseAsString)")
processBodyElement(bb, "", responseBody)
processText(bb, "", responseBody as String)
}
}
protected void processText(BlockBuilder blockBuilder, String property, String value) {
if (value.startsWith('$')) {
value = value.substring(1).replaceAll('\\$value', "responseBody$property")
blockBuilder.addLine(value)
} else {
blockBuilder.addLine("responseBody$property == \"${value}\"")
}
}
protected String
protected String getBodyAsString() {
Object bodyValue = extractServerValueFromBody(request.body.serverValue)
return trimRepeatedQuotes(new JsonOutput().toJson(bodyValue))
@@ -117,7 +126,7 @@ abstract class SpockMethodBodyBuilder {
if (bodyValue instanceof GString) {
bodyValue = extractValue(bodyValue, { DslProperty dslProperty -> dslProperty.serverValue })
} else {
bodyValue = JsonConverter.transformValues(bodyValue, { it instanceof DslProperty ? it.serverValue : it })
bodyValue = MapConverter.transformValues(bodyValue, { it instanceof DslProperty ? it.serverValue : it })
}
return bodyValue
}
@@ -147,28 +156,15 @@ abstract class SpockMethodBodyBuilder {
}
protected void processBodyElement(BlockBuilder blockBuilder, String property, Object value) {
blockBuilder.addLine("responseBody$property == ${value}")
}
protected void processBodyElement(BlockBuilder blockBuilder, String property, String value) {
if (value.startsWith('$')) {
value = value.substring(1).replaceAll('\\$value', "responseBody$property")
blockBuilder.addLine(value)
} else {
blockBuilder.addLine("responseBody$property == '''${value}'''")
}
}
protected void processBodyElement(BlockBuilder blockBuilder, String property, Pattern pattern) {
blockBuilder.addLine("responseBody$property ==~ java.util.regex.Pattern.compile('${pattern.pattern()}')")
}
protected void processBodyElement(BlockBuilder blockBuilder, String property, DslProperty dslProperty) {
processBodyElement(blockBuilder, property, dslProperty.serverValue)
protected void appendJsonPath(BlockBuilder blockBuilder, String json) {
blockBuilder.addLine("DocumentContext parsedJson = JsonPath.parse($json)")
}
protected void processBodyElement(BlockBuilder blockBuilder, String property, ExecutionProperty exec) {
blockBuilder.addLine("${exec.insertValue("responseBody$property")}")
blockBuilder.addLine("${exec.insertValue("parsedJson.read('\\\$$property')")}")
}
protected void processBodyElement(BlockBuilder blockBuilder, String property, Map.Entry entry) {

View File

@@ -10,7 +10,7 @@ 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.JsonConverter.transformValues
import static io.codearte.accurest.util.MapConverter.transformValues
@TypeChecked
abstract class BaseWireMockStubStrategy {

View File

@@ -1,21 +1,21 @@
package io.codearte.accurest.dsl
import com.github.tomakehurst.wiremock.http.RequestMethod
import com.github.tomakehurst.wiremock.matching.RequestPattern
import com.github.tomakehurst.wiremock.matching.ValuePattern
import groovy.json.JsonOutput
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 groovy.transform.TypeCheckingMode
import io.codearte.accurest.dsl.internal.*
import io.codearte.accurest.util.ContentType
import io.codearte.accurest.util.ContentUtils
import io.codearte.accurest.util.JsonPathJsonConverter
import io.codearte.accurest.util.JsonPaths
import io.codearte.accurest.util.MapConverter
import java.util.regex.Pattern
import static io.codearte.accurest.util.ContentUtils.getEqualsTypeFromContentType
import static io.codearte.accurest.util.ContentUtils.recognizeContentTypeFromContent
import static io.codearte.accurest.util.ContentUtils.recognizeContentTypeFromHeader
import static io.codearte.accurest.util.ContentUtils.recognizeContentTypeFromMatchingStrategy
import static io.codearte.accurest.util.ContentUtils.*
import static io.codearte.accurest.util.RegexpBuilders.buildGStringRegexpMatch
import static io.codearte.accurest.util.RegexpBuilders.buildJSONRegexpMatch
@@ -30,74 +30,144 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy {
}
@PackageScope
Map buildClientRequestContent() {
return buildRequestContent(new ClientRequest(request))
RequestPattern buildClientRequestContent() {
RequestPattern requestPattern = new RequestPattern()
appendMethod(requestPattern)
appendHeaders(requestPattern)
appendUrl(requestPattern)
appendQueryParameters(requestPattern)
appendBody(requestPattern)
return requestPattern
}
private Map<String, Object> buildRequestContent(ClientRequest request) {
return ([method : request?.method?.clientValue,
headers : buildClientRequestHeadersSection(request.headers)
] << appendUrl(request) << appendQueryParameters(request) << appendBody(request)).findAll { it.value }
private void appendMethod(RequestPattern requestPattern) {
if(!request.method) {
return
}
requestPattern.setMethod(RequestMethod.fromString(request.method.clientValue?.toString()))
}
private Map<String, Object> appendUrl(ClientRequest clientRequest) {
Object urlPath = clientRequest?.urlPath?.clientValue
private void appendBody(RequestPattern requestPattern) {
if (!request.body) {
return
}
ContentType contentType = tryToGetContentType()
if (contentType == ContentType.JSON) {
JsonPaths values = JsonPathJsonConverter.transformToJsonPathWithStubsSideValues(getMatchingStrategyFromBody(request.body)?.clientValue)
if (values.empty) {
requestPattern.bodyPatterns = [new ValuePattern(jsonCompareMode: org.skyscreamer.jsonassert.JSONCompareMode.LENIENT,
equalToJson: JsonOutput.toJson(getMatchingStrategy(request.body.clientValue).clientValue) ) ]
} else {
requestPattern.bodyPatterns = values.collect { new ValuePattern(matchesJsonPath: it.jsonPath) } ?: null
}
} else if (contentType == ContentType.XML) {
requestPattern.bodyPatterns = [new ValuePattern(equalToXml: getMatchingStrategy(request.body.clientValue).clientValue.toString())]
} else if (containsPattern(request?.body)) {
MatchingStrategy matchingStrategy = appendBodyRegexpMatchPattern(request.body)
requestPattern.bodyPatterns = [convertToValuePattern(matchingStrategy)]
} else {
requestPattern.bodyPatterns = [convertToValuePattern(getMatchingStrategy(request.body.clientValue))]
}
}
private ContentType tryToGetContentType() {
ContentType contentType = recognizeContentTypeFromHeader(request.headers)
if (contentType == ContentType.UNKNOWN) {
if (!request.body.clientValue) {
return ContentType.UNKNOWN
}
return ContentUtils.getClientContentType(request.body.clientValue)
}
return contentType
}
private void appendHeaders(RequestPattern requestPattern) {
if(!request.headers) {
return
}
request.headers.entries.each {
requestPattern.addHeader(it.name, convertToValuePattern(it.clientValue))
}
}
private void appendUrl(RequestPattern requestPattern) {
Object urlPath = request?.urlPath?.clientValue
if (urlPath) {
return [urlPath: urlPath]
requestPattern.setUrlPath(urlPath.toString())
}
Object url = clientRequest?.url?.clientValue
return url instanceof Pattern ? [urlPattern: url.pattern()] : [url: url]
}
private Map<String, Object> appendQueryParameters(ClientRequest clientRequest) {
QueryParameters queryParameters = clientRequest?.urlPath?.queryParameters ?: clientRequest?.url?.queryParameters
return queryParameters && !queryParameters.parameters.isEmpty() ?
[queryParameters: buildUrlPathQueryParameters(queryParameters)] : [:]
}
private Map<String, Object> buildUrlPathQueryParameters(QueryParameters queryParameters) {
return queryParameters.parameters.collectEntries { QueryParameter param ->
parseQueryParameter(param.name, param.clientValue)
if(!request.url) {
return
}
Object url = request?.url?.clientValue
if(url instanceof Pattern) {
requestPattern.setUrlPattern(url.pattern())
} else {
requestPattern.setUrl(url.toString())
}
}
protected Map<String, Object> parseQueryParameter(String name, MatchingStrategy matchingStrategy) {
return buildQueryParameter(name, matchingStrategy.clientValue, matchingStrategy.type)
private void appendQueryParameters(RequestPattern requestPattern) {
QueryParameters queryParameters = request?.urlPath?.queryParameters ?: request?.url?.queryParameters
queryParameters?.parameters?.each {
requestPattern.addQueryParam(it.name, convertToValuePattern(it.clientValue))
}
}
protected Map<String, Object> parseQueryParameter(String name, Object value) {
return buildQueryParameter(name, value, MatchingStrategy.Type.EQUAL_TO)
@TypeChecked(TypeCheckingMode.SKIP)
private static ValuePattern convertToValuePattern(Object object) {
switch (object) {
case Pattern:
Pattern value = object as Pattern
return ValuePattern.matches(value.pattern())
case MatchingStrategy:
MatchingStrategy value = object as MatchingStrategy
switch (value.type) {
case MatchingStrategy.Type.NOT_MATCHING:
return new ValuePattern(doesNotMatch: value.clientValue)
case MatchingStrategy.Type.ABSENT:
return ValuePattern.absent()
default:
return ValuePattern."${value.type.name}"(value.clientValue)
}
default:
return ValuePattern.equalTo(object.toString())
}
}
protected Map<String, Object> parseQueryParameter(String name, Pattern pattern) {
return buildQueryParameter(name, pattern.pattern(), MatchingStrategy.Type.MATCHING)
private MatchingStrategy getMatchingStrategyFromBody(Body body) {
if(!body) {
return null
}
return getMatchingStrategy(body.clientValue)
}
private Map<String, Object> buildQueryParameter(String name, Pattern pattern, MatchingStrategy.Type type) {
return buildQueryParameter(name, pattern.pattern(), type)
private MatchingStrategy getMatchingStrategy(MatchingStrategy matchingStrategy) {
return getMatchingStrategyIncludingContentType(matchingStrategy)
}
private MatchingStrategy getMatchingStrategy(GString gString) {
if (!gString) {
return new MatchingStrategy("", MatchingStrategy.Type.EQUAL_TO)
}
def extractedValue = ContentUtils.extractValue(gString) {
it instanceof DslProperty ? it.clientValue : getStringFromGString(it)
}
def value = getStringFromGString(extractedValue)
return getMatchingStrategy(value)
}
private Map<String, Object> buildQueryParameter(String name, Object value, MatchingStrategy.Type type) {
return [(name): [(type.name) : value]]
private def getStringFromGString(Object object) {
return object instanceof GString ? object.toString() : object
}
private Map<String, Object> appendBody(ClientRequest clientRequest) {
return clientRequest.body? appendBody(clientRequest.body) : [:]
private MatchingStrategy getMatchingStrategy(Object bodyValue) {
return tryToFindMachingStrategy(bodyValue)
}
private Map<String, Object> appendBody(Body body) {
return [bodyPatterns: (appendBodyPatterns(body.clientValue))]
private MatchingStrategy tryToFindMachingStrategy(Object bodyValue) {
return new MatchingStrategy(MapConverter.transformToClientValues(bodyValue), getEqualsTypeFromContentTypeHeader())
}
private List<Map<String, Object>> appendBodyPatterns(MatchingStrategy matchingStrategy) {
return [appendBodyPattern(matchingStrategy)]
}
private List<Map<String, Object>> appendBodyPatterns(Object bodyValue) {
return appendBodyPatterns(new MatchingStrategy(bodyValue, getEqualsTypeFromContentTypeHeader()))
}
private Map<String, Object> appendBodyPattern(MatchingStrategy matchingStrategy) {
private MatchingStrategy getMatchingStrategyIncludingContentType(MatchingStrategy matchingStrategy) {
MatchingStrategy.Type type = matchingStrategy.type
Object value = matchingStrategy.clientValue
ContentType contentType = recognizeContentTypeFromMatchingStrategy(type)
@@ -105,29 +175,22 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy {
contentType = recognizeContentTypeFromContent(value)
type = getEqualsTypeFromContentType(contentType)
}
if (containsPattern(value)) {
return appendBodyRegexpMatchPattern(value, contentType)
}
return buildMatchPattern(new MatchingStrategy(parseBody(value, contentType), type))
return new MatchingStrategy(parseBody(value, contentType), type)
}
private Map<String, Object> appendBodyRegexpMatchPattern(Object value, ContentType contentType) {
private MatchingStrategy appendBodyRegexpMatchPattern(Object value, ContentType contentType) {
switch (contentType) {
case ContentType.JSON:
return buildMatchPattern(new MatchingStrategy(buildJSONRegexpMatch(value), MatchingStrategy.Type.MATCHING))
return new MatchingStrategy(buildJSONRegexpMatch(value), MatchingStrategy.Type.MATCHING)
case ContentType.UNKNOWN:
return buildMatchPattern(new MatchingStrategy(buildGStringRegexpMatch(value), MatchingStrategy.Type.MATCHING))
return new MatchingStrategy(buildGStringRegexpMatch(value), MatchingStrategy.Type.MATCHING)
case ContentType.XML:
throw new IllegalStateException("XML pattern matching is not implemented yet")
}
}
private Map<String, Object> buildMatchPattern(MatchingStrategy matchingStrategy) {
Map<String, ? extends Object> result = [(matchingStrategy.type.name): matchingStrategy.clientValue.toString()]
if (matchingStrategy.type == MatchingStrategy.Type.EQUAL_TO_JSON && matchingStrategy.jsonCompareMode) {
return result << [jsonCompareMode : (matchingStrategy.jsonCompareMode.toString())]
}
return result
private MatchingStrategy appendBodyRegexpMatchPattern(Object value) {
return appendBodyRegexpMatchPattern(value, ContentType.UNKNOWN)
}
private boolean containsPattern(GString bodyAsValue) {

View File

@@ -1,7 +1,9 @@
package io.codearte.accurest.dsl
import com.github.tomakehurst.wiremock.http.HttpHeader
import com.github.tomakehurst.wiremock.http.HttpHeaders
import com.github.tomakehurst.wiremock.http.ResponseDefinition
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
@@ -22,23 +24,31 @@ class WireMockResponseStubStrategy extends BaseWireMockStubStrategy {
}
@PackageScope
Map buildClientResponseContent() {
return buildResponseContent(new ClientResponse(response))
ResponseDefinition buildClientResponseContent() {
ResponseDefinition responseDefinition = new ResponseDefinition()
responseDefinition.setStatus(response.status.clientValue as Integer)
appendHeaders(responseDefinition)
appendBody(responseDefinition)
return responseDefinition
}
private Map<String, Object> buildResponseContent(ClientResponse response) {
return ([status : response?.status?.clientValue,
headers: buildClientResponseHeadersSection(response.headers)
] << appendBody(response)).findAll { it.value }
private void appendHeaders(ResponseDefinition responseDefinition) {
if(!(response.headers)) {
return
}
responseDefinition.setHeaders(new HttpHeaders(response.headers.entries?.collect { new HttpHeader(it.name, it.clientValue.toString()) }))
}
private Map<String, Object> appendBody(ClientResponse response) {
Object body = response?.body?.clientValue
private void appendBody(ResponseDefinition responseDefinition) {
if (!response.body) {
return
}
Object body = response.body.clientValue
ContentType contentType = recognizeContentTypeFromHeader(response.headers)
if (contentType == ContentType.UNKNOWN) {
contentType = recognizeContentTypeFromContent(body)
}
return body != null ? [body: parseBody(body, contentType)] : [:]
responseDefinition.setBody(parseBody(body, contentType))
}

View File

@@ -1,6 +1,8 @@
package io.codearte.accurest.dsl
import groovy.json.JsonOutput
import com.github.tomakehurst.wiremock.http.ResponseDefinition
import com.github.tomakehurst.wiremock.matching.RequestPattern
import com.github.tomakehurst.wiremock.stubbing.StubMapping
import groovy.transform.CompileDynamic
import groovy.transform.CompileStatic
@@ -19,11 +21,14 @@ class WireMockStubStrategy {
@CompileDynamic
String toWireMockClientStub() {
def wiremockStubDefinition = [request : wireMockRequestStubStrategy.buildClientRequestContent(),
response: wireMockResponseStubStrategy.buildClientResponseContent()]
StubMapping stubMapping = new StubMapping()
RequestPattern request = wireMockRequestStubStrategy.buildClientRequestContent()
ResponseDefinition response = wireMockResponseStubStrategy.buildClientResponseContent()
if (priority) {
wiremockStubDefinition.priority = priority
stubMapping.priority = priority
}
return JsonOutput.prettyPrint(JsonOutput.toJson(wiremockStubDefinition))
stubMapping.request = request
stubMapping.response = response
return StubMapping.buildJsonStringFor(stubMapping)
}
}

View File

@@ -2,7 +2,7 @@ package io.codearte.accurest.dsl.internal
import groovy.json.JsonOutput
import groovy.transform.CompileStatic
import io.codearte.accurest.util.JsonConverter
import io.codearte.accurest.util.MapConverter
import java.util.regex.Pattern
@@ -17,7 +17,7 @@ class JsonStructureConverter {
Closure<String> performAdditionalLogicOnSerializedJson,
Closure convertSerializedJsonToSth) {
LinkedList<Object> queue = new LinkedList<>()
def transformedJson = JsonConverter.transformValues(parsedJson, {
def transformedJson = MapConverter.transformValues(parsedJson, {
if(retrievePlaceholders(it)) {
queue.push(it)
return TEMPORARY_PLACEHOLDER

View File

@@ -34,7 +34,7 @@ class MatchingStrategy extends DslProperty {
enum Type {
EQUAL_TO("equalTo"), CONTAINS("contains"), MATCHING("matches"), NOT_MATCHING("doesNotMatch"),
EQUAL_TO("equalTo"), CONTAINS("containing"), MATCHING("matches"), NOT_MATCHING("doesNotMatch"),
EQUAL_TO_JSON("equalToJson"), EQUAL_TO_XML("equalToXml"), ABSENT("absent")
final String name

View File

@@ -1,5 +1,6 @@
package io.codearte.accurest.util
import groovy.json.JsonException
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import groovy.transform.TypeChecked
import groovy.util.logging.Slf4j
@@ -18,6 +19,10 @@ import static org.apache.commons.lang3.StringEscapeUtils.escapeXml11
@Slf4j
class ContentUtils {
public static final Closure GET_STUB_SIDE = {
it instanceof DslProperty ? it.clientValue : it
}
private static final Pattern TEMPORARY_PATTERN_HOLDER = Pattern.compile('REGEXP>>(.*)<<')
private static final String JSON_VALUE_PATTERN_FOR_REGEX = 'REGEXP>>%s<<'
@@ -57,7 +62,57 @@ class ContentUtils {
return extractValueForGString(bodyAsValue, valueProvider)
}
}
}
public static ContentType getClientContentType(GString bodyAsValue) {
try {
extractValueForJSON(bodyAsValue, GET_STUB_SIDE)
return ContentType.JSON
} catch(JsonException e) {
try {
new XmlSlurper().parseText(extractValueForXML(bodyAsValue, GET_STUB_SIDE).toString())
return ContentType.XML
} catch (Exception exception) {
extractValueForGString(bodyAsValue, GET_STUB_SIDE)
return ContentType.UNKNOWN
}
}
}
public static ContentType getClientContentType(String bodyAsValue) {
try {
new JsonSlurper().parseText(bodyAsValue)
return ContentType.JSON
} catch(JsonException e) {
try {
new XmlSlurper().parseText(bodyAsValue)
return ContentType.XML
} catch (Exception exception) {
return ContentType.UNKNOWN
}
}
}
public static ContentType getClientContentType(Object bodyAsValue) {
return ContentType.UNKNOWN
}
public static ContentType getClientContentType(Map bodyAsValue) {
try {
JsonOutput.toJson(bodyAsValue)
return ContentType.JSON
} catch (Exception ignore) {
return ContentType.UNKNOWN
}
}
public static ContentType getClientContentType(List bodyAsValue) {
try {
JsonOutput.toJson(bodyAsValue)
return ContentType.JSON
} catch (Exception ignore) {
return ContentType.UNKNOWN
}
}
private static GStringImpl extractValueForGString(GString bodyAsValue, Closure valueProvider) {
@@ -108,7 +163,7 @@ class ContentUtils {
}
private static Object convertAllTemporaryRegexPlaceholdersBackToPatterns(parsedJson) {
JsonConverter.transformValues(parsedJson, { Object value ->
MapConverter.transformValues(parsedJson, { Object value ->
if (value instanceof String) {
String string = (String) value
Matcher matcher = TEMPORARY_PATTERN_HOLDER.matcher(string)

View File

@@ -0,0 +1,41 @@
package io.codearte.accurest.util
import java.util.regex.Pattern
class JsonPathEntry {
final String jsonPath
final String optionalSuffix
final Object value
JsonPathEntry(String jsonPath, String optionalSuffix, Object value) {
this.jsonPath = jsonPath
this.optionalSuffix = optionalSuffix
this.value = value
}
List<String> buildJsonPathComparison(String parsedJsonVariable) {
if (optionalSuffix) {
return ["!${parsedJsonVariable}.read('''${jsonPath}''', JSONArray).empty"]
} else if (traversesOverCollections()) {
return ["${parsedJsonVariable}.read('''${jsonPath}''', JSONArray).size() == 1",
"${parsedJsonVariable}.read('''${jsonPath}''', JSONArray).get(0) ${operator()} ${potentiallyWrappedWithQuotesValue()}"]
}
return ["${parsedJsonVariable}.read('''${jsonPath}''') ${operator()} ${potentiallyWrappedWithQuotesValue()}"]
}
private boolean traversesOverCollections() {
return jsonPath.contains('[*]')
}
String operator() {
return value instanceof Pattern ? "==~" : "=="
}
String potentiallyWrappedWithQuotesValue() {
return value instanceof Number ? value : "'''$value'''"
}
static JsonPathEntry simple(String jsonPath, Object value) {
return new JsonPathEntry(jsonPath, "", value)
}
}

View File

@@ -0,0 +1,153 @@
package io.codearte.accurest.util
import groovy.json.JsonSlurper
import io.codearte.accurest.dsl.internal.DslProperty
import io.codearte.accurest.dsl.internal.ExecutionProperty
import java.util.regex.Pattern
/**
* @author Marcin Grzejszczak
*/
class JsonPathJsonConverter {
private static final Boolean SERVER_SIDE = false
private static final Boolean CLIENT_SIDE = true
public static final String ROOT_JSON_PATH_ELEMENT = '$'
public static final String ALL_ELEMENTS = "[*]"
public static JsonPaths transformToJsonPathWithTestsSideValues(def json) {
return transformToJsonPathWithValues(json, SERVER_SIDE)
}
public static JsonPaths transformToJsonPathWithStubsSideValues(def json) {
return transformToJsonPathWithValues(json, CLIENT_SIDE)
}
private static JsonPaths transformToJsonPathWithValues(def json, boolean clientSide) {
if(!json) {
return new JsonPaths()
}
JsonPaths pathsAndValues = [] as Set
Object convertedJson = getClientOrServerSideValues(json, clientSide)
traverseRecursivelyForKey(convertedJson, ROOT_JSON_PATH_ELEMENT) { String key, Object value ->
if (value instanceof ExecutionProperty) {
return
}
JsonPathEntry entry = getValueToInsert(key, value)
pathsAndValues.add(entry)
}
return pathsAndValues
}
private static Object getClientOrServerSideValues(json, boolean clientSide) {
return MapConverter.transformValues(json) {
boolean dslProp = it instanceof DslProperty
if (dslProp) {
DslProperty dslProperty = ((DslProperty) it)
return clientSide ?
getClientOrServerSideValues(dslProperty.clientValue, clientSide) : getClientOrServerSideValues(dslProperty.serverValue, clientSide)
}
return it
}
}
protected static def traverseRecursively(Class parentType, String key, def value, Closure closure) {
if (value instanceof String && value) {
try {
def json = new JsonSlurper().parseText(value)
if (json instanceof Map) {
return convertWithKey(parentType, key, json, closure)
}
} catch (Exception ignore) {
return closure(key, value)
}
} else if (isAnEntryWithNonCollectionLikeValue(value)) {
return convertWithKey(List, key, value as Map, closure)
} else if (isAnEntryWithoutNestedStructures(value)) {
return convertWithKey(List, key, value as Map, closure)
} else if (value instanceof Map) {
return convertWithKey(Map, key, value as Map, closure)
} else if (value instanceof List) {
value.each { def element ->
traverseRecursively(List, "$key[*]", element, closure)
}
return value
}
try {
return closure(key, value)
} catch (Exception ignore) {
return value
}
}
private static boolean isAnEntryWithNonCollectionLikeValue(def value) {
if (!(value instanceof Map)) {
return false
}
Map valueAsMap = ((Map) value)
boolean mapHasOneEntry = valueAsMap.size() == 1
if (!mapHasOneEntry) {
return false
}
Object valueOfEntry = valueAsMap.entrySet().first().value
return !(valueOfEntry instanceof Map || valueOfEntry instanceof List)
}
private static boolean isAnEntryWithoutNestedStructures(def value) {
if (!(value instanceof Map)) {
return false
}
Map valueAsMap = ((Map) value)
return valueAsMap.entrySet().every { Map.Entry entry ->
[String, Number].any { entry.value.getClass().isAssignableFrom(it) }
}
}
private static Map convertWithKey(Class parentType, String parentKey, Map map, Closure closureToExecute) {
return map.collectEntries {
String entrykey, value ->
[entrykey, traverseRecursively(parentType, "${parentKey}.${entrykey}", value, closureToExecute)]
}
}
private static void traverseRecursivelyForKey(def json, String rootKey, Closure closure) {
traverseRecursively(Map, rootKey, json, closure)
}
private static JsonPathEntry getValueToInsert(String key, Object value) {
return convertToListElementFiltering(key, value)
}
protected static JsonPathEntry convertToListElementFiltering(String key, Object value) {
if (key.endsWith(ALL_ELEMENTS)) {
int lastAllElements = key.lastIndexOf(ALL_ELEMENTS)
String keyWithoutAllElements = key.substring(0, lastAllElements)
return JsonPathEntry.simple("""$keyWithoutAllElements[?(@ ${compareWith(value)})]""".toString(), value)
}
return getKeyForTraversalOfListWithNonPrimitiveTypes(key, value)
}
private static JsonPathEntry getKeyForTraversalOfListWithNonPrimitiveTypes(String key, Object value) {
int lastDot = key.lastIndexOf('.')
String keyWithoutLastElement = key.substring(0, lastDot)
String lastElement = key.substring(lastDot + 1).replaceAll(~/\[\*\]/, "")
return new JsonPathEntry(
"""$keyWithoutLastElement[?(@.$lastElement ${compareWith(value)})]""".toString(),
lastElement,
value
)
}
protected static String compareWith(Object value) {
if (value instanceof Pattern) {
return """=~ /${(value as Pattern).pattern()}/"""
}
return """== ${potentiallyWrappedWithQuotesValue(value)}"""
}
protected static String potentiallyWrappedWithQuotesValue(Object value) {
return value instanceof Number ? value : "'$value'"
}
}

View File

@@ -0,0 +1,23 @@
package io.codearte.accurest.util
class JsonPaths extends HashSet<JsonPathEntry> {
Object getAt(String key) {
return find {
it.jsonPath == key
}?.value
}
Object putAt(String key, Object value) {
JsonPathEntry entry = find {
it.jsonPath == key
}
if (!entry) {
return null
}
Object oldValue = entry.value
add(new JsonPathEntry(entry.jsonPath, entry.optionalSuffix, value))
return oldValue
}
}

View File

@@ -1,15 +1,16 @@
package io.codearte.accurest.util
import groovy.json.JsonSlurper
import io.codearte.accurest.dsl.internal.DslProperty
/**
* @author Marcin Grzejszczak
*/
class JsonConverter {
class MapConverter {
private static Map convert(Map map, Closure closure) {
return map.collectEntries {
key, value ->
[key, transformValues(value, closure)]
static def transformToClientValues(def value) {
return transformValues(value) {
it instanceof DslProperty ? it.clientValue : it
}
}
@@ -35,4 +36,11 @@ class JsonConverter {
}
}
private static Map convert(Map map, Closure closure) {
return map.collectEntries {
key, value ->
[key, transformValues(value, closure)]
}
}
}

View File

@@ -26,8 +26,8 @@ class JaxRsClientSpockMethodBuilderSpec extends Specification {
when:
builder.appendTo(blockBuilder)
then:
blockBuilder.toString().contains("responseBody.property1 == '''a'''")
blockBuilder.toString().contains("responseBody.property2 == '''b'''")
blockBuilder.toString().contains("\$[?(@.property1 == 'a')]")
blockBuilder.toString().contains("\$[?(@.property2 == 'b')]")
}
@Issue("#79")
@@ -54,9 +54,9 @@ class JaxRsClientSpockMethodBuilderSpec extends Specification {
when:
builder.appendTo(blockBuilder)
then:
blockBuilder.toString().contains("responseBody.property1 == '''a'''")
blockBuilder.toString().contains("responseBody.property2[0].a == '''sth'''")
blockBuilder.toString().contains("responseBody.property2[1].b == '''sthElse'''")
blockBuilder.toString().contains("\$[?(@.property1 == 'a')]")
blockBuilder.toString().contains("\$.property2[*][?(@.a == 'sth')]")
blockBuilder.toString().contains("\$.property2[*][?(@.b == 'sthElse')]")
}
@Issue("#82")
@@ -128,8 +128,8 @@ class JaxRsClientSpockMethodBuilderSpec extends Specification {
when:
builder.appendTo(blockBuilder)
then:
blockBuilder.toString().contains("responseBody[0].property1 == '''a'''")
blockBuilder.toString().contains("responseBody[1].property2 == '''b'''")
blockBuilder.toString().contains("\$[*][?(@.property1 == 'a')]")
blockBuilder.toString().contains("\$[*][?(@.property2 == 'b')]")
}
def "should generate assertions for array inside response body element"() {
@@ -154,8 +154,8 @@ class JaxRsClientSpockMethodBuilderSpec extends Specification {
when:
builder.appendTo(blockBuilder)
then:
blockBuilder.toString().contains("responseBody.property1[0].property2 == '''test1'''")
blockBuilder.toString().contains("responseBody.property1[1].property3 == '''test2'''")
blockBuilder.toString().contains("\$.property1[*][?(@.property3 == 'test2')]")
blockBuilder.toString().contains("\$.property1[*][?(@.property2 == 'test1')]")
}
def "should generate assertions for nested objects in response body"() {
@@ -180,8 +180,8 @@ class JaxRsClientSpockMethodBuilderSpec extends Specification {
when:
builder.appendTo(blockBuilder)
then:
blockBuilder.toString().contains("responseBody.property1 == '''a'''")
blockBuilder.toString().contains("responseBody.property2.property3 == '''b'''")
blockBuilder.toString().contains("\$.property2[?(@.property3 == 'b')]")
blockBuilder.toString().contains("\$[?(@.property1 == 'a')]")
}
def "should generate regex assertions for map objects in response body"() {
@@ -212,8 +212,8 @@ class JaxRsClientSpockMethodBuilderSpec extends Specification {
when:
builder.appendTo(blockBuilder)
then:
blockBuilder.toString().contains("responseBody.property1 == '''a'''")
blockBuilder.toString().contains("responseBody.property2 ==~ java.util.regex.Pattern.compile('[0-9]{3}')")
blockBuilder.toString().contains("\$[?(@.property2 =~ /[0-9]{3}/)]")
blockBuilder.toString().contains("\$[?(@.property1 == 'a')]")
}
def "should generate regex assertions for string objects in response body"() {
@@ -238,8 +238,8 @@ class JaxRsClientSpockMethodBuilderSpec extends Specification {
when:
builder.appendTo(blockBuilder)
then:
blockBuilder.toString().contains("responseBody.property1 == '''a'''")
blockBuilder.toString().contains("responseBody.property2 ==~ java.util.regex.Pattern.compile('[0-9]{3}')")
blockBuilder.toString().contains("\$[?(@.property2 =~ /[0-9]{3}/)]")
blockBuilder.toString().contains("\$[?(@.property1 == 'a')]")
}
def "should ignore 'Accept' header and use 'request' method"() {
@@ -335,8 +335,8 @@ class JaxRsClientSpockMethodBuilderSpec extends Specification {
spockTest.contains("queryParam('age', '99'")
spockTest.contains("queryParam('name', 'Denis.Stepanov'")
spockTest.contains("queryParam('email', 'bob@email.com'")
spockTest.contains("responseBody.property1 == '''a'''")
spockTest.contains("responseBody.property2 == '''b'''")
spockTest.contains('$[?(@.property2 == \'b\')]')
spockTest.contains('$[?(@.property1 == \'a\')]')
}
def "should generate test for empty body"() {
@@ -372,12 +372,14 @@ class JaxRsClientSpockMethodBuilderSpec extends Specification {
body "test"
}
}
JaxRsClientSpockMethodBodyBuilder builder = new JaxRsClientSpockMethodBodyBuilder(contractDsl)
MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.appendTo(blockBuilder)
def spockTest = blockBuilder.toString()
then:
spockTest.contains("responseBody == '''test'''")
spockTest.contains('def responseBody = (response.body.asString())')
spockTest.contains('responseBody == "test"')
}
}

View File

@@ -3,15 +3,13 @@ package io.codearte.accurest.builder
import io.codearte.accurest.dsl.GroovyDsl
import spock.lang.Issue
import spock.lang.Specification
import spock.lang.Unroll
/**
* @author Jakub Kubrynski
*/
class MockMvcSpockMethodBuilderSpec extends Specification {
@Unroll
def "should generate assertions for simple response body for [#spockMethodBuilder]"() {
def "should generate assertions for simple response body"() {
given:
GroovyDsl contractDsl = GroovyDsl.make {
request {
@@ -26,13 +24,13 @@ class MockMvcSpockMethodBuilderSpec extends Specification {
}"""
}
}
SpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.appendTo(blockBuilder)
then:
blockBuilder.toString().contains("responseBody.property1 == '''a'''")
blockBuilder.toString().contains("responseBody.property2 == '''b'''")
blockBuilder.toString().contains("\$[?(@.property1 == 'a')]")
blockBuilder.toString().contains("\$[?(@.property2 == 'b')]")
}
@Issue("#79")
@@ -54,14 +52,14 @@ class MockMvcSpockMethodBuilderSpec extends Specification {
)
}
}
SpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.appendTo(blockBuilder)
then:
blockBuilder.toString().contains("responseBody.property1 == '''a'''")
blockBuilder.toString().contains("responseBody.property2[0].a == '''sth'''")
blockBuilder.toString().contains("responseBody.property2[1].b == '''sthElse'''")
blockBuilder.toString().contains("\$[?(@.property1 == 'a')]")
blockBuilder.toString().contains("\$.property2[*][?(@.a == 'sth')]")
blockBuilder.toString().contains("\$.property2[*][?(@.b == 'sthElse')]")
}
@Issue("#82")
@@ -79,7 +77,7 @@ class MockMvcSpockMethodBuilderSpec extends Specification {
status 200
}
}
SpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.appendTo(blockBuilder)
@@ -102,7 +100,7 @@ class MockMvcSpockMethodBuilderSpec extends Specification {
status 200
}
}
SpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.appendTo(blockBuilder)
@@ -128,13 +126,13 @@ class MockMvcSpockMethodBuilderSpec extends Specification {
}]"""
}
}
SpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.appendTo(blockBuilder)
then:
blockBuilder.toString().contains("responseBody[0].property1 == '''a'''")
blockBuilder.toString().contains("responseBody[1].property2 == '''b'''")
blockBuilder.toString().contains("\$[*][?(@.property1 == 'a')]")
blockBuilder.toString().contains("\$[*][?(@.property2 == 'b')]")
}
def "should generate assertions for array inside response body element"() {
@@ -154,13 +152,13 @@ class MockMvcSpockMethodBuilderSpec extends Specification {
}"""
}
}
SpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.appendTo(blockBuilder)
then:
blockBuilder.toString().contains("responseBody.property1[0].property2 == '''test1'''")
blockBuilder.toString().contains("responseBody.property1[1].property3 == '''test2'''")
blockBuilder.toString().contains("\$.property1[*][?(@.property3 == 'test2')]")
blockBuilder.toString().contains("\$.property1[*][?(@.property2 == 'test1')]")
}
def "should generate assertions for nested objects in response body"() {
@@ -180,13 +178,13 @@ class MockMvcSpockMethodBuilderSpec extends Specification {
'''
}
}
SpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.appendTo(blockBuilder)
then:
blockBuilder.toString().contains("responseBody.property1 == '''a'''")
blockBuilder.toString().contains("responseBody.property2.property3 == '''b'''")
blockBuilder.toString().contains("\$.property2[?(@.property3 == 'b')]")
blockBuilder.toString().contains("\$[?(@.property1 == 'a')]")
}
def "should generate regex assertions for map objects in response body"() {
@@ -212,13 +210,13 @@ class MockMvcSpockMethodBuilderSpec extends Specification {
}
}
SpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.appendTo(blockBuilder)
then:
blockBuilder.toString().contains("responseBody.property1 == '''a'''")
blockBuilder.toString().contains("responseBody.property2 ==~ java.util.regex.Pattern.compile('[0-9]{3}')")
blockBuilder.toString().contains("\$[?(@.property2 =~ /[0-9]{3}/)]")
blockBuilder.toString().contains("\$[?(@.property1 == 'a')]")
}
def "should generate regex assertions for string objects in response body"() {
@@ -238,14 +236,13 @@ class MockMvcSpockMethodBuilderSpec extends Specification {
}
}
SpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.appendTo(blockBuilder)
then:
blockBuilder.toString().contains("responseBody.property1 == '''a'''")
blockBuilder.toString().contains("responseBody.property2 ==~ java.util.regex.Pattern.compile('[0-9]{3}')")
blockBuilder.toString().contains("\$[?(@.property2 =~ /[0-9]{3}/)]")
blockBuilder.toString().contains("\$[?(@.property1 == 'a')]")
}
def "should generate a call with an url path and query parameters"() {
@@ -278,15 +275,15 @@ class MockMvcSpockMethodBuilderSpec extends Specification {
"""
}
}
SpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.appendTo(blockBuilder)
def spockTest = blockBuilder.toString()
then:
spockTest.contains('get("/users?limit=10&offset=20&filter=email&sort=name&search=55&age=99&name=Denis.Stepanov&email=bob@email.com")')
spockTest.contains("responseBody.property1 == '''a'''")
spockTest.contains("responseBody.property2 == '''b'''")
spockTest.contains('$[?(@.property2 == \'b\')]')
spockTest.contains('$[?(@.property1 == \'a\')]')
}
def "should generate test for empty body"() {
@@ -301,7 +298,7 @@ class MockMvcSpockMethodBuilderSpec extends Specification {
status 406
}
}
SpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.appendTo(blockBuilder)
@@ -322,45 +319,14 @@ class MockMvcSpockMethodBuilderSpec extends Specification {
body "test"
}
}
SpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.appendTo(blockBuilder)
def spockTest = blockBuilder.toString()
then:
spockTest.contains('def responseBody = (response.body.asString())')
spockTest.contains("responseBody == '''test'''")
}
@Issue("#127")
def 'should use "stub" as an alias for "client"'() {
given:
GroovyDsl contractDsl = GroovyDsl.make {
request {
method "GET"
url "test"
}
response {
status 200
body(
property: value(
stub(123),
test(123)
)
)
headers {
header('Content-Type': 'application/json')
}
}
}
MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.appendTo(blockBuilder)
then:
blockBuilder.toString().contains("responseBody.property == 123")
spockTest.contains('responseBody == "test"')
}
@Issue('113')
@@ -387,7 +353,7 @@ class MockMvcSpockMethodBuilderSpec extends Specification {
}
}
}
SpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.appendTo(blockBuilder)
@@ -420,7 +386,7 @@ class MockMvcSpockMethodBuilderSpec extends Specification {
}
}
}
SpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.appendTo(blockBuilder)
@@ -429,31 +395,38 @@ class MockMvcSpockMethodBuilderSpec extends Specification {
spockTest.contains('''response.header('Location') ==~ java.util.regex.Pattern.compile('^((http[s]?|ftp):\\/)\\/?([^:\\/\\s]+)(:[0-9]{1,5})?/partners/[0-9]+/users/[0-9]+')''')
}
@Issue('124')
def "should create proper response body matching for multiline strings"() {
def "should work with more complex stuff and jsonpaths"() {
given:
GroovyDsl contractDsl = GroovyDsl.make {
priority 10
request {
method 'POST'
url '/invitations'
url '/validation/client'
headers {
header 'Content-Type': 'application/json'
}
body(
bank_account_number: '0014282912345698765432161182',
email: 'foo@bar.com',
phone_number: '100299300',
personal_id: 'ABC123456'
)
}
response {
status 422
body(
message: "First line\n" +
" Second line"
)
status 200
body(errors: [
[property: "bank_account_number", message: "incorrect_format"]
])
}
}
SpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.appendTo(blockBuilder)
def spockTest = blockBuilder.toString()
then:
spockTest.contains("""responseBody.message == '''First line
Second line'''""")
spockTest.contains('''$.errors[*][?(@.property == 'bank_account_number')]''')
spockTest.contains('''$.errors[*][?(@.message == 'incorrect_format')]''')
}
}

View File

@@ -1,52 +0,0 @@
package io.codearte.accurest.dsl
import groovy.json.JsonSlurper
import spock.lang.Specification
class WireMockGroovyDslResponseSpec extends Specification {
def 'should generate response without body for client side'() {
given:
GroovyDsl dsl = GroovyDsl.make {
response {
status 200
}
}
expect:
new WireMockResponseStubStrategy(dsl).buildClientResponseContent() == new JsonSlurper().parseText(expectedStub)
where:
expectedStub << ['''
{
"status": 200
}
''',
'''
{
"status": 200
}
''']
}
def 'should generate headers for response for client side'() {
given:
GroovyDsl dsl = GroovyDsl.make {
response {
headers {
header 'Content-Type', $(client('text/xml'), server('text/*'))
}
status 200
}
}
expect:
new WireMockResponseStubStrategy(dsl).buildClientResponseContent() == new JsonSlurper().parseText('''
{
"headers": {
"Content-Type": "text/xml"
},
"status": 200
}
''')
}
}

View File

@@ -1,7 +1,7 @@
package io.codearte.accurest.dsl
import groovy.json.JsonBuilder
import groovy.json.JsonSlurper
import org.skyscreamer.jsonassert.JSONAssert
import spock.lang.Issue
class WireMockGroovyDslSpec extends WireMockSpec {
@@ -35,21 +35,21 @@ class WireMockGroovyDslSpec extends WireMockSpec {
when:
String wireMockStub = new WireMockStubStrategy(groovyDsl).toWireMockClientStub()
then:
new JsonSlurper().parseText(wireMockStub) == new JsonSlurper().parseText('''
{
"request": {
"method": "GET",
"urlPattern": "/[0-9]{2}"
},
"response": {
"status": 200,
"body": "{\\"id\\":\\"123\\",\\"surname\\":\\"Kowalsky\\",\\"name\\":\\"Jan\\",\\"created\\":\\"2014-02-02 12:23:43\\"}",
"headers": {
"Content-Type": "text/plain"
}
}
}
''')
JSONAssert.assertEquals('''
{
"request" : {
"urlPattern" : "/[0-9]{2}",
"method" : "GET"
},
"response" : {
"status" : 200,
"body" : "{\\"id\\":\\"123\\",\\"surname\\":\\"Kowalsky\\",\\"name\\":\\"Jan\\",\\"created\\":\\"2014-02-02 12:23:43\\"}",
"headers" : {
"Content-Type" : "text/plain"
}
}
}
''', wireMockStub, false)
and:
stubMappingIsValidWireMockStub(wireMockStub)
}
@@ -80,23 +80,23 @@ class WireMockGroovyDslSpec extends WireMockSpec {
when:
String wireMockStub = new WireMockStubStrategy(groovyDsl).toWireMockClientStub()
then:
new JsonSlurper().parseText(wireMockStub) == new JsonSlurper().parseText('''
JSONAssert.assertEquals('''
{
"request": {
"method": "GET",
"headers": {
"Content-Type": {
"equalTo": "application/vnd.pl.devoxx.aggregatr.v1+json"
}
},
"url": "/ingredients"
},
"response": {
"status": 200,
"body": "{\\"ingredients\\":[{\\"type\\":\\"MALT\\",\\"quantity\\":100},{\\"type\\":\\"WATER\\",\\"quantity\\":200},{\\"type\\":\\"HOP\\",\\"quantity\\":300},{\\"type\\":\\"YIEST\\",\\"quantity\\":400}]}"
"request" : {
"url" : "/ingredients",
"method" : "GET",
"headers" : {
"Content-Type" : {
"equalTo" : "application/vnd.pl.devoxx.aggregatr.v1+json"
}
}
},
"response" : {
"status" : 200,
"body" : "{\\"ingredients\\":[{\\"type\\":\\"MALT\\",\\"quantity\\":100},{\\"type\\":\\"WATER\\",\\"quantity\\":200},{\\"type\\":\\"HOP\\",\\"quantity\\":300},{\\"type\\":\\"YIEST\\",\\"quantity\\":400}]}"
}
}
''')
''', wireMockStub, false)
and:
stubMappingIsValidWireMockStub(wireMockStub)
}
@@ -128,7 +128,7 @@ class WireMockGroovyDslSpec extends WireMockSpec {
when:
String wireMockStub = new WireMockStubStrategy(groovyDsl).toWireMockClientStub()
then:
new JsonSlurper().parseText(wireMockStub) == new JsonSlurper().parseText('''
JSONAssert.assertEquals('''
{
"request": {
"method": "POST",
@@ -149,7 +149,7 @@ class WireMockGroovyDslSpec extends WireMockSpec {
"body": "{\\"paymentId\\":\\"4\\",\\"foundExistingPayment\\":false}"
}
}
''')
''', wireMockStub, false)
and:
stubMappingIsValidWireMockStub(wireMockStub)
}
@@ -180,21 +180,21 @@ class WireMockGroovyDslSpec extends WireMockSpec {
when:
String wireMockStub = new WireMockStubStrategy(groovyDsl).toWireMockClientStub()
then:
new JsonSlurper().parseText(wireMockStub) == new JsonSlurper().parseText('''
JSONAssert.assertEquals(('''
{
"request": {
"method": "GET",
"urlPattern": "/[0-9]{2}"
},
"response": {
"status": 200,
"body": "{\\"created\\":\\"2014-02-02 12:23:43\\",\\"id\\":\\"123\\",\\"name\\":\\"Jan\\",\\"surname\\":\\"Kowalsky\\"}",
"headers": {
"Content-Type": "text/plain"
}
"request" : {
"urlPattern" : "/[0-9]{2}",
"method" : "GET"
},
"response" : {
"status" : 200,
"body" : "{\\"created\\":\\"2014-02-02 12:23:43\\",\\"id\\":\\"123\\",\\"name\\":\\"Jan\\",\\"surname\\":\\"Kowalsky\\"}",
"headers" : {
"Content-Type" : "text/plain"
}
}
}
''')
'''), wireMockStub, false)
and:
stubMappingIsValidWireMockStub(wireMockStub)
}
@@ -227,26 +227,24 @@ class WireMockGroovyDslSpec extends WireMockSpec {
when:
String wireMockStub = new WireMockStubStrategy(groovyDsl).toWireMockClientStub()
then:
new JsonSlurper().parseText(wireMockStub) == new JsonSlurper().parseText('''
JSONAssert.assertEquals('''
{
"request": {
"method": "GET",
"urlPattern": "/[0-9]{2}",
"bodyPatterns": [
{
"equalToJson":"{\\"name\\":\\"Jan\\"}"
}
]
},
"response": {
"status": 200,
"body": "{\\"name\\":\\"Jan\\"}",
"headers": {
"Content-Type": "text/plain"
}
"request" : {
"urlPattern" : "/[0-9]{2}",
"method" : "GET",
"bodyPatterns" : [ {
"matchesJsonPath" : "$[?(@.name == 'Jan')]"
} ]
},
"response" : {
"status" : 200,
"body" : "{\\"name\\":\\"Jan\\"}",
"headers" : {
"Content-Type" : "text/plain"
}
}
}
''')
''', wireMockStub, false)
and:
stubMappingIsValidWireMockStub(wireMockStub)
}
@@ -277,22 +275,26 @@ class WireMockGroovyDslSpec extends WireMockSpec {
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,
}
}
''')
JSONAssert.assertEquals(('''
{
"request" : {
"urlPattern" : "/[0-9]{2}",
"method" : "GET",
"bodyPatterns" : [ {
"matchesJsonPath" : "$[?(@.created == '2014-02-02 12:23:43')]"
}, {
"matchesJsonPath" : "$[?(@.surname == 'Kowalsky')]"
}, {
"matchesJsonPath" : "$[?(@.name == 'Jan')]"
}, {
"matchesJsonPath" : "$[?(@.id == '123')]"
} ]
},
"response" : {
"status" : 200
}
}
'''), wireMockStub, false)
and:
stubMappingIsValidWireMockStub(wireMockStub)
}
@@ -319,27 +321,25 @@ class WireMockGroovyDslSpec extends WireMockSpec {
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
}
}
''')
JSONAssert.assertEquals(('''
{
"request" : {
"url" : "/users",
"method" : "GET",
"bodyPatterns" : [ {
"matchesJsonPath" : "$[?(@.name == 'Jan')]"
} ],
"headers" : {
"Content-Type" : {
"equalTo" : "customtype/json"
}
}
},
"response" : {
"status" : 200
}
}
'''), json, false)
and:
stubMappingIsValidWireMockStub(json)
}
@@ -364,7 +364,7 @@ class WireMockGroovyDslSpec extends WireMockSpec {
when:
String json = toWireMockClientJsonStub(groovyDsl)
then:
parseJson(json) == parseJson('''
JSONAssert.assertEquals(('''
{
"request": {
"method": "GET",
@@ -384,7 +384,7 @@ class WireMockGroovyDslSpec extends WireMockSpec {
"status": 200
}
}
''')
'''), json, false)
and:
stubMappingIsValidWireMockStub(json)
}
@@ -406,7 +406,7 @@ class WireMockGroovyDslSpec extends WireMockSpec {
when:
String json = toWireMockClientJsonStub(groovyDsl)
then:
parseJson(json) == parseJson('''
JSONAssert.assertEquals(('''
{
"request": {
"method": "GET",
@@ -421,7 +421,7 @@ class WireMockGroovyDslSpec extends WireMockSpec {
"status": 200
}
}
''')
'''), json, false)
and:
stubMappingIsValidWireMockStub(json)
}
@@ -443,7 +443,7 @@ class WireMockGroovyDslSpec extends WireMockSpec {
when:
String json = toWireMockClientJsonStub(groovyDsl)
then:
parseJson(json) == parseJson('''
JSONAssert.assertEquals(('''
{
"request": {
"method": "GET",
@@ -454,7 +454,7 @@ class WireMockGroovyDslSpec extends WireMockSpec {
"body":"<user><name>Jozo</name><jobId>&lt;test&gt;</jobId></user>"
}
}
''')
'''), json, false)
and:
stubMappingIsValidWireMockStub(json)
}
@@ -474,7 +474,7 @@ class WireMockGroovyDslSpec extends WireMockSpec {
when:
String json = toWireMockClientJsonStub(groovyDsl)
then:
parseJson(json) == parseJson('''
JSONAssert.assertEquals(('''
{
"request": {
"method": "GET",
@@ -489,7 +489,7 @@ class WireMockGroovyDslSpec extends WireMockSpec {
"status": 200
}
}
''')
'''), json, false)
and:
stubMappingIsValidWireMockStub(json)
}
@@ -511,7 +511,7 @@ class WireMockGroovyDslSpec extends WireMockSpec {
when:
String json = toWireMockClientJsonStub(groovyDsl)
then:
parseJson(json) == parseJson('''
JSONAssert.assertEquals(('''
{
"request": {
"method": "GET",
@@ -526,7 +526,7 @@ class WireMockGroovyDslSpec extends WireMockSpec {
"status": 200
}
}
''')
'''), json, false)
and:
stubMappingIsValidWireMockStub(json)
}
@@ -559,24 +559,24 @@ class WireMockGroovyDslSpec extends WireMockSpec {
when:
String wireMockStub = new WireMockStubStrategy(groovyDsl).toWireMockClientStub()
then:
new JsonSlurper().parseText(wireMockStub) == new JsonSlurper().parseText('''
JSONAssert.assertEquals(('''
{
"request": {
"method": "GET",
"urlPattern": "/[0-9]{2}",
"bodyPatterns": [
{"matches": "\\\\s*\\\\{\\\\s*\\\"personalId\\\"\\\\s*:\\\\s*\\\"?^[0-9]{11}$\\\"?\\\\s*\\\\}\\\\s*"}
]
},
"response": {
"status": 200,
"body": "{\\"name\\":\\"Jan\\"}",
"headers": {
"Content-Type": "text/plain"
}
"request" : {
"urlPattern" : "/[0-9]{2}",
"method" : "GET",
"bodyPatterns" : [ {
"matchesJsonPath" : "$[?(@.personalId =~ /^[0-9]{11}$/)]"
} ]
},
"response" : {
"status" : 200,
"body" : "{\\"name\\":\\"Jan\\"}",
"headers" : {
"Content-Type" : "text/plain"
}
}
}
''')
'''), wireMockStub, false)
and:
stubMappingIsValidWireMockStub(wireMockStub)
}
@@ -614,84 +614,35 @@ class WireMockGroovyDslSpec extends WireMockSpec {
when:
String wireMockStub = new WireMockStubStrategy(groovyDsl).toWireMockClientStub()
then:
new JsonSlurper().parseText(wireMockStub) == new JsonSlurper().parseText('''
JSONAssert.assertEquals(('''
{
"request": {
"method": "PUT",
"headers": {
"Content-Type": {
"equalTo": "application/vnd.fraud.v1+json"
}
},
"url": "/fraudcheck",
"bodyPatterns": [
{"matches": "\\\\s*\\\\{\\\\s*\\"clientPesel\\"\\\\s*:\\\\s*\\"?[0-9]{10}\\"?\\\\s*,\\\\s*\\"loanAmount\\"\\\\s*:\\\\s*\\"?123.123\\"?\\\\s*\\\\}\\\\s*"}
]
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/vnd.fraud.v1+json"
},
"body": "{\\"fraudCheckStatus\\":\\"OK\\",\\"rejectionReason\\":null}"
"request" : {
"url" : "/fraudcheck",
"method" : "PUT",
"bodyPatterns" : [ {
"matchesJsonPath" : "$[?(@.loanAmount == 123.123)]"
}, {
"matchesJsonPath" : "$[?(@.clientPesel =~ /[0-9]{10}/)]"
} ],
"headers" : {
"Content-Type" : {
"equalTo" : "application/vnd.fraud.v1+json"
}
}
},
"response" : {
"status" : 200,
"body" : "{\\"fraudCheckStatus\\":\\"OK\\",\\"rejectionReason\\":null}",
"headers" : {
"Content-Type" : "application/vnd.fraud.v1+json"
}
}
}
''')
'''), wireMockStub, false)
and:
stubMappingIsValidWireMockStub(wireMockStub)
}
def "should generate stub with GET"() {
given:
GroovyDsl groovyDsl = GroovyDsl.make {
request {
method("GET")
}
}
expect:
new WireMockRequestStubStrategy(groovyDsl).buildClientRequestContent() == new JsonSlurper().parseText('''
{
"method":"GET"
}
''')
}
def "should generate request when two elements are provided "() {
given:
GroovyDsl groovyDsl = GroovyDsl.make {
request {
method("GET")
url("/sth")
}
}
expect:
new WireMockRequestStubStrategy(groovyDsl).buildClientRequestContent() == new JsonSlurper().parseText('''
{
"method":"GET",
"url":"/sth"
}
''')
}
def "should generate request with urlPattern for client side"() {
given:
GroovyDsl groovyDsl = GroovyDsl.make {
request {
url $(
client(~/^\/[0-9]{2}$/),
server('/12')
)
}
}
expect:
new WireMockRequestStubStrategy(groovyDsl).buildClientRequestContent() == new JsonSlurper().parseText('''
{
"urlPattern":"^/[0-9]{2}$"
}
''')
}
def "should generate request with urlPath and queryParameters for client side"() {
given:
GroovyDsl groovyDsl = GroovyDsl.make {
@@ -717,7 +668,7 @@ class WireMockGroovyDslSpec extends WireMockSpec {
when:
def json = toWireMockClientJsonStub(groovyDsl)
then:
parseJson(json) == parseJson('''
JSONAssert.assertEquals(('''
{
"request": {
"method": "GET",
@@ -753,7 +704,7 @@ class WireMockGroovyDslSpec extends WireMockSpec {
"status": 200,
}
}
''')
'''), json, false)
and:
stubMappingIsValidWireMockStub(json)
}
@@ -772,7 +723,7 @@ class WireMockGroovyDslSpec extends WireMockSpec {
when:
def json = toWireMockClientJsonStub(groovyDsl)
then:
parseJson(json) == parseJson('''
JSONAssert.assertEquals(('''
{
"request": {
"method": "GET",
@@ -782,7 +733,7 @@ class WireMockGroovyDslSpec extends WireMockSpec {
"status": 200,
}
}
''')
'''), json, false)
and:
stubMappingIsValidWireMockStub(json)
}
@@ -801,7 +752,7 @@ class WireMockGroovyDslSpec extends WireMockSpec {
when:
def json = toWireMockClientJsonStub(groovyDsl)
then:
parseJson(json) == parseJson('''
JSONAssert.assertEquals(('''
{
"request": {
"method": "GET",
@@ -811,7 +762,7 @@ class WireMockGroovyDslSpec extends WireMockSpec {
"status": 200,
}
}
''')
'''), json, false)
and:
stubMappingIsValidWireMockStub(json)
}
@@ -947,7 +898,7 @@ class WireMockGroovyDslSpec extends WireMockSpec {
when:
def json = toWireMockClientJsonStub(groovyDsl)
then:
parseJson(json) == parseJson('''
JSONAssert.assertEquals(('''
{
"request": {
"method": "GET",
@@ -965,46 +916,11 @@ class WireMockGroovyDslSpec extends WireMockSpec {
"status": 200,
}
}
''')
'''), json, false)
and:
stubMappingIsValidWireMockStub(json)
}
def "should generate stub with some headers section for client side"() {
given:
GroovyDsl groovyDsl = GroovyDsl.make {
request {
headers {
header('Content-Type': 'text/xml')
header('Accept': $(
client(regex('text/.*')),
server('text/plain')
))
header('X-Custom-Header': $(
client(regex('^.*2134.*$')),
server('121345')
))
}
}
}
expect:
new WireMockRequestStubStrategy(groovyDsl).buildClientRequestContent() == new JsonSlurper().parseText('''
{
"headers": {
"Content-Type": {
"equalTo": "text/xml"
},
"Accept": {
"matches": "text/.*"
},
"X-Custom-Header": {
"matches": "^.*2134.*$"
}
}
}
''')
}
def 'should convert groovy dsl stub with rich tree Body as String to wireMock stub for the client side'() {
given:
GroovyDsl groovyDsl = GroovyDsl.make {
@@ -1046,25 +962,38 @@ class WireMockGroovyDslSpec extends WireMockSpec {
when:
String wireMockStub = new WireMockStubStrategy(groovyDsl).toWireMockClientStub()
then:
new JsonSlurper().parseText(wireMockStub) == new JsonSlurper().parseText('''
{
"request": {
"method": "GET",
"urlPattern": "/[0-9]{2}",
"bodyPatterns": [
{
"matches": "\\\\s*\\\\{\\\\s*\\"birthDate\\"\\\\s*:\\\\s*\\"?[0-9]{4}-[0-9]{2}-[0-9]{2}\\"?\\\\s*,\\\\s*\\"errors\\"\\\\s*:\\\\s*\\\\[\\\\s*\\\\{\\\\s*\\"propertyName\\"\\\\s*:\\\\s*\\"?[0-9]{2}\\"?\\\\s*,\\\\s*\\"providerValue\\"\\\\s*:\\\\s*\\"?Test\\"?\\\\s*\\\\}\\\\s*,\\\\s*\\\\{\\\\s*\\"propertyName\\"\\\\s*:\\\\s*\\"?[0-9]{2}\\"?\\\\s*,\\\\s*\\"providerValue\\"\\\\s*:\\\\s*\\"?Test\\"?\\\\s*\\\\}\\\\s*\\\\]\\\\s*,\\\\s*\\"firstName\\"\\\\s*:\\\\s*\\"?.*\\"?\\\\s*,\\\\s*\\"lastName\\"\\\\s*:\\\\s*\\"?.*\\"?\\\\s*,\\\\s*\\"personalId\\"\\\\s*:\\\\s*\\"?[0-9]{11}\\"?\\\\s*\\\\}\\\\s*"
}
] },
"response": {
"status": 200,
"body": "{\\"name\\":\\"Jan\\"}",
"headers": {
"Content-Type": "text/plain"
}
}
}
''')
JSONAssert.assertEquals(('''
{
"request" : {
"urlPattern" : "/[0-9]{2}",
"method" : "GET",
"bodyPatterns" : [ {
"matchesJsonPath" : "$.errors[*][?(@.propertyName =~ /[0-9]{2}/)]"
}, {
"matchesJsonPath" : "$.errors[*][?(@.providerValue == 'Test')]"
}, {
"matchesJsonPath" : "$.errors[*][?(@.providerValue == 'Test')]"
}, {
"matchesJsonPath" : "$[?(@.lastName =~ /.*/)]"
}, {
"matchesJsonPath" : "$.errors[*][?(@.propertyName =~ /[0-9]{2}/)]"
}, {
"matchesJsonPath" : "$[?(@.birthDate =~ /[0-9]{4}-[0-9]{2}-[0-9]{2}/)]"
}, {
"matchesJsonPath" : "$[?(@.personalId =~ /[0-9]{11}/)]"
}, {
"matchesJsonPath" : "$[?(@.firstName =~ /.*/)]"
} ]
},
"response" : {
"status" : 200,
"body" : "{\\"name\\":\\"Jan\\"}",
"headers" : {
"Content-Type" : "text/plain"
}
}
}
'''), wireMockStub, false)
}
def 'should use regexp matches when request body match is defined using a map with a pattern'() {
@@ -1097,26 +1026,34 @@ class WireMockGroovyDslSpec extends WireMockSpec {
when:
def json = toWireMockClientJsonStub(groovyDsl)
then:
parseJson(json) == parseJson('''
{
"request": {
"method": "POST",
"url": "/reissue-payment-order",
"bodyPatterns": [
{
"matches": "\\\\s*\\\\{\\\\s*\\"loanNumber\\"\\\\s*:\\\\s*\\"?999997001\\"?\\\\s*,\\\\s*\\"amount\\"\\\\s*:\\\\s*\\"?[0-9.]+\\"?\\\\s*,\\\\s*\\"currency\\"\\\\s*:\\\\s*\\"?DKK\\"?\\\\s*,\\\\s*\\"applicationName\\"\\\\s*:\\\\s*\\"?.*\\"?\\\\s*,\\\\s*\\"username\\"\\\\s*:\\\\s*\\"?.*\\"?\\\\s*,\\\\s*\\"cardId\\"\\\\s*:\\\\s*\\"?1\\"?\\\\s*\\\\}\\\\s*"
}
]
},
"response": {
"status": 200,
"body": "{\\"status\\":\\"OK\\"}",
"headers": {
"Content-Type": "application/json"
}
}
}
''')
JSONAssert.assertEquals(('''
{
"request" : {
"url" : "/reissue-payment-order",
"method" : "POST",
"bodyPatterns" : [ {
"matchesJsonPath" : "$[?(@.loanNumber == '999997001')]"
}, {
"matchesJsonPath" : "$[?(@.username =~ /.*/)]"
}, {
"matchesJsonPath" : "$[?(@.amount =~ /[0-9.]+/)]"
}, {
"matchesJsonPath" : "$[?(@.cardId == 1)]"
}, {
"matchesJsonPath" : "$[?(@.currency == 'DKK')]"
}, {
"matchesJsonPath" : "$[?(@.applicationName =~ /.*/)]"
} ]
},
"response" : {
"status" : 200,
"body" : "{\\"status\\":\\"OK\\"}",
"headers" : {
"Content-Type" : "application/json"
}
}
}
'''), json, false)
}
def "should generate stub for empty body"() {
@@ -1134,7 +1071,7 @@ class WireMockGroovyDslSpec extends WireMockSpec {
when:
def json = toWireMockClientJsonStub(groovyDsl)
then:
parseJson(json) == parseJson('''
JSONAssert.assertEquals(('''
{
"request": {
"method": "POST",
@@ -1149,7 +1086,7 @@ class WireMockGroovyDslSpec extends WireMockSpec {
"status": 406
}
}
''')
'''), json, false)
}
def "should generate stub with priority"() {
@@ -1167,7 +1104,7 @@ class WireMockGroovyDslSpec extends WireMockSpec {
when:
def json = toWireMockClientJsonStub(groovyDsl)
then:
parseJson(json) == parseJson('''
JSONAssert.assertEquals(('''
{
"priority": 9,
"request": {
@@ -1178,7 +1115,7 @@ class WireMockGroovyDslSpec extends WireMockSpec {
"status": 406
}
}
''')
'''), json, false)
}
@Issue("#127")
@@ -1198,21 +1135,19 @@ class WireMockGroovyDslSpec extends WireMockSpec {
when:
String wireMockStub = new WireMockStubStrategy(groovyDsl).toWireMockClientStub()
then:
new JsonSlurper().parseText(wireMockStub) == new JsonSlurper().parseText('''
{
"request": {
"method": "POST",
"bodyPatterns": [
{
"equalToJson": "{\\"property\\":\\"value\\"}"
}
]
},
"response": {
"status": 200
}
}
''')
JSONAssert.assertEquals(('''
{
"request" : {
"method" : "POST",
"bodyPatterns" : [ {
"matchesJsonPath" : "$[?(@.property == 'value')]"
} ]
},
"response" : {
"status" : 200
}
}
'''), wireMockStub, false)
and:
stubMappingIsValidWireMockStub(wireMockStub)
}
@@ -1234,7 +1169,7 @@ class WireMockGroovyDslSpec extends WireMockSpec {
when:
String wireMockStub = new WireMockStubStrategy(groovyDsl).toWireMockClientStub()
then:
new JsonSlurper().parseText(wireMockStub) == new JsonSlurper().parseText('''
JSONAssert.assertEquals(('''
{
"request": {
"method": "POST",
@@ -1248,7 +1183,7 @@ class WireMockGroovyDslSpec extends WireMockSpec {
"status": 200
}
}
''')
'''), wireMockStub, false)
and:
stubMappingIsValidWireMockStub(wireMockStub)
}

View File

@@ -0,0 +1,199 @@
package io.codearte.accurest.util
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import com.jayway.jsonpath.Configuration
import com.jayway.jsonpath.DocumentContext
import com.jayway.jsonpath.JsonPath
import com.jayway.jsonpath.Option
import net.minidev.json.JSONArray
import spock.lang.Specification
import spock.lang.Unroll
import java.util.regex.Pattern
class JsonPathJsonConverterSpec extends Specification {
@Unroll
def 'should convert a json with list as root to a map of path to value'() {
when:
JsonPaths pathAndValues = JsonPathJsonConverter.transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json))
then:
pathAndValues['''$[*].some.nested[?(@.json == 'with value')]'''] == 'with value'
pathAndValues['''$[*].some.nested[?(@.anothervalue == 4)]'''] == 4
pathAndValues['''$[*].some.nested.withlist[*][?(@.name == 'name1')]'''] == 'name1'
pathAndValues['''$[*].some.nested.withlist[*][?(@.name == 'name2')]'''] == 'name2'
pathAndValues['''$[*].some.nested.withlist[*].anothernested[?(@.name == 'name3')]'''] == 'name3'
and:
assertThatJsonPathsInMapAreValid(json, pathAndValues)
where:
json << [
'''
[ {
"some" : {
"nested" : {
"json" : "with value",
"anothervalue": 4,
"withlist" : [
{ "name" :"name1"} , {"name": "name2"}, {"anothernested": { "name": "name3"} }
]
}
}
},
{
"someother" : {
"nested" : {
"json" : "with value",
"anothervalue": 4,
"withlist" : [
{ "name" :"name1"} , {"name": "name2"}
]
}
}
}
]
''',
'''
[{
"someother" : {
"nested" : {
"json" : "with value",
"anothervalue": 4,
"withlist" : [
{ "name" :"name1"} , {"name": "name2"}
]
}
}
},
{
"some" : {
"nested" : {
"json" : "with value",
"anothervalue": 4,
"withlist" : [
{"name": "name2"}, {"anothernested": { "name": "name3"} }, { "name" :"name1"}
]
}
}
}
]''']
}
def 'should convert a json with a map as root to a map of path to value'() {
given:
String json = '''
{
"some" : {
"nested" : {
"json" : "with value",
"anothervalue": 4,
"withlist" : [
{ "name" :"name1"} , {"name": "name2"}
]
}
}
}
'''
when:
JsonPaths pathAndValues = JsonPathJsonConverter.transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json))
then:
pathAndValues['''$.some.nested[?(@.json == 'with value')]'''] == 'with value'
pathAndValues['''$.some.nested[?(@.anothervalue == 4)]'''] == 4
pathAndValues['''$.some.nested.withlist[*][?(@.name == 'name1')]'''] == 'name1'
pathAndValues['''$.some.nested.withlist[*][?(@.name == 'name2')]'''] == 'name2'
and:
assertThatJsonPathsInMapAreValid(json, pathAndValues)
}
def 'should convert a json with a list'() {
given:
String json = '''
{
"items" : ["HOP"]
}
'''
when:
JsonPaths pathAndValues = JsonPathJsonConverter.transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json))
then:
pathAndValues['''$.items[?(@ == 'HOP')]'''] == 'HOP'
and:
assertThatJsonPathsInMapAreValid(json, pathAndValues)
}
def 'should convert a json with a list of errors'() {
given:
String json = '''
{
"errors" : [
{ "property" : "email", "message" : "inconsistent value" },
{ "property" : "email", "message" : "inconsistent value2" }
]
}
'''
when:
JsonPaths pathAndValues = JsonPathJsonConverter.transformToJsonPathWithTestsSideValues(new JsonSlurper().parseText(json))
then:
pathAndValues['''$.errors[*][?(@.property == 'email')]'''] == 'email'
pathAndValues['''$.errors[*][?(@.message == 'inconsistent value')]'''] == 'inconsistent value'
pathAndValues['''$.errors[*][?(@.message == 'inconsistent value2')]'''] == 'inconsistent value2'
pathAndValues['''$.errors[*][?(@.property == 'email')]'''] == 'email'
and:
assertThatJsonPathsInMapAreValid(json, pathAndValues)
}
def 'should convert a map json with a regex pattern'() {
given:
List json = [
[some:
[nested: [
json: "with value",
anothervalue: 4,
withlist:
[
[name: "name2"],
[name: "name1"],
[anothernested:
[name: Pattern.compile('[a-zA-Z]+')]
],
[age: "123456789"]
]
]
]
],
[someother:
[nested: [
json: "with value",
anothervalue: 4,
withlist:
[
[name: "name2"],
[name: "name1"]
]
]
]
]
]
when:
JsonPaths pathAndValues = JsonPathJsonConverter.transformToJsonPathWithTestsSideValues(json)
then:
pathAndValues['''$[*].some.nested[?(@.json == 'with value')]'''] == 'with value'
pathAndValues['''$[*].some.nested[?(@.anothervalue == 4)]'''] == 4
pathAndValues['''$[*].some.nested.withlist[*][?(@.name == 'name1')]'''] == 'name1'
pathAndValues['''$[*].some.nested.withlist[*][?(@.name == 'name2')]''']
(pathAndValues['''$[*].some.nested.withlist[*].anothernested[?(@.name =~ /[a-zA-Z]+/)]'''] as Pattern).pattern() == '[a-zA-Z]+'
when:
pathAndValues['''$[*].some.nested.withlist[*].anothernested[?(@.name =~ /[a-zA-Z]+/)]'''] = "Kowalski"
json.some.nested.withlist[0][2].anothernested.name = "Kowalski"
then:
assertThatJsonPathsInMapAreValid(JsonOutput.prettyPrint(JsonOutput.toJson(json)), pathAndValues)
}
private void assertThatJsonPathsInMapAreValid(String json, JsonPaths pathAndValues) {
DocumentContext parsedJson = JsonPath.using(Configuration.builder().options(Option.ALWAYS_RETURN_LIST).build()).parse(json);
pathAndValues.each {
assert parsedJson.read(it.jsonPath, JSONArray).getAt(it.optionalSuffix ?: 0) == it.optionalSuffix ? [it.value] : it.value
}
}
}

View File

@@ -4,6 +4,7 @@ import io.codearte.accurest.config.AccurestConfigProperties
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.artifacts.DependencyResolveDetails
/**
* @author Jakub Kubrynski
@@ -29,6 +30,21 @@ class AccurestGradlePlugin implements Plugin<Project> {
createGenerateTestsTask(extension)
createAndConfigureGenerateWireMockClientStubsFromDslTask(extension)
deprecatedCreateAndConfigureGenerateWiremockClientStubsFromDslTask()
project.dependencies.add("testCompile", "io.codearte.accurest:accurest-core:+")
project.dependencies.add("testCompile", "com.blogspot.toomuchcoding:wiremock:0.0.1")
project.repositories { jcenter() }
project.configurations {
all {
resolutionStrategy {
eachDependency { DependencyResolveDetails details ->
if (details.requested.group == 'com.github.tomakehurst' && details.requested.name == "wiremock") {
details.useTarget("com.blogspot.toomuchcoding:wiremock:0.0.1")
}
}
}
}
}
project.afterEvaluate {
def hasIdea = project.plugins.findPlugin(IDEA_PLUGIN_CLASS)

View File

@@ -18,7 +18,6 @@ ext {
subprojects {
apply plugin: 'groovy'
repositories {
mavenCentral()
mavenLocal()

View File

@@ -48,6 +48,7 @@ subprojects {
repositories {
mavenLocal()
mavenCentral()
jcenter()
}
//Dependencies in all subprojects - http://solidsoft.wordpress.com/2014/11/13/gradle-tricks-display-dependencies-for-all-subprojects-in-multi-project-build/
@@ -84,15 +85,21 @@ subprojects {
}
project(':accurest-core') {
dependencies {
compile 'org.slf4j:slf4j-api:[1.6.0,)'
compile 'org.codehaus.plexus:plexus-utils:[3.0.0,)'
compile 'commons-io:commons-io:[2.0,)'
compile 'org.apache.commons:commons-lang3:[3.3,)'
compile 'com.google.code.gson:gson:2.3.1'
compile 'com.fasterxml.jackson.core:jackson-databind:2.4.5'
compile 'asm:asm:3.3.1'
compile 'com.blogspot.toomuchcoding:wiremock:0.0.1'
testCompile 'cglib:cglib-nodep:2.2'
testCompile 'org.objenesis:objenesis:2.1'
testCompile 'com.github.tomakehurst:wiremock:1.57'
testCompile 'org.skyscreamer:jsonassert:1.2.3'
}
}
project(':accurest-converters') {
@@ -101,7 +108,7 @@ project(':accurest-converters') {
compile 'org.apache.commons:commons-lang3:[3.0,)'
compile 'commons-io:commons-io:[2.0,)'
compile 'dk.brics.automaton:automaton:1.11-8' // needed for Xeger
testCompile 'com.github.tomakehurst:wiremock:1.57'
testCompile 'com.blogspot.toomuchcoding:wiremock:0.0.1'
testCompile 'org.hamcrest:hamcrest-all:1.3'
}
}

View File

@@ -12,7 +12,7 @@ task sourcesJar(type: Jar) {
}
artifacts {
archives javadocJar, sourcesJar
archives javadocJar, sourcesJar, repackagedJar
}
signing {