diff --git a/accurest-core/src/main/groovy/io/coderate/accurest/dsl/BaseWiremockStubStrategy.groovy b/accurest-core/src/main/groovy/io/coderate/accurest/dsl/BaseWiremockStubStrategy.groovy index 8c02509ad8..d30ace044b 100644 --- a/accurest-core/src/main/groovy/io/coderate/accurest/dsl/BaseWiremockStubStrategy.groovy +++ b/accurest-core/src/main/groovy/io/coderate/accurest/dsl/BaseWiremockStubStrategy.groovy @@ -8,19 +8,25 @@ import io.coderate.accurest.dsl.internal.WithValuePattern @CompileStatic abstract class BaseWiremockStubStrategy { protected Map buildClientHeadersSection(Headers headers) { - return createHeadersSection(headers) { - Map.Entry entry -> [(entry.key): buildClientHeaderFromValuePattern(entry.value)] + if (!headers) { + return null } + return withAssertionHeaders(headers) { + Map.Entry entry -> [(entry.key): buildClientHeaderFromValuePattern(entry.value)] + } << headers?.valueHeaders() } protected Map buildServerHeadersSection(Headers headers) { - return createHeadersSection(headers) { - Map.Entry entry -> [(entry.key): buildServerHeaderFromValuePattern(entry.value)] + if (!headers) { + return null } + return withAssertionHeaders(headers) { + Map.Entry entry -> [(entry.key): buildServerHeaderFromValuePattern(entry.value)] + } << headers.valueHeaders() } - private Map createHeadersSection(Headers headers, Closure closure) { - return headers?.entries()?.collectEntries(closure) + private Map withAssertionHeaders(Headers headers, Closure closure) { + return headers?.assertionEntries()?.collectEntries(closure) } private Map buildClientHeaderFromValuePattern(WithValuePattern valuePattern) { diff --git a/accurest-core/src/main/groovy/io/coderate/accurest/dsl/WiremockRequestStubStrategy.groovy b/accurest-core/src/main/groovy/io/coderate/accurest/dsl/WiremockRequestStubStrategy.groovy index 3693d7864e..c4dfa605d5 100644 --- a/accurest-core/src/main/groovy/io/coderate/accurest/dsl/WiremockRequestStubStrategy.groovy +++ b/accurest-core/src/main/groovy/io/coderate/accurest/dsl/WiremockRequestStubStrategy.groovy @@ -1,10 +1,11 @@ package io.coderate.accurest.dsl -import groovy.json.JsonOutput import groovy.transform.CompileStatic +import groovy.transform.PackageScope import io.coderate.accurest.dsl.internal.Request @CompileStatic +@PackageScope class WiremockRequestStubStrategy extends BaseWiremockStubStrategy { private final Request request @@ -13,31 +14,23 @@ class WiremockRequestStubStrategy extends BaseWiremockStubStrategy { this.request = groovyDsl.request } - String toWiremockClientStub() { - return JsonOutput.toJson(buildClientRequest(request)) - } - - String toWiremockServerStub() { - return JsonOutput.toJson(buildServerRequest(request)) - } - - private Map buildClientRequest(Request request) { - return getRequestSection(request, + @PackageScope Map buildClientRequestContent() { + return buildRequestContent(request, { request.urlPattern?.toClientSide() }, { buildClientHeadersSection(request.headers) }) } - private Map buildServerRequest(Request request) { - return getRequestSection(request, + @PackageScope Map buildServerRequestContent() { + return buildRequestContent(request, { request.urlPattern?.toServerSide() }, { buildServerHeadersSection(request.headers) }) } - private Map> getRequestSection(Request request, Closure buildUrlPattern, Closure buildHeaders) { - return [request: [method : request.method, - url : request.url, - urlPattern: buildUrlPattern(), - urlPath : request.urlPath, - headers : buildHeaders()].findAll { it.value }] + private Map buildRequestContent(Request request, Closure buildUrlPattern, Closure buildHeaders) { + return [method : request.method, + url : request.url, + urlPattern: buildUrlPattern(), + urlPath : request.urlPath, + headers : buildHeaders()].findAll { it.value } } } diff --git a/accurest-core/src/main/groovy/io/coderate/accurest/dsl/WiremockResponseStubStrategy.groovy b/accurest-core/src/main/groovy/io/coderate/accurest/dsl/WiremockResponseStubStrategy.groovy index 1df83b5f58..da013d07f3 100644 --- a/accurest-core/src/main/groovy/io/coderate/accurest/dsl/WiremockResponseStubStrategy.groovy +++ b/accurest-core/src/main/groovy/io/coderate/accurest/dsl/WiremockResponseStubStrategy.groovy @@ -1,37 +1,35 @@ package io.coderate.accurest.dsl -import groovy.json.JsonOutput import groovy.transform.CompileStatic +import groovy.transform.PackageScope import io.coderate.accurest.dsl.internal.Response @CompileStatic +@PackageScope class WiremockResponseStubStrategy extends BaseWiremockStubStrategy { - Response response + private final Response response - WiremockResponseStubStrategy(GroovyDsl groovyDsl) { //TODO: Or Response? + WiremockResponseStubStrategy(GroovyDsl groovyDsl) { this.response = groovyDsl.response } - String toWiremockClientStub() { - return JsonOutput.toJson(buildClientResponse(response)) + @PackageScope Map buildClientResponseContent() { + return buildResponseContent(response, + { response.getBody().forClientSide() }, + { buildClientHeadersSection(response.headers) }) } - private Map buildClientResponse(Response response) { - return getResponseSection(response, { "TODO" }, { buildClientHeadersSection(response.headers) }) + @PackageScope Map buildServerResponseContent() { + return buildResponseContent(response, + { response.getBody().forServerSide() }, + { buildServerHeadersSection(response.headers) }) } - String toWiremockServerStub() { - return JsonOutput.toJson(buildServerResponse(response)) + private Map buildResponseContent(Response response, Closure> buildBody, Closure buildHeaders) { + return [status : response.status, + body : buildBody(), + headers: buildHeaders()].findAll { it.value } } - private Map buildServerResponse(Response response) { - return getResponseSection(response, { "TODO" }, { buildServerHeadersSection(response.headers) }) - } - - private Map> getResponseSection(Response response, Closure buildUrlPattern, Closure buildHeaders) { - return [response: [status : response.status, - headers: buildHeaders()] - .findAll { it.value }] - } } diff --git a/accurest-core/src/main/groovy/io/coderate/accurest/dsl/WiremockStubStrategy.groovy b/accurest-core/src/main/groovy/io/coderate/accurest/dsl/WiremockStubStrategy.groovy new file mode 100644 index 0000000000..c4ced294d6 --- /dev/null +++ b/accurest-core/src/main/groovy/io/coderate/accurest/dsl/WiremockStubStrategy.groovy @@ -0,0 +1,26 @@ +package io.coderate.accurest.dsl + +import groovy.json.JsonOutput +import groovy.transform.CompileStatic + +@CompileStatic +class WiremockStubStrategy { + + private final WiremockRequestStubStrategy wiremockRequestStubStrategy + private final WiremockResponseStubStrategy wiremockResponseStubStrategy + + WiremockStubStrategy(GroovyDsl groovyDsl) { + this.wiremockRequestStubStrategy = new WiremockRequestStubStrategy(groovyDsl) + this.wiremockResponseStubStrategy = new WiremockResponseStubStrategy(groovyDsl) + } + + String toWiremockClientStub() { + return JsonOutput.toJson([request: wiremockRequestStubStrategy.buildClientRequestContent(), + response: wiremockResponseStubStrategy.buildClientResponseContent()]) + } + + String toWiremockServerStub() { + return JsonOutput.toJson([request: wiremockRequestStubStrategy.buildServerRequestContent(), + response: wiremockResponseStubStrategy.buildServerResponseContent()]) + } +} diff --git a/accurest-core/src/main/groovy/io/coderate/accurest/dsl/internal/Body.groovy b/accurest-core/src/main/groovy/io/coderate/accurest/dsl/internal/Body.groovy new file mode 100644 index 0000000000..8d395ee2be --- /dev/null +++ b/accurest-core/src/main/groovy/io/coderate/accurest/dsl/internal/Body.groovy @@ -0,0 +1,24 @@ +package io.coderate.accurest.dsl.internal +import groovy.transform.CompileStatic + +@CompileStatic +class Body { + + private final Map body + + Body() { + this.body = [:] + } + + Body(Map body) { + this.body = body + } + + Map forClientSide() { + return body.collectEntries { Map.Entry entry -> [(entry.key) : entry.value.clientValue] } as Map + } + + Map forServerSide() { + return body.collectEntries { Map.Entry entry -> [(entry.key) : entry.value.serverValue] } as Map + } +} diff --git a/accurest-core/src/main/groovy/io/coderate/accurest/dsl/internal/DslProperty.groovy b/accurest-core/src/main/groovy/io/coderate/accurest/dsl/internal/DslProperty.groovy new file mode 100644 index 0000000000..f52eabef59 --- /dev/null +++ b/accurest-core/src/main/groovy/io/coderate/accurest/dsl/internal/DslProperty.groovy @@ -0,0 +1,19 @@ +package io.coderate.accurest.dsl.internal +import groovy.transform.CompileStatic + +@CompileStatic +class DslProperty { + + final Object clientValue + final Object serverValue + + DslProperty(Object clientValue, Object serverValue) { + this.clientValue = clientValue + this.serverValue = serverValue + } + + DslProperty(Object singleValue) { + this.clientValue = singleValue + this.serverValue = singleValue + } +} diff --git a/accurest-core/src/main/groovy/io/coderate/accurest/dsl/internal/Headers.groovy b/accurest-core/src/main/groovy/io/coderate/accurest/dsl/internal/Headers.groovy index ca7e87e7cb..9ee8dfb242 100644 --- a/accurest-core/src/main/groovy/io/coderate/accurest/dsl/internal/Headers.groovy +++ b/accurest-core/src/main/groovy/io/coderate/accurest/dsl/internal/Headers.groovy @@ -2,15 +2,25 @@ package io.coderate.accurest.dsl.internal class Headers { - private Map headers = [:] + private Map assertionHeaders = [:] + private Map valueHeaders = [:] WithValuePattern header(String headerName) { WithValuePattern withValuePattern = new WithValuePattern() - headers[headerName] = withValuePattern + assertionHeaders[headerName] = withValuePattern return withValuePattern } - Set> entries() { - return Collections.unmodifiableSet(headers.entrySet()) + void header(Map singleHeader) { + Map.Entry first = singleHeader.entrySet().first() + valueHeaders[first?.key] = first?.value + } + + Map valueHeaders() { + return Collections.unmodifiableMap(valueHeaders) + } + + Set> assertionEntries() { + return Collections.unmodifiableSet(assertionHeaders.entrySet()) } } diff --git a/accurest-core/src/main/groovy/io/coderate/accurest/dsl/internal/Response.groovy b/accurest-core/src/main/groovy/io/coderate/accurest/dsl/internal/Response.groovy index 6b0c0d1916..e2993fdf5e 100644 --- a/accurest-core/src/main/groovy/io/coderate/accurest/dsl/internal/Response.groovy +++ b/accurest-core/src/main/groovy/io/coderate/accurest/dsl/internal/Response.groovy @@ -7,8 +7,12 @@ import static io.coderate.accurest.dsl.internal.DelegateHelper.delegateToClosure @TypeChecked class Response { + private static final String CLIENT_PROP_KEY = 'client' + private static final String SERVER_PROP_KEY = 'server' + private int status private Headers headers + private Body body = new Body() void status(int status) { this.status = status @@ -19,6 +23,29 @@ class Response { delegateToClosure(closure, headers) } + void body(Map body) { + this.body = new Body(convertObjectsToDslProperties(body)) + } + + private Map convertObjectsToDslProperties(Map body) { + return body.collectEntries { + Map.Entry entry -> + [(entry.key): entry.value instanceof DslProperty ? entry.value : new DslProperty(entry.value)] + } as Map + } + + DslProperty property(Map properties) { + return new DslProperty(properties[CLIENT_PROP_KEY], properties[SERVER_PROP_KEY]) + } + + DslProperty $(Map properties) { + return property(properties) + } + + Body getBody() { + return body + } + int getStatus() { return status } diff --git a/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockGroovyDslResponseSpec.groovy b/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockGroovyDslResponseSpec.groovy index 65241c420d..201d495af6 100644 --- a/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockGroovyDslResponseSpec.groovy +++ b/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockGroovyDslResponseSpec.groovy @@ -3,7 +3,6 @@ package io.codearte.accurest.dsl import groovy.json.JsonSlurper import io.coderate.accurest.dsl.GroovyDsl import io.coderate.accurest.dsl.WiremockResponseStubStrategy -import spock.lang.Ignore import spock.lang.Specification class WiremockGroovyDslResponseSpec extends Specification { @@ -15,25 +14,19 @@ class WiremockGroovyDslResponseSpec extends Specification { status 200 } } - when: - String wiremockStub = new WiremockResponseStubStrategy(dsl)."toWiremock${side}Stub"() - then: - new JsonSlurper().parseText(wiremockStub) == new JsonSlurper().parseText(expectedStub) + expect: + new WiremockResponseStubStrategy(dsl)."build${side}ResponseContent"() == new JsonSlurper().parseText(expectedStub) where: side << ['Client', 'Server'] expectedStub << [''' { - "response": { - "status": 200 - } + "status": 200 } ''', ''' { - "response": { - "status": 200 - } + "status": 200 } '''] } @@ -43,49 +36,69 @@ class WiremockGroovyDslResponseSpec extends Specification { GroovyDsl dsl = GroovyDsl.make { response { headers { - header('Content-Type').equalTo('text/xml') + header('Content-Type').matches { + client('text/xml') + server('text/*') + } } status 200 } } - when: - String wiremockStub = new WiremockResponseStubStrategy(dsl).toWiremockClientStub() - then: - new JsonSlurper().parseText(wiremockStub) == new JsonSlurper().parseText(''' + expect: + new WiremockResponseStubStrategy(dsl).buildClientResponseContent() == new JsonSlurper().parseText(''' { - "response": { "headers": { "Content-Type": { - "equalTo": "text/xml" + "matches": "text/xml" }, }, "status": 200 - } } ''') } - @Ignore("Not implemented yet") def 'should generate headers for response for server side'() { given: GroovyDsl dsl = GroovyDsl.make { response { status 200 headers { - header('Content-Type').equalTo('text/xml') + header('Content-Type').matches { + client('text/xml') + server('text/*') + } } } } - when: - String wiremockStub = new WiremockResponseStubStrategy(dsl).toWiremockClientStub() - then: - new JsonSlurper().parseText(wiremockStub) == new JsonSlurper().parseText(''' + expect: + new WiremockResponseStubStrategy(dsl).buildServerResponseContent() == new JsonSlurper().parseText(''' { - "response": { - "status": 200, - "headers": - "Content-Type": "text/xml" + "status": 200, + "headers": { + "Content-Type": { + "matches": "text/*" + } + } + } + ''') + } + + def 'should generate an exact header for response for both sides '() { + given: + GroovyDsl dsl = GroovyDsl.make { + response { + status 200 + headers { + header 'Content-Type': 'text/xml' + } + } } + expect: + new WiremockResponseStubStrategy(dsl).buildServerResponseContent() == new JsonSlurper().parseText(''' + { + "status": 200, + "headers": { + "Content-Type": "text/xml" } } ''') diff --git a/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockGroovyDslSpec.groovy b/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockGroovyDslSpec.groovy index a26983984d..f5011af153 100644 --- a/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockGroovyDslSpec.groovy +++ b/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WiremockGroovyDslSpec.groovy @@ -3,40 +3,38 @@ package io.codearte.accurest.dsl import groovy.json.JsonSlurper import io.coderate.accurest.dsl.GroovyDsl import io.coderate.accurest.dsl.WiremockRequestStubStrategy +import io.coderate.accurest.dsl.WiremockStubStrategy import spock.lang.Ignore import spock.lang.Specification class WiremockGroovyDslSpec extends Specification { - // TODO: add alias instead of placeholder - @Ignore - def 'should convert groovy dsl stub to wiremock stub'() { + def 'should convert groovy dsl stub to wiremock stub for the client side'() { given: - GroovyDsl dsl = GroovyDsl.make { - request { - method('GET') - urlPattern { - client('/[0-9]{2}') - server('/12') + GroovyDsl groovyDsl = GroovyDsl.make { + request { + method('GET') + urlPattern { + client('/[0-9]{2}') + server('/12') + } + } + response { + status(200) + body ( + id : property(client: '123', server: { regex('[0-9]+') } ), + name: 'Jan', + created : $(client: '2014-02-02 12:23:43', server: { currentDate(it) }) + ) + headers { + header('Content-Type': 'text/plain') + } } } - response { - status(200) - body { - withPlaceholder(client: '2015-01-14', server: '$anyInt($it)') - withTemplate(''' - { - "date" : "$placeholder0" - } - ''') - } - headers { - Content-Type('text/plain') - } - } - } - expect: - dsl.toWiremockClientStub() == ''' + when: + String wiremockStub = new WiremockStubStrategy(groovyDsl).toWiremockClientStub() + then: + new JsonSlurper().parseText(wiremockStub) == new JsonSlurper().parseText(''' { "request": { "method": "GET", @@ -44,13 +42,63 @@ class WiremockGroovyDslSpec extends Specification { }, "response": { "status": 200, - "body": "2015-01-14", + "body": { + "id": "123", + "name": "Jan", + "created" : "2014-02-02 12:23:43" + }, "headers": { "Content-Type": "text/plain" } } } -''' +''') + } + + def 'should convert groovy dsl stub to wiremock stub for the server side'() { + given: + GroovyDsl groovyDsl = GroovyDsl.make { + request { + method('GET') + urlPattern { + client('/[0-9]{2}') + server('/12') + } + } + response { + status(200) + body ( + id : property(client: '123', server: '321' ), + name: 'Jan', + created : $(client: '2014-02-02 12:23:43', server: '1999-01-01 01:23:45') + ) + headers { + header('Content-Type': 'text/plain') + } + } + } + when: + String wiremockStub = new WiremockStubStrategy(groovyDsl).toWiremockServerStub() + then: + new JsonSlurper().parseText(wiremockStub) == new JsonSlurper().parseText(''' +{ + "request": { + "method": "GET", + "urlPattern": "/12" + }, + "response": { + "status": 200, + "body": { + "id": "321", + "name": "Jan", + "created" : "1999-01-01 01:23:45" + }, + "headers": { + "Content-Type": "text/plain" + } + } +} +''') } def "should generate stub with GET"() { @@ -60,14 +108,10 @@ class WiremockGroovyDslSpec extends Specification { method("GET") } } - when: - String wiremockStub = new WiremockRequestStubStrategy(groovyDsl).toWiremockClientStub() - then: - new JsonSlurper().parseText(wiremockStub) == new JsonSlurper().parseText(''' + expect: + new WiremockRequestStubStrategy(groovyDsl).buildClientRequestContent() == new JsonSlurper().parseText(''' { - "request":{ - "method":"GET" - } + "method":"GET" } ''') } @@ -80,15 +124,11 @@ class WiremockGroovyDslSpec extends Specification { url("/sth") } } - when: - String wiremockStub = new WiremockRequestStubStrategy(groovyDsl).toWiremockClientStub() - then: - new JsonSlurper().parseText(wiremockStub) == new JsonSlurper().parseText(''' + expect: + new WiremockRequestStubStrategy(groovyDsl).buildClientRequestContent() == new JsonSlurper().parseText(''' { - "request":{ - "method":"GET", - "url":"/sth" - } + "method":"GET", + "url":"/sth" } ''') } @@ -102,14 +142,10 @@ class WiremockGroovyDslSpec extends Specification { } } } - when: - String wiremockStub = new WiremockRequestStubStrategy(groovyDsl).toWiremockClientStub() - then: - new JsonSlurper().parseText(wiremockStub) == new JsonSlurper().parseText(''' + expect: + new WiremockRequestStubStrategy(groovyDsl).buildClientRequestContent() == new JsonSlurper().parseText(''' { - "request":{ - "urlPattern":"/^[0-9]{2}$" - } + "urlPattern":"/^[0-9]{2}$" } ''') } @@ -124,14 +160,10 @@ class WiremockGroovyDslSpec extends Specification { } } } - when: - String wiremockStub = new WiremockRequestStubStrategy(groovyDsl).toWiremockServerStub() - then: - new JsonSlurper().parseText(wiremockStub) == new JsonSlurper().parseText(''' + expect: + new WiremockRequestStubStrategy(groovyDsl).buildServerRequestContent() == new JsonSlurper().parseText(''' { - "request":{ - "urlPattern":"/12" - } + "urlPattern":"/12" } ''') } @@ -143,14 +175,10 @@ class WiremockGroovyDslSpec extends Specification { urlPath ('/12') } } - when: - String wiremockStub = new WiremockRequestStubStrategy(groovyDsl).toWiremockClientStub() - then: - new JsonSlurper().parseText(wiremockStub) == new JsonSlurper().parseText(''' + expect: + new WiremockRequestStubStrategy(groovyDsl).buildClientRequestContent() == new JsonSlurper().parseText(''' { - "request":{ - "urlPath":"/12" - } + "urlPath":"/12" } ''') } @@ -162,14 +190,10 @@ class WiremockGroovyDslSpec extends Specification { urlPath ('/12') } } - when: - String wiremockStub = new WiremockRequestStubStrategy(groovyDsl).toWiremockServerStub() - then: - new JsonSlurper().parseText(wiremockStub) == new JsonSlurper().parseText(''' + expect: + new WiremockRequestStubStrategy(groovyDsl).buildClientRequestContent() == new JsonSlurper().parseText(''' { - "request":{ - "urlPath":"/12" - } + "urlPath":"/12" } ''') } @@ -195,25 +219,21 @@ class WiremockGroovyDslSpec extends Specification { } } } - when: - String wiremockStub = new WiremockRequestStubStrategy(groovyDsl).toWiremockClientStub() - then: - new JsonSlurper().parseText(wiremockStub) == new JsonSlurper().parseText(''' + expect: + new WiremockRequestStubStrategy(groovyDsl).buildClientRequestContent() == new JsonSlurper().parseText(''' { - "request":{ - "headers": { - "Content-Type": { - "equalTo": "text/xml" - }, - "Accept": { - "matches": "text/.*" - }, - "etag": { - "doesNotMatch": "abcd.*" - }, - "X-Custom-Header": { - "contains": "2134" - } + "headers": { + "Content-Type": { + "equalTo": "text/xml" + }, + "Accept": { + "matches": "text/.*" + }, + "etag": { + "doesNotMatch": "abcd.*" + }, + "X-Custom-Header": { + "contains": "2134" } } } @@ -241,25 +261,21 @@ class WiremockGroovyDslSpec extends Specification { } } } - when: - String wiremockStub = new WiremockRequestStubStrategy(groovyDsl).toWiremockServerStub() - then: - new JsonSlurper().parseText(wiremockStub) == new JsonSlurper().parseText(''' + expect: + new WiremockRequestStubStrategy(groovyDsl).buildServerRequestContent() == new JsonSlurper().parseText(''' { - "request":{ - "headers": { - "Content-Type": { - "equalTo": "text/xml" - }, - "Accept": { - "matches": "text/plain" - }, - "etag": { - "doesNotMatch": "abcdef" - }, - "X-Custom-Header": { - "contains": "121345" - } + "headers": { + "Content-Type": { + "equalTo": "text/xml" + }, + "Accept": { + "matches": "text/plain" + }, + "etag": { + "doesNotMatch": "abcdef" + }, + "X-Custom-Header": { + "contains": "121345" } } }