diff --git a/compatibility-suite/src/test/groovy/steps/v1/HttpProvider.groovy b/compatibility-suite/src/test/groovy/steps/v1/HttpProvider.groovy index edd8bf0e9..27dc35791 100644 --- a/compatibility-suite/src/test/groovy/steps/v1/HttpProvider.groovy +++ b/compatibility-suite/src/test/groovy/steps/v1/HttpProvider.groovy @@ -13,6 +13,7 @@ import au.com.dius.pact.core.model.OptionalBody import au.com.dius.pact.core.model.Pact 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.Request import au.com.dius.pact.core.model.RequestResponseInteraction import au.com.dius.pact.core.model.RequestResponsePact @@ -35,6 +36,7 @@ import io.cucumber.java.en.Given import io.cucumber.java.en.Then import io.cucumber.java.en.When +@SuppressWarnings('ThrowRuntimeException') class HttpProvider { CompatibilitySuiteWorld world BaseMockServer mockProvider @@ -43,11 +45,21 @@ class HttpProvider { List verificationResults List mockBrokers = [] Map verificationProperties = [:] + List providerStateParams = [] HttpProvider(CompatibilitySuiteWorld world) { this.world = world } + void providerStateCallback(ProviderState state, String isSetup) { + providerStateParams << [state, isSetup] + } + + void failingProviderStateCallback(ProviderState state, String isSetup) { + providerStateParams << [state, isSetup] + throw new RuntimeException('failingProviderStateCallback has failed') + } + @After @SuppressWarnings('UnusedMethodParameter') void after(Scenario scenario) { @@ -63,6 +75,7 @@ class HttpProvider { mockProvider.start() providerInfo = new ProviderInfo('p') providerInfo.port = mockProvider.port + providerInfo.stateChangeTeardown = true } @Given('a Pact file for interaction \\{{int}} is to be verified') @@ -75,6 +88,27 @@ class HttpProvider { } ConsumerInfo consumerInfo = new ConsumerInfo('c') consumerInfo.pactSource = new StringSource(writer.toString()) + if (providerInfo.stateChangeRequestFilter) { + consumerInfo.stateChange = providerInfo.stateChangeRequestFilter + } + providerInfo.consumers << consumerInfo + } + + @Given('a Pact file for interaction \\{{int}} is to be verified with a provider state {string} defined') + void a_pact_file_for_interaction_is_to_be_verified_with_a_provider_state_defined(Integer num, String providerState) { + def interaction = world.interactions[num - 1].copy() + interaction.providerStates << new ProviderState(providerState) + Pact pact = new RequestResponsePact(new Provider('p'), + new Consumer('v1-compatibility-suite-c'), [interaction]) + StringWriter writer = new StringWriter() + writer.withPrintWriter { + DefaultPactWriter.INSTANCE.writePact(pact, it, PactSpecVersion.V1) + } + ConsumerInfo consumerInfo = new ConsumerInfo('c') + consumerInfo.pactSource = new StringSource(writer.toString()) + if (providerInfo.stateChangeRequestFilter) { + consumerInfo.stateChange = providerInfo.stateChangeRequestFilter + } providerInfo.consumers << consumerInfo } @@ -194,4 +228,39 @@ class HttpProvider { def json = new JsonSlurper().parseText( request.body.valueAsString()) assert json.success == false } + + @Given('a provider state callback is configured') + void a_provider_state_callback_is_configured() { + providerInfo.stateChangeRequestFilter = this.&providerStateCallback + } + + @Given('a provider state callback is configured, but will return a failure') + void a_provider_state_callback_is_configured_but_will_return_a_failure() { + providerInfo.stateChangeRequestFilter = this.&failingProviderStateCallback + } + + @Then('the provider state callback will be called before the verification is run') + void the_provider_state_callback_will_be_called_before_the_verification_is_run() { + assert !providerStateParams.findAll { p -> p[1] == 'setup' }.empty + } + + @Then('the provider state callback will receive a setup call with {string} as the provider state parameter') + void the_provider_state_callback_will_receive_a_setup_call_with_as_the_provider_state_parameter(String state) { + assert !providerStateParams.findAll { p -> p[0].name == state && p[1] == 'setup' }.empty + } + + @Then('the provider state callback will be called after the verification is run') + void the_provider_state_callback_will_be_called_after_the_verification_is_run() { + assert !providerStateParams.findAll { p -> p[1] == 'teardown' }.empty + } + + @Then('the provider state callback will receive a teardown call {string} as the provider state parameter') + void the_provider_state_callback_will_receive_a_teardown_call_as_the_provider_state_parameter(String providerState) { + assert !providerStateParams.findAll { p -> p[0].name == providerState && p[1] == 'teardown' }.empty + } + + @Then('the provider state callback will NOT receive a teardown call') + void the_provider_state_callback_will_not_receive_a_teardown_call() { + assert providerStateParams.findAll { p -> p[1] == 'teardown' }.empty + } } diff --git a/core/model/src/main/kotlin/au/com/dius/pact/core/model/RequestResponseInteraction.kt b/core/model/src/main/kotlin/au/com/dius/pact/core/model/RequestResponseInteraction.kt index cd61f47d4..2161bc2de 100644 --- a/core/model/src/main/kotlin/au/com/dius/pact/core/model/RequestResponseInteraction.kt +++ b/core/model/src/main/kotlin/au/com/dius/pact/core/model/RequestResponseInteraction.kt @@ -75,6 +75,10 @@ open class RequestResponseInteraction @JvmOverloads constructor( override fun asSynchronousRequestResponse() = this + fun copy(): RequestResponseInteraction = RequestResponseInteraction( + description, providerStates, request, response, interactionId + ) + companion object : KLogging() { const val COMMA = ", "