diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/WireMockRequestStubStrategy.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/WireMockRequestStubStrategy.groovy index cf69737c95..03304bdbc3 100755 --- a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/WireMockRequestStubStrategy.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/WireMockRequestStubStrategy.groovy @@ -6,16 +6,25 @@ import groovy.json.JsonOutput import groovy.transform.PackageScope import groovy.transform.TypeChecked import groovy.transform.TypeCheckingMode -import io.codearte.accurest.dsl.internal.* +import io.codearte.accurest.dsl.internal.Body +import io.codearte.accurest.dsl.internal.DslProperty +import io.codearte.accurest.dsl.internal.MatchingStrategy +import io.codearte.accurest.dsl.internal.NamedProperty +import io.codearte.accurest.dsl.internal.QueryParameters +import io.codearte.accurest.dsl.internal.RegexPatterns +import io.codearte.accurest.dsl.internal.Request import io.codearte.accurest.util.ContentType import io.codearte.accurest.util.ContentUtils -import io.codearte.accurest.util.JsonToJsonPathsConverter import io.codearte.accurest.util.JsonPaths +import io.codearte.accurest.util.JsonToJsonPathsConverter import io.codearte.accurest.util.MapConverter import java.util.regex.Pattern -import static io.codearte.accurest.util.ContentUtils.* +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.RegexpBuilders.buildGStringRegexpForStubSide import static io.codearte.accurest.util.RegexpBuilders.buildJSONRegexpMatch @@ -37,6 +46,7 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy { appendUrl(requestPattern) appendQueryParameters(requestPattern) appendBody(requestPattern) + appendMultipart(requestPattern) return requestPattern } @@ -69,6 +79,22 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy { requestPattern.bodyPatterns = [convertToValuePattern(getMatchingStrategy(request.body.clientValue))] } } + + private void appendMultipart(RequestPattern requestPattern) { + if (!request.multipart) { + return + } + + if (request.multipart.clientValue instanceof Map) { + List multipartPatterns = (request.multipart.clientValue as Map).collect { + (it.value instanceof NamedProperty + ? ValuePattern.matches(RegexPatterns.multipartFile(it.key, (it.value as NamedProperty).name.clientValue, (it.value as NamedProperty).value.clientValue)) + : ValuePattern.matches(RegexPatterns.multipartParam(it.key, it.value)) ) + } + + requestPattern.bodyPatterns ? requestPattern.bodyPatterns.addAll(multipartPatterns) : (requestPattern.bodyPatterns = multipartPatterns) + } + } private void appendHeaders(RequestPattern requestPattern) { if(!request.headers) { diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Common.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Common.groovy index 89ab8252d2..cdf6d3db1f 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Common.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Common.groovy @@ -52,6 +52,10 @@ class Common { return new NamedProperty(name, value) } + NamedProperty named(Map namedMap){ + return new NamedProperty(namedMap.get('name'), namedMap.get('content')) + } + DslProperty value(ClientDslProperty client, ServerDslProperty server) { assertThatSidesMatch(client.clientValue, server.serverValue) return new DslProperty(client.clientValue, server.serverValue) diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/RegexPatterns.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/RegexPatterns.groovy index 3daa34ec90..1c18226fd9 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/RegexPatterns.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/RegexPatterns.groovy @@ -43,4 +43,12 @@ class RegexPatterns { String url() { return URL.pattern() } + + static String multipartParam(Object name, Object value) { + return ".*--(.*)\r\nContent-Disposition: form-data; name=\"$name\"\r\n(Content-Type: .*\r\n)?(Content-Length: \\d+\r\n)?\r\n$value\r\n--\\1.*" + } + + static String multipartFile(Object name, Object filename, Object content) { + return ".*--(.*)\r\nContent-Disposition: form-data; name=\"$name\"; filename=\"$filename\"\r\n(Content-Type: .*\r\n)?(Content-Length: \\d+\r\n)?\r\n$content\r\n--\\1.*"; + } } diff --git a/accurest-core/src/test/groovy/io/codearte/accurest/builder/MockMvcSpockMethodBuilderSpec.groovy b/accurest-core/src/test/groovy/io/codearte/accurest/builder/MockMvcSpockMethodBuilderSpec.groovy index d98b2b1e64..195886ce0e 100644 --- a/accurest-core/src/test/groovy/io/codearte/accurest/builder/MockMvcSpockMethodBuilderSpec.groovy +++ b/accurest-core/src/test/groovy/io/codearte/accurest/builder/MockMvcSpockMethodBuilderSpec.groovy @@ -1,4 +1,5 @@ package io.codearte.accurest.builder + import io.codearte.accurest.dsl.GroovyDsl import io.codearte.accurest.dsl.WireMockStubStrategy import io.codearte.accurest.dsl.WireMockStubVerifier @@ -7,6 +8,7 @@ import spock.lang.Specification import spock.lang.Unroll import java.util.regex.Pattern + /** * @author Jakub Kubrynski */ @@ -861,4 +863,32 @@ World.'''""") spockTest.contains('.multiPart') } + def "should generate proper test code when having multipart parameters with named as map"() { + given: + GroovyDsl contractDsl = GroovyDsl.make { + request { + method "PUT" + url "/multipart" + multipart( + formParameter: value(client(regex('".+"')), server('"formParameterValue"')), + someBooleanParameter: value(client(regex('(true|false)')), server('true')), + file: named( + name: value(client(regex('.+')), server('filename.csv')), + content: value(client(regex('.+')), server('file content'))) + ) + } + response { + status 200 + } + } + MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.given(blockBuilder) + def spockTest = blockBuilder.toString() + then: + spockTest.contains('.multiPart') + } + + } 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 7502ada771..866a451f47 100755 --- a/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WireMockGroovyDslSpec.groovy +++ b/accurest-core/src/test/groovy/io/codearte/accurest/dsl/WireMockGroovyDslSpec.groovy @@ -1398,4 +1398,50 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie String toWireMockClientJsonStub(groovyDsl) { new WireMockStubStrategy(groovyDsl).toWireMockClientStub() } + + @Issue('180') + @Unroll + def 'should generate stub with multipart parameters'() { + given: + GroovyDsl contractDsl = GroovyDsl.make { + request { + method "PUT" + url "/multipart" + multipart( + formParameter: value(client(regex('".+"')), server('"formParameterValue"')), + someBooleanParameter: value(client(regex('(true|false)')), server('true')), + file: named( + name: value(client(regex('.+')), server('filename.csv')), + content: value(client(regex('.+')), server('file content'))) + ) + } + response { + status 200 + } + } + when: + String wireMockStub = new WireMockStubStrategy(contractDsl).toWireMockClientStub() + then: + println wireMockStub + AssertionUtil.assertThatJsonsAreEqual((''' + { + "request" : { + "url" : "/multipart", + "method" : "PUT", + "bodyPatterns" : [ { + "matches" : ".*--(.*)\\r\\nContent-Disposition: form-data; name=\\"formParameter\\"\\r\\n(Content-Type: .*\\r\\n)?(Content-Length: \\\\d+\\r\\n)?\\r\\n\\".+\\"\\r\\n--\\\\1.*" + }, { + "matches" : ".*--(.*)\\r\\nContent-Disposition: form-data; name=\\"someBooleanParameter\\"\\r\\n(Content-Type: .*\\r\\n)?(Content-Length: \\\\d+\\r\\n)?\\r\\n(true|false)\\r\\n--\\\\1.*" + }, { + "matches" : ".*--(.*)\\r\\nContent-Disposition: form-data; name=\\"file\\"; filename=\\".+\\"\\r\\n(Content-Type: .*\\r\\n)?(Content-Length: \\\\d+\\r\\n)?\\r\\n.+\\r\\n--\\\\1.*" + } ] + }, + "response" : { + "status" : 200 + } + } + '''), wireMockStub) + and: + stubMappingIsValidWireMockStub(wireMockStub) + } }