![JAR search and dependency download from the Maven repository](/logo.png)
net.liftweb.http.testing.TestFramework.scala Maven / Gradle / Ivy
/*
* Copyright 2008-2011 WorldWide Conferencing, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.liftweb
package http
package testing
import scala.language.implicitConversions
import net.liftweb.util.Helpers._
import net.liftweb.util._
import net.liftweb.json._
import JsonDSL._
import net.liftweb.common._
import scala.xml._
import scala.xml.Utility.trim
import java.util.{Map => JavaMap, Set => JavaSet, Iterator => JavaIterator, List => JavaList}
import java.util.regex.Pattern
import java.io.IOException
import org.apache.commons.httpclient._
import org.apache.commons.httpclient.cookie._
import methods._
import java.io.OutputStream
import org.apache.commons.httpclient.auth.AuthScope
trait ToResponse {
self: BaseGetPoster =>
type ResponseType = TestResponse
implicit def responseCapture(fullUrl: String,
httpClient: HttpClient,
getter: HttpMethodBase): ResponseType = {
val ret: ResponseType = try {
(baseUrl + fullUrl, httpClient.executeMethod(getter)) match {
case (server, responseCode) =>
val respHeaders = slurpApacheHeaders(getter.getResponseHeaders)
new HttpResponse(baseUrl,
responseCode, getter.getStatusText,
respHeaders,
for {st <- Box !! getter.getResponseBodyAsStream
bytes <- tryo(readWholeStream(st))
} yield bytes,
httpClient)
}
} catch {
case e: IOException => new CompleteFailure(baseUrl + fullUrl, Full(e))
} finally {
getter.releaseConnection
}
ret
}
}
trait ToBoxTheResponse {
self: BaseGetPoster =>
type ResponseType = Box[TheResponse]
implicit def responseCapture(fullUrl: String,
httpClient: HttpClient,
getter: HttpMethodBase):
Box[TheResponse] = {
val ret = try {
(baseUrl + fullUrl, httpClient.executeMethod(getter)) match {
case (server, responseCode) =>
val respHeaders = slurpApacheHeaders(getter.getResponseHeaders)
Full(new TheResponse(baseUrl,
responseCode, getter.getStatusText,
respHeaders,
for {st <- Box !! getter.getResponseBodyAsStream
bytes <- tryo(readWholeStream(st))
} yield bytes,
httpClient))
}
} catch {
case e: IOException => Failure(baseUrl + fullUrl, Full(e), Empty)
} finally {
getter.releaseConnection
}
ret
}
}
trait GetPoster extends BaseGetPoster with ToResponse
/**
* A trait that wraps the Apache Commons HTTP client and supports GET and POST
*/
trait BaseGetPoster {
type ResponseType
/**
* The base URL for all requests
*/
def baseUrl: String
protected def slurpApacheHeaders(in: Array[Header]):
Map[String, List[String]] = {
val headerSet: List[(String, String)] = for (e <- in.toList) yield (e.getName -> e.getValue)
headerSet.foldLeft[Map[String, List[String]]](Map.empty)((acc, e) =>
acc + (e._1 -> (e._2 :: acc.getOrElse(e._1, Nil))))
}
/**
* Perform an HTTP GET
*
* @param url - the URL to append to the baseUrl
* @param headers - any additional headers to include with the request
* @param faux_params - the request parameters to include with the request
*/
def get(url: String, httpClient: HttpClient,
headers: List[(String, String)],
faux_params: (String, Any)*)
(implicit capture: (String, HttpClient, HttpMethodBase) => ResponseType):
ResponseType
= {
val params = faux_params.toList.map(x => (x._1, x._2.toString))
val fullUrl = url + (params.map(v => urlEncode(v._1) + "=" + urlEncode(v._2)).mkString("&") match {case s if s.length == 0 => ""; case s => "?" + s})
val getter = new GetMethod(baseUrl + fullUrl)
getter.getParams().setCookiePolicy(CookiePolicy.RFC_2965)
for ((name, value) <- headers) getter.setRequestHeader(name, value)
capture(fullUrl, httpClient, getter)
}
/**
* Perform an HTTP DELETE
*
* @param url - the URL to append to the baseUrl
* @param headers - any additional headers to include with the request
* @param faux_params - the request parameters to include with the request
*/
def delete(url: String, httpClient: HttpClient,
headers: List[(String, String)],
faux_params: (String, Any)*)
(implicit capture: (String, HttpClient, HttpMethodBase) => ResponseType):
ResponseType
= {
val params = faux_params.toList.map(x => (x._1, x._2.toString))
val fullUrl = url + (params.map(v => urlEncode(v._1) + "=" + urlEncode(v._2)).mkString("&") match {case s if s.length == 0 => ""; case s => "?" + s})
val getter = new DeleteMethod(baseUrl + fullUrl)
getter.getParams().setCookiePolicy(CookiePolicy.RFC_2965)
for ((name, value) <- headers) getter.setRequestHeader(name, value)
capture(fullUrl, httpClient, getter)
}
/**
* Perform an HTTP POST
*
* @param url - the URL to append to the baseUrl
* @param headers - any additional headers to include with the request
* @param faux_params - the request parameters to include with the request
*/
def post(url: String, httpClient: HttpClient,
headers: List[(String, String)],
faux_params: (String, Any)*)
(implicit capture: (String, HttpClient, HttpMethodBase) => ResponseType):
ResponseType
= {
val params = faux_params.toList.map(x => (x._1, x._2.toString))
val poster = new PostMethod(baseUrl + url)
poster.getParams().setCookiePolicy(CookiePolicy.RFC_2965)
for ((name, value) <- headers) poster.setRequestHeader(name, value)
for ((name, value) <- params) poster.setParameter(name, value)
capture(url, httpClient, poster)
}
implicit def xmlToRequestEntity(body: NodeSeq): RequestEntity =
new RequestEntity {
val bytes = body.toString.getBytes("UTF-8")
def getContentLength() = bytes.length
def getContentType() = "text/xml; charset=utf-8"
def isRepeatable() = true
def writeRequest(out: OutputStream) {
out.write(bytes)
}
}
implicit def jsonToRequestEntity(body: JValue): RequestEntity =
new RequestEntity {
val bytes = compactRender(body).toString.getBytes("UTF-8")
def getContentLength() = bytes.length
def getContentType() = "application/json"
def isRepeatable() = true
def writeRequest(out: OutputStream) {
out.write(bytes)
}
}
/**
* Perform an HTTP POST with an XML body
*
* @param url - the URL to append to the baseUrl
* @param headers - any additional headers to include with the request
* @param body - the xml to post
*/
def post[RT](url: String, httpClient: HttpClient,
headers: List[(String, String)],
body: RT)
(implicit capture: (String, HttpClient, HttpMethodBase) => ResponseType,
bodyToRequestEntity: RT => RequestEntity): ResponseType
= {
val poster = new PostMethod(baseUrl + url)
poster.getParams().setCookiePolicy(CookiePolicy.RFC_2965)
for ((name, value) <- headers) poster.setRequestHeader(name, value)
poster.setRequestEntity(bodyToRequestEntity(body))
capture(url, httpClient, poster)
}
/**
* Perform an HTTP POST with a pile of bytes in the body
*
* @param url - the URL to append to the baseUrl
* @param headers - any additional headers to include with the request
* @param body - the pile of bytes to POST to the target server
* @param contentType - the content type of the pile of bytes
*/
def post(url: String, httpClient: HttpClient,
headers: List[(String, String)],
body: Array[Byte],
contentType: String)
(implicit capture: (String, HttpClient, HttpMethodBase) => ResponseType):
ResponseType
= {
val poster = new PostMethod(baseUrl + url)
poster.getParams().setCookiePolicy(CookiePolicy.RFC_2965)
for ((name, value) <- headers) poster.setRequestHeader(name, value)
poster.setRequestEntity(new RequestEntity {
private val bytes = body
def getContentLength() = bytes.length
def getContentType() = contentType
def isRepeatable() = true
def writeRequest(out: OutputStream) {
out.write(bytes)
}
})
capture(url, httpClient, poster)
}
/**
* Perform an HTTP PUT
*
* @param url - the URL to append to the baseUrl
* @param headers - any additional headers to include with the request
*/
def put(url: String, httpClient: HttpClient,
headers: List[(String, String)])
(implicit capture: (String, HttpClient, HttpMethodBase) => ResponseType):
ResponseType
= {
val poster = new PutMethod(baseUrl + url)
poster.getParams().setCookiePolicy(CookiePolicy.RFC_2965)
for ((name, value) <- headers) poster.setRequestHeader(name, value)
capture(url, httpClient, poster)
}
/**
* Perform an HTTP PUT with an XML body
*
* @param url - the URL to append to the baseUrl
* @param headers - any additional headers to include with the request
* @param body - the xml to post
*/
def put[RT](url: String, httpClient: HttpClient,
headers: List[(String, String)],
body: RT)
(implicit capture: (String, HttpClient, HttpMethodBase) => ResponseType,
bodyToRequestEntity: RT => RequestEntity): ResponseType
= {
val poster = new PutMethod(baseUrl + url)
poster.getParams().setCookiePolicy(CookiePolicy.RFC_2965)
for ((name, value) <- headers) poster.setRequestHeader(name, value)
poster.setRequestEntity(bodyToRequestEntity(body))
capture(url, httpClient, poster)
}
/**
* Perform an HTTP PUT with a pile of bytes in the body
*
* @param url - the URL to append to the baseUrl
* @param headers - any additional headers to include with the request
* @param body - the pile of bytes to POST to the target server
* @param contentType - the content type of the pile of bytes
*/
def put(url: String, httpClient: HttpClient,
headers: List[(String, String)],
body: Array[Byte],
contentType: String)
(implicit capture: (String, HttpClient, HttpMethodBase) => ResponseType):
ResponseType
= {
val poster = new PutMethod(baseUrl + url)
poster.getParams().setCookiePolicy(CookiePolicy.RFC_2965)
for ((name, value) <- headers) poster.setRequestHeader(name, value)
poster.setRequestEntity(new RequestEntity {
private val bytes = body
def getContentLength() = bytes.length
def getContentType() = contentType
def isRepeatable() = true
def writeRequest(out: OutputStream) {
out.write(bytes)
}
})
capture(url, httpClient, poster)
}
}
/**
* A trait for reporting failures
*/
trait ReportFailure {
def fail(msg: String): Nothing
}
trait GetPosterHelper {
self: BaseGetPoster =>
/**
* Create the HTTP client for a new get/post request
*/
def theHttpClient: HttpClient
/**
* Perform an HTTP GET with a newly minted httpClient
*
* @param url the URL to make the request on
* @param params the parameters to pass
*/
def get(url: String, params: (String, Any)*)
(implicit capture: (String, HttpClient, HttpMethodBase) => ResponseType):
ResponseType =
get(url, theHttpClient, Nil, params: _*)(capture)
/**
* Perform an HTTP DELETE with a newly minted httpClient
*
* @param url the URL to make the request on
* @param params the parameters to pass
*/
def delete(url: String, params: (String, Any)*)
(implicit capture: (String, HttpClient, HttpMethodBase) => ResponseType):
ResponseType =
delete(url, theHttpClient, Nil, params: _*)(capture)
/**
* Perform an HTTP POST with a newly minted httpClient
*
* @param url the URL to make the request on
* @param params the parameters to pass
*/
def post(url: String, params: (String, Any)*)
(implicit capture: (String, HttpClient, HttpMethodBase) => ResponseType):
ResponseType =
post(url, theHttpClient, Nil, params: _*)(capture)
/**
* Perform an HTTP POST with a newly minted httpClient
*
* @param url the URL to make the request on
* @param xml the XML to POST to the server
*/
def post[RT](url: String, xml: RT)
(implicit capture: (String, HttpClient, HttpMethodBase) => ResponseType,
bodyToRequestEntity: RT => RequestEntity): ResponseType =
post(url, theHttpClient, Nil, xml)(capture, bodyToRequestEntity)
/**
* Perform an HTTP POST with a newly minted httpClient
*
* @param url the URL to make the request on
* @param body the bytes to POST to the server
* @param contentType the content type of the message
*/
def post(url: String, body: Array[Byte], contentType: String)
(implicit capture: (String, HttpClient, HttpMethodBase) => ResponseType): ResponseType =
post(url, theHttpClient, Nil, body, contentType)(capture)
/**
* Perform an HTTP PUT with a newly minted httpClient
*
* @param url the URL to make the request on
* @param xml the XML to PUT to the server
*/
def put[RT](url: String, xml: RT)
(implicit capture: (String, HttpClient, HttpMethodBase) => ResponseType,
bodyToRequestEntity: RT => RequestEntity): ResponseType =
put(url, theHttpClient, Nil, xml)(capture, bodyToRequestEntity)
/**
* Perform an HTTP POST with a newly minted httpClient
*
* @param url the URL to make the request on
* @param body the bytes to POST to the server
* @param contentType the content type of the message
*/
def put(url: String, body: Array[Byte], contentType: String)
(implicit capture: (String, HttpClient, HttpMethodBase) => ResponseType): ResponseType =
put(url, theHttpClient, Nil, body, contentType)(capture)
}
/**
* Mix this trait into your test so you can make HTTP requests on a target
*/
trait TestKit extends ClientBuilder with GetPoster with GetPosterHelper {
/**
* The base URL for all GET and POST requests
*/
def baseUrl: String
class TestHandler(res: TestResponse) {
def then(f: TestResponse => TestResponse): TestResponse = f(res)
def also(f: TestResponse => Any): TestResponse = {f(res); res}
}
implicit def reqToHander(in: TestResponse): TestHandler = new TestHandler(in)
}
trait ClientBuilder {
/**
* Create the HTTP client for a new get/post request
*/
def theHttpClient: HttpClient = buildNoAuthClient
/**
* Create a new HTTP client that does not do any form of AUTH
*/
def buildNoAuthClient =
new HttpClient(new SimpleHttpConnectionManager(false))
/**
* Create a new HTTP client that does BASIC AUTH with username/pwd
*/
def buildBasicAuthClient(name: String, pwd: String) = {
val ret = new HttpClient(new SimpleHttpConnectionManager(false))
val defaultcreds = new UsernamePasswordCredentials(name, pwd)
ret.getState().setCredentials(AuthScope.ANY, defaultcreds)
ret
}
}
/**
* Mix this trait into your test so you can make HTTP requests on a target
*/
trait RequestKit extends ClientBuilder with BaseGetPoster with GetPosterHelper with ToBoxTheResponse {
/**
* The base URL for all GET and POST requests
*/
def baseUrl: String
}
/**
* A legacy test framework
*/
trait TestFramework extends TestKit {
// def runner: TestRunner
def tests: List[Item]
def buildRunner: TestRunner
/**
* Create the base HTTP client
*/
override def theHttpClient: HttpClient = defaultHttpClient
lazy val defaultHttpClient = buildNoAuthClient
// protected lazy val httpClient = new HttpClient(new MultiThreadedHttpConnectionManager)
def fork(cnt: Int)(f: Int => Any) {
val threads = for (t <- (1 to cnt).toList) yield {
val th = new Thread(new Runnable {def run {f(t)}})
th.start
th
}
def waitAll(in: List[Thread]) {
in match {
case Nil =>
case x :: xs => x.join; waitAll(xs)
}
}
waitAll(threads)
}
}
object TestHelpers {
/**
* Get the function name given a particular comet actor name
*
* @param cometName the name (default prefix) for the comet actor
* @param body the body of the response
*
* @return the name of the JSON function associated with the Comet actor
*/
def jsonFuncForCometName(cometName: String, body: String): Box[String] = {
val p = Pattern.compile("""JSON Func """ + cometName + """ \$\$ ([Ff][^ ]*)""")
val m = p.matcher(body)
if (m.find) Full(m.group(1))
else Empty
}
/**
* Given an HTML page, find the list of "lift_toWatch" names and values
* These can be fed back into a comet request
*
* @param body the page body returned from an HTTP request
*
* @return a list of the "to watch" tokens and the last update tokens
*/
def toWatchFromPage(body: String): List[(String, String)] = {
val p = Pattern.compile("""lift_toWatch[ ]*\=[ ]*\{([^}]*)\}""")
val rp = new REMatcher(body, p)
val p2 = Pattern.compile("""'([^']*)'\: ([0-9]*)""")
for {
it <- rp.capture;
_ = println("Captured: " + it);
_ = println("Does match: " + p2.matcher(it).find);
q = new REMatcher(it, p2);
em <- q.eachFound
} yield {
(em(1), em(2))
}
}
/**
* Given the body of a Comet response, parse for updates "lift_toWatch" values
* and update the current sequence to reflect any updated values
*
* @param old the old toWatch sequence
* @param body the body of the comet response
*
* @return the updated sequences
*/
def toWatchUpdates(old: Seq[(String, String)], body: String): Seq[(String, String)] = {
val p = Pattern.compile("""lift_toWatch\[\'([^\']*)\'] \= \'([0-9]*)""")
val re = new REMatcher(body, p)
val np = re.eachFound.foldLeft(Map(old: _*))((a, b) => a + ((b(1), b(2))))
np.iterator.toList
}
def getCookie(headers: List[(String, String)],
respHeaders: Map[String, List[String]]): Box[String] = {
val ret = (headers.filter {case ("Cookie", _) => true; case _ => false}.
map(_._2) :::
respHeaders.get("Set-Cookie").toList.flatMap(x => x)) match {
case Nil => Empty
case "" :: Nil => Empty
case "" :: xs => Full(xs.mkString(","))
case xs => Full(xs.mkString(","))
}
ret
}
type CRK = JavaList[String]
implicit def jitToIt[T](in: JavaIterator[T]): Iterator[T] = new Iterator[T] {
def next: T = in.next
def hasNext = in.hasNext
}
private def snurpHeaders(in: JavaMap[String, CRK]): Map[String, List[String]] = {
def morePulling(e: JavaMap.Entry[String, CRK]): (String, List[String]) = {
e.getValue match {
case null => (e.getKey, Nil)
case a => (e.getKey, a.iterator.toList)
}
}
Map(in.entrySet.iterator.toList.filter(e => (e ne null) && (e.getKey != null)).map(e => morePulling(e)): _*)
}
}
/**
* A response returned from an HTTP request. Responses can be chained and tested in a for comprehension:
*
*
* implicit val
*
* for {
* login <- post("/api/login", "user" -> "me", "pwd" -> "me") !@ "Failed to log in"
* info <- login.get("/api/info") if info.bodyAsString must_== "My Info"
* moreInfo <- info.post("/api/moreInfo", <info>Some Info</info>)
* } moreInfoheaders("X-MyInfo") must_== List("hello", "goodbye")
*
*/
trait Response {
type SelfType
type FuncType
/**
* The XML for the body
*/
def xml: Box[Elem]
/**
* The response headers
*/
def headers: Map[String, List[String]]
/**
* Test the response as a 200. If the response is not a 200, call the errorFunc with the msg
*
* @param msg the String to report as an error
* @param errorFunc the error reporting thing.
*/
def !@(msg: => String)(implicit errorFunc: ReportFailure): SelfType
/**
* Test that the server gave a response. If the server failed to respond, call the errorFunc with the msg
*
* @param msg the String to report as an error
* @param errorFunc the error reporting thing.
*/
def !(msg: => String)(implicit errorFunc: ReportFailure): SelfType
/**
* Test that the server gave a particular response code. If the response is not a 200, call the errorFunc with the msg
*
* @param msg the String to report as an error
* @param errorFunc the error reporting thing.
*/
def !(code: Int, msg: => String)(implicit errorFunc: ReportFailure): SelfType
/**
* Test that the server response contains a particular node anywhere in the xml
* with the exact attributes and children.
* If the response does not contain valid xml or does not contain the exact node,
* call the errorFunc with the msg.
*
* @param node the XML node to search for in the response
* @param msg the String to report as an error
* @param errorFunc the error reporting thing.
*/
def \\(node: Node, msg: => String)(implicit errorFunc: ReportFailure): SelfType
/**
* Test that the server response contains a node with a particular label anywhere in the xml.
* If the response does not contain valid xml or does not contain the node,
* call the errorFunc with the msg
*
* @param label the label for the XML node to search for in the response
* @param msg the String to report as an error
* @param errorFunc the error reporting thing.
*/
def \\(label: String, msg: => String)(implicit errorFunc: ReportFailure): SelfType
/**
* Test that the server response does not contain a particular node anywhere in the xml
* with the exact attributes and children.
* If the response does contain valid xml and does contain the exact node,
* call the errorFunc with the msg.
*
* @param node the XML node to search for in the response
* @param msg the String to report as an error
* @param errorFunc the error reporting thing.
*/
def !\\(node: Node, msg: => String)(implicit errorFunc: ReportFailure): SelfType
/**
* Test that the server response does not contain a node with a particular label anywhere in the xml.
* If the response does contain valid xml and does contain the node,
* call the errorFunc with the msg
*
* @param label the label for the XML node to search for in the response
* @param msg the String to report as an error
* @param errorFunc the error reporting thing.
*/
def !\\(label: String, msg: => String)(implicit errorFunc: ReportFailure): SelfType
/**
* Test that the server response contains a particular node as a direct child
* with the exact attributes and children.
* If the response does not contain valid xml or does not contain the exact node,
* call the errorFunc with the msg.
*
* @param node the XML node to search for in the response
* @param msg the String to report as an error
* @param errorFunc the error reporting thing.
*/
def \(node: Node, msg: => String)(implicit errorFunc: ReportFailure): SelfType
/**
* Test that the server response contains a node with a particular label as a direct child.
* If the response does not contain valid xml or does not contain the node,
* call the errorFunc with the msg
*
* @param label the label for the XML node to search for in the response
* @param msg the String to report as an error
* @param errorFunc the error reporting thing.
*/
def \(label: String, msg: => String)(implicit errorFunc: ReportFailure): SelfType
/**
* Test that the server response does not contain a particular node as a direct child
* with the exact attributes and children.
* If the response does contain valid xml and does contain the exact node,
* call the errorFunc with the msg.
*
* @param node the XML node to search for in the response
* @param msg the String to report as an error
* @param errorFunc the error reporting thing.
*/
def !\(node: Node, msg: => String)(implicit errorFunc: ReportFailure): SelfType
/**
* Test that the server response does not contain a node with a particular label as a direct child.
* If the response does contain valid xml and does contain the node,
* call the errorFunc with the msg
*
* @param label the label for the XML node to search for in the response
* @param msg the String to report as an error
* @param errorFunc the error reporting thing.
*/
def !\(label: String, msg: => String)(implicit errorFunc: ReportFailure): SelfType
/**
* the Response has a foreach method for chaining in a for comprehension
*/
def foreach(f: FuncType => Unit): Unit
/**
* the Response has a filter method for chaining in a for comprehension. Note that the filter method does *NOT* have
* to return a Boolean, any expression (e.g., an assertion)
*/
def filter(f: FuncType => Unit): FuncType
}
/**
* The response to an HTTP request, as long as the server responds with *SOMETHING*
*
*/
class HttpResponse(baseUrl: String,
code: Int, msg: String,
headers: Map[String, List[String]],
body: Box[Array[Byte]],
theHttpClient: HttpClient) extends
BaseResponse(baseUrl, code, msg, headers, body, theHttpClient) with
ToResponse with TestResponse {
}
/**
* The response to an HTTP request, as long as the server responds with *SOMETHING*
*
*/
class TheResponse(baseUrl: String,
code: Int, msg: String,
headers: Map[String, List[String]],
body: Box[Array[Byte]],
theHttpClient: HttpClient) extends
BaseResponse(baseUrl, code, msg, headers, body, theHttpClient) with
ToBoxTheResponse {
type SelfType = TheResponse
}
trait TestResponse extends Response {
override type SelfType = HttpResponse
override type FuncType = HttpResponse
}
/**
* The response to an HTTP request, as long as the server responds with *SOMETHING*
*
*/
abstract class BaseResponse(override val baseUrl: String,
val code: Int, val msg: String,
override val headers: Map[String, List[String]],
val body: Box[Array[Byte]],
val theHttpClient: HttpClient) extends
Response with BaseGetPoster with GetPosterHelper
{
private object FindElem {
def unapply(in: NodeSeq): Option[Elem] = in match {
case e: Elem => Some(e)
case d: Document => unapply(d.docElem)
case g: Group => unapply(g.nodes)
case n: Text => None
case sn: SpecialNode => None
case n: NodeSeq =>
val ns: Seq[Node] = n
val x: Seq[Elem] = ns.flatMap(v => unapply(v))
x.headOption
case _ => None
}
}
/**
* Get the body of the response as XML
*/
override lazy val xml: Box[Elem] =
for {
b <- body
nodeSeq <- PCDataXmlParser(new java.io.ByteArrayInputStream(b))
xml <- nodeSeq.toList match {
case (x: Elem) :: _ => Full(x)
case _ => Empty
}
} yield xml
lazy val html5AsXml: Box[Elem] =
for {
b <- body
nodeSeq <- Html5.parse(new java.io.ByteArrayInputStream(b))
xml <- nodeSeq.toList match {
case (x: Elem) :: _ => Full(x)
case _ => Empty
}
} yield xml
/**
* The content type header of the response
*/
lazy val contentType: String = headers.filter {case (name, value) => name equalsIgnoreCase "content-type"}.toList.headOption.map(_._2.head) getOrElse ""
/**
* The response body as a UTF-8 encoded String
*/
lazy val bodyAsString =
for {
b <- body
} yield new String(b, "UTF-8")
def !@(msg: => String)(implicit errorFunc: ReportFailure): SelfType =
if (code == 200) this.asInstanceOf[SelfType] else {errorFunc.fail(msg)}
def !(msg: => String)(implicit errorFunc: ReportFailure): SelfType =
this.asInstanceOf[SelfType]
def !(code: Int, msg: => String)(implicit errorFunc: ReportFailure): SelfType =
if (this.code != code) errorFunc.fail(msg) else this.asInstanceOf[SelfType]
def xmlMatch(findFunc: Elem => NodeSeq, filterFunc: Node => Boolean): Boolean =
xml.toList flatMap (theXml => findFunc(theXml)) exists ( n => filterFunc(trim(n)))
def getOrFail(success: Boolean, msg: String, errorFunc: ReportFailure) =
if (success)
this.asInstanceOf[SelfType]
else
errorFunc.fail(msg)
def \\(node: Node, msg: => String)(implicit errorFunc: ReportFailure): SelfType =
getOrFail(xmlMatch(_ \\ node.label, _ == trim(node)), msg, errorFunc)
def \\(label: String, msg: => String)(implicit errorFunc: ReportFailure): SelfType =
getOrFail(xmlMatch(_ \\ label, _ => true), msg, errorFunc)
def !\\(node: Node, msg: => String)(implicit errorFunc: ReportFailure): SelfType =
getOrFail(!xmlMatch(_ \\ node.label, _ == trim(node)), msg, errorFunc)
def !\\(label: String, msg: => String)(implicit errorFunc: ReportFailure): SelfType =
getOrFail(!xmlMatch(_ \\ label, _ => true), msg, errorFunc)
def \(node: Node, msg: => String)(implicit errorFunc: ReportFailure): SelfType =
getOrFail(xmlMatch(_ \ node.label, _ == trim(node)), msg, errorFunc)
def \(label: String, msg: => String)(implicit errorFunc: ReportFailure): SelfType =
getOrFail(xmlMatch(_ \ label, _ => true), msg, errorFunc)
def !\(node: Node, msg: => String)(implicit errorFunc: ReportFailure): SelfType =
getOrFail(!xmlMatch(_ \ node.label, _ == trim(node)), msg, errorFunc)
def !\(label: String, msg: => String)(implicit errorFunc: ReportFailure): SelfType =
getOrFail(!xmlMatch(_ \ label, _ => true), msg, errorFunc)
def foreach(f: FuncType => Unit): Unit = f(this.asInstanceOf[FuncType])
def filter(f: FuncType => Unit): FuncType = {
val st = this.asInstanceOf[FuncType]
f(st)
st
}
def withFilter(f: FuncType => Unit): FuncType = this.filter(f)
}
class CompleteFailure(val serverName: String, val exception: Box[Throwable]) extends TestResponse {
override def toString = serverName + (exception.map(e => " Exception: " + e.getMessage) openOr "")
def headers: Map[String, List[String]] = throw (exception openOr new java.io.IOException("HTTP Failure"))
def xml: Box[Elem] = throw (exception openOr new java.io.IOException("HTTP Failure"))
def !@(msg: => String)(implicit errorFunc: ReportFailure): SelfType = errorFunc.fail(msg)
def !(msg: => String)(implicit errorFunc: ReportFailure): SelfType = errorFunc.fail(msg)
def !(code: Int, msg: => String)(implicit errorFunc: ReportFailure): SelfType = errorFunc.fail(msg)
def \\(node: Node, msg: => String)(implicit errorFunc: ReportFailure): SelfType = errorFunc.fail(msg)
def \\(label: String, msg: => String)(implicit errorFunc: ReportFailure): SelfType = errorFunc.fail(msg)
def !\\(node: Node, msg: => String)(implicit errorFunc: ReportFailure): SelfType = errorFunc.fail(msg)
def !\\(label: String, msg: => String)(implicit errorFunc: ReportFailure): SelfType = errorFunc.fail(msg)
def \(node: Node, msg: => String)(implicit errorFunc: ReportFailure): SelfType = errorFunc.fail(msg)
def \(label: String, msg: => String)(implicit errorFunc: ReportFailure): SelfType = errorFunc.fail(msg)
def !\(node: Node, msg: => String)(implicit errorFunc: ReportFailure): SelfType = errorFunc.fail(msg)
def !\(label: String, msg: => String)(implicit errorFunc: ReportFailure): SelfType = errorFunc.fail(msg)
def foreach(f: HttpResponse => Unit): Unit = throw (exception openOr new java.io.IOException("HTTP Failure"))
def filter(f: HttpResponse => Unit): HttpResponse = throw (exception openOr new java.io.IOException("HTTP Failure"))
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy