From 832718413c1abba4ce6cfa2b18d503475ffdb969 Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Fri, 24 Jun 2022 15:57:15 +1000 Subject: [PATCH] feat(Gradle): Add auth option for no auth --- .../com/dius/pact/core/support/HttpClient.kt | 8 + .../gradle/GradleProviderInfoSpec.groovy | 3 +- .../provider/gradle/PactPluginSpec.groovy | 230 ++++++++++++++++++ .../provider/gradle/PactPluginTest.groovy | 182 -------------- .../com/dius/pact/provider/ProviderClient.kt | 2 +- .../dius/pact/provider/ProviderVerifier.kt | 5 +- 6 files changed, 244 insertions(+), 186 deletions(-) create mode 100644 provider/gradle/src/test/groovy/au/com/dius/pact/provider/gradle/PactPluginSpec.groovy delete mode 100644 provider/gradle/src/test/groovy/au/com/dius/pact/provider/gradle/PactPluginTest.groovy diff --git a/core/support/src/main/kotlin/au/com/dius/pact/core/support/HttpClient.kt b/core/support/src/main/kotlin/au/com/dius/pact/core/support/HttpClient.kt index a34b12ca05..717614bb0a 100644 --- a/core/support/src/main/kotlin/au/com/dius/pact/core/support/HttpClient.kt +++ b/core/support/src/main/kotlin/au/com/dius/pact/core/support/HttpClient.kt @@ -27,6 +27,11 @@ import java.net.URI * Authentication options */ sealed class Auth { + /** + * No Auth + */ + object None : Auth() + /** * Basic authentication (username/password) */ @@ -44,6 +49,7 @@ sealed class Auth { ep.parseExpression(this.username, DataType.RAW, resolver).toString(), ep.parseExpression(this.password, DataType.RAW, resolver).toString()) is BearerAuthentication -> BearerAuthentication(ep.parseExpression(this.token, DataType.RAW, resolver).toString()) + else -> this } } @@ -51,6 +57,7 @@ sealed class Auth { return when (this) { is BasicAuthentication -> listOf("basic", this.username, this.password) is BearerAuthentication -> listOf("bearer", this.token) + else -> emptyList() } } } @@ -83,6 +90,7 @@ object HttpClient : KLogging() { defaultHeaders["Authorization"] = "Bearer " + authentication.token SystemDefaultCredentialsProvider() } + else -> SystemDefaultCredentialsProvider() } } is List<*> -> { diff --git a/provider/gradle/src/test/groovy/au/com/dius/pact/provider/gradle/GradleProviderInfoSpec.groovy b/provider/gradle/src/test/groovy/au/com/dius/pact/provider/gradle/GradleProviderInfoSpec.groovy index 7006b8622a..3a9d0ca0a6 100644 --- a/provider/gradle/src/test/groovy/au/com/dius/pact/provider/gradle/GradleProviderInfoSpec.groovy +++ b/provider/gradle/src/test/groovy/au/com/dius/pact/provider/gradle/GradleProviderInfoSpec.groovy @@ -1,6 +1,7 @@ package au.com.dius.pact.provider.gradle import au.com.dius.pact.core.pactbroker.ConsumerVersionSelector +import au.com.dius.pact.core.support.Auth import au.com.dius.pact.provider.PactVerification import org.gradle.api.GradleScriptException import org.gradle.api.Project @@ -9,7 +10,7 @@ import spock.lang.Unroll class GradleProviderInfoSpec extends Specification { - def 'defaults the consumer verification type to what is set on the provider'() { + def 'hasPactWith - defaults the consumer verification type to what is set on the provider'() { given: def provider = new GradleProviderInfo('provider', Mock(Project)) provider.verificationType = PactVerification.ANNOTATED_METHOD diff --git a/provider/gradle/src/test/groovy/au/com/dius/pact/provider/gradle/PactPluginSpec.groovy b/provider/gradle/src/test/groovy/au/com/dius/pact/provider/gradle/PactPluginSpec.groovy new file mode 100644 index 0000000000..3fe66373ca --- /dev/null +++ b/provider/gradle/src/test/groovy/au/com/dius/pact/provider/gradle/PactPluginSpec.groovy @@ -0,0 +1,230 @@ +package au.com.dius.pact.provider.gradle + +import au.com.dius.pact.core.support.Auth +import au.com.dius.pact.provider.PactVerification +import org.gradle.api.Project +import org.gradle.api.ProjectConfigurationException +import org.gradle.testfixtures.ProjectBuilder +import spock.lang.Specification + +class PactPluginSpec extends Specification { + + private PactPlugin plugin + private Project project + + void setup() { + project = ProjectBuilder.builder().build() + plugin = new PactPlugin() + plugin.apply(project) + } + + def 'defines a pactVerify task'() { + expect: + project.tasks.pactVerify + } + + def 'defines a pactPublish task'() { + expect: + project.tasks.pactPublish + } + + def 'defines a task for each defined provider'() { + given: + project.pact { + serviceProviders { + provider1 { + + } + + provider2 { + + } + } + } + + when: + project.evaluate() + + then: + project.tasks.pactVerify_provider1 + project.tasks.pactVerify_provider2 + } + + def 'replaces white space with underscores'() { + given: + project.pact { + serviceProviders { + 'invalid Name' { + + } + } + } + + when: + project.evaluate() + + then: + project.tasks.pactVerify_invalid_Name + } + + def 'defines a task for each file in the pact file directory'() { + given: + def resource = getClass().classLoader.getResource('pacts/foo_pact.json') + File pactFileDirectory = new File(resource.file).parentFile + project.pact { + serviceProviders { + provider1 { + hasPactsWith('many consumers') { + pactFileLocation = project.file("${pactFileDirectory.absolutePath}") + stateChange = 'http://localhost:8080/state' + } + } + } + } + + when: + project.evaluate() + def consumers = project.tasks.pactVerify_provider1.providerToVerify.consumers + + then: + consumers.size() == 2 + consumers.find { it.name == 'Foo Consumer' } + consumers.find { it.name == 'Bar Consumer' } + } + + def 'configures the providers and consumers correctly'() { + given: + def pactFileUrl = 'http://localhost:8000/pacts/provider/prividera/consumer/consumera/latest' + def stateChangeUrl = 'http://localhost:8080/stateChange' + project.pact { + serviceProviders { + ProviderA { providerInfo -> + startProviderTask = 'jettyEclipseRun' + terminateProviderTask = 'jettyEclipseStop' + + port = 1234 + + hasPactWith('ConsumerA') { + pactSource = pactFileUrl + stateChange = stateChangeUrl + verificationType = 'REQUEST_RESPONSE' + } + } + } + } + + when: + project.evaluate() + + def provider = project.tasks.pactVerify_ProviderA.providerToVerify + def consumer = provider.consumers.first() + + then: + provider.startProviderTask == 'jettyEclipseRun' + provider.terminateProviderTask == 'jettyEclipseStop' + provider.port == 1234 + + consumer.name == 'ConsumerA' + consumer.pactSource == pactFileUrl + consumer.stateChange == stateChangeUrl + consumer.verificationType == PactVerification.REQUEST_RESPONSE + } + + def 'do not set the state change url automatically'() { + given: + def pactFileUrl = 'http://localhost:8000/pacts/provider/prividera/consumer/consumera/latest' + project.pact { + serviceProviders { + ProviderA { providerInfo -> + hasPactWith('ConsumerA') { + pactSource = url(pactFileUrl) + } + } + } + } + + when: + project.evaluate() + def consumer = project.tasks.pactVerify_ProviderA.providerToVerify.consumers.first() + + then: + consumer.pactSource.toString() == pactFileUrl + consumer.stateChange == null + } + + def 'configures the publish task correctly'() { + given: + project.pact { + + serviceProviders { + ProviderA { + hasPactWith('ConsumerA') { + + } + } + } + + publish { + pactDirectory = '/pact/dir' + pactBrokerUrl = 'http://pactbroker:1234' + } + } + + when: + project.evaluate() + + then: + project.pact.publish.pactDirectory == '/pact/dir' + project.pact.publish.pactBrokerUrl == 'http://pactbroker:1234' + } + + def 'fails if there pact is not a valid configuration'() { + given: + project.ext.pact = '123' + project.pact { + serviceProviders { + ProviderA { + hasPactWith('ConsumerA') { + + } + } + } + } + + when: + project.evaluate() + + then: + thrown(ProjectConfigurationException) + } + + def 'hasPactWith - allows all the values for the consumer to be configured'() { + given: + project.pact { + serviceProviders { + ProviderA { + hasPactWith('boddy the consumer') { + stateChange = url('http://localhost:8001/tasks/pactStateChange') + stateChangeUsesBody = false + packagesToScan = ['one', 'two'] + verificationType = PactVerification.REQUEST_RESPONSE + pactSource = project.file('path/to/pact') + } + } + } + } + + when: + project.evaluate() + def consumer = project.tasks.pactVerify_ProviderA.providerToVerify.consumers.first() + + then: + consumer.name == 'boddy the consumer' + consumer.auth == Auth.None.INSTANCE + consumer.packagesToScan == ['one', 'two'] + consumer.pactSource instanceof File + consumer.pactSource.toString().endsWith('path/to/pact') + consumer.stateChange.toString() == 'http://localhost:8001/tasks/pactStateChange' + !consumer.stateChangeUsesBody + } +} diff --git a/provider/gradle/src/test/groovy/au/com/dius/pact/provider/gradle/PactPluginTest.groovy b/provider/gradle/src/test/groovy/au/com/dius/pact/provider/gradle/PactPluginTest.groovy deleted file mode 100644 index 83de9a085e..0000000000 --- a/provider/gradle/src/test/groovy/au/com/dius/pact/provider/gradle/PactPluginTest.groovy +++ /dev/null @@ -1,182 +0,0 @@ -package au.com.dius.pact.provider.gradle - -import au.com.dius.pact.provider.PactVerification -import org.gradle.api.Project -import org.gradle.api.ProjectConfigurationException -import org.gradle.testfixtures.ProjectBuilder -import org.junit.Before -import org.junit.Test - -class PactPluginTest { - - private PactPlugin plugin - private Project project - - @Before - void setup() { - project = ProjectBuilder.builder().build() - plugin = new PactPlugin() - plugin.apply(project) - } - - @Test - void 'defines a pactVerify task'() { - assert project.tasks.pactVerify - } - - @Test - void 'defines a pactPublish task'() { - assert project.tasks.pactPublish - } - - @Test - void 'defines a task for each defined provider'() { - project.pact { - serviceProviders { - provider1 { - - } - - provider2 { - - } - } - } - - project.evaluate() - - assert project.tasks.pactVerify_provider1 - assert project.tasks.pactVerify_provider2 - } - - @Test - void 'replaces white space with underscores'() { - project.pact { - serviceProviders { - 'invalid Name' { - - } - } - } - project.evaluate() - - assert project.tasks.pactVerify_invalid_Name - } - - @Test - void 'defines a task for each file in the pact file directory'() { - def resource = getClass().classLoader.getResource('pacts/foo_pact.json') - File pactFileDirectory = new File(resource.file).parentFile - project.pact { - serviceProviders { - provider1 { - hasPactsWith('many consumers') { - pactFileLocation = project.file("${pactFileDirectory.absolutePath}") - stateChange = 'http://localhost:8080/state' - } - } - } - } - project.evaluate() - - def consumers = project.tasks.pactVerify_provider1.providerToVerify.consumers - assert consumers.size() == 2 - assert consumers.find { it.name == 'Foo Consumer' } - assert consumers.find { it.name == 'Bar Consumer' } - } - - @Test - void 'configures the providers and consumers correctly'() { - def pactFileUrl = 'http://localhost:8000/pacts/provider/prividera/consumer/consumera/latest' - def stateChangeUrl = 'http://localhost:8080/stateChange' - project.pact { - serviceProviders { - ProviderA { providerInfo -> - startProviderTask = 'jettyEclipseRun' - terminateProviderTask = 'jettyEclipseStop' - - port = 1234 - - hasPactWith('ConsumerA') { - pactSource = pactFileUrl - stateChange = stateChangeUrl - verificationType = 'REQUEST_RESPONSE' - } - } - } - } - - project.evaluate() - - def provider = project.tasks.pactVerify_ProviderA.providerToVerify - assert provider.startProviderTask == 'jettyEclipseRun' - assert provider.terminateProviderTask == 'jettyEclipseStop' - assert provider.port == 1234 - - def consumer = provider.consumers.first() - assert consumer.name == 'ConsumerA' - assert consumer.pactSource == pactFileUrl - assert consumer.stateChange == stateChangeUrl - assert consumer.verificationType == PactVerification.REQUEST_RESPONSE - } - - @Test - void 'do not set the state change url automatically'() { - def pactFileUrl = 'http://localhost:8000/pacts/provider/prividera/consumer/consumera/latest' - project.pact { - serviceProviders { - ProviderA { providerInfo -> - hasPactWith('ConsumerA') { - pactSource = url(pactFileUrl) - } - } - } - } - - project.evaluate() - - def consumer = project.tasks.pactVerify_ProviderA.providerToVerify.consumers.first() - assert consumer.pactSource.toString() == pactFileUrl - assert consumer.stateChange == null - } - - @Test - void 'configures the publish task correctly'() { - project.pact { - - serviceProviders { - ProviderA { - hasPactWith('ConsumerA') { - - } - } - } - - publish { - pactDirectory = '/pact/dir' - pactBrokerUrl = 'http://pactbroker:1234' - } - } - - project.evaluate() - - assert project.pact.publish.pactDirectory == '/pact/dir' - assert project.pact.publish.pactBrokerUrl == 'http://pactbroker:1234' - } - - @Test(expected = ProjectConfigurationException) - void 'fails if there pact is not a valid configuration'() { - project.ext.pact = '123' - project.pact { - serviceProviders { - ProviderA { - hasPactWith('ConsumerA') { - - } - } - } - } - - project.evaluate() - } -} diff --git a/provider/src/main/kotlin/au/com/dius/pact/provider/ProviderClient.kt b/provider/src/main/kotlin/au/com/dius/pact/provider/ProviderClient.kt index fe959d2210..d1390e703d 100644 --- a/provider/src/main/kotlin/au/com/dius/pact/provider/ProviderClient.kt +++ b/provider/src/main/kotlin/au/com/dius/pact/provider/ProviderClient.kt @@ -100,7 +100,7 @@ open class ConsumerInfo @JvmOverloads constructor ( override val notices: List = emptyList(), override val pending: Boolean = false, override val wip: Boolean = false, - override val auth: Auth? = null + override val auth: Auth? = Auth.None ) : IConsumerInfo { override fun toPactConsumer() = au.com.dius.pact.core.model.Consumer(name) diff --git a/provider/src/main/kotlin/au/com/dius/pact/provider/ProviderVerifier.kt b/provider/src/main/kotlin/au/com/dius/pact/provider/ProviderVerifier.kt index 18ebe744df..5307baec4a 100644 --- a/provider/src/main/kotlin/au/com/dius/pact/provider/ProviderVerifier.kt +++ b/provider/src/main/kotlin/au/com/dius/pact/provider/ProviderVerifier.kt @@ -23,8 +23,9 @@ import au.com.dius.pact.core.model.generators.GeneratorTestMode import au.com.dius.pact.core.model.messaging.Message import au.com.dius.pact.core.model.messaging.MessageInteraction import au.com.dius.pact.core.pactbroker.IPactBrokerClient -import au.com.dius.pact.core.support.Metrics +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.expressions.SystemPropertyResolver import au.com.dius.pact.core.support.hasProperty import au.com.dius.pact.core.support.ifNullOrEmpty @@ -910,7 +911,7 @@ open class ProviderVerifier @JvmOverloads constructor ( return if (pactSource is UrlPactSource) { val options = mutableMapOf() - if (consumer.auth != null) { + if (consumer.auth != null && consumer.auth !is Auth.None) { options["authentication"] = consumer.auth!! } else if (consumer.pactFileAuthentication.isNotEmpty()) { options["authentication"] = consumer.pactFileAuthentication