Skip to content

Commit

Permalink
fix: record successful verification results by interaction ID #1266
Browse files Browse the repository at this point in the history
  • Loading branch information
Ronald Holshausen committed Dec 13, 2020
1 parent 59ef8ec commit 7427a2c
Show file tree
Hide file tree
Showing 18 changed files with 212 additions and 183 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,14 @@ import java.util.function.Consumer
data class PactResponse(val pactFile: JsonValue.Object, val links: Map<String, Any?>)

sealed class TestResult {
data class Ok(val interactionId: String? = null) : TestResult() {
data class Ok(val interactionIds: Set<String> = emptySet()) : TestResult() {
constructor(interactionId: String?) : this(if (interactionId.isNullOrEmpty())
emptySet() else setOf(interactionId))

override fun toBoolean() = true

override fun merge(result: TestResult) = when (result) {
is Ok -> this.copy(interactionId = interactionId ?: result.interactionId)
is Ok -> this.copy(interactionIds = interactionIds + result.interactionIds)
is Failed -> result.merge(this)
}
}
Expand All @@ -39,14 +42,29 @@ sealed class TestResult {
override fun toBoolean() = false

override fun merge(result: TestResult) = when (result) {
is Ok -> if (result.interactionId != null)
if (results.find { it["interactionId"] == result.interactionId } != null) {
this
is Ok -> if (result.interactionIds.isEmpty()) {
this
} else {
this.copy(results = results + mapOf("interactionId" to result.interactionId))
val allResults = results + result.interactionIds.associateBy { "interactionId" }
val grouped = allResults.groupBy { it["interactionId"] }
val filtered = grouped.mapValues { entry ->
val interactionId = entry.key as String?
if (entry.value.size == 1) {
entry.value
} else {
entry.value.map { map -> map.filterKeys { it != "interactionId" } }
.filter { it.isNotEmpty() }
.map { map ->
if (interactionId.isNullOrEmpty()) {
map
} else {
map + ("interactionId" to interactionId)
}
}
}
}
this.copy(results = filtered.values.flatten())
}
else
this
is Failed -> Failed(results + result.results, when {
description.isNotEmpty() && result.description.isNotEmpty() && description != result.description ->
"$description, ${result.description}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ class PactBrokerClientSpec extends Specification {
halClient.postJson('URL', _) >> new Ok(true)

expect:
client.publishVerificationResults(attributes, new TestResult.Ok(null), '0', null).class.simpleName == result
client.publishVerificationResults(attributes, new TestResult.Ok(), '0', null).class.simpleName == result

where:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ class TestResultSpec extends Specification {
where:

result1 | result2 | result3
new TestResult.Ok(null) | new TestResult.Ok(null) | new TestResult.Ok(null)
new TestResult.Ok(null) | new TestResult.Ok('123') | new TestResult.Ok('123')
new TestResult.Ok('123') | new TestResult.Ok(null) | new TestResult.Ok('123')
new TestResult.Ok('123') | new TestResult.Ok('456') | new TestResult.Ok('123')
new TestResult.Ok(null) | new TestResult.Failed([[error: 'Bang']], '') | new TestResult.Failed([[error: 'Bang']], '')
new TestResult.Ok() | new TestResult.Ok() | new TestResult.Ok()
new TestResult.Ok() | new TestResult.Ok('123') | new TestResult.Ok('123')
new TestResult.Ok('123') | new TestResult.Ok() | new TestResult.Ok('123')
new TestResult.Ok('123') | new TestResult.Ok('456') | new TestResult.Ok(['123', '456'] as Set)
new TestResult.Ok() | new TestResult.Failed([[error: 'Bang']], '') | new TestResult.Failed([[error: 'Bang']], '')
new TestResult.Ok('123') | new TestResult.Failed([[error: 'Bang']], '') | new TestResult.Failed([[error: 'Bang'], [interactionId: '123']], '')
new TestResult.Ok('123') | new TestResult.Failed([[error: 'Bang', interactionId: '123']], '') | new TestResult.Failed([[error: 'Bang', interactionId: '123']], '')
new TestResult.Failed([[error: 'Bang']], '') | new TestResult.Ok(null) | new TestResult.Failed([[error: 'Bang']], '')
new TestResult.Failed([[error: 'Bang']], '') | new TestResult.Ok() | new TestResult.Failed([[error: 'Bang']], '')
new TestResult.Failed([[error: 'Bang']], '') | new TestResult.Ok('123') | new TestResult.Failed([[error: 'Bang'], [interactionId: '123']], '')
new TestResult.Failed([[error: 'Bang', interactionId: '123']], '') | new TestResult.Ok('123') | new TestResult.Failed([[error: 'Bang', interactionId: '123']], '')
new TestResult.Failed([[error: 'Bang']], '') | new TestResult.Failed(['Boom', 'Splat'], '') | new TestResult.Failed([[error: 'Bang'], 'Boom', 'Splat'], '')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ class PactBrokerClientPactSpec extends Specification {
href: 'http://localhost:8080/pacts/provider/Provider/consumer/Foo%20Consumer/pact-version/1234567890' +
'/verification-results'
]
], new TestResult.Ok(null), '10.0.0').value
], new TestResult.Ok([] as Set), '10.0.0').value
}

then:
Expand All @@ -392,7 +392,7 @@ class PactBrokerClientPactSpec extends Specification {
href: 'http://localhost:8080/pacts/provider/Provider/consumer/Foo%20Consumer/pact-version/1234567890' +
'/verification-results'
]
], new TestResult.Ok(null), '10.0.0', 'http://localhost:8080/build').value
], new TestResult.Ok([] as Set), '10.0.0', 'http://localhost:8080/build').value
}

then:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ class PactVerificationTaskSpec extends Specification {
then:
def ex = thrown(GradleScriptException)
ex.message == 'There were 1 non-pending pact failures for provider Test Service'
1 * verifier.verifyProvider(_) >> [new VerificationResult.Failed([], '', '', [
1 * verifier.verifyProvider(_) >> [new VerificationResult.Failed('', '', ['': [
new VerificationFailureType.MismatchFailure(new StatusMismatch(200, 400),
new RequestResponseInteraction('Test'), new RequestResponsePact(provider, consumer))
], false, null) ]
]], false) ]
}

def 'does not raise an exception if the verification passed'() {
Expand All @@ -62,7 +62,7 @@ class PactVerificationTaskSpec extends Specification {

then:
noExceptionThrown()
1 * verifier.verifyProvider(_) >> [ new VerificationResult.Ok(null) ]
1 * verifier.verifyProvider(_) >> [ new VerificationResult.Ok() ]
}

def 'does not raise an exception if the pact is pending'() {
Expand All @@ -71,6 +71,6 @@ class PactVerificationTaskSpec extends Specification {

then:
noExceptionThrown()
1 * verifier.verifyProvider(_) >> [new VerificationResult.Failed([], '', '', [], true, null) ]
1 * verifier.verifyProvider(_) >> [new VerificationResult.Failed('', '', [:], true) ]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -169,11 +169,10 @@ open class InteractionRunner<I>(
notifier.fireTestFailure(Failure(description, e))
notifier.fireTestFinished(description)
}
testResult = VerificationResult.Failed(listOf(mapOf("message" to "Request to provider failed with an exception",
"exception" to e)),
"Request to provider failed with an exception", description.displayName,
listOf(VerificationFailureType.ExceptionFailure("Request to provider failed with an exception", e)),
pending, interaction.interactionId)
testResult = VerificationResult.Failed("Request to provider failed with an exception", description.displayName,
mapOf(interaction.interactionId.orEmpty() to
listOf(VerificationFailureType.ExceptionFailure("Request to provider failed with an exception", e))),
pending)
} finally {
if (pact is FilteredPact) {
testResultAccumulator.updateTestResult(pact.pact, interaction, testResult.toTestResult(), pactSource)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,10 @@ data class PactVerificationContext @JvmOverloads constructor(
it.requestFailed(providerInfo, interaction, interactionMessage, e,
verifier!!.projectHasProperty.apply(ProviderVerifier.PACT_SHOW_STACKTRACE))
}
listOf(VerificationResult.Failed(listOf(mapOf("message" to "Request to provider failed with an exception",
"exception" to e)),
"Request to provider failed with an exception", interactionMessage,
listOf(VerificationFailureType.ExceptionFailure("Request to provider failed with an exception", e)),
consumer.pending, interaction.interactionId))
listOf(VerificationResult.Failed("Request to provider failed with an exception", interactionMessage,
mapOf(interaction.interactionId.orEmpty() to
listOf(VerificationFailureType.ExceptionFailure("Request to provider failed with an exception", e))),
consumer.pending))
}
} else {
return listOf(verifier!!.verifyResponseByInvokingProviderMethods(providerInfo, consumer, interaction,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,12 @@ class PactVerificationStateChangeExtension(
} catch (e: Exception) {
val pending = pactSource is BrokerUrlSource && pactSource.result?.pending == true
logger.error(e) { "Provider state change callback failed" }
testContext.testExecutionResult.add(VerificationResult.Failed(description = "Provider state change callback failed",
results = listOf(mapOf("exception" to e)),
failures = listOf(VerificationFailureType.StateChangeFailure("Provider state change callback failed", StateChangeResult(Err(e)))),
pending = pending,
interactionId = interaction.interactionId
val error = StateChangeResult(Err(e))
testContext.testExecutionResult.add(VerificationResult.Failed(
description = "Provider state change callback failed",
failures = mapOf(interaction.interactionId.orEmpty() to
listOf(VerificationFailureType.StateChangeFailure("Provider state change callback failed", error))),
pending = pending
))
if (!pending) {
throw AssertionError("Provider state change callback failed", e)
Expand All @@ -63,11 +64,12 @@ class PactVerificationStateChangeExtension(
} catch (e: Exception) {
val pending = pactSource is BrokerUrlSource && pactSource.result?.pending == true
logger.error(e) { "Provider state change callback failed" }
testContext.testExecutionResult.add(VerificationResult.Failed(description = "Provider state change teardown callback failed",
results = listOf(mapOf("exception" to e)),
failures = listOf(VerificationFailureType.StateChangeFailure("Provider state change teardown callback failed", StateChangeResult(Err(e)))),
pending = pending,
interactionId = interaction.interactionId
val error = StateChangeResult(Err(e))
testContext.testExecutionResult.add(VerificationResult.Failed(
description = "Provider state change teardown callback failed",
failures = mapOf(interaction.interactionId.orEmpty() to listOf(
VerificationFailureType.StateChangeFailure("Provider state change teardown callback failed", error))),
pending = pending
))
if (!pending) {
throw AssertionError("Provider state change callback failed", e)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,7 @@ class PactVerificationContextSpec extends Specification {
context.testExecutionResult[0] instanceof VerificationResult.Failed
context.testExecutionResult[0].description == 'Request to provider failed with an exception'
context.testExecutionResult[0].failures.size() == 1
context.testExecutionResult[0].failures[0] instanceof VerificationFailureType.ExceptionFailure
context.testExecutionResult[0].interactionId == '12345'
context.testExecutionResult[0].failures['12345'][0] instanceof VerificationFailureType.ExceptionFailure
}

@SuppressWarnings('UnnecessaryGetter')
Expand Down Expand Up @@ -99,7 +98,6 @@ class PactVerificationContextSpec extends Specification {
context.testExecutionResult[0] instanceof VerificationResult.Failed
context.testExecutionResult[0].description == 'Request to provider failed with an exception'
context.testExecutionResult[0].failures.size() == 1
context.testExecutionResult[0].failures[0] instanceof VerificationFailureType.ExceptionFailure
context.testExecutionResult[0].interactionId == '12345'
context.testExecutionResult[0].failures['12345'][0] instanceof VerificationFailureType.ExceptionFailure
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,10 @@ open class MvcProviderVerifier(private val debugRequestResponse: Boolean = false
reporters.forEach {
it.requestFailed(provider, interaction, interactionMessage, e, projectHasProperty.apply(PACT_SHOW_STACKTRACE))
}
return VerificationResult.Failed(listOf(mapOf("message" to "Request to provider method failed with an exception",
"exception" to e)),
"Request to provider method failed with an exception", interactionMessage,
listOf(VerificationFailureType.ExceptionFailure("Request to provider method failed with an exception", e)),
pending, interaction.interactionId)
return VerificationResult.Failed("Request to provider method failed with an exception", interactionMessage,
mapOf(interaction.interactionId.orEmpty() to listOf(
VerificationFailureType.ExceptionFailure("Request to provider method failed with an exception", e))),
pending)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,10 @@ class WebFluxProviderVerifier : ProviderVerifier() {
e, projectHasProperty.apply(PACT_SHOW_STACKTRACE)
)
}
return VerificationResult.Failed(
listOf(mapOf("message" to "Request to provider method failed with an exception", "exception" to e)),
"Request to provider method failed with an exception", interactionMessage,
listOf(VerificationFailureType.ExceptionFailure("Request to provider method failed with an exception", e)),
pending, interaction.interactionId)
return VerificationResult.Failed("Request to provider method failed with an exception", interactionMessage,
mapOf(interaction.interactionId.orEmpty() to listOf(
VerificationFailureType.ExceptionFailure("Request to provider method failed with an exception", e))),
pending)
}
}

Expand Down
Loading

0 comments on commit 7427a2c

Please sign in to comment.