Skip to content

Instantly share code, notes, and snippets.

@kenbot
Created April 17, 2014 00:35
Show Gist options
  • Save kenbot/cbea510cf99d88e87989 to your computer and use it in GitHub Desktop.
Save kenbot/cbea510cf99d88e87989 to your computer and use it in GitHub Desktop.
Horrid Pact/Play provider boilerplate
package myaccount.pact
import au.com.dius.pact.provider.PactFileSource
import org.specs2.mutable.Specification
import scala.concurrent.{Await, Promise, Future}
import scala.concurrent.duration._
import org.specs2.specification.{FormattingFragments => FF, Step, Fragments}
import au.com.dius.pact.model.{ResponseMatching, Response, Request}
import play.api.test.WithServer
import java.io.File
import au.com.dius.pact.model.Matching.MatchFound
import akka.actor.ActorSystem
import spray.http._
import spray.http.HttpRequest
import au.com.dius.pact.provider.PactConfiguration
import spray.http.HttpHeaders.RawHeader
import spray.http.HttpResponse
import play.api.test.FakeApplication
import au.com.dius.pact.model.spray.Conversions
import au.com.dius.pact.model.JsonDiff.DiffConfig
trait PactPlaySpecification extends Specification {
object StructuralResponseMatching extends ResponseMatching(DiffConfig(allowUnexpectedKeys=true, structural=true))
def pactRoot: File
def pactConfig: PactConfiguration
def startAppInState(state: String): FakeApplication
lazy val playExecutionContext = play.api.libs.concurrent.Execution.Implicits.defaultContext
private val aSys = Promise[ActorSystem]()
private def startActorSystem = {
aSys.success(ActorSystem("Pact-Provider-Verification-Actor-System"))
}
private def stopActorSystem = {
aSys.future.map(_.shutdown())(playExecutionContext)
}
private def invoke(baseUrl: String, request: Request): Future[Response] = {
aSys.future.flatMap{ actorSystem =>
implicit val system = actorSystem
implicit val executionContext = system.dispatcher
val pipeline: HttpRequest => Future[HttpResponse] = _root_.spray.client.pipelining.sendReceive
val method = HttpMethods.getForKey(request.method.toString.toUpperCase).get
val uri = Uri(s"$baseUrl${request.path}")
val headers: List[HttpHeader] = request.headers.map(_.toList.map{case (key, value) => RawHeader(key, value)}).getOrElse(Nil)
val entity: HttpEntity = request.bodyString.map(HttpEntity(ContentTypes.`application/json`, _)).getOrElse(HttpEntity.Empty)
println(s"invoking service with: $request")
pipeline(HttpRequest(method, uri, headers, entity)).map{ sprayResponse =>
Conversions.sprayToPactResponse(sprayResponse)
}(playExecutionContext)
}(playExecutionContext)
}
println("loading files from "+ pactRoot.getAbsolutePath)
PactFileSource.loadFiles(pactRoot).map { pact =>
println("fragment for pact: "+pact)
addFragments(FF.p)
addFragments(pact.provider.name + " should")
pact.interactions.map { interaction =>
interaction.description >> new WithServer(startAppInState(interaction.providerState)) {
val actualResponse = {
val request: Request = interaction.request
Await.result(invoke(s"http://localhost:$port", request), Duration(10, SECONDS))
}
StructuralResponseMatching.matchRules(interaction.response, actualResponse) must beEqualTo(MatchFound)
}
}
}
override def map(fs: =>Fragments) = Step(startActorSystem) ^ fs ^ Step(stopActorSystem)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment