Skip to content

Commit

Permalink
feat: allow multiple provider tags when publishing results #1187
Browse files Browse the repository at this point in the history
  • Loading branch information
Ronald Holshausen committed Aug 22, 2020
1 parent 1f0e8f0 commit 979a7db
Show file tree
Hide file tree
Showing 11 changed files with 121 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -347,8 +347,9 @@ open class PactBrokerClient(val pactBrokerUrl: String, override val options: Map
}
}

@Deprecated("Use publishProviderTags", replaceWith = ReplaceWith("publishProviderTags"))
fun publishProviderTag(docAttributes: Map<String, Any?>, name: String, tag: String, version: String) {
return try {
try {
val halClient = newHalClient()
.withDocContext(docAttributes)
.navigate(PROVIDER)
Expand All @@ -361,6 +362,22 @@ open class PactBrokerClient(val pactBrokerUrl: String, override val options: Map
}
}

fun publishProviderTags(docAttributes: Map<String, Any?>, name: String, tags: List<String>, version: String) {
try {
val halClient = newHalClient()
.withDocContext(docAttributes)
.navigate(PROVIDER)
tags.forEach {
when (val result = halClient.putJson(PROVIDER_TAG_VERSION, mapOf("version" to version, "tag" to it), "{}")) {
is Ok<*> -> logger.debug { "Pushed tag $it for provider $name and version $version" }
is Err<Exception> -> logger.error(result.error) { "Failed to push tag $it for provider $name and version $version" }
}
}
} catch (e: NotFoundHalResponse) {
logger.error(e) { "Could not tag provider $name, link was missing" }
}
}

open fun canIDeploy(pacticipant: String, pacticipantVersion: String, latest: Latest, to: String?): CanIDeployResult {
val halClient = newHalClient()
val result = halClient.getJson("/matrix" + buildMatrixQuery(pacticipant, pacticipantVersion, latest, to),
Expand Down
9 changes: 6 additions & 3 deletions provider/gradle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ The following project properties can be specified with `-Pproperty=value` on the
|`pact.matching.wildcard`|Enables matching of map values ignoring the keys when this property is set to 'true'|
|`pact.verifier.disableUrlPathDecoding`|Disables decoding of request paths|
|`pact.pactbroker.httpclient.usePreemptiveAuthentication`|Enables preemptive authentication with the pact broker when set to `true`|
|`pact.provider.tag`|Sets the provider tag to push before publishing verification results|
|`pact.provider.tag`|Sets the provider tag to push before publishing verification results (can use a comma separated list)|
|`pact.content_type.override.<TYPE>.<SUBTYPE>=<VAL>` where `<VAL>` may be `text` or `binary`|Overrides the handling of a particular content type [4.1.3+]|

## Specifying the provider hostname at runtime
Expand Down Expand Up @@ -906,7 +906,7 @@ pact {
serviceProviders {
provider1 {
providerVersion = { branchName() + '-' + abbreviatedId() }
providerTag = { branchName() }
providerTags = { [ branchName() ] }
hasPactsFromPactBroker('http://pact-broker:5000/', authentication: ['Basic', pactBrokerUser, pactBrokerPassword])
}
}
Expand All @@ -917,7 +917,10 @@ or you can set the `pact.provider.tag` JVM system property. For example:

```console
$ ./gradlew -d pactverify -Ppact.verifier.publishResults=true -Dpact.provider.tag=Test2
```
```

From 4.1.8+, you can specify multiple tags with an array for the `providerTag` value, or a comma separated string for the `pact.provider.tag`
system property.

# Pending Pact Support (version 4.1.0 and later)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ import org.gradle.util.ConfigureUtil
*/
class GradleProviderInfo extends ProviderInfo {
def providerVersion
/**
* @deprecated Use providerTags instead
*/
@Deprecated
def providerTag
Closure<List<String>> providerTags
PactBrokerConsumerConfig brokerConfig

GradleProviderInfo(String name) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,14 @@ class PactVerificationTask extends PactVerificationBaseTask {
project.sourceSets.test.runtimeClasspath*.toURL()
}
providerVersion = providerToVerify.providerVersion ?: { project.version }
if (providerToVerify.providerTag) {
providerTag = providerToVerify.providerTag
if (providerToVerify.providerTags) {
providerTags = providerToVerify.providerTags
} else if (providerToVerify.providerTag) {
if (providerToVerify.providerTag instanceof Closure) {
providerTags = { [ providerToVerify.providerTag.call() ] }
} else {
providerTags = { [ providerToVerify.providerTag ] }
}
}

if (project.pact.reports) {
Expand Down
3 changes: 3 additions & 0 deletions provider/junit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,9 @@ To enable publishing of results, set the Java system property or environment var
You can have a tag pushed against the provider version before the verification results are published. To do this
you need set the `pact.provider.tag` JVM system property to the tag value.

From 4.1.8+, you can specify multiple tags with a comma separated string for the `pact.provider.tag`
system property.

# Pending Pact Support (version 4.1.0 and later)

If your Pact broker supports pending pacts, you can enable support for that by enabling that on your Pact broker annotation or with JVM system properties. You also need to provide the tags that will be published with your provider's verification results. The broker will then label any pacts found that don't have a successful verification result as pending. That way, if they fail verification, the verifier will ignore those failures and not fail the build.
Expand Down
3 changes: 3 additions & 0 deletions provider/maven/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,9 @@ To turn on the verification publishing, set the system property `pact.verifier.p
You can have a tag pushed against the provider version before the verification results are published. To do this
you need set the `pact.provider.tag` JVM system property to the tag value.

From 4.1.8+, you can specify multiple tags with a comma separated string for the `pact.provider.tag`
system property.

# Enabling other verification reports

By default the verification report is written to the console. You can also enable a JSON or Markdown report by setting
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,14 @@ interface IProviderVerifier {
/**
* Callback to get the provider tag
*/
@Deprecated("Use version that returns multiple tags", replaceWith = ReplaceWith("providerTags"))
var providerTag: Supplier<String?>?

/**
* Callback to get the provider tags
*/
var providerTags: Supplier<List<String>>?

/**
* Run the verification for the given provider and return any failures
*/
Expand Down Expand Up @@ -237,7 +243,10 @@ open class ProviderVerifier @JvmOverloads constructor (
override var reporters: List<VerifierReporter> = listOf(AnsiConsoleReporter("console", File("/tmp/"))),
override var providerMethodInstance: Function<Method, Any> = Function { m -> m.declaringClass.newInstance() },
override var providerVersion: Supplier<String> = ProviderVersion { System.getProperty(PACT_PROVIDER_VERSION) },
override var providerTag: Supplier<String?>? = Supplier { System.getProperty(PACT_PROVIDER_TAG) }
override var providerTag: Supplier<String?>? = Supplier { System.getProperty(PACT_PROVIDER_TAG) },
override var providerTags: Supplier<List<String>>? = Supplier {
System.getProperty(PACT_PROVIDER_TAG).orEmpty().split(',').map { it.trim() }.filter { it.isNotEmpty() }
}
) : IProviderVerifier {

override var projectHasProperty = Function<String, Boolean> { name -> !System.getProperty(name).isNullOrEmpty() }
Expand Down Expand Up @@ -672,7 +681,7 @@ open class ProviderVerifier @JvmOverloads constructor (
result.toTestResult(),
providerVersion.get(),
client,
providerTag?.get())
providerTags?.get().orEmpty())
}
result
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ object DefaultTestResultAccumulator : TestResultAccumulator, KLogging() {
} else {
verificationReporter.reportResults(pact, interactionResults.values.fold(TestResult.Ok) {
acc: TestResult, result -> acc.merge(result)
}, lookupProviderVersion(), null, lookupProviderTag())
}, lookupProviderVersion(), null, lookupProviderTags())
}
testResults.remove(pactHash)
} else {
Expand Down Expand Up @@ -105,7 +105,8 @@ object DefaultTestResultAccumulator : TestResultAccumulator, KLogging() {
}
}

private fun lookupProviderTag(): String? = System.getProperty("pact.provider.tag")
private fun lookupProviderTags() = System.getProperty("pact.provider.tag").orEmpty().split(',')
.map { it.trim() }.filter { it.isNotEmpty() }

fun unverifiedInteractions(pact: Pact<out Interaction>, results: MutableMap<Int, TestResult>): List<Interaction> {
logger.debug { "Number of interactions #${pact.interactions.size} and results: ${results.values}" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ interface VerificationReporter {
/**
* Publish the results to the pact broker. If the tag is given, then the provider will be tagged with that first.
*/
@Deprecated("Use version that takes a list of provider tags")
fun reportResults(
pact: Pact<out Interaction>,
result: TestResult,
Expand All @@ -23,6 +24,17 @@ interface VerificationReporter {
tag: String? = null
)

/**
* Publish the results to the pact broker. If the tags are given, then the provider will be tagged with those first.
*/
fun reportResults(
pact: Pact<out Interaction>,
result: TestResult,
version: String,
client: PactBrokerClient? = null,
tags: List<String> = emptyList()
)

/**
* This must return true unless the pact.verifier.publishResults property has the value of "true"
*/
Expand All @@ -40,11 +52,25 @@ object DefaultVerificationReporter : VerificationReporter, KLogging() {
version: String,
client: PactBrokerClient?,
tag: String?
) {
if (tag.isNullOrEmpty()) {
reportResults(pact, result, version, client, emptyList())
} else {
reportResults(pact, result, version, client, listOf(tag))
}
}

override fun reportResults(
pact: Pact<out Interaction>,
result: TestResult,
version: String,
client: PactBrokerClient?,
tags: List<String>
) {
when (val source = pact.source) {
is BrokerUrlSource -> {
val brokerClient = client ?: PactBrokerClient(source.pactBrokerUrl, source.options)
publishResult(brokerClient, source, result, version, pact, tag)
publishResult(brokerClient, source, result, version, pact, tags)
}
else -> logger.info { "Skipping publishing verification results for source $source" }
}
Expand All @@ -56,10 +82,10 @@ object DefaultVerificationReporter : VerificationReporter, KLogging() {
result: TestResult,
version: String,
pact: Pact<out I>,
tag: String?
tags: List<String>
) {
if (!tag.isNullOrEmpty()) {
brokerClient.publishProviderTag(source.attributes, pact.provider.name, tag, version)
if (tags.isNotEmpty()) {
brokerClient.publishProviderTags(source.attributes, pact.provider.name, tags, version)
}
val publishResult = brokerClient.publishVerificationResults(source.attributes, result, version)
if (publishResult is Err) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -403,11 +403,13 @@ class ProviderVerifierSpec extends Specification {

@Unroll
@SuppressWarnings('UnnecessaryGetter')
@RestoreSystemProperties
def 'after verifying a pact, the results are reported back using reportVerificationResults'() {
given:
ProviderInfo provider = new ProviderInfo('Test Provider')
ConsumerInfo consumer = new ConsumerInfo(name: 'Test Consumer', pactSource: UnknownPactSource.INSTANCE)
PactBrokerClient pactBrokerClient = Mock(PactBrokerClient, constructorArgs: [''])
verifier.verificationReporter = Mock(VerificationReporter)
verifier.pactReader = Stub(PactReader)
def statechange = Stub(StateChange) {
executeStateChange(*_) >> new StateChangeResult(new Ok([:]))
Expand All @@ -427,11 +429,13 @@ class ProviderVerifierSpec extends Specification {
verifier.pactReader.loadPact(_) >> mockPact
mockPact.interactions >> [interaction1, interaction2]

System.setProperty('pact.provider.tag', 'tag1,tag2 , tag3 ')

when:
verifier.runVerificationForConsumer([:], provider, consumer, pactBrokerClient)

then:
1 * pactBrokerClient.publishVerificationResults(_, finalResult, '0.0.0', _)
1 * verifier.verificationReporter.reportResults(_, finalResult, '0.0.0', pactBrokerClient, ['tag1', 'tag2', 'tag3'])
1 * verifier.verifyResponseFromProvider(provider, interaction1, _, _, _, _, false) >> result1
1 * verifier.verifyResponseFromProvider(provider, interaction2, _, _, _, _, false) >> result2

Expand Down Expand Up @@ -490,7 +494,7 @@ class ProviderVerifierSpec extends Specification {
def client = Mock(PactBrokerClient)

when:
DefaultVerificationReporter.INSTANCE.reportResults(pact, TestResult.Ok.INSTANCE, '0', client, null)
DefaultVerificationReporter.INSTANCE.reportResults(pact, TestResult.Ok.INSTANCE, '0', client, [])

then:
1 * client.publishVerificationResults(links, TestResult.Ok.INSTANCE, '0', null) >> new Ok(true)
Expand All @@ -505,7 +509,7 @@ class ProviderVerifierSpec extends Specification {
def client = Mock(PactBrokerClient)

when:
DefaultVerificationReporter.INSTANCE.reportResults(pact, TestResult.Ok.INSTANCE, '0', client, null)
DefaultVerificationReporter.INSTANCE.reportResults(pact, TestResult.Ok.INSTANCE, '0', client, [])

then:
0 * client.publishVerificationResults(_, TestResult.Ok.INSTANCE, '0', null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class TestResultAccumulatorSpec extends Specification {
testResultAccumulator.updateTestResult(mutablePact, interaction3, TestResult.Ok.INSTANCE, null)

then:
1 * mockVerificationReporter.reportResults(_, TestResult.Ok.INSTANCE, _, null, null)
1 * mockVerificationReporter.reportResults(_, TestResult.Ok.INSTANCE, _, null, [])

cleanup:
testResultAccumulator.verificationReporter = DefaultVerificationReporter.INSTANCE
Expand Down Expand Up @@ -231,7 +231,32 @@ class TestResultAccumulatorSpec extends Specification {

then:
1 * testResultAccumulator.verificationReporter.reportResults(_, TestResult.Ok.INSTANCE, _, _,
'updateTestResultTag')
['updateTestResultTag'])
testResultAccumulator.testResults.isEmpty()

cleanup:
testResultAccumulator.verificationReporter = reporter
}

@RestoreSystemProperties
@SuppressWarnings('UnnecessaryGetter')
def 'updateTestResult - include all the provider tags'() {
given:
def pact = new RequestResponsePact(new Provider('provider'), new Consumer('consumer'),
[interaction1])
testResultAccumulator.testResults.clear()
def reporter = testResultAccumulator.verificationReporter
testResultAccumulator.verificationReporter = Mock(VerificationReporter) {
publishingResultsDisabled() >> false
}
System.setProperty('pact.provider.tag', 'tag1,tag2 , tag3 ')

when:
testResultAccumulator.updateTestResult(pact, interaction1, TestResult.Ok.INSTANCE, null)

then:
1 * testResultAccumulator.verificationReporter.reportResults(_, TestResult.Ok.INSTANCE, _, _,
['tag1', 'tag2', 'tag3'])
testResultAccumulator.testResults.isEmpty()

cleanup:
Expand Down

0 comments on commit 979a7db

Please sign in to comment.