-
-
Save kenbot/cbea510cf99d88e87989 to your computer and use it in GitHub Desktop.
Horrid Pact/Play provider boilerplate
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
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