Skip to content

Commit

Permalink
Merge pull request #1147 from pendsley/feat/wip-pacts
Browse files Browse the repository at this point in the history
Feat/wip pacts
  • Loading branch information
Ronald Holshausen authored Jun 26, 2020
2 parents 65cb3be + 2d99c5e commit ac1865a
Show file tree
Hide file tree
Showing 13 changed files with 449 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ interface IPactBrokerClient {
providerName: String,
selectors: List<ConsumerVersionSelector>,
providerTags: List<String> = emptyList(),
enablePending: Boolean = false
enablePending: Boolean = false,
includeWipPactsSince: String
): Result<List<PactBrokerResult>, Exception>

fun getUrlForProvider(providerName: String, tag: String): String?
Expand Down Expand Up @@ -145,7 +146,8 @@ open class PactBrokerClient(val pactBrokerUrl: String, override val options: Map
providerName: String,
selectors: List<ConsumerVersionSelector>,
providerTags: List<String>,
enablePending: Boolean
enablePending: Boolean,
includeWipPactsSince: String
): Result<List<PactBrokerResult>, Exception> {
val navigateResult = handleWith<IHalClient> { newHalClient().navigate() }
val halClient = when (navigateResult) {
Expand All @@ -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 {
Expand All @@ -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<String>, notices, pending)
PactBrokerResult(name, href, pactBrokerUrl, options["authentication"] as List<String>, notices, pending, wip = wip)
} else {
PactBrokerResult(name, href, pactBrokerUrl, emptyList(), notices, pending)
PactBrokerResult(name, href, pactBrokerUrl, emptyList(), notices, pending, wip = wip)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ data class PactBrokerResult(
val pactFileAuthentication: List<String> = listOf(),
val notices: List<VerificationNotice> = listOf(),
val pending: Boolean = false,
val tag: String? = null
val tag: String? = null,
val wip: Boolean = false
)

data class VerificationNotice(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 != []
Expand All @@ -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 == []
Expand All @@ -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 != []
Expand All @@ -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 != []
Expand All @@ -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
Expand Down Expand Up @@ -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']
Expand All @@ -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 != []
Expand All @@ -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 == []
Expand Down Expand Up @@ -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
Expand All @@ -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
)
}

Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
}
}
128 changes: 126 additions & 2 deletions pact-publish/src/test/groovy/broker/PactBrokerClientPactSpec.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
}
}
Loading

0 comments on commit ac1865a

Please sign in to comment.