Skip to content
This repository has been archived by the owner on Feb 19, 2021. It is now read-only.

Commit

Permalink
upgrade to play25 (#57)
Browse files Browse the repository at this point in the history
* upgrade to play25

* upgrade example

* use context in tests
  • Loading branch information
joprice authored and kailuowang committed Aug 1, 2016
1 parent 24f2d1b commit 67b6159
Show file tree
Hide file tree
Showing 17 changed files with 103 additions and 67 deletions.
1 change: 1 addition & 0 deletions build.sbt
Expand Up @@ -60,6 +60,7 @@ val noPublishing = Seq(publish := (), publishLocal := (), publishArtifact := fal
val commonSettings = Seq(
scalaVersion := "2.11.8",
scalacOptions ++= Seq(
"-feature",
"-deprecation",
"-unchecked",
"-Xlint"
Expand Down
Expand Up @@ -54,7 +54,19 @@ case class Endpoint(

def shutdown(): Unit = if (handlerRef != handlerActor) handlerRef ! PoisonPill

def unapply(request: Request[AnyContent]): Option[RouteParams] = routeExtractors.unapply(request)
def unapply(request: Request[AnyContent]): Option[RouteParams] = {
// queryString's parser parses an empty string as Map("" -> Seq()), so we replace query strings made up of all empty values
// with an empty map
// https://github.com/playframework/playframework/blob/master/framework/src/play/src/main/scala/play/core/parsers/FormUrlEncodedParser.scala#L23
routeExtractors.unapply(request).map { params
if (params.queryString.forall {
case (key, values)
key.trim.isEmpty && values.forall(_.trim.isEmpty)
}) {
params.copy(queryString = Map.empty)
} else params
}
}

//todo: think of a way to get rid of the ask below, e.g. create an new one-time actor for handling (just like ask),
// or have distributed request have the reply to Address and then send it to handlerRef as the implicit sender.
Expand All @@ -70,8 +82,8 @@ case class Endpoint(
}
val message = extractor.run((routeParams, request))
message.fold[Future[Result]](
Future.successful(_),
(t: T) handleMessageWithBackend(t)
Future.successful,
handleMessageWithBackend
).flatMap(identity)
}

Expand All @@ -82,7 +94,7 @@ case class Endpoint(
routing.Route(routeInfo.verb.value, routing.PathPattern(toCPart(StaticPart(prefix.value) +: localParts)))
}

implicit private def toCPart(parts: Seq[PathPart]): Seq[routing.PathPart] = parts map {
private def toCPart(parts: Seq[PathPart]): Seq[routing.PathPart] = parts map {
case DynamicPart(n, c, e) routing.DynamicPart(n, c, e)
case StaticPart(v) routing.StaticPart(v)
}
Expand Down
28 changes: 16 additions & 12 deletions distributed/src/main/scala/asobu/distributed/service/Action.scala
@@ -1,16 +1,16 @@
package asobu.distributed.service

import akka.actor._
import akka.cluster.Cluster
import Action.{DistributedResult, DistributedRequest, UnrecognizedMessage}
import Action.{DistributedRequest, DistributedResult, UnrecognizedMessage}
import akka.stream.Materializer
import akka.util.ByteString
import asobu.distributed.gateway.Endpoint.Prefix
import asobu.distributed.{Headers, EndpointDefImpl, EndpointDefinition}
import asobu.dsl.Extractor
import play.api.libs.iteratee.{Enumerator, Iteratee}
import play.api.mvc.{ResponseHeader, Result, AnyContent}
import asobu.distributed.{EndpointDefImpl, EndpointDefinition, Headers}
import play.api.http.HttpEntity
import play.api.mvc.{AnyContent, ResponseHeader, Result}
import play.routes.compiler.Route

import scala.concurrent.Future
import scala.reflect.internal.util.NoPosition
import scala.util.parsing.input.Positional

trait Action {
Expand Down Expand Up @@ -73,18 +73,22 @@ object Action {
body: Array[Byte] = Array.empty
) {
def toResult =
Result(new ResponseHeader(status.code, headers.toMap), Enumerator(body))
Result(new ResponseHeader(status.code, headers.toMap), HttpEntity.Strict(ByteString(body), None))
}

object DistributedResult {

implicit def from(r: Result): Future[DistributedResult] = {
def from(result: Result)(implicit mat: Materializer): Future[DistributedResult] = {
import scala.concurrent.ExecutionContext.Implicits.global
(r.body run Iteratee.getChunks) map { chunks
val body = chunks.toArray.flatten
DistributedResult(HttpStatus(r.header.status), r.header.headers.toSeq, body)
result.body.consumeData.map { data
DistributedResult(
HttpStatus(result.header.status),
result.header.headers.toSeq,
data.toArray[Byte]
)
}
}

}

}
@@ -1,21 +1,22 @@
package asobu.distributed.service

import akka.actor.{ActorSystem, ActorRef}
import akka.actor.{ActorRef, ActorSystem}
import akka.util.Timeout
import asobu.distributed.gateway.Endpoint.Prefix
import asobu.distributed.service.Action.{DistributedRequest, DistributedResult}
import asobu.distributed.{Headers, RequestExtractorDefinition, EndpointDefinition}
import asobu.dsl.{ExtractorFunctions, ExtractResult, Extractor}

import play.api.libs.json.{Reads, Json, Writes}
import play.api.mvc.{Results, Result}
import asobu.distributed.{EndpointDefinition, Headers, RequestExtractorDefinition}
import asobu.dsl.{ExtractResult, Extractor, ExtractorFunctions}
import play.api.libs.json.{Json, Reads, Writes}
import play.api.mvc.{Result, Results}
import play.api.mvc.Results._
import shapeless.LabelledGeneric

import scala.concurrent.{ExecutionContext, Future}
import scala.reflect._
import akka.pattern.ask
import akka.stream.Materializer
import asobu.dsl.CatsInstances._

import scala.concurrent.ExecutionContext.Implicits.global

trait Syntax extends ExtractorFunctions {
Expand Down Expand Up @@ -76,10 +77,10 @@ trait Syntax extends ExtractorFunctions {
def >>[C](extractor: Extractor[B, C]): Extractor[A, C] = self.andThen(extractor)
}

implicit def toBackend[T](extractor: Extractor[T, Result]): (Headers, T) Future[DistributedResult] =
implicit def toBackend[T](extractor: Extractor[T, Result])(implicit mat: Materializer): (Headers, T) Future[DistributedResult] =
extractor.compose((p: (Headers, T)) ExtractResult.pure(p._2))

implicit def toBackendWHeaders[T](extractor: Extractor[(Headers, T), Result]): (Headers, T) Future[DistributedResult] =
implicit def toBackendWHeaders[T](extractor: Extractor[(Headers, T), Result])(implicit mat: Materializer): (Headers, T) Future[DistributedResult] =
(headers: Headers, t: T) extractor.
run((headers, t)).fold(identity, identity).flatMap(DistributedResult.from(_))

Expand Down
Expand Up @@ -2,6 +2,7 @@ package asobu.distributed

import asobu.distributed.CustomRequestExtractorDefinition.Interpreter
import akka.actor.{ActorRef, ActorRefFactory, ActorSystem}
import akka.stream.ActorMaterializer
import akka.util.Timeout
import asobu.distributed.gateway.Endpoint.Prefix
import asobu.distributed.gateway.{DefaultHandlerBridgeProps, EndpointsRouter, Gateway, GatewayRouter}
Expand Down Expand Up @@ -102,7 +103,7 @@ object End2EndSpec {
}

//The routes file is in resources/TestController.routes
case class TestController(serviceBackend: ActorRef) extends DistributedController {
case class TestController(serviceBackend: ActorRef)(implicit mat: ActorMaterializer) extends DistributedController {
import Domain._
implicit val catFormat = Json.format[Cat]
implicit val dogFormat = Json.format[Dog]
Expand Down Expand Up @@ -132,6 +133,7 @@ object End2EndSpec {
}

case class App()(implicit system: ActorSystem) {
implicit val mat = ActorMaterializer()
val started = init(Prefix("/api"))(
TestController(testServiceBackendRef(system))
)
Expand Down
@@ -1,24 +1,26 @@
package asobu.distributed.service

import akka.actor.{Props, Actor}
import akka.actor.{Actor, Props}
import akka.actor.Actor.Receive
import akka.stream.ActorMaterializer
import akka.util.Timeout
import asobu.distributed.gateway.Endpoint.Prefix
import asobu.distributed.service.Action.DistributedRequest
import asobu.distributed.service.ActionExtractorSpec._
import asobu.distributed.{util, PredefinedDefs, EndpointDefinition}
import asobu.distributed.util.{MockRoute, ScopeWithActor, SpecWithActorCluster, SerializableTest}
import asobu.distributed.{EndpointDefinition, PredefinedDefs, util}
import asobu.distributed.util.{MockRoute, ScopeWithActor, SerializableTest, SpecWithActorCluster}
import asobu.dsl.ExtractResult
import asobu.dsl.extractors.JsonBodyExtractor
import org.specs2.concurrent.ExecutionEnv
import org.specs2.mutable.Specification
import org.specs2.specification.mutable.ExecutionEnvironment
import play.api.libs.json.{JsString, JsNumber, Json}
import play.api.libs.json.{JsNumber, JsString, Json}
import play.api.mvc.Results.Ok
import play.core.routing.RouteParams
import play.routes.compiler.{HandlerCall, PathPattern, HttpVerb, Route}
import play.routes.compiler.{HandlerCall, HttpVerb, PathPattern, Route}
import shapeless._
import shapeless.record.Record

import concurrent.duration._
import scala.concurrent.Future
import play.api.test.FakeRequest
Expand All @@ -40,6 +42,7 @@ class SyntaxSpec extends SpecWithActorCluster with SerializableTest with Executi

implicit val ao: Timeout = 1.seconds
val testBE = system.actorOf(testBackend)
implicit val mat = ActorMaterializer()

def is(implicit ee: ExecutionEnv) = {
"can build endpoint extracting params only" >> new SyntaxScope {
Expand Down
@@ -1,12 +1,13 @@
package asobu.dsl

import asobu.dsl.Syntax._
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import play.api.mvc.Results._
import play.api.mvc.{EssentialAction, Request}
import play.api.test._
import shapeless.HNil
import shapeless.syntax.singleton._

import scala.concurrent.Future

object ControllerMethodBuilderSpec extends PlaySpecification {
Expand All @@ -15,7 +16,7 @@ object ControllerMethodBuilderSpec extends PlaySpecification {

"Builder " should {

"build from header extractor" in {
"build from header extractor" in new WithSystem {
val method = handle(
Extractor(req 'name ->> req.headers("name") :: HNil),
(rm: Request[ReqMessage]) Future.successful(Ok(rm.body.name + rm.body.id))
Expand All @@ -31,7 +32,7 @@ object ControllerMethodBuilderSpec extends PlaySpecification {

}

"build directly from director" in {
"build directly from director" in new WithSystem {
val method = handle((rm: Request[ReqMessage]) Future.successful(Ok(rm.body.name + rm.body.id)))

val req = FakeRequest()
Expand Down
34 changes: 14 additions & 20 deletions dsl/src/test/scala/asobu/dsl/SyntaxSpec.scala
@@ -1,24 +1,19 @@
package asobu.dsl

import asobu.dsl
import asobu.dsl._
import asobu.dsl.Syntax._
import asobu.dsl.SyntaxFacilitators._
import asobu.dsl.extractors.HeaderExtractors
import org.joda.time.DateTime
import org.specs2.concurrent.ExecutionEnv
import play.api.cache.CacheApi
import play.api.http.Status._
import org.specs2.specification.{After, Scope}
import play.api.libs.json.{JsValue, Json}
import play.api.mvc.Results._
import play.api.mvc._
import play.api.test.{FakeRequest, PlaySpecification}
import shapeless._
import shapeless.syntax.singleton._

import scala.concurrent.Future
import scala.concurrent.duration._
import scala.reflect.ClassTag

object SyntaxSpec {
case class RequestMsg(id: String, name: String, bar: Double)
Expand Down Expand Up @@ -52,7 +47,7 @@ object SyntaxSpec {

case class ProcessResult(content: Option[String])

class SyntaxSpec extends PlaySpecification {
class SyntaxSpec(implicit executionEnv: ExecutionEnv) extends PlaySpecification {
import SyntaxSpec._
import asobu.dsl.DefaultImplicits._
val defaultTimeout = 10.seconds
Expand All @@ -66,7 +61,7 @@ class SyntaxSpec extends PlaySpecification {

"end to end syntax" >> {

"with normal extraction" >> {
"with normal extraction" >> new WithSystem {

val controller = new Controller {
val withExtraction = handle(
Expand All @@ -84,10 +79,9 @@ class SyntaxSpec extends PlaySpecification {

val bodyText: String = contentAsString(result)
bodyText === "myId hello! mike"

}

"with body extraction" >> {
"with body extraction" >> new WithSystem {

val controller = new Controller {
val combined = handle(
Expand All @@ -106,7 +100,7 @@ class SyntaxSpec extends PlaySpecification {
(respBody \ "msg").as[String] === "hello! mike"
}

"with extraction combination" >> {
"with extraction combination" >> new WithSystem {
import asobu.dsl.DefaultExtractorImplicits._
import scala.concurrent.ExecutionContext.Implicits.global
val controller = new Controller {
Expand All @@ -126,7 +120,7 @@ class SyntaxSpec extends PlaySpecification {
(respBody \ "msg").as[String] === "hello! mike"
}

"without extraction" >> {
"without extraction" >> new WithSystem {
val controller = new Controller {
val withOutExtraction = handle(
process[RequestMsg] using actor next expect[ResponseMsg].respondJson(Ok(_))
Expand All @@ -145,7 +139,8 @@ class SyntaxSpec extends PlaySpecification {
}

case class SomeOtherMessage(boo: String)
"failure when unexpected Message" >> { implicit ev: ExecutionEnv

"failure when unexpected Message" >> new WithSystem { //implicit ev: ExecutionEnv ⇒
val controller = new Controller {
val withOutExtraction = handle(
process[RequestMsg] using actor next expect[SomeOtherMessage].respond(Ok)
Expand All @@ -164,7 +159,7 @@ class SyntaxSpec extends PlaySpecification {

}

"without any fields" >> {
"without any fields" >> new WithSystem {
val controller = new Controller {
val withOutFields = handle(
process[SpecialRequest.type] using actor next expect[ResponseMsg].respondJson(Ok(_))
Expand All @@ -182,7 +177,7 @@ class SyntaxSpec extends PlaySpecification {

}

"with filter " >> { implicit ev: ExecutionEnv
"with filter " >> new WithSystem {

val withFilter = handle(
process[RequestMsg] using actor next expect[ResponseMsg].respond(Ok) `with` authenticated
Expand Down Expand Up @@ -211,8 +206,7 @@ class SyntaxSpec extends PlaySpecification {
}
)

"with AuthExtractor" >> { implicit ev: ExecutionEnv

"with AuthExtractor" >> new WithSystem {
val handler = handle(
fromAuthorized(GetSessionInfo).from(id = (_: SessionInfo).sessionId),
process[RequestMsg] using actor next expect[ResponseMsg].respondJson(Ok)
Expand Down Expand Up @@ -241,19 +235,19 @@ class SyntaxSpec extends PlaySpecification {

val dir: Directive[ProcessResult] = expect[ProcessResult].respondJson(Ok(_)).ifEmpty(_.content).respond(NotFound)

"returns original result when field is filled" >> { implicit ev: ExecutionEnv
"returns original result when field is filled" >> { //implicit ev: ExecutionEnv ⇒
val result = dir(FakeRequest().withBody(ProcessResult(Some("content"))))
result.map(_.header.status) must be_==(OK).awaitFor(defaultTimeout)
}

"returns alternative result when field is empty" >> { implicit ev: ExecutionEnv
"returns alternative result when field is empty" >> { //implicit ev: ExecutionEnv ⇒
val result = dir(FakeRequest().withBody(ProcessResult(None)))
result.map(_.header.status) must be_==(NOT_FOUND).awaitFor(defaultTimeout)
}

}

"with filter" >> { implicit ev: ExecutionEnv
"with filter" >> new WithSystem {
import Filters._

val endpoint = handle(
Expand Down
13 changes: 13 additions & 0 deletions dsl/src/test/scala/asobu/dsl/WithSystem.scala
@@ -0,0 +1,13 @@
package asobu.dsl

import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import scala.concurrent.Await
import org.specs2.specification.{After, Scope}
import scala.concurrent.duration.Duration

trait WithSystem extends Scope with After {
implicit val system = ActorSystem()
implicit val mat = ActorMaterializer()
def after = Await.result(system.terminate(), Duration.Inf)
}
4 changes: 2 additions & 2 deletions example/api/buildinfo.properties
@@ -1,2 +1,2 @@
#Fri Jul 29 16:25:35 EDT 2016
buildnumber=185
#Mon Aug 01 08:15:24 EDT 2016
buildnumber=199
4 changes: 2 additions & 2 deletions example/backend/buildinfo.properties
@@ -1,2 +1,2 @@
#Fri Jul 29 16:25:35 EDT 2016
buildnumber=70
#Mon Aug 01 08:15:24 EDT 2016
buildnumber=84

0 comments on commit 67b6159

Please sign in to comment.