Skip to content

Commit

Permalink
fix: write empty bodies to the Pact file #1611
Browse files Browse the repository at this point in the history
  • Loading branch information
rholshausen committed Nov 25, 2022
1 parent 7083f8c commit aece98d
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ package au.com.dius.pact.consumer.dsl

import au.com.dius.pact.consumer.ConsumerPactBuilder
import au.com.dius.pact.core.model.OptionalBody
import au.com.dius.pact.core.model.PactSpecVersion
import au.com.dius.pact.core.model.generators.Generators
import au.com.dius.pact.core.model.matchingrules.MatchingRuleGroup
import au.com.dius.pact.core.model.matchingrules.MatchingRulesImpl
import au.com.dius.pact.core.model.matchingrules.RegexMatcher
import au.com.dius.pact.core.model.matchingrules.TypeMatcher
import com.google.common.net.MediaType
import org.apache.http.entity.ContentType
import spock.lang.Issue
import spock.lang.Specification
Expand Down Expand Up @@ -45,7 +45,6 @@ class PactDslResponseSpec extends Specification {
'application/json;charset=iso-8859-1' | true
'application/json' | true
ContentType.APPLICATION_JSON.toString() | true
MediaType.JSON_UTF_8.toString() | true
'application/json;foo=bar' | false
'application/json;charset=*' | false
'application/xml' | false
Expand Down Expand Up @@ -146,4 +145,22 @@ class PactDslResponseSpec extends Specification {
response.responseHeaders == ['content-type': ['text/plain']]
}

@Issue('#1611')
def 'supports empty bodies'() {
given:
def builder = ConsumerPactBuilder.consumer('empty-body-consumer')
.hasPactWith('empty-body-service')
.uponReceiving('a request for an empty body')
.path('/path')
.willRespondWith()
.body('')

when:
def pact = builder.toPact()
def interaction = pact.interactions.first()

then:
interaction.response.body.state == OptionalBody.State.EMPTY
interaction.toMap(PactSpecVersion.V3).response == [status: 200, body: '']
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package au.com.dius.pact.core.model

import au.com.dius.pact.core.model.ContentType.Companion.HTMLREGEXP
import au.com.dius.pact.core.model.ContentType.Companion.JSONREGEXP
import au.com.dius.pact.core.model.ContentType.Companion.UNKNOWN
import au.com.dius.pact.core.model.ContentType.Companion.XMLREGEXP
import au.com.dius.pact.core.model.ContentType.Companion.XMLREGEXP2
import au.com.dius.pact.core.support.json.JsonParser
import mu.KLogging
import org.apache.commons.codec.binary.Hex
import org.apache.tika.config.TikaConfig
Expand All @@ -15,14 +17,14 @@ import java.util.Base64
/**
* Class to represent missing, empty, null and present bodies
*/
data class OptionalBody(
data class OptionalBody @JvmOverloads constructor(
val state: State,
val value: ByteArray? = null,
var contentType: ContentType = ContentType.UNKNOWN
var contentType: ContentType = UNKNOWN
) {

init {
if (contentType == ContentType.UNKNOWN) {
if (contentType == UNKNOWN) {
val detectedContentType = detectContentType()
if (detectedContentType != null) {
this.contentType = detectedContentType
Expand Down Expand Up @@ -130,7 +132,7 @@ data class OptionalBody(
else -> null
}

private fun detectStandardTextContentType(): ContentType? = when {
fun detectStandardTextContentType(): ContentType? = when {
isPresent() -> {
val newLine = '\n'.toByte()
val cReturn = '\r'.toByte()
Expand Down Expand Up @@ -190,6 +192,7 @@ data class OptionalBody(
}
}

@Suppress("TooGenericExceptionCaught")
private val tika = try { TikaConfig() } catch (e: RuntimeException) {
logger.warn(e) { "Could not initialise Tika, detecting content types will be disabled" }
null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ open class RequestResponseInteraction @JvmOverloads constructor(
companion object : KLogging() {
const val COMMA = ", "

@JvmStatic
fun requestToMap(request: Request, pactSpecVersion: PactSpecVersion): Map<String, Any?> {
val map = mutableMapOf<String, Any?>(
"method" to request.method.toUpperCase(),
Expand All @@ -81,9 +82,13 @@ open class RequestResponseInteraction @JvmOverloads constructor(
if (request.query.isNotEmpty()) {
map["query"] = if (pactSpecVersion >= PactSpecVersion.V3) request.query else mapToQueryStr(request.query)
}

if (request.body.isPresent()) {
map["body"] = setupBodyForJson(request)
} else if (request.body.isEmpty()) {
map["body"] = ""
}

if (request.matchingRules.isNotEmpty()) {
map["matchingRules"] = request.matchingRules.toMap(pactSpecVersion)
}
Expand All @@ -94,14 +99,19 @@ open class RequestResponseInteraction @JvmOverloads constructor(
return map
}

@JvmStatic
fun responseToMap(response: Response, pactSpecVersion: PactSpecVersion): Map<String, Any?> {
val map = mutableMapOf<String, Any?>("status" to response.status)
if (response.headers.isNotEmpty()) {
map["headers"] = response.headers.entries.associate { (key, value) -> key to value.joinToString(COMMA) }
}

if (response.body.isPresent()) {
map["body"] = setupBodyForJson(response)
} else if (response.body.isEmpty()) {
map["body"] = ""
}

if (response.matchingRules.isNotEmpty()) {
map["matchingRules"] = response.matchingRules.toMap(pactSpecVersion)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import spock.lang.Unroll

import java.nio.charset.Charset

@SuppressWarnings('LineLength')
class OptionalBodySpec extends Specification {

@Unroll
Expand All @@ -13,11 +14,11 @@ class OptionalBodySpec extends Specification {
body.missing == value

where:
body | value
OptionalBody.missing() | true
OptionalBody.empty() | false
OptionalBody.nullBody() | false
OptionalBody.body('a'.bytes) | false
body | value
OptionalBody.missing() | true
OptionalBody.empty() | false
OptionalBody.nullBody() | false
OptionalBody.body('a'.bytes) | false
}

@Unroll
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,12 @@ class RequestResponseInteractionSpec extends Specification {
'include[]=course_image&include[]=favorites'
}

@Issue('#1611')
def 'supports empty bodies'() {
expect:
RequestResponseInteraction.requestToMap(new Request(body: OptionalBody.empty()), PactSpecVersion.V3) ==
[method: 'GET', path: '/', body: '']
RequestResponseInteraction.responseToMap(new Response(body: OptionalBody.empty()), PactSpecVersion.V3) ==
[status: 200, body: '']
}
}

0 comments on commit aece98d

Please sign in to comment.