=ht* #17279 rename akka-http-* modules where agreed

This commit is contained in:
Mathias 2015-04-24 11:49:53 +02:00
parent 20530be054
commit 5859c39f8b
140 changed files with 330 additions and 11018 deletions

View file

@ -1,29 +0,0 @@
/*
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.http.testkit
import scala.concurrent.duration._
import scala.concurrent.{ ExecutionContext, Await }
import akka.http.unmarshalling.{ Unmarshal, FromEntityUnmarshaller }
import akka.http.marshalling._
import akka.http.model.HttpEntity
import akka.stream.FlowMaterializer
import scala.util.Try
trait MarshallingTestUtils {
def marshal[T: ToEntityMarshaller](value: T)(implicit ec: ExecutionContext, mat: FlowMaterializer): HttpEntity.Strict =
Await.result(Marshal(value).to[HttpEntity].flatMap(_.toStrict(1.second)), 1.second)
def unmarshalValue[T: FromEntityUnmarshaller](entity: HttpEntity)(implicit ec: ExecutionContext, mat: FlowMaterializer): T =
unmarshal(entity).get
def unmarshal[T: FromEntityUnmarshaller](entity: HttpEntity)(implicit ec: ExecutionContext, mat: FlowMaterializer): Try[T] = {
val fut = Unmarshal(entity).to[T]
Await.ready(fut, 1.second)
fut.value.get
}
}

View file

@ -1,140 +0,0 @@
/*
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.http.testkit
import com.typesafe.config.{ ConfigFactory, Config }
import scala.collection.immutable
import scala.concurrent.{ Await, Future }
import scala.concurrent.duration._
import scala.util.DynamicVariable
import scala.reflect.ClassTag
import akka.actor.ActorSystem
import akka.stream.ActorFlowMaterializer
import akka.http.client.RequestBuilding
import akka.http.util.FastFuture
import akka.http.server._
import akka.http.unmarshalling._
import akka.http.model._
import headers.Host
import FastFuture._
trait RouteTest extends RequestBuilding with RouteTestResultComponent with MarshallingTestUtils {
this: TestFrameworkInterface
/** Override to supply a custom ActorSystem */
protected def createActorSystem(): ActorSystem =
ActorSystem(actorSystemNameFrom(getClass), testConfig)
def actorSystemNameFrom(clazz: Class[_]) =
clazz.getName
.replace('.', '-')
.replace('_', '-')
.filter(_ != '$')
def testConfigSource: String = ""
def testConfig: Config = {
val source = testConfigSource
val config = if (source.isEmpty) ConfigFactory.empty() else ConfigFactory.parseString(source)
config.withFallback(ConfigFactory.load())
}
implicit val system = createActorSystem()
implicit def executor = system.dispatcher
implicit val materializer = ActorFlowMaterializer()
def cleanUp(): Unit = system.shutdown()
private val dynRR = new DynamicVariable[RouteTestResult](null)
private def result =
if (dynRR.value ne null) dynRR.value
else sys.error("This value is only available inside of a `check` construct!")
def check[T](body: T): RouteTestResult T = result dynRR.withValue(result.awaitResult)(body)
def handled: Boolean = result.handled
def response: HttpResponse = result.response
def responseEntity: HttpEntity = result.entity
def chunks: immutable.Seq[HttpEntity.ChunkStreamPart] = result.chunks
def entityAs[T: FromEntityUnmarshaller: ClassTag](implicit timeout: Duration = 1.second): T = {
def msg(e: Throwable) = s"Could not unmarshal entity to type '${implicitly[ClassTag[T]]}' for `entityAs` assertion: $e\n\nResponse was: $response"
Await.result(Unmarshal(responseEntity).to[T].fast.recover[T] { case error failTest(msg(error)) }, timeout)
}
def responseAs[T: FromResponseUnmarshaller: ClassTag](implicit timeout: Duration = 1.second): T = {
def msg(e: Throwable) = s"Could not unmarshal response to type '${implicitly[ClassTag[T]]}' for `responseAs` assertion: $e\n\nResponse was: $response"
Await.result(Unmarshal(response).to[T].fast.recover[T] { case error failTest(msg(error)) }, timeout)
}
def contentType: ContentType = responseEntity.contentType
def mediaType: MediaType = contentType.mediaType
def charset: HttpCharset = contentType.charset
def definedCharset: Option[HttpCharset] = contentType.definedCharset
def headers: immutable.Seq[HttpHeader] = response.headers
def header[T <: HttpHeader: ClassTag]: Option[T] = response.header[T]
def header(name: String): Option[HttpHeader] = response.headers.find(_.is(name.toLowerCase))
def status: StatusCode = response.status
def closingExtension: String = chunks.lastOption match {
case Some(HttpEntity.LastChunk(extension, _)) extension
case _ ""
}
def trailer: immutable.Seq[HttpHeader] = chunks.lastOption match {
case Some(HttpEntity.LastChunk(_, trailer)) trailer
case _ Nil
}
def rejections: immutable.Seq[Rejection] = result.rejections
def rejection: Rejection = {
val r = rejections
if (r.size == 1) r.head else failTest("Expected a single rejection but got %s (%s)".format(r.size, r))
}
/**
* A dummy that can be used as `~> runRoute` to run the route but without blocking for the result.
* The result of the pipeline is the result that can later be checked with `check`. See the
* "separate running route from checking" example from ScalatestRouteTestSpec.scala.
*/
def runRoute: RouteTestResult RouteTestResult = akka.http.util.identityFunc
// there is already an implicit class WithTransformation in scope (inherited from akka.http.testkit.TransformerPipelineSupport)
// however, this one takes precedence
implicit class WithTransformation2(request: HttpRequest) {
def ~>[A, B](f: A B)(implicit ta: TildeArrow[A, B]): ta.Out = ta(request, f)
}
abstract class TildeArrow[A, B] {
type Out
def apply(request: HttpRequest, f: A B): Out
}
case class DefaultHostInfo(host: Host, securedConnection: Boolean)
object DefaultHostInfo {
implicit def defaultHost: DefaultHostInfo = DefaultHostInfo(Host("example.com"), securedConnection = false)
}
object TildeArrow {
implicit object InjectIntoRequestTransformer extends TildeArrow[HttpRequest, HttpRequest] {
type Out = HttpRequest
def apply(request: HttpRequest, f: HttpRequest HttpRequest) = f(request)
}
implicit def injectIntoRoute(implicit timeout: RouteTestTimeout, setup: RoutingSetup,
defaultHostInfo: DefaultHostInfo) =
new TildeArrow[RequestContext, Future[RouteResult]] {
type Out = RouteTestResult
def apply(request: HttpRequest, route: Route): Out = {
val routeTestResult = new RouteTestResult(timeout.duration)
val effectiveRequest =
request.withEffectiveUri(
securedConnection = defaultHostInfo.securedConnection,
defaultHostHeader = defaultHostInfo.host)
val ctx = new RequestContextImpl(effectiveRequest, setup.routingLog.requestLog(effectiveRequest), setup.settings)
val sealedExceptionHandler = setup.exceptionHandler.seal(setup.settings)(setup.executionContext)
val semiSealedRoute = // sealed for exceptions but not for rejections
Directives.handleExceptions(sealedExceptionHandler) { route }
val deferrableRouteResult = semiSealedRoute(ctx)
deferrableRouteResult.fast.foreach(routeTestResult.handleResult)(setup.executor)
routeTestResult
}
}
}
}
//FIXME: trait Specs2RouteTest extends RouteTest with Specs2Interface

View file

@ -1,101 +0,0 @@
/*
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.http.testkit
import java.util.concurrent.CountDownLatch
import scala.collection.immutable
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext
import akka.http.util._
import akka.stream.FlowMaterializer
import akka.stream.scaladsl._
import akka.http.model.HttpEntity.ChunkStreamPart
import akka.http.server._
import akka.http.model._
trait RouteTestResultComponent {
def failTest(msg: String): Nothing
/**
* A receptacle for the response or rejections created by a route.
*/
class RouteTestResult(timeout: FiniteDuration)(implicit fm: FlowMaterializer) {
private[this] var result: Option[Either[immutable.Seq[Rejection], HttpResponse]] = None
private[this] val latch = new CountDownLatch(1)
def handled: Boolean = synchronized { result.isDefined && result.get.isRight }
def rejections: immutable.Seq[Rejection] = synchronized {
result match {
case Some(Left(rejections)) rejections
case Some(Right(response)) failTest("Request was not rejected, response was " + response)
case None failNeitherCompletedNorRejected()
}
}
def response: HttpResponse = rawResponse.copy(entity = entity)
/** Returns a "fresh" entity with a "fresh" unconsumed byte- or chunk stream (if not strict) */
def entity: ResponseEntity = entityRecreator()
def chunks: immutable.Seq[ChunkStreamPart] =
entity match {
case HttpEntity.Chunked(_, chunks) awaitAllElements[ChunkStreamPart](chunks)
case _ Nil
}
def ~>[T](f: RouteTestResult T): T = f(this)
private def rawResponse: HttpResponse = synchronized {
result match {
case Some(Right(response)) response
case Some(Left(Nil)) failTest("Request was rejected")
case Some(Left(rejection :: Nil)) failTest("Request was rejected with rejection " + rejection)
case Some(Left(rejections)) failTest("Request was rejected with rejections " + rejections)
case None failNeitherCompletedNorRejected()
}
}
private[testkit] def handleResult(rr: RouteResult)(implicit ec: ExecutionContext): Unit =
synchronized {
if (result.isEmpty) {
result = rr match {
case RouteResult.Complete(response) Some(Right(response))
case RouteResult.Rejected(rejections) Some(Left(RejectionHandler.applyTransformations(rejections)))
}
latch.countDown()
} else failTest("Route completed/rejected more than once")
}
private[testkit] def awaitResult: this.type = {
latch.await(timeout.toMillis, MILLISECONDS)
this
}
private[this] lazy val entityRecreator: () ResponseEntity =
rawResponse.entity match {
case s: HttpEntity.Strict () s
case HttpEntity.Default(contentType, contentLength, data)
val dataChunks = awaitAllElements(data);
{ () HttpEntity.Default(contentType, contentLength, Source(dataChunks)) }
case HttpEntity.CloseDelimited(contentType, data)
val dataChunks = awaitAllElements(data);
{ () HttpEntity.CloseDelimited(contentType, Source(dataChunks)) }
case HttpEntity.Chunked(contentType, chunks)
val dataChunks = awaitAllElements(chunks);
{ () HttpEntity.Chunked(contentType, Source(dataChunks)) }
}
private def failNeitherCompletedNorRejected(): Nothing =
failTest("Request was neither completed nor rejected within " + timeout)
private def awaitAllElements[T](data: Source[T, _]): immutable.Seq[T] =
data.grouped(100000).runWith(Sink.head).awaitResult(timeout)
}
}

View file

@ -1,15 +0,0 @@
/*
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.http.testkit
import scala.concurrent.duration._
import akka.actor.ActorSystem
import akka.testkit._
case class RouteTestTimeout(duration: FiniteDuration)
object RouteTestTimeout {
implicit def default(implicit system: ActorSystem) = RouteTestTimeout(1.second dilated)
}

View file

@ -1,31 +0,0 @@
/*
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.http.testkit
import scala.util.Try
import scala.concurrent.{ ExecutionContext, Future, Await }
import scala.concurrent.duration._
import org.scalatest.Suite
import org.scalatest.matchers.Matcher
import akka.http.model.HttpEntity
import akka.http.unmarshalling.FromEntityUnmarshaller
import akka.stream.FlowMaterializer
trait ScalatestUtils extends MarshallingTestUtils {
import org.scalatest.Matchers._
def evaluateTo[T](value: T): Matcher[Future[T]] =
equal(value).matcher[T] compose (x Await.result(x, 1.second))
def haveFailedWith(t: Throwable): Matcher[Future[_]] =
equal(t).matcher[Throwable] compose (x Await.result(x.failed, 1.second))
def unmarshalToValue[T: FromEntityUnmarshaller](value: T)(implicit ec: ExecutionContext, mat: FlowMaterializer): Matcher[HttpEntity] =
equal(value).matcher[T] compose (unmarshalValue(_))
def unmarshalTo[T: FromEntityUnmarshaller](value: Try[T])(implicit ec: ExecutionContext, mat: FlowMaterializer): Matcher[HttpEntity] =
equal(value).matcher[Try[T]] compose (unmarshal(_))
}
trait ScalatestRouteTest extends RouteTest with TestFrameworkInterface.Scalatest with ScalatestUtils { this: Suite }

View file

@ -1,30 +0,0 @@
/*
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.http.testkit
import org.scalatest.exceptions.TestFailedException
import org.scalatest.{ BeforeAndAfterAll, Suite }
trait TestFrameworkInterface {
def cleanUp()
def failTest(msg: String): Nothing
}
object TestFrameworkInterface {
trait Scalatest extends TestFrameworkInterface with BeforeAndAfterAll {
this: Suite
def failTest(msg: String) = throw new TestFailedException(msg, 11)
abstract override protected def afterAll(): Unit = {
cleanUp()
super.afterAll()
}
}
}