From 287b16c4498fca0679d96b0c30a79198e381d1a3 Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Mon, 16 Dec 2024 10:34:56 +1100 Subject: [PATCH] feat: Pass any transport config to the plugin in the test context under the transport_config key --- .../pact/consumer/junit5/PactConsumerTest.kt | 7 ++---- .../dius/pact/consumer/PluginMockServer.kt | 11 +++++++-- .../pact/consumer/junit/MockServerConfig.kt | 13 +++++++++- .../pact/consumer/model/MockProviderConfig.kt | 11 +++++---- .../pact/consumer/PluginMockServerSpec.groovy | 24 +++++++++++++++++-- .../au/com/dius/pact/core/support/Json.kt | 2 ++ 6 files changed, 54 insertions(+), 14 deletions(-) diff --git a/consumer/junit5/src/main/kotlin/au/com/dius/pact/consumer/junit5/PactConsumerTest.kt b/consumer/junit5/src/main/kotlin/au/com/dius/pact/consumer/junit5/PactConsumerTest.kt index e1de10732f..61cfa46a63 100644 --- a/consumer/junit5/src/main/kotlin/au/com/dius/pact/consumer/junit5/PactConsumerTest.kt +++ b/consumer/junit5/src/main/kotlin/au/com/dius/pact/consumer/junit5/PactConsumerTest.kt @@ -1,15 +1,12 @@ package au.com.dius.pact.consumer.junit5 -import org.junit.jupiter.api.Tag import org.junit.jupiter.api.extension.ExtendWith -import java.lang.annotation.Retention -import java.lang.annotation.RetentionPolicy // Shorthand for @ExtendWith(PactConsumerTestExt::class) @ExtendWith(PactConsumerTestExt::class) -@Retention(RetentionPolicy.RUNTIME) +@Retention(AnnotationRetention.RUNTIME) @Target( AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS ) -annotation class PactConsumerTest \ No newline at end of file +annotation class PactConsumerTest diff --git a/consumer/src/main/kotlin/au/com/dius/pact/consumer/PluginMockServer.kt b/consumer/src/main/kotlin/au/com/dius/pact/consumer/PluginMockServer.kt index 7e14e5175d..abbd1da7d7 100644 --- a/consumer/src/main/kotlin/au/com/dius/pact/consumer/PluginMockServer.kt +++ b/consumer/src/main/kotlin/au/com/dius/pact/consumer/PluginMockServer.kt @@ -8,6 +8,8 @@ import au.com.dius.pact.core.model.Pact import au.com.dius.pact.core.support.contains import au.com.dius.pact.core.support.isNotEmpty import au.com.dius.pact.core.support.Result +import au.com.dius.pact.core.support.json.JsonValue +import au.com.dius.pact.core.support.toJson import io.pact.plugins.jvm.core.CatalogueEntry import io.pact.plugins.jvm.core.CatalogueManager import io.pact.plugins.jvm.core.DefaultPluginManager @@ -17,7 +19,8 @@ import io.pact.plugins.jvm.core.PluginManager import io.github.oshai.kotlinlogging.KLogging /** - * Mock server provided by a plugin + * Mock server provided by a plugin. Any additional transport configuration will be passed to the plugin + * mock server in the test context under the "transport_config" key. */ @Suppress("TooGenericExceptionThrown") class PluginMockServer(pact: BasePact, config: MockProviderConfig) : BaseMockServer(pact, config) { @@ -40,9 +43,13 @@ class PluginMockServer(pact: BasePact, config: MockProviderConfig) : BaseMockSer if (entry == null) { throw InvalidMockServerRegistryEntry(config.transportRegistryEntry) } + val testContext = mutableMapOf() + if (config.transportConfig.isNotEmpty()) { + testContext["transport_config"] = config.transportConfig.toJson() + } transportEntry = entry - mockServerDetails = pluginManager.startMockServer(transportEntry, config.toPluginMockServerConfig(), pact) + mockServerDetails = pluginManager.startMockServer(transportEntry, config.toPluginMockServerConfig(), pact, testContext) } @Suppress("EmptyFunctionBlock") diff --git a/consumer/src/main/kotlin/au/com/dius/pact/consumer/junit/MockServerConfig.kt b/consumer/src/main/kotlin/au/com/dius/pact/consumer/junit/MockServerConfig.kt index 1d7256ec91..0e86f34e34 100644 --- a/consumer/src/main/kotlin/au/com/dius/pact/consumer/junit/MockServerConfig.kt +++ b/consumer/src/main/kotlin/au/com/dius/pact/consumer/junit/MockServerConfig.kt @@ -3,6 +3,11 @@ package au.com.dius.pact.consumer.junit import au.com.dius.pact.consumer.model.MockServerImplementation import java.lang.annotation.Inherited +/** + * Key/Value pair for a Transport Configuration Entry + */ +annotation class TransportConfigurationEntry(val key: String, val value: String) + /** * Annotation to configure the mock server for a consumer test */ @@ -62,7 +67,13 @@ annotation class MockServerConfig( /** * Provider name this mock server is associated with. This is only needed when there are multiple for the same test */ - val providerName: String = "" + val providerName: String = "", + + /** + * Configuration required for the transport used. This is mostly used where plugins provide things like mock servers + * and require additional configuration. + */ + val transportConfig: Array = [] ) @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) diff --git a/consumer/src/main/kotlin/au/com/dius/pact/consumer/model/MockProviderConfig.kt b/consumer/src/main/kotlin/au/com/dius/pact/consumer/model/MockProviderConfig.kt index f83b9e6c54..3b3630d2bf 100644 --- a/consumer/src/main/kotlin/au/com/dius/pact/consumer/model/MockProviderConfig.kt +++ b/consumer/src/main/kotlin/au/com/dius/pact/consumer/model/MockProviderConfig.kt @@ -42,7 +42,7 @@ enum class MockServerImplementation { /** * Configuration of the Pact Mock Server. * - * By default this class will setup the configuration for a http mock server running on + * By default, this class will set up the configuration for a http mock server running on * local host and a random port */ open class MockProviderConfig @JvmOverloads constructor ( @@ -52,7 +52,8 @@ open class MockProviderConfig @JvmOverloads constructor ( open val scheme: String = HTTP, open val mockServerImplementation: MockServerImplementation = MockServerImplementation.Default, open val addCloseHeader: Boolean = false, - open val transportRegistryEntry: String = "" + open val transportRegistryEntry: String = "", + val transportConfig: Map = emptyMap() ) { fun url(): String { @@ -90,7 +91,8 @@ open class MockProviderConfig @JvmOverloads constructor ( config.mockServerImplementation else mockServerImplementation, addCloseHeader, - transportRegistryEntry.ifEmpty { config.transportRegistryEntry } + transportRegistryEntry.ifEmpty { config.transportRegistryEntry }, + transportConfig + config.transportConfig ) } } @@ -132,7 +134,8 @@ open class MockProviderConfig @JvmOverloads constructor ( if (annotation.tls) "https" else HTTP, annotation.implementation, System.getProperty("pact.mockserver.addCloseHeader") == "true", - annotation.registryEntry + annotation.registryEntry, + annotation.transportConfig.associate { it.key to it.value } ) } else { null diff --git a/consumer/src/test/groovy/au/com/dius/pact/consumer/PluginMockServerSpec.groovy b/consumer/src/test/groovy/au/com/dius/pact/consumer/PluginMockServerSpec.groovy index 5cd84964e6..8935adbfcd 100644 --- a/consumer/src/test/groovy/au/com/dius/pact/consumer/PluginMockServerSpec.groovy +++ b/consumer/src/test/groovy/au/com/dius/pact/consumer/PluginMockServerSpec.groovy @@ -10,6 +10,7 @@ import au.com.dius.pact.core.model.RequestResponseInteraction import au.com.dius.pact.core.model.RequestResponsePact import au.com.dius.pact.core.model.V4Interaction import au.com.dius.pact.core.model.V4Pact +import au.com.dius.pact.core.support.json.JsonValue import io.pact.plugin.Plugin import io.pact.plugins.jvm.core.CatalogueEntry import io.pact.plugins.jvm.core.CatalogueEntryProviderType @@ -55,7 +56,7 @@ class PluginMockServerSpec extends Specification { mockServer.start() then: - 1 * pluginManager.startMockServer(expectedEntry, mockServerConfig, pact) + 1 * pluginManager.startMockServer(expectedEntry, mockServerConfig, pact, [:]) mockServer.transportEntry == expectedEntry } @@ -73,7 +74,26 @@ class PluginMockServerSpec extends Specification { mockServer.start() then: - 1 * pluginManager.startMockServer(expectedEntry, mockServerConfig, pact) + 1 * pluginManager.startMockServer(expectedEntry, mockServerConfig, pact, [:]) + mockServer.transportEntry == expectedEntry + } + + def 'start - passes any transport configuration to the plugin'() { + given: + config = new MockProviderConfig('127.0.0.1', 0, PactSpecVersion.V3, 'http', MockServerImplementation.JavaHttpServer, + false, 'test', [replicationTopic: 'test/RP']) + def mockServerConfig = new MockServerConfig('127.0.0.1', 0, false) + def expectedEntry = new CatalogueEntry(CatalogueEntryType.TRANSPORT, CatalogueEntryProviderType.PLUGIN, + 'test', 'test') + mockServer = new PluginMockServer(pact, config) + mockServer.pluginManager = pluginManager + def configJson = new JsonValue.Object([replicationTopic: new JsonValue.StringValue('test/RP')]) + + when: + mockServer.start() + + then: + 1 * pluginManager.startMockServer(expectedEntry, mockServerConfig, pact, [transport_config: configJson]) mockServer.transportEntry == expectedEntry } diff --git a/core/support/src/main/kotlin/au/com/dius/pact/core/support/Json.kt b/core/support/src/main/kotlin/au/com/dius/pact/core/support/Json.kt index 4cb24b7c5f..515cdb9515 100644 --- a/core/support/src/main/kotlin/au/com/dius/pact/core/support/Json.kt +++ b/core/support/src/main/kotlin/au/com/dius/pact/core/support/Json.kt @@ -139,3 +139,5 @@ fun jsonObject(pairs: List>) = JsonValue.Object( public fun String.toJson() = JsonValue.StringValue(this) public fun String?.toJson() = if (this == null) JsonValue.Null else JsonValue.StringValue(this) + +public fun Map.toJson() = jsonObject(this.toList())