-
-
Notifications
You must be signed in to change notification settings - Fork 481
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added functionality to publish a created contract on disk to a broker…
…. Verified with both pactflow as open source pact broker
- Loading branch information
Showing
7 changed files
with
194 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
107 changes: 107 additions & 0 deletions
107
pact-jvm-server/src/main/scala/au/com/dius/pact/server/Publish.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
package au.com.dius.pact.server | ||
|
||
import au.com.dius.pact.core.model.{OptionalBody, Request, Response} | ||
import com.typesafe.scalalogging.StrictLogging | ||
|
||
import scala.collection.JavaConverters._ | ||
import scala.io.Source | ||
import java.io.{File, IOException} | ||
|
||
import requests.{RequestAuth, RequestFailedException, headers} | ||
|
||
object Publish extends StrictLogging { | ||
|
||
def apply(request: Request, oldState: ServerState, config: Config): Result = { | ||
def jsonBody = JsonUtils.parseJsonString(request.getBody.valueAsString()) | ||
def consumer: Option[String] = getVarFromJson("consumer", jsonBody) | ||
def consumerVersion: Option[String] = getVarFromJson("consumerVersion", jsonBody) | ||
def provider: Option[String] = getVarFromJson("provider", jsonBody) | ||
def broker: Option[String] = getBrokerUrlFromConfig(config) | ||
def authToken: Option[String] = getVarFromConfig(config.authToken) | ||
|
||
var response = new Response(500, ResponseUtils.CrossSiteHeaders.asJava) | ||
if (broker.isDefined) { | ||
if (consumer.isDefined && consumerVersion.isDefined && provider.isDefined) { | ||
response = publishPact(consumer.get, consumerVersion.get, provider.get, broker.get, authToken) | ||
} else { | ||
def errorJson: String = "{\"error\": \"body should contain consumer, consumerVersion and provider.\"}" | ||
def body: OptionalBody = OptionalBody.body(errorJson.getBytes()) | ||
response = new Response(400, ResponseUtils.CrossSiteHeaders.asJava, body) | ||
} | ||
} else { | ||
def errorJson: String = "{\"error\" : \"Broker url not correctly configured please run server with -b or --broker 'http://pact-broker.adomain.com' option\" }" | ||
def body: OptionalBody = OptionalBody.body(errorJson.getBytes()) | ||
response = new Response(500, ResponseUtils.CrossSiteHeaders.asJava, body) | ||
} | ||
Result(response, oldState) | ||
} | ||
|
||
private def publishPact(consumer: String, consumerVersion: String, provider: String, broker: String, authToken: Option[String]) = { | ||
def fileName: String = s"${consumer}-${provider}.json" | ||
|
||
logger.debug("Publishing pact with following details: ") | ||
logger.debug("Consumer: " + consumer) | ||
logger.debug("ConsumerVersion: " + consumerVersion) | ||
logger.debug("Provider: " + provider) | ||
logger.debug("Pact Broker: " + broker) | ||
|
||
try { | ||
val content = readContract(fileName) | ||
def url = s"${broker}/pacts/provider/${provider}/consumer/${consumer}/version/${consumerVersion}" | ||
var auth: RequestAuth = RequestAuth.Empty | ||
if (authToken.isDefined) { | ||
auth = RequestAuth.Bearer(authToken.get) | ||
} | ||
def response = requests.put( | ||
url, | ||
auth, | ||
headers = Map("Content-Type" -> "application/json", "Accept" -> "application/hal+json, application/json, */*; q=0.01"), | ||
data = content | ||
) | ||
logger.debug("Statuscode from broker: " + response.statusCode) | ||
if(response.statusCode > 199 && response.statusCode < 400) { | ||
logger.debug("Pact succesfully shared. deleting file..") | ||
removePact(fileName) | ||
} | ||
new Response(response.statusCode, ResponseUtils.CrossSiteHeaders.asJava, OptionalBody.body(response.data.array)) | ||
} catch { | ||
case e: IOException => new Response(500, ResponseUtils.CrossSiteHeaders.asJava, OptionalBody.body(s"""{"error": "Got IO Exception while reading file. ${e.getMessage}"}""".getBytes())) | ||
case e: RequestFailedException => new Response(e.response.statusCode, ResponseUtils.CrossSiteHeaders.asJava, OptionalBody.body(e.response.data.array)) | ||
case _ => new Response(500, ResponseUtils.CrossSiteHeaders.asJava, OptionalBody.body("Something unknown happened..".getBytes())) | ||
} | ||
} | ||
|
||
private def removePact(fileName: String): Unit = { | ||
def file = new File(s"${System.getProperty("pact.rootDir", "target/pacts")}/$fileName") | ||
if (file.exists()) { | ||
file.delete() | ||
} | ||
} | ||
|
||
private def getVarFromConfig(variable: String) = { | ||
if (!variable.isEmpty) Some(variable) | ||
else None | ||
} | ||
|
||
def getBrokerUrlFromConfig(config: Config): Option[String] = { | ||
if (!config.broker.isEmpty && config.broker.startsWith("http")) Some(config.broker) | ||
else None | ||
} | ||
|
||
private def getVarFromJson(variable: String, json: Any): Option[String] = json match { | ||
case map: Map[AnyRef, AnyRef] => { | ||
if (map.contains(variable)) Some(map(variable).toString) | ||
else None | ||
} | ||
case _ => None | ||
} | ||
|
||
def readContract(fileName: String): String = { | ||
def filePath = s"${System.getProperty("pact.rootDir", "target/pacts")}/$fileName" | ||
def fileReader = Source.fromFile(filePath) | ||
def content = fileReader.getLines().mkString | ||
fileReader.close() | ||
logger.debug(content) | ||
content | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
58 changes: 58 additions & 0 deletions
58
pact-jvm-server/src/test/groovy/au/com/dius/pact/server/PublishSpec.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package au.com.dius.pact.server | ||
|
||
import au.com.dius.pact.server.Config | ||
import au.com.dius.pact.server.Publish | ||
import spock.lang.Specification | ||
|
||
class PublishSpec extends Specification { | ||
|
||
def 'invalid broker url in config will not set broker'() { | ||
given: | ||
def config = new Config(80, '0.0.0.0', false, 100, 200, false, 3, '', '', 0, 'invalid', 'abc#3') | ||
// def pact = PublishSpec.getResourceAsStream('/create-pact.json').text | ||
|
||
when: | ||
def result = Publish.getBrokerUrlFromConfig(config) | ||
|
||
then: | ||
!result.isDefined() | ||
} | ||
|
||
def 'valid broker url will set broker'() { | ||
given: | ||
def config = new Config(80, '0.0.0.0', false, 100, 200, false, 3, '', '', 0, 'https://valid.broker.com', 'abc#3') | ||
|
||
when: | ||
def result = Publish.getBrokerUrlFromConfig(config) | ||
|
||
then: | ||
result.isDefined() | ||
} | ||
|
||
def 'successful read on valid file'() { | ||
given: | ||
def content = """ {"consumer": "testconsumer", "provider": "testprovider"} """ | ||
def fileName = "test.json" | ||
def rootDir = System.getProperty("pact.rootDir", "target/pacts") | ||
def file = new File("${rootDir}/$fileName") | ||
new File(rootDir).mkdirs() | ||
file.write(content) | ||
|
||
when: | ||
def result = Publish.readContract(fileName) | ||
|
||
then: | ||
content == result | ||
|
||
cleanup: | ||
new File(System.getProperty("pact.rootDir", "target")).deleteDir() | ||
} | ||
|
||
def 'unsuccessful read on invalid file'() { | ||
when: | ||
Publish.readContract("invalid") | ||
|
||
then: | ||
thrown(IOException) | ||
} | ||
} |