From 418c1d39e0b5c1634f080458786d0b9236fdb81b Mon Sep 17 00:00:00 2001 From: Phil Endsley Date: Thu, 25 Jun 2020 08:03:09 -0500 Subject: [PATCH 1/3] feat: Add support for includeWipPactsSince parameter --- .../pact/core/pactbroker/PactBrokerClient.kt | 15 +- .../core/pactbroker/PactBrokerConsumer.kt | 3 +- .../pactbroker/PactBrokerClientSpec.groovy | 80 ++++++-- .../broker/PactBrokerClientPactSpec.groovy | 128 +++++++++++- .../DescriptionGeneratorTest.groovy | 2 +- .../junit/loader/PactBrokerLoaderSpec.groovy | 188 ++++++++++++------ .../junitsupport/loader/PactBroker.java | 6 + .../com/dius/pact/provider/ProviderClient.kt | 12 +- .../au/com/dius/pact/provider/ProviderInfo.kt | 4 +- .../junitsupport/loader/PactBrokerLoader.kt | 13 +- .../pact/provider/ProviderInfoSpec.groovy | 55 ++++- 11 files changed, 410 insertions(+), 96 deletions(-) diff --git a/core/pactbroker/src/main/kotlin/au/com/dius/pact/core/pactbroker/PactBrokerClient.kt b/core/pactbroker/src/main/kotlin/au/com/dius/pact/core/pactbroker/PactBrokerClient.kt index 5e92521c5c..dbd3596230 100644 --- a/core/pactbroker/src/main/kotlin/au/com/dius/pact/core/pactbroker/PactBrokerClient.kt +++ b/core/pactbroker/src/main/kotlin/au/com/dius/pact/core/pactbroker/PactBrokerClient.kt @@ -76,7 +76,8 @@ interface IPactBrokerClient { providerName: String, selectors: List, providerTags: List = emptyList(), - enablePending: Boolean = false + enablePending: Boolean = false, + includeWipPactsSince: String ): Result, Exception> fun getUrlForProvider(providerName: String, tag: String): String? @@ -145,7 +146,8 @@ open class PactBrokerClient(val pactBrokerUrl: String, override val options: Map providerName: String, selectors: List, providerTags: List, - enablePending: Boolean + enablePending: Boolean, + includeWipPactsSince: String ): Result, Exception> { val navigateResult = handleWith { newHalClient().navigate() } val halClient = when (navigateResult) { @@ -164,6 +166,9 @@ open class PactBrokerClient(val pactBrokerUrl: String, override val options: Map if (enablePending) { body["providerVersionTags"] = jsonArray(providerTags) body["includePendingStatus"] = true + if (!includeWipPactsSince.isBlank()) { + body["includeWipPactsSince"] = includeWipPactsSince + } } return handleWith { @@ -179,10 +184,12 @@ open class PactBrokerClient(val pactBrokerUrl: String, override val options: Map if (properties is JsonValue.Object && properties.has("pending") && properties["pending"].isBoolean) { pending = properties["pending"].asBoolean() } + val wip = if (properties.has("wip") && properties["wip"].isBoolean) properties["wip"].asBoolean() + else false if (options.containsKey("authentication")) { - PactBrokerResult(name, href, pactBrokerUrl, options["authentication"] as List, notices, pending) + PactBrokerResult(name, href, pactBrokerUrl, options["authentication"] as List, notices, pending, wip = wip) } else { - PactBrokerResult(name, href, pactBrokerUrl, emptyList(), notices, pending) + PactBrokerResult(name, href, pactBrokerUrl, emptyList(), notices, pending, wip = wip) } } } diff --git a/core/pactbroker/src/main/kotlin/au/com/dius/pact/core/pactbroker/PactBrokerConsumer.kt b/core/pactbroker/src/main/kotlin/au/com/dius/pact/core/pactbroker/PactBrokerConsumer.kt index b8c074a9d9..4445942ec9 100644 --- a/core/pactbroker/src/main/kotlin/au/com/dius/pact/core/pactbroker/PactBrokerConsumer.kt +++ b/core/pactbroker/src/main/kotlin/au/com/dius/pact/core/pactbroker/PactBrokerConsumer.kt @@ -10,7 +10,8 @@ data class PactBrokerResult( val pactFileAuthentication: List = listOf(), val notices: List = listOf(), val pending: Boolean = false, - val tag: String? = null + val tag: String? = null, + val wip: Boolean = false ) data class VerificationNotice( diff --git a/core/pactbroker/src/test/groovy/au/com/dius/pact/core/pactbroker/PactBrokerClientSpec.groovy b/core/pactbroker/src/test/groovy/au/com/dius/pact/core/pactbroker/PactBrokerClientSpec.groovy index ee42fae554..2c816f577e 100644 --- a/core/pactbroker/src/test/groovy/au/com/dius/pact/core/pactbroker/PactBrokerClientSpec.groovy +++ b/core/pactbroker/src/test/groovy/au/com/dius/pact/core/pactbroker/PactBrokerClientSpec.groovy @@ -48,7 +48,7 @@ class PactBrokerClientSpec extends Specification { } when: - def consumers = client.fetchConsumersWithSelectors('provider', [], [], false).value + def consumers = client.fetchConsumersWithSelectors('provider', [], [], false, '').value then: consumers != [] @@ -69,7 +69,7 @@ class PactBrokerClientSpec extends Specification { } when: - def consumers = client.fetchConsumersWithSelectors('provider', [], [], false).value + def consumers = client.fetchConsumersWithSelectors('provider', [], [], false, '').value then: consumers == [] @@ -87,7 +87,7 @@ class PactBrokerClientSpec extends Specification { } when: - def consumers = client.fetchConsumersWithSelectors('provider', [], [], false).value + def consumers = client.fetchConsumersWithSelectors('provider', [], [], false, '').value then: consumers != [] @@ -108,7 +108,7 @@ class PactBrokerClientSpec extends Specification { when: def consumers = client.fetchConsumersWithSelectors('provider', - [ new ConsumerVersionSelector('tag', true) ], [], false).value + [ new ConsumerVersionSelector('tag', true) ], [], false, '').value then: consumers != [] @@ -130,7 +130,7 @@ class PactBrokerClientSpec extends Specification { when: def consumers = client.fetchConsumersWithSelectors('provider', [ new ConsumerVersionSelector('tag', true), - new ConsumerVersionSelector('anotherTag', true) ], [], false).value + new ConsumerVersionSelector('anotherTag', true) ], [], false, '').value then: consumers.size() == 2 @@ -160,7 +160,7 @@ class PactBrokerClientSpec extends Specification { when: def consumers = client.fetchConsumersWithSelectors('provider', - [ new ConsumerVersionSelector('tag', true) ], [], false).value + [ new ConsumerVersionSelector('tag', true) ], [], false, '').value then: consumers.first().pactFileAuthentication == ['Basic', '1', '2'] @@ -179,7 +179,7 @@ class PactBrokerClientSpec extends Specification { when: def consumers = client.fetchConsumersWithSelectors('provider', - [ new ConsumerVersionSelector('tag', true) ], [], false).value + [ new ConsumerVersionSelector('tag', true) ], [], false, '').value then: consumers != [] @@ -200,7 +200,7 @@ class PactBrokerClientSpec extends Specification { when: def consumers = client.fetchConsumersWithSelectors('provider', - [ new ConsumerVersionSelector('tag', true) ], [], false).value + [ new ConsumerVersionSelector('tag', true) ], [], false, '').value then: consumers == [] @@ -393,7 +393,7 @@ class PactBrokerClientSpec extends Specification { ''') when: - def result = client.fetchConsumersWithSelectors('provider', selectors, [], false) + def result = client.fetchConsumersWithSelectors('provider', selectors, [], false, '') then: 1 * halClient.navigate() >> halClient @@ -407,7 +407,8 @@ class PactBrokerClientSpec extends Specification { 'The pact at ... is being verified because it matches the following configured selection criterion: latest pact for a consumer version tagged \'DEV\'') ], false, - null + null, + false ) } @@ -427,7 +428,7 @@ class PactBrokerClientSpec extends Specification { ''') when: - def result = client.fetchConsumersWithSelectors('provider', [], [], false) + def result = client.fetchConsumersWithSelectors('provider', [], [], false, '') then: 1 * halClient.navigate() >> halClient @@ -445,7 +446,7 @@ class PactBrokerClientSpec extends Specification { } when: - def result = client.fetchConsumersWithSelectors('provider', [], [], false) + def result = client.fetchConsumersWithSelectors('provider', [], [], false, '') then: 1 * halClient.navigate() >> halClient @@ -455,4 +456,59 @@ class PactBrokerClientSpec extends Specification { 1 * client.fetchConsumers('provider') >> [] result instanceof Ok } + + def 'fetching pacts with selectors does not include wip pacts when pending parameter is false'() { + given: + def halClient = Mock(IHalClient) + PactBrokerClient client = Spy(PactBrokerClient, constructorArgs: ['baseUrl']) { + newHalClient() >> halClient + } + def selectors = [ new ConsumerVersionSelector('DEV', true) ] + def json = '{"consumerVersionSelectors":[{"tag":"DEV","latest":true}]}' + def jsonResult = JsonParser.INSTANCE.parseString(''' + { + "_embedded": { + "pacts": [ + ] + } + } + ''') + when: + def result = client.fetchConsumersWithSelectors('provider', selectors, [], false, '2020-24-06') + + then: + 1 * halClient.navigate() >> halClient + 1 * halClient.linkUrl('pb:provider-pacts-for-verification') >> 'URL' + 1 * halClient.postJson('pb:provider-pacts-for-verification', [provider: 'provider'], json) >> new Ok(jsonResult) + result instanceof Ok + } + + def 'fetching pacts with selectors includes wip pacts when parameter not blank'() { + given: + def halClient = Mock(IHalClient) + PactBrokerClient client = Spy(PactBrokerClient, constructorArgs: ['baseUrl']) { + newHalClient() >> halClient + } + def selectors = [ new ConsumerVersionSelector('DEV', true) ] + def json = '{"consumerVersionSelectors":[{"tag":"DEV","latest":true}],' + + '"providerVersionTags":[],' + + '"includePendingStatus":true,' + + '"includeWipPactsSince":"2020-24-06"}' + def jsonResult = JsonParser.INSTANCE.parseString(''' + { + "_embedded": { + "pacts": [ + ] + } + } + ''') + when: + def result = client.fetchConsumersWithSelectors('provider', selectors, [], true, '2020-24-06') + + then: + 1 * halClient.navigate() >> halClient + 1 * halClient.linkUrl('pb:provider-pacts-for-verification') >> 'URL' + 1 * halClient.postJson('pb:provider-pacts-for-verification', [provider: 'provider'], json) >> new Ok(jsonResult) + result instanceof Ok + } } diff --git a/pact-publish/src/test/groovy/broker/PactBrokerClientPactSpec.groovy b/pact-publish/src/test/groovy/broker/PactBrokerClientPactSpec.groovy index 68ee371221..1b611db33f 100644 --- a/pact-publish/src/test/groovy/broker/PactBrokerClientPactSpec.groovy +++ b/pact-publish/src/test/groovy/broker/PactBrokerClientPactSpec.groovy @@ -565,7 +565,7 @@ class PactBrokerClientPactSpec extends Specification { def result = pactBroker.runTest { server, context -> def consumerPacts = pactBrokerClient.fetchConsumersWithSelectors('Activity Service', [ new ConsumerVersionSelector('test', true) - ], [], false) + ], [], false, '') assert consumerPacts instanceof Ok assert consumerPacts.value.size == 2 assert !consumerPacts.value[0].pending @@ -678,7 +678,7 @@ class PactBrokerClientPactSpec extends Specification { def result = pactBroker.runTest { server, context -> def consumerPacts = pactBrokerClient.fetchConsumersWithSelectors('Activity Service', [ new ConsumerVersionSelector('test', true) - ], ['master'], true) + ], ['master'], true, '') assert consumerPacts instanceof Ok assert consumerPacts.value.size == 2 assert !consumerPacts.value[0].pending @@ -688,4 +688,128 @@ class PactBrokerClientPactSpec extends Specification { then: result instanceof PactVerificationResult.Ok } + + def 'fetch pacts when wip pacts feature is on'() { + given: + pactBroker { + uponReceiving('a request to the root') + withAttributes(path: '/') + willRespondWith(status: 200) + withBody(contentType: 'application/hal+json') { + '_links' { + 'pb:provider-pacts-for-verification' { + href url('http://localhost:8080', 'pacts', 'provider', '{provider}', 'for-verification') + title 'Pact versions to be verified for the specified provider' + templated true + } + } + } + given('Two consumer pacts exist for the provider', [ + provider: 'Activity Service', + consumer1: 'Foo Web Client', + consumer2: 'Foo Web Client 2' + ]) + given('pact for consumer2 is wip', [ + consumer2: 'Foo Web Client 2' + ]) + uponReceiving('a request for the provider pacts') + withAttributes(method: 'POST', path: '/pacts/provider/Activity Service/for-verification') + withBody(contentType: 'application/hal+json') { + consumerVersionSelectors([ + { + tag 'test' + latest true + } + ]) + providerVersionTags(['master']) + includePendingStatus true + includeWipPactsSince '2020-06-24' + } + willRespondWith(status: 200) + withBody(contentType: 'application/hal+json') { + '_embedded' { + pacts = [ + { + shortDescription 'latest' + 'verificationProperties' { + notices = [ + { + when 'before_verification' + text 'The pact at https://test.pact.dius.com.au/pacts/provider/Activity%20Service/consumer/Foo%20Web%20Client/pact-version/384826ff3a2856e28dfae553efab302863dcd727 is being verified because it matches the following configured selection criterion: latest pact between a consumer and Activity Service' + } + ] + noteToDevelopers 'Please print out the text from the \'notices\' rather than using the inclusionReason and the pendingReason fields. These will be removed when this API moves out of beta.' + } + '_links' { + self { + href 'https://test.pact.dius.com.au/pacts/provider/Activity%20Service/consumer/Foo%20Web%20Client/pact-version/384826ff3a2856e28dfae553efab302863dcd727' + name 'Pact between Foo Web Client (0.0.0-TEST) and Activity Service' + } + } + }, + { + shortDescription 'latest' + 'verificationProperties' { + pending true + wip true + notices = [ + { + when 'before_verification' + text 'The pact at https://test.pact-dev.dius.com.au/pacts/provider/Bar/consumer/Foo/pact-version/dd222221d7d3d915ec6315ca3ebbd76831aab6a3 is being verified because it is a \'work in progress\' pact (ie. it is the pact for the latest versions of Foo tagged with \'feature-x\' and is still in pending state). Read more at https//pact.io/wip' + }, + { + when 'before_verification' + text 'This pact is in pending state for this version of Bar because a successful verification result for Bar has not yet been published. If this verification fails, it will not cause the overall build to fail. Read more at https://pact.io/pending' + }, + { + when 'after_verification:success_true_published_false' + text 'This pact is still in pending state for Bar as the successful verification results have not yet been published.' + }, + { + when 'after_verification:success_false_published_false' + text 'This pact is still in pending state for Bar as a successful verification result has not yet been published' + }, + { + when 'after_verification:success_true_published_true' + text 'This pact is no longer in pending state for Bar, as a successful verification result with this tag has been published. If a verification for a version with fails in the future, it will fail the build. Read more at https//pact.io/pending' + }, + { + when 'after_verification:success_false_published_true' + text 'This pact is still in pending state for Bar as the successful verification results have not yet been published.' + } + ] + noteToDevelopers 'Please print out the text from the \'notices\' rather than using the inclusionReason and the pendingReason fields. These will be removed when this API moves out of beta.' + } + '_links' { + self { + href 'https://test.pact.dius.com.au/pacts/provider/Activity%20Service/consumer/Foo%20Web%20Client%202/pact-version/21ac89178372169288d3f17fee9f7901d9ed5e8b' + name 'Pact between Foo Web Client 2 (0.0.0-TEST) and Activity Service' + } + } + } + ] + } + '_links' { + self { + href 'https://test.pact.dius.com.au/pacts/provider/Activity%20Service/for-verification' + title 'Pacts to be verified' + } + } + } + } + + when: + def result = pactBroker.runTest { server, context -> + def consumerPacts = pactBrokerClient.fetchConsumersWithSelectors('Activity Service', [ + new ConsumerVersionSelector('test', true) + ], ['master'], true, '2020-06-24') + assert consumerPacts instanceof Ok + assert consumerPacts.value.size == 2 + assert !consumerPacts.value[0].wip + assert consumerPacts.value[1].wip + } + + then: + result instanceof PactVerificationResult.Ok + } } diff --git a/provider/junit/src/test/groovy/au/com/dius/pact/provider/junit/descriptions/DescriptionGeneratorTest.groovy b/provider/junit/src/test/groovy/au/com/dius/pact/provider/junit/descriptions/DescriptionGeneratorTest.groovy index 3134dca008..21f61134e4 100644 --- a/provider/junit/src/test/groovy/au/com/dius/pact/provider/junit/descriptions/DescriptionGeneratorTest.groovy +++ b/provider/junit/src/test/groovy/au/com/dius/pact/provider/junit/descriptions/DescriptionGeneratorTest.groovy @@ -74,7 +74,7 @@ class DescriptionGeneratorTest extends Specification { def interaction = new RequestResponseInteraction('Interaction 1', [ new ProviderState('Test State') ], new Request(), new Response()) def pactSource = new BrokerUrlSource('url', 'url', [:], [:], 'master', - new PactBrokerResult('test', 'test', 'test', [], [], pending == 'enabled', null)) + new PactBrokerResult('test', 'test', 'test', [], [], pending == 'enabled', null, false)) def pact = new RequestResponsePact(new Provider(), new Consumer('the-consumer-name'), [ interaction ], [:], pactSource) def generator = new DescriptionGenerator(clazz, pact) diff --git a/provider/junit/src/test/groovy/au/com/dius/pact/provider/junit/loader/PactBrokerLoaderSpec.groovy b/provider/junit/src/test/groovy/au/com/dius/pact/provider/junit/loader/PactBrokerLoaderSpec.groovy index 250c35d3f6..b5ada6de30 100644 --- a/provider/junit/src/test/groovy/au/com/dius/pact/provider/junit/loader/PactBrokerLoaderSpec.groovy +++ b/provider/junit/src/test/groovy/au/com/dius/pact/provider/junit/loader/PactBrokerLoaderSpec.groovy @@ -33,6 +33,9 @@ class PactBrokerLoaderSpec extends Specification { private List tags private List consumerVersionSelectors private List consumers + private String enablePendingPacts + private List providerTags + private String includeWipPactsSince private IPactBrokerClient brokerClient private Pact mockPact private PactReader mockReader @@ -44,6 +47,9 @@ class PactBrokerLoaderSpec extends Specification { tags = [] consumerVersionSelectors = [] consumers = [] + enablePendingPacts = '' + providerTags = [] + includeWipPactsSince = '' brokerClient = Mock(IPactBrokerClient) { getOptions() >> [:] } @@ -55,7 +61,7 @@ class PactBrokerLoaderSpec extends Specification { pactBrokerLoader = { boolean failIfNoPactsFound = true -> IPactBrokerClient client = brokerClient def loader = new PactBrokerLoader(host, port, protocol, tags, consumerVersionSelectors, consumers, - failIfNoPactsFound, null, null, null, '', []) { + failIfNoPactsFound, null, null, null, enablePendingPacts, providerTags, includeWipPactsSince) { @Override IPactBrokerClient newPactBrokerClient(URI url, ValueResolver resolver) { client @@ -71,7 +77,7 @@ class PactBrokerLoaderSpec extends Specification { def list = pactBrokerLoader().load('test') then: - 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _) >> new Ok([]) + 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _) >> new Ok([]) notThrown(NoPactsFoundException) list.empty } @@ -81,13 +87,13 @@ class PactBrokerLoaderSpec extends Specification { def result = pactBrokerLoader(false).load('test') then: - 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _) >> new Ok([]) + 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _) >> new Ok([]) result == [] } def 'Throws any Exception On Execution Exception'() { given: - 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _) >> new Err(new InvalidHalResponse('message')) + 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _) >> new Err(new InvalidHalResponse('message')) when: pactBrokerLoader().load('test') @@ -125,7 +131,7 @@ class PactBrokerLoaderSpec extends Specification { then: result == [] - 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _) >> new Ok([]) + 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _) >> new Ok([]) } @RestoreSystemProperties @@ -149,7 +155,7 @@ class PactBrokerLoaderSpec extends Specification { then: result == [] - 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _) >> new Ok([]) + 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _) >> new Ok([]) } @RestoreSystemProperties @@ -217,7 +223,7 @@ class PactBrokerLoaderSpec extends Specification { then: noExceptionThrown() - 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _) >> new Ok([]) + 1 * brokerClient.fetchConsumersWithSelectors('test', _, _, _, _) >> new Ok([]) } def 'Loads pacts for each provided tag'() { @@ -229,9 +235,9 @@ class PactBrokerLoaderSpec extends Specification { new ConsumerVersionSelector('c', true) ] def expected = [ - new PactBrokerResult('test', 'a', '', [], [], false, null), - new PactBrokerResult('test', 'b', '', [], [], false, null), - new PactBrokerResult('test', 'c', '', [], [], false, null) + new PactBrokerResult('test', 'a', '', [], [], false, null, false), + new PactBrokerResult('test', 'b', '', [], [], false, null, false), + new PactBrokerResult('test', 'c', '', [], [], false, null, false) ] when: @@ -239,7 +245,7 @@ class PactBrokerLoaderSpec extends Specification { then: brokerClient.getOptions() >> [:] - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false) >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok(expected) 0 * brokerClient._ result.size() == 3 } @@ -257,9 +263,9 @@ class PactBrokerLoaderSpec extends Specification { new ConsumerVersionSelector('c', true) ] def expected = [ - new PactBrokerResult('test', 'a', '', [], [], false, null), - new PactBrokerResult('test', 'b', '', [], [], false, null), - new PactBrokerResult('test', 'c', '', [], [], false, null) + new PactBrokerResult('test', 'a', '', [], [], false, null, false), + new PactBrokerResult('test', 'b', '', [], [], false, null, false), + new PactBrokerResult('test', 'c', '', [], [], false, null, false) ] when: @@ -267,7 +273,7 @@ class PactBrokerLoaderSpec extends Specification { then: brokerClient.getOptions() >> [:] - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false) >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok(expected) 0 * brokerClient._ result.size() == 3 } @@ -283,15 +289,15 @@ class PactBrokerLoaderSpec extends Specification { new ConsumerVersionSelector('two', true) ] def expected = [ - new PactBrokerResult('test', 'one', '', [], [], false, null), - new PactBrokerResult('test', 'two', '', [], [], false, null) + new PactBrokerResult('test', 'one', '', [], [], false, null, false), + new PactBrokerResult('test', 'two', '', [], [], false, null, false) ] when: def result = pactBrokerLoader().load('test') then: - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false) >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok(expected) result.size() == 2 } @@ -307,29 +313,29 @@ class PactBrokerLoaderSpec extends Specification { new ConsumerVersionSelector('two', false) ] def expected = [ - new PactBrokerResult('test', 'one', '', [], [], false, null), - new PactBrokerResult('test', 'two', '', [], [], false, null) + new PactBrokerResult('test', 'one', '', [], [], false, null, false), + new PactBrokerResult('test', 'two', '', [], [], false, null, false) ] when: def result = pactBrokerLoader().load('test') then: - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false) >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok(expected) result.size() == 2 } def 'Loads the latest pacts if no consumer version selector or tag is provided'() { given: tags = [] - def expected = [ new PactBrokerResult('test', 'latest', '', [], [], false, null) ] + def expected = [ new PactBrokerResult('test', 'latest', '', [], [], false, null, false) ] when: def result = pactBrokerLoader().load('test') then: result.size() == 1 - 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], false) >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], false, '') >> new Ok(expected) } @SuppressWarnings('GStringExpressionWithinString') @@ -338,7 +344,7 @@ class PactBrokerLoaderSpec extends Specification { tags = ['${a}', '${latest}', '${b}'] def loader = pactBrokerLoader() loader.valueResolver = [resolveValue: { val -> 'X' } ] as ValueResolver - def expected = [ new PactBrokerResult('test', 'a', '', [], [], false, null) ] + def expected = [ new PactBrokerResult('test', 'a', '', [], [], false, null, false) ] def selectors = [ new ConsumerVersionSelector('X', true), new ConsumerVersionSelector('X', true), @@ -350,7 +356,7 @@ class PactBrokerLoaderSpec extends Specification { then: 1 * brokerClient.getOptions() >> [:] - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false) >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok(expected) 0 * brokerClient._ result.size() == 1 } @@ -366,7 +372,7 @@ class PactBrokerLoaderSpec extends Specification { ] def newLoader = pactBrokerLoader() newLoader.valueResolver = [resolveValue: { val -> 'X' }] as ValueResolver - def expected = [ new PactBrokerResult('test', 'a', '', [], [], false, null) ] + def expected = [ new PactBrokerResult('test', 'a', '', [], [], false, null, false) ] def selectors = [ new ConsumerVersionSelector('X', true), new ConsumerVersionSelector('X', false), @@ -378,7 +384,7 @@ class PactBrokerLoaderSpec extends Specification { then: 1 * brokerClient.getOptions() >> [:] - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false) >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok(expected) 0 * brokerClient._ result.size() == 1 } @@ -395,15 +401,15 @@ class PactBrokerLoaderSpec extends Specification { new ConsumerVersionSelector('three', true) ] def expected = [ - new PactBrokerResult('test', 'one', '', [], [], false, null), - new PactBrokerResult('test', 'two', '', [], [], false, null) + new PactBrokerResult('test', 'one', '', [], [], false, null, false), + new PactBrokerResult('test', 'two', '', [], [], false, null, false) ] when: def result = pactBrokerLoader().load('test') then: - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false) >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok(expected) result.size() == 2 } @@ -426,10 +432,10 @@ class PactBrokerLoaderSpec extends Specification { given: consumers = ['a', 'b', 'c'] def expected = [ - new PactBrokerResult('a', '', '', [], [], false, null), - new PactBrokerResult('b', '', '', [], [], false, null), - new PactBrokerResult('c', '', '', [], [], false, null), - new PactBrokerResult('d', '', '', [], [], false, null) + new PactBrokerResult('a', '', '', [], [], false, null, false), + new PactBrokerResult('b', '', '', [], [], false, null, false), + new PactBrokerResult('c', '', '', [], [], false, null, false), + new PactBrokerResult('d', '', '', [], [], false, null, false) ] when: @@ -437,7 +443,7 @@ class PactBrokerLoaderSpec extends Specification { then: brokerClient.getOptions() >> [:] - 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], false) >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], false, '') >> new Ok(expected) 0 * brokerClient._ result.size() == 3 } @@ -449,10 +455,10 @@ class PactBrokerLoaderSpec extends Specification { System.setProperty('composite', "a${VALUES_SEPARATOR}b${VALUES_SEPARATOR}c") consumers = ['${composite}'] def expected = [ - new PactBrokerResult('a', '', '', [], [], false, null), - new PactBrokerResult('b', '', '', [], [], false, null), - new PactBrokerResult('c', '', '', [], [], false, null), - new PactBrokerResult('d', '', '', [], [], false, null) + new PactBrokerResult('a', '', '', [], [], false, null, false), + new PactBrokerResult('b', '', '', [], [], false, null, false), + new PactBrokerResult('c', '', '', [], [], false, null, false), + new PactBrokerResult('d', '', '', [], [], false, null, false) ] when: @@ -460,7 +466,7 @@ class PactBrokerLoaderSpec extends Specification { then: brokerClient.getOptions() >> [:] - 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], false) >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], false, '') >> new Ok(expected) 0 * brokerClient._ result.size() == 3 } @@ -469,10 +475,10 @@ class PactBrokerLoaderSpec extends Specification { given: consumers = [] def expected = [ - new PactBrokerResult('a', '', '', [], [], false, null), - new PactBrokerResult('b', '', '', [], [], false, null), - new PactBrokerResult('c', '', '', [], [], false, null), - new PactBrokerResult('d', '', '', [], [], false, null) + new PactBrokerResult('a', '', '', [], [], false, null, false), + new PactBrokerResult('b', '', '', [], [], false, null, false), + new PactBrokerResult('c', '', '', [], [], false, null, false), + new PactBrokerResult('d', '', '', [], [], false, null, false) ] when: @@ -480,7 +486,7 @@ class PactBrokerLoaderSpec extends Specification { then: brokerClient.getOptions() >> [:] - 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], false) >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], false, '') >> new Ok(expected) 0 * brokerClient._ result.size() == 4 } @@ -491,10 +497,10 @@ class PactBrokerLoaderSpec extends Specification { given: consumers = ['${pactbroker.consumers:}'] def expected = [ - new PactBrokerResult('a', '', '', [], [], false, null), - new PactBrokerResult('b', '', '', [], [], false, null), - new PactBrokerResult('c', '', '', [], [], false, null), - new PactBrokerResult('d', '', '', [], [], false, null) + new PactBrokerResult('a', '', '', [], [], false, null, false), + new PactBrokerResult('b', '', '', [], [], false, null, false), + new PactBrokerResult('c', '', '', [], [], false, null, false), + new PactBrokerResult('d', '', '', [], [], false, null, false) ] when: @@ -502,7 +508,7 @@ class PactBrokerLoaderSpec extends Specification { then: brokerClient.getOptions() >> [:] - 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], false) >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], false, '') >> new Ok(expected) 0 * brokerClient._ result.size() == 4 } @@ -512,10 +518,10 @@ class PactBrokerLoaderSpec extends Specification { consumers = ['a', 'b', 'c'] tags = ['demo'] def expected = [ - new PactBrokerResult('a', '', '', [], [], false, 'demo'), - new PactBrokerResult('b', '', '', [], [], false, 'demo'), - new PactBrokerResult('c', '', '', [], [], false, 'demo'), - new PactBrokerResult('d', '', '', [], [], false, 'demo') + new PactBrokerResult('a', '', '', [], [], false, 'demo', false), + new PactBrokerResult('b', '', '', [], [], false, 'demo', false), + new PactBrokerResult('c', '', '', [], [], false, 'demo', false), + new PactBrokerResult('d', '', '', [], [], false, 'demo', false) ] def selectors = [ new ConsumerVersionSelector('demo', true) ] @@ -524,7 +530,7 @@ class PactBrokerLoaderSpec extends Specification { then: brokerClient.getOptions() >> [:] - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false) >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok(expected) 0 * brokerClient._ result.size() == 3 } @@ -534,10 +540,10 @@ class PactBrokerLoaderSpec extends Specification { consumers = ['a', 'b', 'c'] consumerVersionSelectors = [createVersionSelector('demo', 'true')] def expected = [ - new PactBrokerResult('a', '', '', [], [], false, 'demo'), - new PactBrokerResult('b', '', '', [], [], false, 'demo'), - new PactBrokerResult('c', '', '', [], [], false, 'demo'), - new PactBrokerResult('d', '', '', [], [], false, 'demo') + new PactBrokerResult('a', '', '', [], [], false, 'demo', false), + new PactBrokerResult('b', '', '', [], [], false, 'demo', false), + new PactBrokerResult('c', '', '', [], [], false, 'demo', false), + new PactBrokerResult('d', '', '', [], [], false, 'demo', false) ] def selectors = [ new ConsumerVersionSelector('demo', true) ] @@ -546,7 +552,63 @@ class PactBrokerLoaderSpec extends Specification { then: brokerClient.getOptions() >> [:] - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false) >> new Ok(expected) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok(expected) + 0 * brokerClient._ + result.size() == 3 + } + + def 'Does not loads wip pacts when pending is false'() { + given: + consumerVersionSelectors = [ + createVersionSelector('a', 'true'), + createVersionSelector('b', 'false'), + ] + includeWipPactsSince = '2020-06-25' + def selectors = [ + new ConsumerVersionSelector('a', true), + new ConsumerVersionSelector('b', false), + ] + def expected = [ + new PactBrokerResult('test', 'a', '', [], [], false, null, false), + new PactBrokerResult('test', 'b', '', [], [], false, null, false), + new PactBrokerResult('test', 'c', '', [], [], false, null, false), + ] + + when: + def result = pactBrokerLoader().load('test') + + then: + brokerClient.getOptions() >> [:] + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok(expected) + 0 * brokerClient._ + result.size() == 3 + } + + def 'Loads wip pacts when pending and includeWipPactsSince parameters set'() { + given: + consumerVersionSelectors = [ + createVersionSelector('a', 'true'), + createVersionSelector('b', 'false'), + ] + enablePendingPacts = 'true' + providerTags = ['dev'] + includeWipPactsSince = '2020-06-25' + def selectors = [ + new ConsumerVersionSelector('a', true), + new ConsumerVersionSelector('b', false), + ] + def expected = [ + new PactBrokerResult('test', 'a', '', [], [], false, null, false), + new PactBrokerResult('test', 'b1', '', [], [], true, null, false), + new PactBrokerResult('test', 'b2', '', [], [], true, null, true), + ] + + when: + def result = pactBrokerLoader().load('test') + + then: + brokerClient.getOptions() >> [:] + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, ['dev'], true, '2020-06-25') >> new Ok(expected) 0 * brokerClient._ result.size() == 3 } @@ -573,7 +635,7 @@ class PactBrokerLoaderSpec extends Specification { pactBrokerLoader().load('test') then: - 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], false) >> new Ok([]) + 1 * brokerClient.fetchConsumersWithSelectors('test', [], [], false, '') >> new Ok([]) noExceptionThrown() } @@ -600,7 +662,7 @@ class PactBrokerLoaderSpec extends Specification { then: result == [] - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false) >> new Ok([]) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok([]) } def 'configured from annotation with https and no port'() { @@ -628,7 +690,7 @@ class PactBrokerLoaderSpec extends Specification { then: result == [] - 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false) >> new Ok([]) + 1 * brokerClient.fetchConsumersWithSelectors('test', selectors, [], false, '') >> new Ok([]) } def 'Auth: Uses no auth if no auth is provided'() { diff --git a/provider/src/main/java/au/com/dius/pact/provider/junitsupport/loader/PactBroker.java b/provider/src/main/java/au/com/dius/pact/provider/junitsupport/loader/PactBroker.java index 0f3ea13662..31caecac99 100644 --- a/provider/src/main/java/au/com/dius/pact/provider/junitsupport/loader/PactBroker.java +++ b/provider/src/main/java/au/com/dius/pact/provider/junitsupport/loader/PactBroker.java @@ -79,4 +79,10 @@ PactBrokerAuth authentication() default @PactBrokerAuth(username = "${pactbroker * Provider Tags to use to evaluate pending pacts */ String[] providerTags() default "${pactbroker.providerTags:}"; + + /** + * The earliest date WIP pacts should be included (ex: YYYY-MM-DD). If no date is provided, WIP pacts will not be + * included. + */ + String includeWipPactsSince() default "${pactbroker.includeWipPactsSince:}"; } 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 a133294bbc..7a7546efa4 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 @@ -76,6 +76,7 @@ interface IConsumerInfo { var pactFileAuthentication: List val notices: List val pending: Boolean + val wip: Boolean } @Suppress("LongParameterList") @@ -88,7 +89,8 @@ open class ConsumerInfo @JvmOverloads constructor ( override var pactSource: Any? = null, override var pactFileAuthentication: List = emptyList(), override val notices: List = emptyList(), - override val pending: Boolean = false + override val pending: Boolean = false, + override val wip: Boolean = false ) : IConsumerInfo { fun toPactConsumer() = au.com.dius.pact.core.model.Consumer(name) @@ -100,7 +102,7 @@ open class ConsumerInfo @JvmOverloads constructor ( override fun toString(): String { return "ConsumerInfo(name='$name', stateChange=$stateChange, stateChangeUsesBody=$stateChangeUsesBody, " + "packagesToScan=$packagesToScan, verificationType=$verificationType, pactSource=$pactSource, " + - "pactFileAuthentication=$pactFileAuthentication, notices=$notices, pending=$pending)" + "pactFileAuthentication=$pactFileAuthentication, notices=$notices, pending=$pending, wip=$wip)" } override fun equals(other: Any?): Boolean { @@ -118,6 +120,7 @@ open class ConsumerInfo @JvmOverloads constructor ( if (pactFileAuthentication != other.pactFileAuthentication) return false if (notices != other.notices) return false if (pending != other.pending) return false + if (wip != other.wip) return false return true } @@ -132,6 +135,7 @@ open class ConsumerInfo @JvmOverloads constructor ( result = 31 * result + pactFileAuthentication.hashCode() result = 31 * result + notices.hashCode() result = 31 * result + pending.hashCode() + result = 31 * result + wip.hashCode() return result } @@ -139,8 +143,8 @@ open class ConsumerInfo @JvmOverloads constructor ( fun from(result: PactBrokerResult) = ConsumerInfo(name = result.name, pactSource = BrokerUrlSource(url = result.source, pactBrokerUrl = result.pactBrokerUrl, result = result), - pactFileAuthentication = result.pactFileAuthentication, notices = result.notices, - pending = result.pending + pactFileAuthentication = result.pactFileAuthentication, notices = result.notices, pending = result.pending, + wip = result.wip ) } } diff --git a/provider/src/main/kotlin/au/com/dius/pact/provider/ProviderInfo.kt b/provider/src/main/kotlin/au/com/dius/pact/provider/ProviderInfo.kt index 9ab31fd650..f34b7ec086 100644 --- a/provider/src/main/kotlin/au/com/dius/pact/provider/ProviderInfo.kt +++ b/provider/src/main/kotlin/au/com/dius/pact/provider/ProviderInfo.kt @@ -80,8 +80,10 @@ open class ProviderInfo @JvmOverloads constructor ( } else { emptyList() } + val includePactsSince = Utils.lookupInMap(options, "includeWipPactsSince", String::class.java, "") val client = pactBrokerClient(pactBrokerUrl, options) - val consumersFromBroker = client.fetchConsumersWithSelectors(name, selectors, providerTags, enablePending) + val consumersFromBroker = client.fetchConsumersWithSelectors(name, selectors, providerTags, enablePending, + includePactsSince) .map { results -> results.map { ConsumerInfo.from(it) } } return when (consumersFromBroker) { diff --git a/provider/src/main/kotlin/au/com/dius/pact/provider/junitsupport/loader/PactBrokerLoader.kt b/provider/src/main/kotlin/au/com/dius/pact/provider/junitsupport/loader/PactBrokerLoader.kt index 73f0facc43..602145210e 100644 --- a/provider/src/main/kotlin/au/com/dius/pact/provider/junitsupport/loader/PactBrokerLoader.kt +++ b/provider/src/main/kotlin/au/com/dius/pact/provider/junitsupport/loader/PactBrokerLoader.kt @@ -43,7 +43,8 @@ open class PactBrokerLoader( var valueResolverClass: KClass?, valueResolver: ValueResolver? = null, val enablePendingPacts: String = "false", - val providerTags: List = emptyList() + val providerTags: List = emptyList(), + val includeWipPactsSince: String = "" ) : OverrideablePactLoader { private var resolver: ValueResolver? = valueResolver @@ -64,7 +65,8 @@ open class PactBrokerLoader( pactBroker.valueResolver, null, pactBroker.enablePendingPacts, - pactBroker.providerTags.toList() + pactBroker.providerTags.toList(), + pactBroker.includeWipPactsSince ) override fun description(): String { @@ -157,7 +159,8 @@ open class PactBrokerLoader( selectors: List, resolver: ValueResolver ): List> { - logger.debug { "Loading pacts from pact broker for provider $providerName and consumer version selectors $selectors" } + logger.debug { "Loading pacts from pact broker for provider $providerName and consumer version selectors " + + "$selectors" } val pending = parseExpression(enablePendingPacts, DataType.BOOLEAN, resolver) as Boolean val providerTags = providerTags.flatMap { parseListExpression(it, resolver) }.filter { it.isNotEmpty() } if (pending && providerTags.none { it.isNotEmpty() }) { @@ -166,12 +169,14 @@ open class PactBrokerLoader( "provider application version with the providerTags property that will be published with the verification " + "results.") } + val wipSinceDate = if (pending) parseExpression(includeWipPactsSince, DataType.STRING, resolver) as String else "" val uriBuilder = brokerUrl(resolver) try { val pactBrokerClient = newPactBrokerClient(uriBuilder.build(), resolver) - val result = pactBrokerClient.fetchConsumersWithSelectors(providerName, selectors, providerTags, pending) + val result = pactBrokerClient.fetchConsumersWithSelectors(providerName, selectors, providerTags, pending, + wipSinceDate) var consumers = when (result) { is Ok -> result.value is Err -> throw result.error diff --git a/provider/src/test/groovy/au/com/dius/pact/provider/ProviderInfoSpec.groovy b/provider/src/test/groovy/au/com/dius/pact/provider/ProviderInfoSpec.groovy index d4d882fb36..61143047b9 100644 --- a/provider/src/test/groovy/au/com/dius/pact/provider/ProviderInfoSpec.groovy +++ b/provider/src/test/groovy/au/com/dius/pact/provider/ProviderInfoSpec.groovy @@ -73,8 +73,8 @@ class ProviderInfoSpec extends Specification { def result = providerInfo.hasPactsFromPactBrokerWithSelectors(options, url, selectors) then: - pactBrokerClient.fetchConsumersWithSelectors('TestProvider', selectors, [], false) >> new Ok([ - new PactBrokerResult('consumer', '', url, [], [], false, null) + pactBrokerClient.fetchConsumersWithSelectors('TestProvider', selectors, [], false, '') >> new Ok([ + new PactBrokerResult('consumer', '', url, [], [], false, null, false) ]) result.size == 1 result[0].name == 'consumer' @@ -96,8 +96,8 @@ class ProviderInfoSpec extends Specification { def result = providerInfo.hasPactsFromPactBrokerWithSelectors(options, url, selectors) then: - pactBrokerClient.fetchConsumersWithSelectors('TestProvider', selectors, ['master'], true) >> new Ok([ - new PactBrokerResult('consumer', '', url, [], [], true, null) + pactBrokerClient.fetchConsumersWithSelectors('TestProvider', selectors, ['master'], true, '') >> new Ok([ + new PactBrokerResult('consumer', '', url, [], [], true, null, false) ]) result.size == 1 result[0].name == 'consumer' @@ -122,4 +122,51 @@ class ProviderInfoSpec extends Specification { exception.message == 'No providerTags: To use the pending pacts feature, you need to provide the list of ' + 'provider names for the provider application version that will be published with the verification results' } + + def 'does not include wip pacts if the option is not present'() { + given: + def options = [ + enablePending: true, + providerTags: ['master'] + ] + def url = 'http://localhost:8080' + def selectors = [ + new ConsumerVersionSelector('test', true) + ] + + when: + def result = providerInfo.hasPactsFromPactBrokerWithSelectors(options, url, selectors) + + then: + pactBrokerClient.fetchConsumersWithSelectors('TestProvider', selectors, ['master'], true, '') >> new Ok([ + new PactBrokerResult('consumer', '', url, [], [], false, null, false) + ]) + result.size == 1 + result[0].name == 'consumer' + !result[0].pending + } + + def 'does include wip pacts if the option is present'() { + given: + def options = [ + enablePending: true, + providerTags: ['master'], + includeWipPactsSince: '2020-05-23' + ] + def url = 'http://localhost:8080' + def selectors = [ + new ConsumerVersionSelector('test', true) + ] + + when: + def result = providerInfo.hasPactsFromPactBrokerWithSelectors(options, url, selectors) + + then: + pactBrokerClient.fetchConsumersWithSelectors('TestProvider', selectors, ['master'], true, '2020-05-23') >> new Ok([ + new PactBrokerResult('consumer', '', url, [], [], true, null, true) + ]) + result.size == 1 + result[0].name == 'consumer' + result[0].pending + } } From b3d6d19aaa725ac8e4948621b84f2ed5636d8853 Mon Sep 17 00:00:00 2001 From: Phil Endsley Date: Thu, 25 Jun 2020 12:02:36 -0500 Subject: [PATCH 2/3] docs: Update junit README with consumerVersionSelectors example --- provider/junit/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/provider/junit/README.md b/provider/junit/README.md index 00b55c99f4..26cc6f5324 100644 --- a/provider/junit/README.md +++ b/provider/junit/README.md @@ -272,6 +272,20 @@ For any other value the latest pact tagged with the specified tag is loaded. Specifying multiple tags is an OR operation. For example if you specify `tags = {"dev", "prod"}` then both the latest pact file tagged with `dev` and the latest pact file taggged with `prod` is loaded. +In 4.1.4+, tags was deprecated in favor of consumerVersionSelectors. Consumer version selectors give you the ability to +include pacts for the latest version of a tag, or all versions of a tag. + +```java +@PactBroker( + host="pactbroker", + port="80", + consumerVersionSelectors={ + @ConsumerVersionSelector(tag = "dev"), // Verify the latest version tagged with dev + @ConsumerVersionSelector(tag = "prod", latest = "false") // Verify all versions tagged with prod + } +) +``` + #### Using authentication with the with the pact broker You can use basic authentication with the `@PactBroker` annotation by setting the `authentication` value to a `@PactBrokerAuth` From 2d99c5edad4dcd3d21469999e1a5affe3258cad5 Mon Sep 17 00:00:00 2001 From: Phil Endsley Date: Thu, 25 Jun 2020 12:21:50 -0500 Subject: [PATCH 3/3] docs: Update junit README for WIP pact support --- provider/junit/README.md | 21 +++++++++++++++++++++ provider/junit5/README.md | 4 ++++ 2 files changed, 25 insertions(+) diff --git a/provider/junit/README.md b/provider/junit/README.md index 26cc6f5324..bb1049e08e 100644 --- a/provider/junit/README.md +++ b/provider/junit/README.md @@ -570,3 +570,24 @@ public class PactJUnitTest { You can also use the `pactbroker.enablePending` and `pactbroker.providerTags` JVM system properties. Then any pending pacts will not cause a build failure. + +# Work In Progress (WIP) Pact Support (version 4.1.5 and later) + +If your Pact broker supports wip pacts, you can enable support by enabling it on your Pact broker annotation, or with +JVM system properties. You also need to enable pending pacts. Once enabled, your provider will verify any "work in progress" +pacts that have been published since a given date. A WIP pact is a pact that is the latest for its tag that does not have +any successful verification results with the provider tag. + +```java +@Provider("Activity Service") +@PactBroker(host = "test.pactflow.io", tags = {"test"}, scheme = "https", + enablePendingPacts = "true", + providerTags = "master" + includeWipPactsSince = "2020-06-19" +) +public class PactJUnitTest { +``` + +You can also use the `pactbroker.includeWipPactsSince` JVM system property. + +Since all WIP pacts are also pending pacts, failed verifications will not cause a build failure. diff --git a/provider/junit5/README.md b/provider/junit5/README.md index 2acc6e38a5..4969f65e81 100644 --- a/provider/junit5/README.md +++ b/provider/junit5/README.md @@ -144,3 +144,7 @@ public class PactJUnitTest { You can also use the `pactbroker.enablePending` and `pactbroker.providerTags` JVM system properties. Then any pending pacts will not cause a build failure. + +# Work In Progress (WIP) Pact Support (version 4.1.5 and later) + +WIP pacts work in the same way as with JUnit 4 tests, refer to the [Pact junit runner](../junit/README.md) docs.