Skip to content

Commit

Permalink
feat: add methods to setup provider states on PactBuilder #1646
Browse files Browse the repository at this point in the history
  • Loading branch information
rholshausen committed Jan 12, 2023
1 parent e8e5457 commit 0506476
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import au.com.dius.pact.core.model.InteractionMarkup
import au.com.dius.pact.core.model.OptionalBody
import au.com.dius.pact.core.model.PactSpecVersion
import au.com.dius.pact.core.model.Provider
import au.com.dius.pact.core.model.ProviderState
import au.com.dius.pact.core.model.UnknownPactSource
import au.com.dius.pact.core.model.V4Interaction
import au.com.dius.pact.core.model.V4Pact
Expand All @@ -41,6 +42,7 @@ import java.nio.file.Path
import java.nio.file.Paths
import kotlin.io.path.exists

@Suppress("TooManyFunctions")
open class PactBuilder(
var consumer: String = "consumer",
var provider: String = "provider",
Expand All @@ -49,6 +51,7 @@ open class PactBuilder(
private val plugins: MutableList<PactPlugin> = mutableListOf()
private val interactions: MutableList<V4Interaction> = mutableListOf()
private var currentInteraction: V4Interaction? = null
private val providerStates: MutableList<ProviderState> = mutableListOf()
private val pluginConfiguration: MutableMap<String, MutableMap<String, JsonValue>> = mutableMapOf()
private val additionalMetadata: MutableMap<String, JsonValue> = mutableMapOf()

Expand All @@ -65,7 +68,7 @@ open class PactBuilder(
}

/**
* Use the old HTTP Pact DSL
* Use the old Message Pact DSL
*/
fun usingLegacyMessageDsl(): MessagePactBuilder {
return MessagePactBuilder(pactVersion).consumer(consumer).hasPactWith(provider)
Expand Down Expand Up @@ -111,6 +114,59 @@ open class PactBuilder(
}
}

/**
* Describe the state the provider needs to be in for the pact test to be verified. Any parameters for the provider
* state can be provided in the second parameter.
*/
@JvmOverloads
fun given(state: String, params: Map<String, Any?> = emptyMap()): PactBuilder {
if (currentInteraction != null) {
currentInteraction!!.providerStates.add(ProviderState(state, params))
} else {
providerStates.add(ProviderState(state, params))
}
return this
}

/**
* Describe the state the provider needs to be in for the pact test to be verified.
*
* @param firstKey Key of first parameter element
* @param firstValue Value of first parameter element
* @param paramsKeyValuePair Additional parameters in key-value pairs
*/
fun given(state: String, firstKey: String, firstValue: Any?, vararg paramsKeyValuePair: Any): PactBuilder {
require(paramsKeyValuePair.size % 2 == 0) {
"Pairs of key value should be provided, but there is one key without value."
}
val params = mutableMapOf(firstKey to firstValue)
var i = 0
while (i < paramsKeyValuePair.size) {
params[paramsKeyValuePair[i].toString()] = paramsKeyValuePair[i + 1]
i += 2
}
if (currentInteraction != null) {
currentInteraction!!.providerStates.add(ProviderState(state, params))
} else {
providerStates.add(ProviderState(state, params))
}
return this
}

/**
* Describe the state the provider needs to be in for the pact test to be verified.
*
* @param params Additional parameters in key-value pairs
*/
fun given(state: String, vararg params: Pair<String, Any>): PactBuilder {
if (currentInteraction != null) {
currentInteraction!!.providerStates.add(ProviderState(state, params.toMap()))
} else {
providerStates.add(ProviderState(state, params.toMap()))
}
return this
}

/**
* Adds an interaction with the given description and type. If interactionType is not specified (is the empty string)
* will default to an HTTP interaction
Expand Down Expand Up @@ -139,6 +195,12 @@ open class PactBuilder(
TODO("Interactions of type '$interactionType' are not currently supported")
}
}

if (providerStates.isNotEmpty()) {
currentInteraction!!.providerStates.addAll(providerStates)
providerStates.clear()
}

return this
}

Expand All @@ -155,7 +217,8 @@ open class PactBuilder(
}

/**
* Values to configure the interaction
* Values to configure the interaction. In the case of an interaction configured by a plugin, you need to follow
* the plugin documentation of what values must be specified here.
*/
fun with(values: Map<String, Any?>): PactBuilder {
require(currentInteraction != null) {
Expand Down Expand Up @@ -216,6 +279,7 @@ open class PactBuilder(
return this
}

@Suppress("LongMethod")
private fun setupMessageContents(
contents: Any?,
interaction: V4Interaction
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import au.com.dius.pact.core.model.HttpRequest
import au.com.dius.pact.core.model.HttpResponse
import au.com.dius.pact.core.model.OptionalBody
import au.com.dius.pact.core.model.PactSpecVersion
import au.com.dius.pact.core.model.ProviderState
import au.com.dius.pact.core.model.V4Pact
import kotlin.Pair
import spock.lang.Issue
import au.com.dius.pact.core.model.V4Interaction
import spock.lang.Ignore
import spock.lang.Specification
import spock.lang.Unroll

Expand Down Expand Up @@ -64,8 +65,6 @@ class PactBuilderSpec extends Specification {
builder.currentInteraction instanceof V4Interaction.SynchronousHttp
}

@Ignore
// This test is currently failing due to dependency linking issues
def 'supports configuring the HTTP interaction attributes'() {
given:
def builder = new PactBuilder('test', 'test', PactSpecVersion.V4)
Expand Down Expand Up @@ -93,6 +92,29 @@ class PactBuilderSpec extends Specification {
then:
http.request == new HttpRequest('PUT', '/reports/report002.csv', [a: ['b']], ['x-a': ['b']],
OptionalBody.body('"a"', ContentType.JSON))
http.response == new HttpResponse(205, ['x-b': ['a']], OptionalBody.body('"b"', ContentType.JSON))
http.response == new HttpResponse(200, ['x-b': ['b']], OptionalBody.body('"b"', ContentType.JSON))
}

@Issue('#1646')
def 'supports setting up provider states'() {
given:
def builder = new PactBuilder('test', 'test', PactSpecVersion.V4)

when:
def pact = builder
.given('test1')
.given('test2', [a: 'b', c: 'd'])
.expectsToReceive('test interaction', '')
.given('test3', 'a', 100)
.given('test4', new Pair('a', 100), new Pair('b', 1000))
.toPact()

then:
pact.interactions.first().providerStates == [
new ProviderState('test1'),
new ProviderState('test2', [a: 'b', c: 'd']),
new ProviderState('test3', [a: 100]),
new ProviderState('test4', [a: 100, b: 1000])
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import au.com.dius.pact.core.support.json.JsonValue
abstract class BaseInteraction(
override val interactionId: String? = null,
override val description: String,
override val providerStates: List<ProviderState> = listOf(),
override val providerStates: MutableList<ProviderState> = mutableListOf(),
override val comments: MutableMap<String, JsonValue> = mutableMapOf()
) : Interaction {
fun displayState(): String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ open class RequestResponseInteraction @JvmOverloads constructor(
override val request: Request = Request(),
override val response: Response = Response(),
interactionId: String? = null
) : BaseInteraction(interactionId, description, providerStates), SynchronousRequestResponse {
) : BaseInteraction(interactionId, description, providerStates.toMutableList()), SynchronousRequestResponse {

override fun toString() =
"Interaction: $description\n\tin states ${displayState()}\nrequest:\n$request\n\nresponse:\n$response"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ sealed class V4Interaction(
val pluginConfiguration: MutableMap<String, MutableMap<String, JsonValue>> = mutableMapOf(),
var interactionMarkup: InteractionMarkup = InteractionMarkup(),
var transport: String? = null
) : BaseInteraction(interactionId, description, providerStates, comments) {
) : BaseInteraction(interactionId, description, providerStates.toMutableList(), comments) {
override fun conflictsWith(other: Interaction): Boolean {
return false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class Message @JvmOverloads constructor(
var generators: Generators = Generators(),
var metadata: MutableMap<String, Any?> = mutableMapOf(),
interactionId: String? = null
) : BaseInteraction(interactionId, description, providerStates), MessageInteraction {
) : BaseInteraction(interactionId, description, providerStates.toMutableList()), MessageInteraction {

fun contentsAsBytes() = when {
isKafkaSchemaRegistryJson() -> KafkaSchemaRegistryWireFormatter.addMagicBytes(contents.orEmpty())
Expand Down

0 comments on commit 0506476

Please sign in to comment.