Skip to content

Commit

Permalink
reduce use of eithers in test creation to make easier to understand
Browse files Browse the repository at this point in the history
  • Loading branch information
caoilte committed Sep 14, 2015
1 parent 04fb629 commit e919aa3
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,15 @@ object LogAccessRoutingDemo extends App {
val exceptionRouteOrDemoArgs = demoArgs()
val (
requestTimeoutInMillis, responseDelayInMillis) = exceptionRouteOrDemoArgs.right.getOrElse(1000L, 1000L)
val exceptionRouteOrDelayedResponse:Either[Route,DelayedResponse] = exceptionRouteOrDemoArgs.right.map(_ => DelayedResponse(responseDelayInMillis, "hello"))

val serviceActorProps = {
exceptionRouteOrDemoArgs.fold( route => {
RouteServiceActor.apply(new DemoAccessLogger, route, "hello")
}, tupleArgs => {
DelayedResponseServiceActor.apply(new DemoAccessLogger, DelayedResponse(tupleArgs._2), "hello")
})
}

val config = ConfigFactory.parseString(
s"""
|spray.can {
Expand All @@ -85,9 +93,7 @@ object LogAccessRoutingDemo extends App {
implicit val system = ActorSystem("log-access-routing-demo", config)


val serviceActor = system.actorOf(Props(
new TestLogAccessRoutingActor(new DemoAccessLogger, exceptionRouteOrDelayedResponse, "hello"))
)
val serviceActor = system.actorOf(serviceActorProps)


val serverStartedFuture = IO(Http).ask(Http.Bind(serviceActor, "localhost", 8085)).flatMap {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.caoilte.spray.routing

import org.caoilte.spray.routing.TestAccessLogger.{AccessAlreadyLogged, LogAccess, LogEvent}
import org.scalatest.FlatSpec
import akka.testkit.TestKit
import com.typesafe.config.ConfigFactory
Expand Down Expand Up @@ -36,7 +37,7 @@ class LogAccessRoutingTests extends FlatSpec with ScalaFutures {
it should "'Log Access' with a 200 response and an Access Time less than the request timeout" in {
aTestLogAccessRoutingActor(
requestTimeoutMillis = 4000,
routeOrDelayedResponse = Right(DelayedResponse(500))) { testKit =>
httpServiceActorFactory = DelayedResponseServiceActor.factory(DelayedResponse(500), PATH)) { testKit =>
import testKit._

whenReady(makeHttpCall(), timeout(Span(2, Seconds))) { s =>
Expand All @@ -59,7 +60,7 @@ class LogAccessRoutingTests extends FlatSpec with ScalaFutures {
it should "'Log Access' with a 500 response and an Access Time less than the request timeout" in {
aTestLogAccessRoutingActor(
requestTimeoutMillis = 4000,
routeOrDelayedResponse = Left(FailureRoutes.exceptionRoute)) { testKit =>
httpServiceActorFactory = RouteServiceActor.factory(FailureRoutes.exceptionRoute, PATH)) { testKit =>
import testKit._


Expand All @@ -82,7 +83,7 @@ class LogAccessRoutingTests extends FlatSpec with ScalaFutures {
it should "'Log Access' with a 500 response and an Access Time less than the request timeout" in {
aTestLogAccessRoutingActor(
requestTimeoutMillis = 4000,
routeOrDelayedResponse = Left(FailureRoutes.failureRoute)) { testKit =>
httpServiceActorFactory = RouteServiceActor.factory(FailureRoutes.failureRoute, PATH)) { testKit =>
import testKit._


Expand All @@ -106,7 +107,7 @@ class LogAccessRoutingTests extends FlatSpec with ScalaFutures {
"and then 'Access already logged' with a 200 response and an Access Time more than the Request Timeout time" in {
aTestLogAccessRoutingActor(
requestTimeoutMillis = 50,
routeOrDelayedResponse = Right(DelayedResponse(500))) { testKit =>
httpServiceActorFactory = DelayedResponseServiceActor.factory(DelayedResponse(500), PATH)) { testKit =>
import testKit._

whenReady(makeHttpCall(), timeout(Span(2, Seconds))) { s =>
Expand Down Expand Up @@ -136,7 +137,7 @@ class LogAccessRoutingTests extends FlatSpec with ScalaFutures {
"appropriate error message" in {
aTestLogAccessRoutingActor(
requestTimeoutMillis = 10,
routeOrDelayedResponse = Right(DelayedResponse(2000))) { testKit =>
httpServiceActorFactory = DelayedResponseServiceActor.factory(DelayedResponse(2000), PATH)) { testKit =>
import testKit._


Expand Down Expand Up @@ -169,7 +170,7 @@ class LogAccessRoutingTests extends FlatSpec with ScalaFutures {
it should "'Log Access' for a request with an unacceptable Accept header by making a 406 response with an Access Time less than the request timeout" in {
aTestLogAccessRoutingActor(
requestTimeoutMillis = 4000,
routeOrDelayedResponse = Right(DelayedResponse(50))) { testKit =>
httpServiceActorFactory = DelayedResponseServiceActor.factory(DelayedResponse(50), PATH)) { testKit =>
import testKit._

whenReady(makeHttpCall(MediaTypes.`application/json`), timeout(Span(2, Seconds))) { s =>
Expand All @@ -196,22 +197,8 @@ class LogAccessRoutingTests extends FlatSpec with ScalaFutures {
val PATH = "test"
val URI:Uri = Uri(s"$HOST/$PATH")

sealed trait LogType
case object LogAccess extends LogType
case object AccessAlreadyLogged extends LogType


case class LogEvent(request: HttpRequest, response: HttpResponse, time: Long, logAccessType: LogType)

class TestAccessLogger(listener:ActorRef) extends AccessLogger {
override def logAccess(request: HttpRequest, response: HttpResponse, time: Long) = {
listener ! LogEvent(request, response, time, LogAccess)
}

override def accessAlreadyLogged(request: HttpRequest, response: HttpResponse, time: Long) = {
listener ! LogEvent(request, response, time, AccessAlreadyLogged)
}
}

// going to have to use 'request-timeout = infinite' - spray-can timeout handling is FUBAR
def CONFIG(requestTimeout:String = "1 s") =
Expand All @@ -234,18 +221,15 @@ class LogAccessRoutingTests extends FlatSpec with ScalaFutures {

def aTestLogAccessRoutingActor(
requestTimeoutMillis:Long,
routeOrDelayedResponse:Either[Route,DelayedResponse]
httpServiceActorFactory: TestKit => Props
)
(callback: TestKit => Unit) {
val config = ConfigFactory.parseString(CONFIG(s"$requestTimeoutMillis ms"))
implicit val system = ActorSystem("test-system", config)
val testKit = new TestKit(system)

try {
val accessLogger = new TestAccessLogger(testKit.testActor)
val serviceActor = system.actorOf(Props(
new TestLogAccessRoutingActor(accessLogger, routeOrDelayedResponse, PATH))
)
val serviceActor = system.actorOf(httpServiceActorFactory(testKit))

val sprayServerStartResult = IO(Http).ask(Http.Bind(serviceActor, "localhost", PORT)).flatMap {
case b: Http.Bound Future.successful(b)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,52 @@
package org.caoilte.spray.routing

import spray.http.{HttpEntity, ContentTypes}
import akka.testkit.TestKit
import org.caoilte.spray.routing.TestAccessLogger.TestAccessLogger
import spray.http.{HttpResponse, HttpRequest, HttpEntity, ContentTypes}
import spray.routing._
import akka.actor.{Props, ActorRef, Actor}
import scala.concurrent._
import akka.pattern.ask
import akka.util.Timeout
import java.util.concurrent.TimeUnit

object TestAccessLogger {
sealed trait LogType
case object LogAccess extends LogType
case object AccessAlreadyLogged extends LogType

case class LogEvent(request: HttpRequest, response: HttpResponse, time: Long, logAccessType: LogType)

class TestAccessLogger(listener:ActorRef) extends AccessLogger {
override def logAccess(request: HttpRequest, response: HttpResponse, time: Long) = {
listener ! LogEvent(request, response, time, LogAccess)
}

override def accessAlreadyLogged(request: HttpRequest, response: HttpResponse, time: Long) = {
listener ! LogEvent(request, response, time, AccessAlreadyLogged)
}
}
}


case object DelayedResponse {
val DEFAULT_RESPONSE = "response"
}

case class DelayedResponse(thinkingMillis: Long, responseMessage:String = DelayedResponse.DEFAULT_RESPONSE)

class TestLogAccessRoutingActor(val accessLogger: AccessLogger,
routeOrDelayedResponse:Either[Route,DelayedResponse], path:String)
object DelayedResponseServiceActor {
def factory(delayedResponse: DelayedResponse, path:String): (TestKit => Props) = testKit => {
apply(new TestAccessLogger(testKit.testActor), delayedResponse, path)
}
def apply(accessLogger: AccessLogger, delayedResponse: DelayedResponse, path:String):Props = {
Props(new DelayedResponseServiceActor(accessLogger, delayedResponse, path))
}
}

class DelayedResponseServiceActor(val accessLogger: AccessLogger, delayedResponse: DelayedResponse, path:String)
extends HttpServiceActor with LogAccessRoutingActor {

case object RequestForDelayedResponse


Expand All @@ -37,25 +67,42 @@ class TestLogAccessRoutingActor(val accessLogger: AccessLogger,
implicit def executionContext = actorRefFactory.dispatcher

override def preStart {
routeOrDelayedResponse.right.map( response => {
testAc = context.actorOf(Props(new DelayedResponseActor(response)), "delayed-response-test-actor")
})
testAc = context.actorOf(Props(new DelayedResponseActor(delayedResponse)), "delayed-response-test-actor")
super.preStart
}

val routes:Route = {
path(path) {
get {
routeOrDelayedResponse match {
case Left(route) => route
case Right(DelayedResponse(thinkingMillis, _)) => {
implicit val TIMEOUT: Timeout = Timeout(thinkingMillis * 2, TimeUnit.MILLISECONDS)
complete((testAc ? RequestForDelayedResponse).mapTo[HttpEntity])
}
}
implicit val TIMEOUT: Timeout = Timeout(delayedResponse.thinkingMillis * 2, TimeUnit.MILLISECONDS)
complete((testAc ? RequestForDelayedResponse).mapTo[HttpEntity])
}
}
}

override def receive = runRoute(routes)
}


object RouteServiceActor {
def factory(route: Route, path:String): (TestKit => Props) = testKit => {
apply(new TestAccessLogger(testKit.testActor), route, path)
}
def apply(accessLogger: AccessLogger, route: Route, path:String):Props = {
Props(new RouteServiceActor(accessLogger, route, path))
}
}

class RouteServiceActor(val accessLogger: AccessLogger, route: Route, path:String)
extends HttpServiceActor with LogAccessRoutingActor {

val routes:Route = {
path(path) {
get {
route
}
}
}

override def receive = runRoute(routes)
}

0 comments on commit e919aa3

Please sign in to comment.