Skip to content

Commit

Permalink
Merge branch 'master' into v4.x
Browse files Browse the repository at this point in the history
  • Loading branch information
Ronald Holshausen committed May 5, 2019
2 parents 229f8d5 + ed9dba4 commit 1e2e346
Show file tree
Hide file tree
Showing 32 changed files with 752 additions and 374 deletions.
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
To generate the log, run `git log --pretty='* %h - %s (%an, %ad)' TAGNAME..HEAD` replacing TAGNAME and HEAD as appropriate.

# 3.6.6 - Bugfix Release

* ad59aa4d - refactor: verification methods now return test results instead of boolean (Ronald Holshausen, Sun May 5 16:07:28 2019 +1000)
* dcd05213 - feat: update the verification results to be a test result instead of a boolean (Ronald Holshausen, Sun May 5 12:16:56 2019 +1000)
* ae17dc5b - doc: updated doco about using bearer tokens (Ronald Holshausen, Sat May 4 17:30:51 2019 +1000)
* a88e6a17 - fix: the build (Ronald Holshausen, Sat May 4 17:21:14 2019 +1000)
* b26bed53 - feat: added pact test for publishing verification results (Ronald Holshausen, Sat May 4 16:48:23 2019 +1000)
* 1610f9d3 - feat: added pact-publish module to enable pactception (Ronald Holshausen, Sat May 4 16:28:48 2019 +1000)
* ac704677 - fix: for failing build #876 (Ronald Holshausen, Fri May 3 18:21:50 2019 +1000)
* cf937f44 - fix: correct the use of matchers with query parameters #876 (Ronald Holshausen, Fri May 3 18:05:48 2019 +1000)
* 3c5c65b7 - doc: add note about using Maven isolated classpath and message verification tests #763 (Ronald Holshausen, Fri May 3 16:43:27 2019 +1000)
* 2f447e9d - test: updated JUnit 5 test with a does not exist example (Ronald Holshausen, Thu Apr 25 18:29:43 2019 +1000)
* a1b97980 - fix: correctly handle the message content type with charsets when verifying #874 (Ronald Holshausen, Thu Apr 25 17:51:53 2019 +1000)
* efe3e0fe - fix: correctly handle the message content type with charsets #874 (Ronald Holshausen, Thu Apr 25 17:17:02 2019 +1000)
* dbe9bc21 - fix: only set the message content type if it has not been specified #874 (Ronald Holshausen, Thu Apr 25 16:06:44 2019 +1000)
* 3d43a33a - chore: update clojure to latest (Ronald Holshausen, Mon Apr 22 11:16:22 2019 +1000)
* 3c8267a5 - Revert "fix: exclude clojure test from appveyor build" (Ronald Holshausen, Mon Apr 22 11:15:54 2019 +1000)
* 616ade41 - chore: update nebula.clojure plugin (Ronald Holshausen, Mon Apr 22 11:09:55 2019 +1000)
* 49bf7fc5 - Update README.md (Ronald Holshausen, Mon Apr 22 11:02:29 2019 +1000)
* 550cf6f7 - bump version to 3.6.6 (Ronald Holshausen, Sun Apr 21 15:38:11 2019 +1000)

# 3.6.5 - Bugfix Release + Matching on message metadata

* c3b8e3ad - fix: exclude clojure test from appveyor build (Ronald Holshausen, Sun Apr 21 14:57:07 2019 +1000)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ sealed class PactVerificationResult {
}

data class UnexpectedRequest(val request: Request) : PactVerificationResult() {
override fun getDescription(): String {
return "Unexpected Request:\n$request"
}
override fun getDescription() = "Unexpected Request:\n$request"
}

data class ExpectedButNotReceived(val expectedRequests: List<Request>) : PactVerificationResult() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package au.com.dius.pact.core.pactbroker
import au.com.dius.pact.com.github.michaelbull.result.Err
import au.com.dius.pact.com.github.michaelbull.result.Ok
import au.com.dius.pact.com.github.michaelbull.result.Result
import au.com.dius.pact.core.support.isNotEmpty
import au.com.dius.pact.core.pactbroker.util.HttpClientUtils.buildUrl
import au.com.dius.pact.core.pactbroker.util.HttpClientUtils.isJsonResponse
import com.github.salomonbrys.kotson.array
Expand Down Expand Up @@ -367,14 +368,14 @@ open class HalClient @JvmOverloads constructor(
if (resp.entity.contentType != null) {
val contentType = ContentType.getOrDefault(resp.entity)
if (isJsonResponse(contentType)) {
var error = "Unknown error"
if (body != null) {
var error = ""
if (body.isNotEmpty()) {
val jsonBody = JsonParser().parse(body)
if (jsonBody != null && jsonBody.obj.has("errors")) {
if (jsonBody["errors"].isJsonArray) {
error = jsonBody["errors"].asJsonArray.joinToString(", ") { it.asString }
error = " - " + jsonBody["errors"].asJsonArray.joinToString(", ") { it.asString }
} else if (jsonBody["errors"].isJsonObject) {
error = jsonBody["errors"].asJsonObject.entrySet().joinToString(", ") {
error = " - " + jsonBody["errors"].asJsonObject.entrySet().joinToString(", ") {
if (it.value.isJsonArray) {
"${it.key}: ${it.value.array.joinToString(", ") { it.asString }}"
} else {
Expand All @@ -384,7 +385,7 @@ open class HalClient @JvmOverloads constructor(
}
}
}
return closure.apply("FAILED", "${resp.statusLine.statusCode} ${resp.statusLine.reasonPhrase} - $error")
return closure.apply("FAILED", "${resp.statusLine.statusCode} ${resp.statusLine.reasonPhrase}$error")
} else {
return closure.apply("FAILED", "${resp.statusLine.statusCode} ${resp.statusLine.reasonPhrase} - $body")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,33 @@ import java.util.function.Consumer
*/
data class PactResponse(val pactFile: Any, val links: Map<String, Map<String, Any>>)

sealed class TestResult {
object Ok: TestResult() {
override fun toBoolean() = true

override fun merge(result: TestResult) = when (result) {
is Ok -> this
is Failed -> result
}
}

data class Failed(var results: List<Any> = emptyList()): TestResult() {
override fun toBoolean() = false

override fun merge(result: TestResult) = when (result) {
is Ok -> this
is Failed -> Failed(results + result.results)
}
}

abstract fun toBoolean(): Boolean
abstract fun merge(result: TestResult): TestResult

companion object {
fun fromBoolean(result: Boolean) = if (result) Ok else Failed()
}
}

/**
* Client for the pact broker service
*/
Expand Down Expand Up @@ -114,20 +141,30 @@ open class PactBrokerClient(val pactBrokerUrl: String, val options: Map<String,

open fun newHalClient(): IHalClient = HalClient(pactBrokerUrl, options)

@Deprecated(message = "Use the version that takes a test result",
replaceWith = ReplaceWith("publishVerificationResults"))
open fun publishVerificationResults(
docAttributes: Map<String, Map<String, Any>>,
result: Boolean,
version: String,
buildUrl: String? = null
): Result<Boolean, Exception>
= publishVerificationResults(docAttributes, TestResult.fromBoolean(result), version, buildUrl)

/**
* Publishes the result to the "pb:publish-verification-results" link in the document attributes.
*/
@JvmOverloads
open fun publishVerificationResults(
docAttributes: Map<String, Map<String, Any>>,
result: Boolean,
result: TestResult,
version: String,
buildUrl: String? = null
): Result<Boolean, Exception> {
val halClient = newHalClient()
val publishLink = docAttributes.mapKeys { it.key.toLowerCase() } ["pb:publish-verification-results"] // ktlint-disable curly-spacing
return if (publishLink != null) {
val jsonObject = jsonObject("success" to result, "providerApplicationVersion" to version)
val jsonObject = jsonObject("success" to result.toBoolean(), "providerApplicationVersion" to version)
if (buildUrl != null) {
jsonObject.add("buildUrl", buildUrl.toJson())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,8 +264,8 @@ class HalClientSpec extends Specification {
where:

description | body | firstArg | secondArg
'body is null' | null | 'FAILED' | '400 Not OK - Unknown error'
'body is a parsed json doc with no errors' | '{}' | 'FAILED' | '400 Not OK - Unknown error'
'body is null' | null | 'FAILED' | '400 Not OK'
'body is a parsed json doc with no errors' | '{}' | 'FAILED' | '400 Not OK'
'body is a parsed json doc with errors' | '{"errors":["one","two","three"]}' | 'FAILED' | '400 Not OK - one, two, three'

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package au.com.dius.pact.core.pactbroker

import spock.lang.Specification
import spock.lang.Unroll

@SuppressWarnings('LineLength')
class TestResultSpec extends Specification {

@Unroll
def 'merging results test'() {
expect:
result1.merge(result2) == result3

where:

result1 | result2 | result3
TestResult.Ok.INSTANCE | TestResult.Ok.INSTANCE | TestResult.Ok.INSTANCE
TestResult.Ok.INSTANCE | new TestResult.Failed(['Bang']) | new TestResult.Failed(['Bang'])
new TestResult.Failed(['Bang']) | TestResult.Ok.INSTANCE | new TestResult.Failed(['Bang'])
new TestResult.Failed(['Bang']) | new TestResult.Failed(['Boom', 'Splat']) | new TestResult.Failed(['Bang', 'Boom', 'Splat'])
}

}
3 changes: 3 additions & 0 deletions pact-publish/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Pact Publish

Module for generating and publishing pacts to the pact broker
25 changes: 25 additions & 0 deletions pact-publish/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
buildscript {
dependencies {
classpath "au.com.dius:pact-jvm-provider-gradle:4.0.0-beta.1"
}
}

if (System.env.PACT_PUBLISH == 'true') {
apply plugin: 'au.com.dius.pact'
}

dependencies {
testCompile project(":consumer:pact-jvm-consumer-groovy")
}

if (System.env.PACT_PUBLISH == 'true') {
pact {
publish {
pactBrokerUrl = 'https://pact-foundation.pact.dius.com.au'
if (project.hasProperty('pactBrokerToken')) {
pactBrokerToken = project.pactBrokerToken
}
excludes = ['JVM Pact Broker Client-Imaginary Pact Broker']
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package au.com.dius.pact.provider.broker
package broker

import au.com.dius.pact.com.github.michaelbull.result.Ok
import au.com.dius.pact.consumer.PactVerificationResult
import au.com.dius.pact.consumer.groovy.PactBuilder
import au.com.dius.pact.core.pactbroker.PactBrokerClient
import au.com.dius.pact.core.pactbroker.TestResult
import spock.lang.Specification

@SuppressWarnings('UnnecessaryGetter')
Expand All @@ -11,7 +13,7 @@ class PactBrokerClientPactSpec extends Specification {
private PactBrokerClient pactBrokerClient
private File pactFile
private String pactContents
private PactBuilder pactBroker
private PactBuilder pactBroker, imaginaryBroker

def setup() {
pactBrokerClient = new PactBrokerClient('http://localhost:8080')
Expand All @@ -34,6 +36,13 @@ class PactBrokerClientPactSpec extends Specification {
hasPactWith 'Pact Broker'
port 8080
}

imaginaryBroker = new PactBuilder()
imaginaryBroker {
serviceConsumer 'JVM Pact Broker Client'
hasPactWith 'Imaginary Pact Broker'
port 8080
}
}

def 'returns success when uploading a pact is ok'() {
Expand All @@ -53,7 +62,29 @@ class PactBrokerClientPactSpec extends Specification {
}

then:
result instanceof PactVerificationResult.Ok
result == PactVerificationResult.Ok.INSTANCE
}

def 'returns an error when forbidden to publish the pact'() {
given:
pactBroker {
uponReceiving('a pact publish request which will be forbidden')
withAttributes(method: 'PUT',
path: '/pacts/provider/Provider/consumer/Foo Consumer/version/10.0.0',
body: pactContents
)
willRespondWith(status: 401, headers: [
'Content-Type': 'application/json'
])
}

when:
def result = pactBroker.runTest { server, context ->
assert pactBrokerClient.uploadPactFile(pactFile, '10.0.0') == 'FAILED! 401 Unauthorized'
}

then:
result == PactVerificationResult.Ok.INSTANCE
}

@SuppressWarnings('LineLength')
Expand Down Expand Up @@ -87,7 +118,7 @@ class PactBrokerClientPactSpec extends Specification {
}

then:
result instanceof PactVerificationResult.Ok
result == PactVerificationResult.Ok.INSTANCE
}

@SuppressWarnings('LineLength')
Expand Down Expand Up @@ -118,13 +149,13 @@ class PactBrokerClientPactSpec extends Specification {
}

then:
result instanceof PactVerificationResult.Ok
result == PactVerificationResult.Ok.INSTANCE
}

@SuppressWarnings('LineLength')
def 'handles non-json failure responses'() {
given:
pactBroker {
imaginaryBroker {
given('Non-JSON response')
uponReceiving('a pact publish request')
withAttributes(method: 'PUT',
Expand All @@ -137,12 +168,12 @@ class PactBrokerClientPactSpec extends Specification {
}

when:
def result = pactBroker.runTest { server, context ->
def result = imaginaryBroker.runTest { server, context ->
assert pactBrokerClient.uploadPactFile(pactFile, '10.0.0') == 'FAILED! 400 Bad Request - Enjoy this bit of text'
}

then:
result instanceof PactVerificationResult.Ok
result == PactVerificationResult.Ok.INSTANCE
}

def 'pact broker navigation test'() {
Expand All @@ -156,7 +187,7 @@ class PactBrokerClientPactSpec extends Specification {
uponReceiving('a request to the root')
withAttributes(path: '/')
willRespondWith(status: 200)
withBody(mimeType: 'application/hal+json') {
withBody('application/hal+json') {
'_links' {
'pb:latest-provider-pacts' {
href url('http://localhost:8080', 'pacts', 'provider', '{provider}', 'latest')
Expand All @@ -168,7 +199,7 @@ class PactBrokerClientPactSpec extends Specification {
uponReceiving('a request for the provider pacts')
withAttributes(path: '/pacts/provider/Activity Service/latest')
willRespondWith(status: 200)
withBody(mimeType: 'application/hal+json') {
withBody('application/hal+json') {
'_links' {
provider {
href url('http://localhost:8080', 'pacticipants', regexp('[^\\/]+', 'Activity Service'))
Expand All @@ -191,6 +222,58 @@ class PactBrokerClientPactSpec extends Specification {
}

then:
result instanceof PactVerificationResult.Ok
result == PactVerificationResult.Ok.INSTANCE
}

def 'publishing verification results pact test'() {
given:
pactBroker {
given('A pact has been published between the Provider and Foo Consumer')
uponReceiving('a pact publish verification request')
withAttributes(method: 'POST',
path: '/pacts/provider/Provider/consumer/Foo Consumer/pact-version/1234567890/verification-results',
body: [success: true, providerApplicationVersion: '10.0.0']
)
willRespondWith(status: 201)
}

when:
def result = pactBroker.runTest { server, context ->
assert pactBrokerClient.publishVerificationResults([
'pb:publish-verification-results': [
href: 'http://localhost:8080/pacts/provider/Provider/consumer/Foo%20Consumer/pact-version/1234567890' +
'/verification-results'
]
], TestResult.Ok.INSTANCE, '10.0.0') instanceof Ok
}

then:
result == PactVerificationResult.Ok.INSTANCE
}

def 'publishing verification results pact test with build info'() {
given:
pactBroker {
given('A pact has been published between the Provider and Foo Consumer')
uponReceiving('a pact publish verification request')
withAttributes(method: 'POST',
path: '/pacts/provider/Provider/consumer/Foo Consumer/pact-version/1234567890/verification-results',
body: [success: true, providerApplicationVersion: '10.0.0', buildUrl: 'http://localhost:8080/build']
)
willRespondWith(status: 201)
}

when:
def result = pactBroker.runTest { server, context ->
assert pactBrokerClient.publishVerificationResults([
'pb:publish-verification-results': [
href: 'http://localhost:8080/pacts/provider/Provider/consumer/Foo%20Consumer/pact-version/1234567890' +
'/verification-results'
]
], TestResult.Ok.INSTANCE, '10.0.0', 'http://localhost:8080/build') instanceof Ok
}

then:
result == PactVerificationResult.Ok.INSTANCE
}
}
Loading

0 comments on commit 1e2e346

Please sign in to comment.