Skip to content

Commit

Permalink
fix(JUnit5): Initialise any plugins before running the provider verif…
Browse files Browse the repository at this point in the history
…ication
  • Loading branch information
rholshausen committed Mar 16, 2023
1 parent f4c1862 commit e2905ae
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 31 deletions.
2 changes: 1 addition & 1 deletion config/detekt-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ style:
active: false
includeLineWrapping: false
ForbiddenComment:
active: true
active: false
values:
- 'FIXME:'
- 'STOPSHIP:'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -402,15 +402,4 @@ fun calculateCharset(headers: Map<String, List<String?>>): Charset {
return default
}

fun interactionCatalogueEntries(): List<CatalogueEntry> {
return listOf(
CatalogueEntry(CatalogueEntryType.TRANSPORT, CatalogueEntryProviderType.CORE, "core",
"http", mapOf()),
CatalogueEntry(CatalogueEntryType.TRANSPORT, CatalogueEntryProviderType.CORE, "core",
"https", mapOf()),
CatalogueEntry(CatalogueEntryType.INTERACTION, CatalogueEntryProviderType.CORE, "core",
"message", mapOf()),
CatalogueEntry(CatalogueEntryType.INTERACTION, CatalogueEntryProviderType.CORE, "core",
"synchronous-message", mapOf())
)
}
fun interactionCatalogueEntries() = au.com.dius.pact.core.matchers.interactionCatalogueEntries()
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package au.com.dius.pact.core.matchers

import io.pact.plugins.jvm.core.CatalogueEntry
import io.pact.plugins.jvm.core.CatalogueEntryProviderType
import io.pact.plugins.jvm.core.CatalogueEntryType

/**
* Configures all the core transport catalogue entries
*/
fun interactionCatalogueEntries(): List<CatalogueEntry> {
return listOf(
CatalogueEntry(
CatalogueEntryType.TRANSPORT, CatalogueEntryProviderType.CORE, "core",
"http", mapOf()),
CatalogueEntry(CatalogueEntryType.TRANSPORT, CatalogueEntryProviderType.CORE, "core",
"https", mapOf()),
CatalogueEntry(CatalogueEntryType.INTERACTION, CatalogueEntryProviderType.CORE, "core",
"message", mapOf()),
CatalogueEntry(CatalogueEntryType.INTERACTION, CatalogueEntryProviderType.CORE, "core",
"synchronous-message", mapOf())
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,7 @@ open class V4Pact @JvmOverloads constructor(
}
}

fun pluginData(): List<PluginData> {
open fun pluginData(): List<PluginData> {
return when (val plugins = metadata["plugins"]) {
is List<*> -> plugins.mapNotNull {
when (it) {
Expand All @@ -678,4 +678,9 @@ open class V4Pact @JvmOverloads constructor(
else -> emptyList()
}
}

open fun requiresPlugins(): Boolean {
val pluginData = metadata["plugins"]
return pluginData is List<*> && pluginData.isNotEmpty()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import au.com.dius.pact.core.model.RequestResponseInteraction
import au.com.dius.pact.core.model.UnknownPactSource
import au.com.dius.pact.core.model.V4Interaction
import au.com.dius.pact.core.model.generators.GeneratorTestMode
import au.com.dius.pact.core.support.Json
import au.com.dius.pact.core.support.MetricEvent
import au.com.dius.pact.core.support.Metrics
import au.com.dius.pact.core.support.Result
Expand All @@ -21,6 +22,7 @@ import au.com.dius.pact.provider.ProviderVerifier
import au.com.dius.pact.provider.VerificationFailureType
import au.com.dius.pact.provider.VerificationResult
import au.com.dius.pact.provider.junitsupport.TestDescription
import io.pact.plugins.jvm.core.PluginConfiguration
import org.junit.jupiter.api.extension.ExtensionContext

/**
Expand Down Expand Up @@ -55,7 +57,7 @@ data class PactVerificationContext @JvmOverloads constructor(
try {
Metrics.sendMetrics(MetricEvent.ProviderVerificationRan(1, "junit5"))

val result = validateTestExecution(client, request, testContext.executionContext ?: mutableMapOf())
val result = validateTestExecution(client, request, testContext.executionContext ?: mutableMapOf(), pact)
verifier!!.displayOutput(result.flatMap { it.getResultOutput() })

this.testExecutionResult.addAll(result.filterIsInstance<VerificationResult.Failed>())
Expand All @@ -81,7 +83,8 @@ data class PactVerificationContext @JvmOverloads constructor(
private fun validateTestExecution(
client: Any?,
request: Any?,
context: MutableMap<String, Any>
context: MutableMap<String, Any>,
pact: Pact
): List<VerificationResult> {
var interactionMessage = "Verifying a pact between ${consumer.name} and ${providerInfo.name}" +
" - ${interaction.description}"
Expand All @@ -92,19 +95,27 @@ data class PactVerificationContext @JvmOverloads constructor(
when (providerInfo.verificationType) {
null, PactVerification.REQUEST_RESPONSE -> {
return try {
val reqResInteraction = if (interaction is V4Interaction.SynchronousHttp) {
interaction.asV3Interaction()
val (reqResInteraction, pluginData) = if (interaction is V4Interaction.SynchronousHttp) {
interaction.asV3Interaction() to interaction.pluginConfiguration.toMap()
} else {
interaction as RequestResponseInteraction
interaction as RequestResponseInteraction to emptyMap()
}
val pactPluginData = pact.asV4Pact().get()?.pluginData() ?: emptyList()
val expectedResponse = DefaultResponseGenerator.generateResponse(reqResInteraction.response, context,
GeneratorTestMode.Provider, emptyList(), emptyMap()) // TODO: need to pass any plugin config here
GeneratorTestMode.Provider, pactPluginData, pluginData)
val actualResponse = target.executeInteraction(client, request)
val pluginContext = pactPluginData.associate {
it.name to PluginConfiguration(
pluginData[it.name].orEmpty().toMutableMap(),
it.configuration.mapValues { (_, v) -> Json.toJson(v) }.toMutableMap()
)
}

listOf(
verifier!!.verifyRequestResponsePact(
expectedResponse, actualResponse, interactionMessage, mutableMapOf(),
reqResInteraction.interactionId.orEmpty(), consumer.pending
reqResInteraction.interactionId.orEmpty(), consumer.pending,
pluginContext
)
)
} catch (e: Exception) {
Expand All @@ -127,7 +138,7 @@ data class PactVerificationContext @JvmOverloads constructor(
}
}
PactVerification.PLUGIN -> {
val v4pact = when(val p = pact.asV4Pact()) {
val v4pact = when(val p = this.pact.asV4Pact()) {
is Result.Ok -> p.value
is Result.Err -> return listOf(
VerificationResult.Failed(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ open class PactVerificationExtension(

setupReporters(verifier, serviceName, interaction.description, extContext, testContext.valueResolver)

verifier.initialisePlugins(pact)
verifier.initialiseReporters(testContext.providerInfo)
verifier.reportVerificationForConsumer(consumer, testContext.providerInfo, pactSource)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ package au.com.dius.pact.provider
import au.com.dius.pact.core.matchers.BodyMismatch
import au.com.dius.pact.core.matchers.BodyTypeMismatch
import au.com.dius.pact.core.matchers.HeaderMismatch
import au.com.dius.pact.core.matchers.MatchingConfig
import au.com.dius.pact.core.matchers.MetadataMismatch
import au.com.dius.pact.core.matchers.StatusMismatch
import au.com.dius.pact.core.matchers.generators.ArrayContainsJsonGenerator
import au.com.dius.pact.core.matchers.interactionCatalogueEntries
import au.com.dius.pact.core.matchers.matcherCatalogueEntries
import au.com.dius.pact.core.model.BrokerUrlSource
import au.com.dius.pact.core.model.ContentType
import au.com.dius.pact.core.model.DefaultPactReader
Expand All @@ -30,7 +33,8 @@ import au.com.dius.pact.core.support.Auth
import au.com.dius.pact.core.support.MetricEvent
import au.com.dius.pact.core.support.Metrics
import au.com.dius.pact.core.support.Result
import au.com.dius.pact.core.support.Result.*
import au.com.dius.pact.core.support.Result.Err
import au.com.dius.pact.core.support.Result.Ok
import au.com.dius.pact.core.support.expressions.SystemPropertyResolver
import au.com.dius.pact.core.support.hasProperty
import au.com.dius.pact.core.support.ifNullOrEmpty
Expand All @@ -41,8 +45,11 @@ import au.com.dius.pact.provider.reporters.VerifierReporter
import groovy.lang.Closure
import io.github.classgraph.ClassGraph
import io.pact.plugins.jvm.core.CatalogueEntry
import io.pact.plugins.jvm.core.CatalogueManager
import io.pact.plugins.jvm.core.DefaultPluginManager
import io.pact.plugins.jvm.core.InteractionVerificationDetails
import io.pact.plugins.jvm.core.PluginConfiguration
import io.pact.plugins.jvm.core.PluginManager
import mu.KLogging
import java.io.File
import java.lang.reflect.Method
Expand Down Expand Up @@ -270,9 +277,25 @@ interface IProviderVerifier {
interactionMessage: String,
failures: MutableMap<String, Any>,
interactionId: String,
pending: Boolean
pending: Boolean,
pluginConfiguration: Map<String, PluginConfiguration>
): VerificationResult

/**
* Compares the expected and actual responses
*/
@Suppress("LongParameterList")
@Deprecated("Use the version that passes in any plugin configuration")
fun verifyRequestResponsePact(
expectedResponse: IResponse,
actualResponse: ProviderResponse,
interactionMessage: String,
failures: MutableMap<String, Any>,
interactionId: String,
pending: Boolean
): VerificationResult = verifyRequestResponsePact(expectedResponse, actualResponse, interactionMessage, failures,
interactionId, pending, emptyMap())

/**
* If publishing of verification results has been disabled
*/
Expand Down Expand Up @@ -353,6 +376,7 @@ open class ProviderVerifier @JvmOverloads constructor (
var stateChangeHandler: StateChange = DefaultStateChange
var pactReader: PactReader = DefaultPactReader
override var verificationSource: String? = null
var pluginManager: PluginManager = DefaultPluginManager

/**
* This will return true unless the pact.verifier.publishResults property has the value of "true"
Expand Down Expand Up @@ -412,8 +436,15 @@ open class ProviderVerifier @JvmOverloads constructor (
val actualResponse = ProviderResponse(response["statusCode"] as Int,
response["headers"] as Map<String, List<String>>, ContentType.UNKNOWN, body
)
result = result.merge(this.verifyRequestResponsePact(expectedResponse, actualResponse, interactionMessage,
failures, interactionId.orEmpty(), pending))
result = result.merge(this.verifyRequestResponsePact(
expectedResponse,
actualResponse,
interactionMessage,
failures,
interactionId.orEmpty(),
pending,
emptyMap() // TODO: pass any plugin config here
))
}
result
}
Expand Down Expand Up @@ -468,7 +499,8 @@ open class ProviderVerifier @JvmOverloads constructor (
interactionMessage,
failures,
interactionId,
pending
pending,
emptyMap() // TODO: Pass in any plugin config here
)
}
} catch (e: Exception) {
Expand Down Expand Up @@ -786,9 +818,10 @@ open class ProviderVerifier @JvmOverloads constructor (
interactionMessage: String,
failures: MutableMap<String, Any>,
interactionId: String,
pending: Boolean
pending: Boolean,
pluginConfiguration: Map<String, PluginConfiguration>
): VerificationResult {
val comparison = ResponseComparison.compareResponse(expectedResponse, actualResponse)
val comparison = ResponseComparison.compareResponse(expectedResponse, actualResponse, pluginConfiguration)

reporters.forEach { it.returnsAResponseWhich() }

Expand Down Expand Up @@ -874,8 +907,15 @@ open class ProviderVerifier @JvmOverloads constructor (
val expectedResponse = interaction.response.generatedResponse(context, GeneratorTestMode.Provider)
val actualResponse = client.makeRequest(interaction.request.generatedRequest(context, GeneratorTestMode.Provider))

verifyRequestResponsePact(expectedResponse, actualResponse, interactionMessage, failures,
interaction.interactionId.orEmpty(), pending)
verifyRequestResponsePact(
expectedResponse,
actualResponse,
interactionMessage,
failures,
interaction.interactionId.orEmpty(),
pending,
emptyMap() // TODO: Pass any plugin config in here
)
} catch (e: Exception) {
failures[interactionMessage] = e
reporters.forEach {
Expand Down Expand Up @@ -920,7 +960,10 @@ open class ProviderVerifier @JvmOverloads constructor (
client: IPactBrokerClient? = null
): VerificationResult {
val pact = FilteredPact(loadPactFileForConsumer(consumer)) { filterInteractions(it) }

reportVerificationForConsumer(consumer, provider, pact.source)
initialisePlugins(pact)

return if (pact.interactions.isEmpty()) {
reporters.forEach { it.warnPactFileHasNoInteractions(pact as Pact) }
VerificationResult.Ok()
Expand Down Expand Up @@ -956,6 +999,30 @@ open class ProviderVerifier @JvmOverloads constructor (
}
}

/**
* Initialise any required plugins and plugin entries required for the verification
*/
fun initialisePlugins(pact: Pact) {
CatalogueManager.registerCoreEntries(
MatchingConfig.contentMatcherCatalogueEntries() +
matcherCatalogueEntries() +
interactionCatalogueEntries() +
MatchingConfig.contentHandlerCatalogueEntries()
)
val v4pact = pact.asV4Pact().get()
if (v4pact != null && v4pact.requiresPlugins()) {
logger.info { "Pact file requires plugins, will load those now" }
for (pluginDetails in v4pact.pluginData()) {
val result = pluginManager.loadPlugin(pluginDetails.name, pluginDetails.version)
if (result is Err) {
throw RuntimeException(
"Failed to load plugin ${pluginDetails.name}/${pluginDetails.version} - ${result.error}"
)
}
}
}
}

override fun reportVerificationForConsumer(
consumer: IConsumerInfo,
provider: IProviderInfo,
Expand Down
Loading

0 comments on commit e2905ae

Please sign in to comment.