|
Play Framework/Scala example source code file (Helpers.scala)
The Helpers.scala Play Framework example source code
/*
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package play.api.test
import scala.language.reflectiveCalls
import play.api._
import play.api.mvc._
import play.api.http._
import play.api.libs.iteratee._
import play.api.libs.json.{ Json, JsValue }
import play.twirl.api.Content
import org.openqa.selenium._
import org.openqa.selenium.firefox._
import org.openqa.selenium.htmlunit._
import scala.concurrent.Await
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import akka.util.Timeout
/**
* Helper functions to run tests.
*/
trait PlayRunners {
val GET = "GET"
val POST = "POST"
val PUT = "PUT"
val DELETE = "DELETE"
val HEAD = "HEAD"
val HTMLUNIT = classOf[HtmlUnitDriver]
val FIREFOX = classOf[FirefoxDriver]
/**
* Executes a block of code in a running application.
*/
def running[T](app: Application)(block: => T): T = {
synchronized {
try {
Play.start(app)
block
} finally {
Play.stop()
}
}
}
/**
* Executes a block of code in a running server.
*/
def running[T](testServer: TestServer)(block: => T): T = {
synchronized {
try {
testServer.start()
block
} finally {
testServer.stop()
}
}
}
/**
* Executes a block of code in a running server, with a test browser.
*/
def running[T, WEBDRIVER <: WebDriver](testServer: TestServer, webDriver: Class[WEBDRIVER])(block: TestBrowser => T): T = {
running(testServer, WebDriverFactory(webDriver))(block)
}
/**
* Executes a block of code in a running server, with a test browser.
*/
def running[T](testServer: TestServer, webDriver: WebDriver)(block: TestBrowser => T): T = {
var browser: TestBrowser = null
synchronized {
try {
testServer.start()
browser = TestBrowser(webDriver, None)
block(browser)
} finally {
if (browser != null) {
browser.quit()
}
testServer.stop()
}
}
}
/**
* The port to use for a test server. Defaults to 19001. May be configured using the system property
* testserver.port
*/
lazy val testServerPort = Option(System.getProperty("testserver.port")).map(_.toInt).getOrElse(19001)
/**
* Constructs a in-memory (h2) database configuration to add to a FakeApplication.
*/
def inMemoryDatabase(name: String = "default", options: Map[String, String] = Map.empty[String, String]): Map[String, String] = {
val optionsForDbUrl = options.map { case (k, v) => k + "=" + v }.mkString(";", ";", "")
Map(
("db." + name + ".driver") -> "org.h2.Driver",
("db." + name + ".url") -> ("jdbc:h2:mem:play-test-" + scala.util.Random.nextInt + optionsForDbUrl)
)
}
}
trait Writeables {
implicit def writeableOf_AnyContentAsJson(implicit codec: Codec): Writeable[AnyContentAsJson] =
Writeable.writeableOf_JsValue.map(c => c.json)
implicit def writeableOf_AnyContentAsXml(implicit codec: Codec): Writeable[AnyContentAsXml] =
Writeable.writeableOf_NodeSeq.map(c => c.xml)
implicit def writeableOf_AnyContentAsFormUrlEncoded(implicit code: Codec): Writeable[AnyContentAsFormUrlEncoded] =
Writeable.writeableOf_urlEncodedForm.map(c => c.data)
implicit def writeableOf_AnyContentAsRaw: Writeable[AnyContentAsRaw] =
Writeable.wBytes.map(c => c.raw.initialData)
implicit def writeableOf_AnyContentAsText(implicit code: Codec): Writeable[AnyContentAsText] =
Writeable.wString.map(c => c.txt)
implicit def writeableOf_AnyContentAsEmpty(implicit code: Codec): Writeable[AnyContentAsEmpty.type] =
Writeable(_ => Array.empty[Byte], None)
}
trait DefaultAwaitTimeout {
/**
* The default await timeout. Override this to change it.
*/
implicit def defaultAwaitTimeout: Timeout = 20.seconds
/**
* How long we should wait for something that we expect *not* to happen, e.g.
* waiting to make sure that a channel is *not* closed by some concurrent process.
*
* NegativeTimeout is a separate type to a normal Timeout because we'll want to
* set it to a lower value. This is because in normal usage we'll need to wait
* for the full length of time to show that nothing has happened in that time.
* If the value is too high then we'll spend a lot of time waiting during normal
* usage. If it is too low, however, we may miss events that occur after the
* timeout has finished. This is a necessary tradeoff.
*
* Where possible, tests should avoid using a NegativeTimeout. Tests will often
* know exactly when an event should occur. In this case they can perform a
* check for the event immediately rather than using using NegativeTimeout.
*/
case class NegativeTimeout(t: Timeout)
implicit val defaultNegativeTimeout = NegativeTimeout(200.millis)
}
trait FutureAwaits {
self: DefaultAwaitTimeout =>
import java.util.concurrent.TimeUnit
/**
* Block until a Promise is redeemed.
*/
def await[T](future: Future[T])(implicit timeout: Timeout): T = Await.result(future, timeout.duration)
/**
* Block until a Promise is redeemed with the specified timeout.
*/
def await[T](future: Future[T], timeout: Long, unit: TimeUnit): T =
Await.result(future, Duration(timeout, unit))
}
trait EssentialActionCaller {
self: Writeables =>
/**
* Execute an [[play.api.mvc.EssentialAction]].
*
* The body is serialised using the implicit writable, so that the action body parser can deserialise it.
*/
def call[T](action: EssentialAction, req: FakeRequest[T])(implicit w: Writeable[T]): Future[Result] =
call(action, req, req.body)
/**
* Execute an [[play.api.mvc.EssentialAction]].
*
* The body is serialised using the implicit writable, so that the action body parser can deserialise it.
*/
def call[T](action: EssentialAction, rh: RequestHeader, body: T)(implicit w: Writeable[T]): Future[Result] = {
import play.api.http.HeaderNames._
val newContentType = rh.headers.get(CONTENT_TYPE).fold(w.contentType)(_ => None)
val rhWithCt = newContentType.map { ct =>
rh.copy(headers = FakeHeaders((rh.headers.toMap + (CONTENT_TYPE -> Seq(ct))).toSeq))
}.getOrElse(rh)
val requestBody = Enumerator(body) &> w.toEnumeratee
requestBody |>>> action(rhWithCt)
}
}
trait RouteInvokers extends EssentialActionCaller {
self: Writeables =>
// Java compatibility
def jRoute(app: Application, rh: RequestHeader): Option[Future[Result]] = route(app, rh, AnyContentAsEmpty)
def jRoute(app: Application, rh: RequestHeader, body: Array[Byte]): Option[Future[Result]] = route(app, rh, body)(Writeable.wBytes)
def jRoute(rh: RequestHeader, body: Array[Byte]): Option[Future[Result]] = jRoute(Play.current, rh, body)
def jRoute[T](app: Application, r: FakeRequest[T]): Option[Future[Result]] = {
(r.body: @unchecked) match {
case body: AnyContentAsFormUrlEncoded => route(app, r, body)
case body: AnyContentAsJson => route(app, r, body)
case body: AnyContentAsXml => route(app, r, body)
case body: AnyContentAsText => route(app, r, body)
case body: AnyContentAsRaw => route(app, r, body)
case body: AnyContentAsEmpty.type => route(app, r, body)
//case _ => MatchError is thrown
}
}
/**
* Use the Router to determine the Action to call for this request and execute it.
*
* The body is serialised using the implicit writable, so that the action body parser can deserialise it.
*/
def route[T](app: Application, rh: RequestHeader, body: T)(implicit w: Writeable[T]): Option[Future[Result]] = {
val handler = app.global.onRouteRequest(rh)
val taggedRh = handler.map({
case h: RequestTaggingHandler => h.tagRequest(rh)
case _ => rh
}).getOrElse(rh)
handler.flatMap {
case a: EssentialAction =>
val filteredAction = app.global.doFilter(a)
Some(call(filteredAction, taggedRh, body))
case _ => None
}
}
/**
* Use the Router to determine the Action to call for this request and execute it.
*
* The body is serialised using the implicit writable, so that the action body parser can deserialise it.
*/
def route[T](rh: RequestHeader, body: T)(implicit w: Writeable[T]): Option[Future[Result]] = route(Play.current, rh, body)
/**
* Use the Router to determine the Action to call for this request and execute it.
*
* The body is serialised using the implicit writable, so that the action body parser can deserialise it.
*/
def route[T](app: Application, req: Request[T])(implicit w: Writeable[T]): Option[Future[Result]] = route(app, req, req.body)
/**
* Use the Router to determine the Action to call for this request and execute it.
*
* The body is serialised using the implicit writable, so that the action body parser can deserialise it.
*/
def route[T](req: Request[T])(implicit w: Writeable[T]): Option[Future[Result]] = route(Play.current, req)
}
trait ResultExtractors {
self: HeaderNames with Status =>
/**
* Extracts the Content-Type of this Content value.
*/
def contentType(of: Content)(implicit timeout: Timeout): String = of.contentType
/**
* Extracts the content as String.
*/
def contentAsString(of: Content)(implicit timeout: Timeout): String = of.body
/**
* Extracts the content as bytes.
*/
def contentAsBytes(of: Content)(implicit timeout: Timeout): Array[Byte] = of.body.getBytes
/**
* Extracts the content as Json.
*/
def contentAsJson(of: Content)(implicit timeout: Timeout): JsValue = Json.parse(of.body)
/**
* Extracts the Content-Type of this Result value.
*/
def contentType(of: Future[Result])(implicit timeout: Timeout): Option[String] = header(CONTENT_TYPE, of).map(_.split(";").take(1).mkString.trim)
/**
* Extracts the Charset of this Result value.
*/
def charset(of: Future[Result])(implicit timeout: Timeout): Option[String] = header(CONTENT_TYPE, of) match {
case Some(s) if s.contains("charset=") => Some(s.split("; charset=").drop(1).mkString.trim)
case _ => None
}
/**
* Extracts the content as String.
*/
def contentAsString(of: Future[Result])(implicit timeout: Timeout): String = new String(contentAsBytes(of), charset(of).getOrElse("utf-8"))
/**
* Extracts the content as bytes.
*/
def contentAsBytes(of: Future[Result])(implicit timeout: Timeout): Array[Byte] =
Await.result(Await.result(of, timeout.duration).body |>>> Iteratee.consume[Array[Byte]](), timeout.duration)
/**
* Extracts the content as Json.
*/
def contentAsJson(of: Future[Result])(implicit timeout: Timeout): JsValue = Json.parse(contentAsString(of))
/**
* Extracts the Status code of this Result value.
*/
def status(of: Future[Result])(implicit timeout: Timeout): Int = Await.result(of, timeout.duration).header.status
/**
* Extracts the Cookies of this Result value.
*/
def cookies(of: Future[Result])(implicit timeout: Timeout): Cookies = Cookies(header(SET_COOKIE, of))
/**
* Extracts the Flash values of this Result value.
*/
def flash(of: Future[Result])(implicit timeout: Timeout): Flash = Flash.decodeFromCookie(cookies(of).get(Flash.COOKIE_NAME))
/**
* Extracts the Session of this Result value.
* Extracts the Session from this Result value.
*/
def session(of: Future[Result])(implicit timeout: Timeout): Session = Session.decodeFromCookie(cookies(of).get(Session.COOKIE_NAME))
/**
* Extracts the Location header of this Result value if this Result is a Redirect.
*/
def redirectLocation(of: Future[Result])(implicit timeout: Timeout): Option[String] = Await.result(of, timeout.duration).header match {
case ResponseHeader(FOUND, headers) => headers.get(LOCATION)
case ResponseHeader(SEE_OTHER, headers) => headers.get(LOCATION)
case ResponseHeader(TEMPORARY_REDIRECT, headers) => headers.get(LOCATION)
case ResponseHeader(MOVED_PERMANENTLY, headers) => headers.get(LOCATION)
case ResponseHeader(_, _) => None
}
/**
* Extracts an Header value of this Result value.
*/
def header(header: String, of: Future[Result])(implicit timeout: Timeout): Option[String] = headers(of).get(header)
/**
* Extracts all Headers of this Result value.
*/
def headers(of: Future[Result])(implicit timeout: Timeout): Map[String, String] = Await.result(of, timeout.duration).header.headers
}
object Helpers extends PlayRunners
with HeaderNames
with Status
with HttpProtocol
with DefaultAwaitTimeout
with ResultExtractors
with Writeables
with EssentialActionCaller
with RouteInvokers
with FutureAwaits
Other Play Framework source code examplesHere is a short list of links related to this Play Framework Helpers.scala source code file: |
| ... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.