From fe762dc9c3c0be1da0a9bcdd091dd8c6e50082d7 Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Tue, 26 Jul 2022 13:45:48 +1000 Subject: [PATCH] fix: support multipart form posts with multiple parts #1574 --- .../consumer/junit5/PostImageBodyTest.groovy | 2 ++ .../pact/consumer/dsl/PactDslRequestBase.kt | 28 +++++++++++++------ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/consumer/junit5/src/test/groovy/au/com/dius/pact/consumer/junit5/PostImageBodyTest.groovy b/consumer/junit5/src/test/groovy/au/com/dius/pact/consumer/junit5/PostImageBodyTest.groovy index 25c8c52a94..87665fd4e8 100644 --- a/consumer/junit5/src/test/groovy/au/com/dius/pact/consumer/junit5/PostImageBodyTest.groovy +++ b/consumer/junit5/src/test/groovy/au/com/dius/pact/consumer/junit5/PostImageBodyTest.groovy @@ -26,6 +26,7 @@ class PostImageBodyTest { .method('POST') .path('/images') .withFileUpload('photo', 'ron.jpg', 'image/jpeg', stream.bytes) + .withFileUpload('text', 'ron.txt', 'text/plain', 'hello world!'.bytes) .willRespondWith() .status(200) .body(new PactDslJsonBody() @@ -45,6 +46,7 @@ class PostImageBodyTest { def data = MultipartEntityBuilder.create() .setMode(HttpMultipartMode.BROWSER_COMPATIBLE) .addBinaryBody('photo', stream, ContentType.create('image/jpeg'), 'ron.jpg') + .addBinaryBody('text', 'some text stuff'.bytes, ContentType.create('text/plain'), 'ron.txt') .build() def request = RequestBuilder .post(mockServer.url + '/images') diff --git a/consumer/src/main/kotlin/au/com/dius/pact/consumer/dsl/PactDslRequestBase.kt b/consumer/src/main/kotlin/au/com/dius/pact/consumer/dsl/PactDslRequestBase.kt index f5b9e4426e..a06d889759 100644 --- a/consumer/src/main/kotlin/au/com/dius/pact/consumer/dsl/PactDslRequestBase.kt +++ b/consumer/src/main/kotlin/au/com/dius/pact/consumer/dsl/PactDslRequestBase.kt @@ -43,6 +43,8 @@ open class PactDslRequestBase( @JvmField var requestGenerators = Generators() + var multipartBuilder: MultipartEntityBuilder? = null + protected fun setupDefaultValues() { if (defaultRequestValues != null) { if (StringUtils.isNotEmpty(defaultRequestValues.requestMethod)) { @@ -67,21 +69,29 @@ open class PactDslRequestBase( ContentType.create(fileContentType) else ContentType.DEFAULT_TEXT - val multipart = MultipartEntityBuilder.create() - .setMode(HttpMultipartMode.EXTENDED) - .addBinaryBody(partName, data, contentType, fileName) - setupMultipart(multipart) + if (multipartBuilder == null) { + multipartBuilder = MultipartEntityBuilder.create() + .setMode(HttpMultipartMode.EXTENDED) + .addBinaryBody(partName, data, contentType, fileName) + } else { + multipartBuilder!!.addBinaryBody(partName, data, contentType, fileName) + } + setupMultipart(multipartBuilder!!) } fun setupMultipart(multipart: MultipartEntityBuilder) { val entity = multipart.build() val os = ByteArrayOutputStream() entity.writeTo(os) - requestBody = body(os.toByteArray(), - au.com.dius.pact.core.model.ContentType(entity.contentType)) - requestMatchers.addCategory("header").addRule(CONTENT_TYPE, RegexMatcher(MULTIPART_HEADER_REGEX, - entity.contentType)) - requestHeaders[CONTENT_TYPE] = listOf(entity.contentType) + requestBody = body(os.toByteArray(), au.com.dius.pact.core.model.ContentType(entity.contentType)) + val matchingRuleCategory = requestMatchers.addCategory("header") + if (!matchingRuleCategory.matchingRules.containsKey(CONTENT_TYPE)) { + matchingRuleCategory.addRule(CONTENT_TYPE, RegexMatcher(MULTIPART_HEADER_REGEX, + entity.contentType)) + } + if (!requestHeaders.containsKey(CONTENT_TYPE)) { + requestHeaders[CONTENT_TYPE] = listOf(entity.contentType) + } } protected fun queryMatchingDateBase(field: String, pattern: String?, example: String?): PactDslRequestBase {