Skip to content

Commit

Permalink
fix: include consumer in the selectors; only filter by consumer if us…
Browse files Browse the repository at this point in the history
…ing old endpoint #1193
  • Loading branch information
Ronald Holshausen committed Oct 1, 2020
1 parent 1e2fb65 commit 677cc2d
Show file tree
Hide file tree
Showing 15 changed files with 568 additions and 203 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,11 @@ data class CanIDeployResult(val ok: Boolean, val message: String, val reason: St
/**
* Consumer version selector. See https://docs.pact.io/pact_broker/advanced_topics/selectors
*/
data class ConsumerVersionSelector(val tag: String, val latest: Boolean = true) {
data class ConsumerVersionSelector(
val tag: String? = null,
val latest: Boolean = true,
val consumer: String? = null
) {
fun toJson() = JsonValue.Object("tag" to Json.toJson(tag), "latest" to Json.toJson(latest))
}

Expand Down Expand Up @@ -157,47 +161,61 @@ open class PactBrokerClient(val pactBrokerUrl: String, override val options: Map
halClient.linkUrl(BETA_PROVIDER_PACTS_FOR_VERIFICATION) != null -> BETA_PROVIDER_PACTS_FOR_VERIFICATION
else -> null
}
if (pactsForVerification != null) {
val body = JsonValue.Object(
"consumerVersionSelectors" to jsonArray(selectors.map { it.toJson() })
)
if (enablePending) {
body["providerVersionTags"] = jsonArray(providerTags)
body["includePendingStatus"] = true
if (!includeWipPactsSince.isBlank()) {
body["includeWipPactsSince"] = includeWipPactsSince
}
}

return handleWith {
halClient.postJson(pactsForVerification, mapOf("provider" to providerName), body.serialise()).map { result ->
result["_embedded"]["pacts"].asArray().map { pactJson ->
val selfLink = pactJson["_links"]["self"]
val href = Json.toString(selfLink["href"])
val name = Json.toString(selfLink["name"])
val properties = pactJson["verificationProperties"]
val notices = properties["notices"].asArray()
.map { VerificationNotice.fromJson(it.asObject()) }
var pending = false
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, wip = wip)
} else {
PactBrokerResult(name, href, pactBrokerUrl, emptyList(), notices, pending, wip = wip)
}
}
}
}
return if (pactsForVerification != null) {
fetchPactsUsingNewEndpoint(selectors, enablePending, providerTags, includeWipPactsSince, halClient, pactsForVerification, providerName)
} else {
return handleWith {
handleWith {
if (selectors.isEmpty()) {
fetchConsumers(providerName)
} else {
selectors.flatMap { fetchConsumersWithTag(providerName, it.tag) }
selectors.flatMap { fetchConsumersWithTag(providerName, it.tag!!) }
}
}
}
}

private fun fetchPactsUsingNewEndpoint(
selectors: List<ConsumerVersionSelector>,
enablePending: Boolean,
providerTags: List<String>,
includeWipPactsSince: String,
halClient: IHalClient,
pactsForVerification: String,
providerName: String
): Result<List<PactBrokerResult>, Exception> {
val body = JsonValue.Object(
"consumerVersionSelectors" to jsonArray(selectors.map { it.toJson() })
)
if (enablePending) {
body["providerVersionTags"] = jsonArray(providerTags)
body["includePendingStatus"] = true
if (!includeWipPactsSince.isBlank()) {
body["includeWipPactsSince"] = includeWipPactsSince
}
}

return handleWith {
halClient.postJson(pactsForVerification, mapOf("provider" to providerName), body.serialise()).map { result ->
result["_embedded"]["pacts"].asArray().map { pactJson ->
val selfLink = pactJson["_links"]["self"]
val href = Json.toString(selfLink["href"])
val name = Json.toString(selfLink["name"])
val properties = pactJson["verificationProperties"]
val notices = properties["notices"].asArray()
.map { VerificationNotice.fromJson(it.asObject()) }
var pending = false
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,
wip = wip, usedNewEndpoint = true)
} else {
PactBrokerResult(name, href, pactBrokerUrl, emptyList(), notices, pending, wip = wip,
usedNewEndpoint = true)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ data class PactBrokerResult(
val notices: List<VerificationNotice> = listOf(),
val pending: Boolean = false,
val tag: String? = null,
val wip: Boolean = false
val wip: Boolean = false,
val usedNewEndpoint: Boolean = false
)

data class VerificationNotice(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class PactBrokerClientSpec extends Specification {
halClient.navigate(_, _) >> halClient
halClient.forAll(_, _) >> { args -> args[1].accept([name: 'bob', href: 'http://bob.com/']) }

def client = Spy(PactBrokerClient, constructorArgs: [
PactBrokerClient client = Spy(PactBrokerClient, constructorArgs: [
'http://pactBrokerUrl', MapsKt.mapOf(new Pair('authentication', ['Basic', '1', '2']))]) {
newHalClient() >> halClient
}
Expand All @@ -64,7 +64,7 @@ class PactBrokerClientSpec extends Specification {
halClient.navigate(_, _) >> halClient
halClient.forAll(_, _) >> { args -> throw new NotFoundHalResponse() }

def client = Spy(PactBrokerClient, constructorArgs: ['baseUrl']) {
PactBrokerClient client = Spy(PactBrokerClient, constructorArgs: ['baseUrl']) {
newHalClient() >> halClient
}

Expand All @@ -82,7 +82,7 @@ class PactBrokerClientSpec extends Specification {
halClient.navigate(_, _) >> halClient
halClient.forAll(_, _) >> { args -> args[1].accept([name: 'bob', href: 'http://bob.com/a%20b/100+ab']) }

def client = Spy(PactBrokerClient, constructorArgs: ['http://pactBrokerUrl']) {
PactBrokerClient client = Spy(PactBrokerClient, constructorArgs: ['http://pactBrokerUrl']) {
newHalClient() >> halClient
}

Expand All @@ -102,13 +102,13 @@ class PactBrokerClientSpec extends Specification {
halClient.navigate(_, _) >> halClient
halClient.forAll(_, _) >> { args -> args[1].accept([name: 'bob', href: 'http://bob.com/']) }

def client = Spy(PactBrokerClient, constructorArgs: ['http://pactBrokerUrl']) {
PactBrokerClient client = Spy(PactBrokerClient, constructorArgs: ['http://pactBrokerUrl']) {
newHalClient() >> halClient
}

when:
def consumers = client.fetchConsumersWithSelectors('provider',
[ new ConsumerVersionSelector('tag', true) ], [], false, '').value
[ new ConsumerVersionSelector('tag', true, null) ], [], false, '').value

then:
consumers != []
Expand All @@ -123,14 +123,14 @@ class PactBrokerClientSpec extends Specification {
halClient.navigate(_, _) >> halClient
halClient.forAll(_, _) >> { args -> args[1].accept([name: 'bob', href: 'http://bob.com/']) }

def client = Spy(PactBrokerClient, constructorArgs: ['http://pactBrokerUrl']) {
PactBrokerClient client = Spy(PactBrokerClient, constructorArgs: ['http://pactBrokerUrl']) {
newHalClient() >> halClient
}

when:
def consumers = client.fetchConsumersWithSelectors('provider',
[ new ConsumerVersionSelector('tag', true),
new ConsumerVersionSelector('anotherTag', true) ], [], false, '').value
[ new ConsumerVersionSelector('tag', true, null),
new ConsumerVersionSelector('anotherTag', true, null) ], [], false, '').value

then:
consumers.size() == 2
Expand All @@ -153,14 +153,14 @@ class PactBrokerClientSpec extends Specification {
halClient.navigate(_, _) >> halClient
halClient.forAll(_, _) >> { args -> args[1].accept([name: 'bob', href: 'http://bob.com/']) }

def client = Spy(PactBrokerClient, constructorArgs: [
PactBrokerClient client = Spy(PactBrokerClient, constructorArgs: [
'http://pactBrokerUrl', MapsKt.mapOf(new Pair('authentication', ['Basic', '1', '2']))]) {
newHalClient() >> halClient
}

when:
def consumers = client.fetchConsumersWithSelectors('provider',
[ new ConsumerVersionSelector('tag', true) ], [], false, '').value
[ new ConsumerVersionSelector('tag', true, null) ], [], false, '').value

then:
consumers.first().pactFileAuthentication == ['Basic', '1', '2']
Expand All @@ -173,13 +173,13 @@ class PactBrokerClientSpec extends Specification {
halClient.navigate(_, _) >> halClient
halClient.forAll(_, _) >> { args -> args[1].accept([name: 'bob', href: 'http://bob.com/a%20b/100+ab']) }

def client = Spy(PactBrokerClient, constructorArgs: ['http://pactBrokerUrl']) {
PactBrokerClient client = Spy(PactBrokerClient, constructorArgs: ['http://pactBrokerUrl']) {
newHalClient() >> halClient
}

when:
def consumers = client.fetchConsumersWithSelectors('provider',
[ new ConsumerVersionSelector('tag', true) ], [], false, '').value
[ new ConsumerVersionSelector('tag', true, null) ], [], false, '').value

then:
consumers != []
Expand All @@ -194,13 +194,13 @@ class PactBrokerClientSpec extends Specification {
halClient.navigate(_, _) >> halClient
halClient.forAll(_, _) >> { args -> throw new NotFoundHalResponse() }

def client = Spy(PactBrokerClient, constructorArgs: ['baseUrl']) {
PactBrokerClient client = Spy(PactBrokerClient, constructorArgs: ['baseUrl']) {
newHalClient() >> halClient
}

when:
def consumers = client.fetchConsumersWithSelectors('provider',
[ new ConsumerVersionSelector('tag', true) ], [], false, '').value
[ new ConsumerVersionSelector('tag', true, null) ], [], false, '').value

then:
consumers == []
Expand Down Expand Up @@ -360,11 +360,11 @@ class PactBrokerClientSpec extends Specification {
@SuppressWarnings('LineLength')
def 'fetching pacts with selectors uses the provider-pacts-for-verification link and returns a list of results'() {
given:
def halClient = Mock(IHalClient)
IHalClient halClient = Mock(IHalClient)
PactBrokerClient client = Spy(PactBrokerClient, constructorArgs: ['baseUrl']) {
newHalClient() >> halClient
}
def selectors = [ new ConsumerVersionSelector('DEV', true) ]
def selectors = [ new ConsumerVersionSelector('DEV', true, null) ]
def json = '{"consumerVersionSelectors":[{"tag":"DEV","latest":true}]}'
def jsonResult = JsonParser.INSTANCE.parseString('''
{
Expand Down Expand Up @@ -406,9 +406,7 @@ class PactBrokerClientSpec extends Specification {
new VerificationNotice('before_verification',
'The pact at ... is being verified because it matches the following configured selection criterion: latest pact for a consumer version tagged \'DEV\'')
],
false,
null,
false
false, null, false, true
)
}

Expand Down Expand Up @@ -463,7 +461,7 @@ class PactBrokerClientSpec extends Specification {
PactBrokerClient client = Spy(PactBrokerClient, constructorArgs: ['baseUrl']) {
newHalClient() >> halClient
}
def selectors = [ new ConsumerVersionSelector('DEV', true) ]
def selectors = [ new ConsumerVersionSelector('DEV', true, null) ]
def json = '{"consumerVersionSelectors":[{"tag":"DEV","latest":true}]}'
def jsonResult = JsonParser.INSTANCE.parseString('''
{
Expand All @@ -489,7 +487,7 @@ class PactBrokerClientSpec extends Specification {
PactBrokerClient client = Spy(PactBrokerClient, constructorArgs: ['baseUrl']) {
newHalClient() >> halClient
}
def selectors = [ new ConsumerVersionSelector('DEV', true) ]
def selectors = [ new ConsumerVersionSelector('DEV', true, null) ]
def json = '{"consumerVersionSelectors":[{"tag":"DEV","latest":true}],' +
'"providerVersionTags":[],' +
'"includePendingStatus":true,' +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,18 @@ object Utils {
} catch (_: Throwable) { }
}
}

fun <T1, T2> permutations(list1: List<T1>, list2: List<T2>): List<Pair<T1?, T2?>> {
val result = mutableListOf<Pair<T1?, T2?>>()
if (list1.isNotEmpty() || list2.isNotEmpty()) {
val firstList = if (list1.isEmpty()) listOf<T1?>(null) else list1
val secondList = if (list2.isEmpty()) listOf<T2?>(null) else list2
for (item1 in firstList) {
for (item2 in secondList) {
result.add(item1 to item2)
}
}
}
return result
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package au.com.dius.pact.core.support

import kotlin.Pair
import spock.lang.Specification
import spock.lang.Unroll

Expand All @@ -20,4 +21,65 @@ class UtilsSpec extends Specification {
[key: null] | Boolean | true || true
}

def 'permutations'() {
given:
List<Integer> list1 = [1, 2, 3]
List<String> list2 = ['A', 'B']

when:
def result = Utils.INSTANCE.permutations(list1, list2)

then:
result == [
new Pair(1, 'A'),
new Pair(1, 'B'),
new Pair(2, 'A'),
new Pair(2, 'B'),
new Pair(3, 'A'),
new Pair(3, 'B')
]
}

def 'permutations when the first list is empty'() {
given:
List<Integer> list1 = []
List<String> list2 = ['A', 'B']

when:
def result = Utils.INSTANCE.permutations(list1, list2)

then:
result == [
new Pair(null, 'A'),
new Pair(null, 'B')
]
}

def 'permutations when the second list is empty'() {
given:
List<Integer> list1 = [1, 2, 3]
List<String> list2 = []

when:
def result = Utils.INSTANCE.permutations(list1, list2)

then:
result == [
new Pair(1, null),
new Pair(2, null),
new Pair(3, null)
]
}

def 'permutations when the lists are empty'() {
given:
List<Integer> list1 = []
List<String> list2 = []

when:
def result = Utils.INSTANCE.permutations(list1, list2)

then:
result == []
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ class PactBrokerClientPactSpec extends Specification {
when:
def result = pactBroker.runTest { server, context ->
def consumerPacts = pactBrokerClient.fetchConsumersWithSelectors('Activity Service', [
new ConsumerVersionSelector('test', true)
new ConsumerVersionSelector('test', true, null)
], [], false, '')
assert consumerPacts instanceof Ok
assert consumerPacts.value.size == 2
Expand Down Expand Up @@ -673,7 +673,7 @@ class PactBrokerClientPactSpec extends Specification {
when:
def result = pactBroker.runTest { server, context ->
def consumerPacts = pactBrokerClient.fetchConsumersWithSelectors('Activity Service', [
new ConsumerVersionSelector('test', true)
new ConsumerVersionSelector('test', true, null)
], ['master'], true, '')
assert consumerPacts instanceof Ok
assert consumerPacts.value.size == 2
Expand Down Expand Up @@ -797,7 +797,7 @@ class PactBrokerClientPactSpec extends Specification {
when:
def result = pactBroker.runTest { server, context ->
def consumerPacts = pactBrokerClient.fetchConsumersWithSelectors('Activity Service', [
new ConsumerVersionSelector('test', true)
new ConsumerVersionSelector('test', true, null)
], ['master'], true, '2020-06-24')
assert consumerPacts instanceof Ok
assert consumerPacts.value.size == 2
Expand Down
Loading

1 comment on commit 677cc2d

@bethesque
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Party time.

Please sign in to comment.