I took the existing macwire example and extended the controller like so CoffeeController.scala
package com.softwaremill.play24.controllers
import com.softwaremill.play24.dao.CoffeeDao
import play.api.i18n.Lang
import play.api.libs.json.Json
import play.api.mvc._
import scala.concurrent.{Future}
import play.api.libs.concurrent.Execution.Implicits.defaultContext
import play.api.mvc.Results._
class CoffeeController(
coffeeDao: CoffeeDao
)(implicit ec: SomeContextBuilder) extends AnotherController {
def fetchAll() = DecoratedAction() { request =>
coffeeDao.all.map { coffees =>
Ok(Json.toJson(coffees))
}
}
def priced(price: Double) = ResolvedDecoratedAction() { request =>
coffeeDao.byPriceWithSuppliers(price).map { result =>
Ok(Json.toJson(result.toMap))
}
}
}
trait ContextBuilder[U <: TraitLike] {
def build(request: Request[AnyContent]): Future[Either[Result, RequestWithContext[U]]]
def buildAuthenticated(request: Request[AnyContent]): Future[Either[Result, RequestWithResolvedContext[U]]]
}
trait TraitLike {
def id: String
}
trait WithSessionId {
self: RequestHeader =>
lazy val sessionId = self.session.get("auth").getOrElse(java.util.UUID.randomUUID().toString)
}
case class RequestWithContext[U <: TraitLike](request: Request[AnyContent], lang: Lang, anything: Option[U]) extends WrappedRequest(request) with WithSessionId
case class RequestWithResolvedContext[U <: TraitLike](request: Request[AnyContent], lang: Lang, anything: U, rememberMe: Boolean = false) extends WrappedRequest(request) with WithSessionId
case class Trait(val id: String) extends TraitLike
class AnotherController[U <: TraitLike](implicit ctxBuilder: ContextBuilder[U]) extends Controller {
def DecoratedAction(bodyParser: BodyParser[AnyContent] = parse.anyContent)(f: RequestWithContext[U] => Future[Result]) = Action.async {
implicit request =>
ctxBuilder.build(request) flatMap {
case Left(r) =>
Future.successful(r)
case Right(requestContext) =>
f(requestContext).map(_.addingToSession( ("auth" , requestContext.sessionId) ))
}
}
def ResolvedDecoratedAction(bodyParser: BodyParser[AnyContent] = parse.anyContent)(f: RequestWithResolvedContext[U] => Future[Result]) = Action.async {
implicit request =>
ctxBuilder.buildAuthenticated(request) flatMap {
case Left(r) =>
Future.successful(r)
case Right(requestContext) =>
f(requestContext).map(_.addingToSession( ("auth", requestContext.sessionId) ))
}
}
}
class SomeContextBuilder extends ContextBuilder[TraitLike] {
override def build(request: Request[AnyContent]): Future[Either[Result, RequestWithContext[TraitLike]]] = Future.successful(Right(RequestWithContext(request, Lang("en-us"),None)))
override def buildAuthenticated(request: Request[AnyContent]): Future[Either[Result, RequestWithResolvedContext[TraitLike]]] = Future.successful(Right(RequestWithResolvedContext(request, Lang("en-us"),Trait("id"),false)))
}
ControllerModule.scala
package com.softwaremill.play24.modules
import com.softwaremill.macwire._
import com.softwaremill.play24.controllers.{SomeContextBuilder, SupplierController, CoffeeController}
import com.softwaremill.play24.dao.{CoffeeDao, SupplierDao}
import play.api.libs.ws.WSClient
import scala.concurrent.ExecutionContext
trait ControllerModule {
// Dependencies
implicit def ec: ExecutionContext
implicit val ctxBuilder = wire[SomeContextBuilder]
def wsClient: WSClient
def supplierDao: SupplierDao
def coffeeDao: CoffeeDao
// Controllers
lazy val supplierController = wire[SupplierController]
lazy val coffeeController = wire[CoffeeController]
}
However when I run the tests I'm getting a stacktrace:
[error] ! return priced by coffee, supplier
[error] No configuration setting found for key 'play.crypto.secret' (SimpleConfig.java:152)
[error] com.typesafe.config.impl.SimpleConfig.findKeyOrNull(SimpleConfig.java:152)
[error] com.typesafe.config.impl.SimpleConfig.findOrNull(SimpleConfig.java:170)
[error] com.typesafe.config.impl.SimpleConfig.findOrNull(SimpleConfig.java:176)
[error] com.typesafe.config.impl.SimpleConfig.findOrNull(SimpleConfig.java:176)
[error] com.typesafe.config.impl.SimpleConfig.findOrNull(SimpleConfig.java:193)
[error] com.typesafe.config.impl.SimpleConfig.findOrNull(SimpleConfig.java:198)
[error] com.typesafe.config.impl.SimpleConfig.getIsNull(SimpleConfig.java:208)
[error] play.api.PlayConfig.getOptional(Configuration.scala:951)
[error] play.api.PlayConfig.getOptionalDeprecated(Configuration.scala:996)
[error] play.api.libs.CryptoConfigParser.get$lzycompute(Crypto.scala:232)
[error] play.api.libs.CryptoConfigParser.get(Crypto.scala:203)
[error] play.api.libs.Crypto$$anonfun$crypto$1.apply(Crypto.scala:42)
[error] play.api.libs.Crypto$$anonfun$crypto$1.apply(Crypto.scala:40)
[error] play.api.libs.Crypto$.crypto(Crypto.scala:43)
[error] play.api.libs.Crypto$.sign(Crypto.scala:67)
[error] play.api.mvc.CookieBaker$class.encode(Http.scala:502)
[error] play.api.mvc.Session$.encode(Http.scala:651)
[error] play.api.mvc.CookieBaker$class.encodeAsCookie(Http.scala:554)
[error] play.api.mvc.Session$.encodeAsCookie(Http.scala:651)
[error] play.api.mvc.Result.withSession(Results.scala:170)
[error] play.api.mvc.Result.addingToSession(Results.scala:262)
[error] com.softwaremill.play24.controllers.AnotherController$$anonfun$ResolvedDecoratedAction$1$$anonfun$apply$5$$anonfun$apply$6.apply(CoffeeController.scala:64)
[error] com.softwaremill.play24.controllers.AnotherController$$anonfun$ResolvedDecoratedAction$1$$anonfun$apply$5$$anonfun$apply$6.apply(CoffeeController.scala:64)
I could try running(FakeApplication()){...} but then I get routes injector errors. Currently the code uses routesGenerator := InjectedRoutesGenerator in the build.sbt, but I don't think it translates over into test phase.
I have put the code up on here https://github.com/tashiscool/Play24MacwireMockingFailure
If you run activator test you should see the errors in the controllers tests.
i ran into the exact same problem. i spent a little bit of time looking into it, it appears that via FakeRequest#withSession
, you can end up calling some parts of the Crypto
library within play that depend on config but have no way to pass in a FakeApplication
.
...but i did find a simple workaround that might work for you as well. basically just wrapping FakeRequest
with a mockito spy, and then stubbing the methods that try to call the internal Crypto
API.
import org.mockito.Mockito.{doReturn, spy}
import play.api.mvc.{AnyContentAsEmpty, Session}
import play.api.test.FakeRequest
trait AuthSupport {
def fakeRequest(): FakeRequest[AnyContentAsEmpty.type] = {
val request = spy(FakeRequest())
doReturn(Session(Map("userId" -> "1"))).when(request).session
request
}
}
Looks like you didn't configured play secret in application.conf
Can you try and define it?
Look here for more details
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.