I am using Play framework 2.2.x and SecureSocial and for testing I am trying to override a method in a superclass. Actually I am getting a compile error using the test helper classes from secure social and I can not figure it out as I am not all that familiar with Scala.
What I don't understand is why my ide things the method is correctly overridden but when I compile I get the error. I know scala is not that well integrated with the ides but I can not see why the override is incorrect.
/**
* This is the secure social class and method I am trying to override.
I have left the other methods out for clarity. The problem method is the doAuth method
**/
package securesocial.core
import providers.utils.RoutesHelper
import play.api.mvc.{SimpleResult, AnyContent, Request}
import play.api.{Play, Application, Plugin}
import concurrent.{Await, Future}
import play.api.libs.ws.Response
abstract class IdentityProvider(application: Application) extends Plugin with Registrable {
/**
* Subclasses need to implement the authentication logic. This method needs to return
* a User object that then gets passed to the fillProfile method
*
* #param request
* #return Either a Result or a User
* This is the method I am having trouble trying to override
*/
def doAuth()(implicit request: Request[AnyContent]):Either[SimpleResult, SocialUser]
}
This is the my class and the doAuth() override
package testkit
import play.api.Logger
import securesocial.core._
import play.api.mvc.{Result, Request}
import securesocial.core.IdentityId
class AlwaysValidIdentityProvider(app:play.api.Application) extends IdentityProvider(app){
val logger = Logger("securesocial.stubs.AlwaysValidIdentityProvider")
def authMethod: AuthenticationMethod = AuthenticationMethod("naive")
override def doAuth()(implicit request: Request[play.api.mvc.AnyContent]): Either[Result, SocialUser] ={
val userId = request.body.toString
val r =Right(SocialUserGenerator.socialUserGen(IdentityId(userId, id), authMethod).sample.get)
r
}
def fillProfile(user: SocialUser): SocialUser = {
user
}
def id: String = "naive"
}
The error I am getting is: As you can see it thinks I am overriding nothing.
[error] /Users/zola/Development/play/receipt-manager/rm-play/test/testkit/AlwaysValidIdentityProvider.scala:8: class AlwaysValidIdentityProvider needs to be abstract, since method doAuth in class IdentityProvider of type [A]()(implicit request: play.api.mvc.Request[A])Either[play.api.mvc.Result,securesocial.core.SocialUser] is not defined
[error] class AlwaysValidIdentityProvider(app:play.api.Application) extends IdentityProvider(app){
[error] ^
[error] /Users/zola/Development/play/receipt-manager/rm-play/test/testkit/AlwaysValidIdentityProvider.scala:13: method doAuth overrides nothing.
[error] Note: the super classes of class AlwaysValidIdentityProvider contain the following, non final members named doAuth:
[error] def doAuth[A]()(implicit request: play.api.mvc.Request[A]): Either[play.api.mvc.Result,securesocial.core.SocialUser]
[error] override def doAuth()(implicit request: Request[play.api.mvc.AnyContent]): Either[Result, SocialUser] ={
[error] ^
[error] two errors found
That's because the method you are overriding is not already defined. You have a signature in the abstract class and that's it.
Try this instead:
def doAuth()(implicit request: Request[play.api.mvc.AnyContent]): Either[Result, SocialUser] ={
val userId = request.body.toString
val r =Right(SocialUserGenerator.socialUserGen(IdentityId(userId, id), authMethod).sample.get)
r
}
To solve the issue I looked at other classes within SecureSocial and they way they implemented the method was
def doAuth[A]()(implicit request: Request[A]): Either[Result, SocialUser] = {
val userId = request.body.toString
val r =Right(SocialUserGenerator.socialUserGen(IdentityId(userId, id), authMethod).sample.get)
r
}
Related
I'm using sbt to build some of the riscv boom from the source code, but the sbt complains that it "could not find implicit value for parameter valName: : freechips.rocketchip.diplomacy.ValName". The detailed error message are as below:
[error] F:\hiMCU\my_proj\src\main\scala\freechips\rocketchip\tile\BaseTile.scala:170:42: could not find implicit value for parameter valName: freechips.rocketchip.diplomacy.ValName
[error] Error occurred in an application involving default arguments.
[error] protected val tlMasterXbar = LazyModule(new TLXbar)
The code where sbt complains is as below:
abstract class BaseTile private (val crossing: ClockCrossingType, q: Parameters)
extends LazyModule()(q)
with CrossesToOnlyOneClockDomain
with HasNonDiplomaticTileParameters
{
// Public constructor alters Parameters to supply some legacy compatibility keys
def this(tileParams: TileParams, crossing: ClockCrossingType, lookup: LookupByHartIdImpl, p: Parameters) = {
this(crossing, p.alterMap(Map(
TileKey -> tileParams,
TileVisibilityNodeKey -> TLEphemeralNode()(ValName("tile_master")),
LookupByHartId -> lookup
)))
}
def module: BaseTileModuleImp[BaseTile]
def masterNode: TLOutwardNode
def slaveNode: TLInwardNode
def intInwardNode: IntInwardNode // Interrupts to the core from external devices
def intOutwardNode: IntOutwardNode // Interrupts from tile-internal devices (e.g. BEU)
def haltNode: IntOutwardNode // Unrecoverable error has occurred; suggest reset
def ceaseNode: IntOutwardNode // Tile has ceased to retire instructions
def wfiNode: IntOutwardNode // Tile is waiting for an interrupt
protected val tlOtherMastersNode = TLIdentityNode()
protected val tlSlaveXbar = LazyModule(new TLXbar)
protected val tlMasterXbar = LazyModule(new TLXbar)
protected val intXbar = LazyModule(new IntXbar)
....
}
The LazyModule object code is as below:
object LazyModule
{
protected[diplomacy] var scope: Option[LazyModule] = None
private var index = 0
def apply[T <: LazyModule](bc: T)(implicit valName: ValName, sourceInfo: SourceInfo): T = {
// Make sure the user put LazyModule around modules in the correct order
// If this require fails, probably some grandchild was missing a LazyModule
// ... or you applied LazyModule twice
require (scope.isDefined, s"LazyModule() applied to ${bc.name} twice ${sourceLine(sourceInfo)}")
require (scope.get eq bc, s"LazyModule() applied to ${bc.name} before ${scope.get.name} ${sourceLine(sourceInfo)}")
scope = bc.parent
bc.info = sourceInfo
if (!bc.suggestedNameVar.isDefined) bc.suggestName(valName.name)
bc
}
}
I think the sbt should find some val of type freechips.rocketchip.diplomacy.ValName, but it didn't find such kind of val.
You need to have an object of type ValName in the scope where your LazyModules are instantiated:
implicit val valName = ValName("MyXbars")
For more details on Scala's implicit please see https://docs.scala-lang.org/tutorials/tour/implicit-parameters.html.html
You generally shouldn't need to manually create a ValName, the Scala compiler can materialize them automatically based on the name of the val you're assigning the LazyModule to. You didn't include your imports in your example, but can you try importing ValName?
import freechips.rocketchip.diplomacy.ValName
In most of rocket-chip code, this is imported via wildcard importing everything in the diplomacy package
import freechips.rocketchip.diplomacy._
In my Module.scala I'm binding a concrete implementation of a trait defined as follows:
trait AccessGroupRepository[F[_]] {}
#Singleton
class AccessGroupRepositoryImpl #Inject()(db: OldDataBase, c: IOContextShift)
extends AccessGroupRepository[IO] {}
and the binding is done using TypeLiteral:
bind(new TypeLiteral[AccessGroupRepository[IO]] {}).to(classOf[AccessGroupRepositoryImpl])
Now, I need to override this binding when testing with a Mockito mock:
override val application: Application = guiceApplicationBuilder
.overrides(bind(new TypeLiteral[AccessGroupRepository[IO]] {}).to(agRepoMock))
but I get the following error:
overloaded method value bind with alternatives:
[error] [T](implicit evidence$1: scala.reflect.ClassTag[T])play.api.inject.BindingKey[T] <and>
[error] [T](clazz: Class[T])play.api.inject.BindingKey[T]
[error] cannot be applied to (com.google.inject.TypeLiteral[api.v1.accessgroup.AccessGroupRepository[cats.effect.IO]])
[error] .overrides(bind(repoTypeLiteral).to(agRepoMock))
[error] ^
How could I solve that?
This question relates to How to bind a class that extends a Trait with a monadic type parameter using Scala Guice?
TypeLiteral isn't available yet in scala implementation of Play Guice API.
Current valid solution for generics, is creating a test module with desired mock definitions, and passing it within overrides:
object CustomMockComponentModule extends AbstractModule {
val agRepoMock = ...
#Provides
#Singleton
def mockBean(): AccessGroupRepository[IO] = agRepoMock
}
...
override val application: Application = guiceApplicationBuilder
.overrides(CustomMockComponentModule)
.build()
I have the following piece of code
import play.api.i18n.{MessagesApi, Messages, I18nSupport}
import play.api.libs.json.Json
case class HttpMessage(key: String, message: String)
object HttpMessage {
implicit val jsonFormat = Json.format[HttpMessage]
def apply(key: String): HttpMessage = {
HttpMessage(key, Messages(key))
}
}
When compiled, it throws
[error] could not find implicit value for parameter messages: play.api.i18n.Messages
[error] HttpMessage(key, messages(key))
[error] ^
I made some research and it seems that it cannot find an implicit value for MessagesAPI. It seems it must be inject like in controllers but I do not know how because I am facing an object and case class here. #Inject annotation is not accepted.
How can I fix this?
Approach from https://stackoverflow.com/a/30843682/4496364 :
import play.api.Play.current
import play.api.i18n.Messages.Implicits._
The first line is deprecated since Play now uses DI everywhere possible.
My approach (can't say if good or bad):
case class HttpMessage(key: String, message: String)
object HttpMessage {
implicit val jsonFormat = Json.format[HttpMessage]
def apply(key: String)(implicit messages: Messages): HttpMessage = {
HttpMessage(key, Messages(key))
}
}
I had to create similar solution, so I used the implicit way, which Play uses also in it's templates. You must have implicit request in your controller for this to work. Also, in all service-like classes you need to forward this implicit messages: Messages...
I'm trying to reprocude this or this, but I keep getting an error I am not able to fix...
First of all, here are my dependencies:
compile 'io.spray:spray-can_2.11:1.3.1'
compile 'io.spray:spray-routing_2.11:1.3.1',
compile 'io.spray:spray-json_2.11:1.2.6'
Now what I'm trying to do is:
class WHttpService extends Actor with HttpService with ActorLogging {
implicit def actorRefFactory = context
def receive = runRoute(route)
lazy val route = logRequest(showReq _) {
// Way too much imports but I tried all I could find
import spray.json._
import DefaultJsonProtocol._
import MasterJsonProtocol._
import spray.httpx.SprayJsonSupport._
path("server" / Segment / DoubleNumber / DoubleNumber) { (login, first, second) =>
get {
complete {
Answer(1, "test")
}
}
}
}
private def showReq(req : HttpRequest) = LogEntry(req.uri, InfoLevel)
}
With:
case object MasterJsonProtocol extends DefaultJsonProtocol with SprayJsonSupport {
import spray.json._
case class Answer(code: Int, content: String)
implicit val anwserFormat: JsonFormat[Answer] = jsonFormat2(Answer)
}
Now I get this error:
Error:(42, 19) type mismatch;
found : MasterJsonProtocol.Answer
required: spray.httpx.marshalling.ToResponseMarshallable
Answer(1, "test")
^
I tried a lot of things but can't manage to make it works.
I tried with
Answer(1, "test").toJson
Answer(1, "test").toJson.asJsObject
Finally what I did was
complete {
Answer(1, "test").toJson.compactPrint
}
This works but it is sent to the client as Content-Type: text/plain when I need application/json.
Anyone see what the problem is here?
Edit: I added a sample project on github https://github.com/ydemartino/spray-test
Move your model outside of the json protocol and make it a regular object (not a case object)
case class Answer(code: Int, content: String)
object MasterJsonProtocol extends DefaultJsonProtocol {
implicit val anwserFormat = jsonFormat2(Answer)
}
Edit
Also clean up your imports:
class WHttpService extends Actor with HttpService with ActorLogging {
implicit def actorRefFactory = context
def receive = runRoute(route)
lazy val route = logRequest(showReq _) {
// Way too much imports but I tried all I could find
import MasterJsonProtocol._
import spray.httpx.SprayJsonSupport._
path("server" / Segment / DoubleNumber / DoubleNumber) { (login, first, second) =>
get {
complete {
Answer(1, "test")
}
}
}
}
private def showReq(req : HttpRequest) = LogEntry(req.uri, InfoLevel)
}
I created a pull request to fix your problem: https://github.com/ydemartino/spray-test/pull/1
The json protocol object has to be declared before it can be used implicitly. I'm not wholly sure why the compiler can't figure it out, but moving the object declaration to the top fixed it.
For your actual project make sure to declare packages in each file then use those packages to in the import statements.
In my case the name of the unresolvable implicit format instance conflicted with a local definition, so it got shadowed. The compiler was graciously silent about that. Only discovered that by accident after hours of head-banging.
I am trying folow the example from Mock Objects in Play[2.0] but unfortunately I am not having success.
I have a UsersController that uses a UserModel.
trait UserModel extends ModelCompanion[User, ObjectId] {
// ...
}
Next, the abstract controller
abstract class UsersController extends Controller {
val userModel: UserModel
def sayHello = Action(parse.json) { request =>
// return a play Action. Doesn't use userModel
}
// Other methods
}
In the routes file, I call method say Hello in this way:
POST /hello controllers.Users.sayHello
In test directory, I created a subclass of UsersController using a UserModel mock.
package controllers
import org.specs2.mock.Mockito
object UserControllersTest extends UsersController with Mockito {
val userModel = mock[models.UserModel]
}
Now, the main part. I created a Spec test following the Jacob Groundwater example in the page mentioned before. In pluing argument for FakeApplication, I included a calling to UserControllersTest.
package controllers
import org.specs2.mutable.Specification
import play.api.libs.json.Json
import play.api.test._
import play.api.test.Helpers._
class UsersSayHelloSpec extends Specification {
running(FakeApplication()) {
"Users.SayHello" should {
def sendJson(jsonMap: Map[String, String], shouldBeCorrect: Boolean) = {
running(new FakeApplication(
additionalPlugins = Seq("controllers.UserControllersTest"))) {
// Preapration
val jsonRequisition = Json.toJson(jsonMap)
val Some(result) = routeAndCall(FakeRequest(POST,
"/hello",
FakeHeaders(Map("Content-Type" -> Seq("application/json"))),
jsonRequisition))
// ...
}
}
"Not process a empty String" in {
sendJson(Map.empty[String, String], false)
}
// Other tests calling sendJson ...
}
}
}
However, when I run the test I got this error message:
[info] Users.SayHello should
[error] ! Not process a empty String
[error] PlayException: Cannot load plugin [Plugin [controllers.UserControllersTest] cannot been instantiated.] (Application.scala:171)
...
[error] play.api.Application.<init>(Application.scala:158)
[error] play.api.test.FakeApplication.<init>(Fakes.scala:141)
[error] controllers.UsersSayHelloSpec$$anonfun$1$$anonfun$apply$5.sendJson$1(UsersSayHelloSpec.scala:20)
[error] controllers.UsersSayHelloSpec$$anonfun$1$$anonfun$apply$5$$anonfun$apply$26.apply(UsersSayHelloSpec.scala:46)
[error] controllers.UsersSayHelloSpec$$anonfun$1$$anonfun$apply$5$$anonfun$apply$26.apply(UsersSayHelloSpec.scala:46)
Where UsersSayHelloSpec.scala:20 referes to line where I call running method.
So my question is: What am I doing wrong?
I'm not sure what exactly are you trying to do, but the answer for question 'What am I doing wrong?' is:
The parameter 'additionalPlugins' is for additional Play plugins, and 'controllers.UserControllersTest' is not a Play plugin. It's a Controller.
You can read about Play 2 plugins here: http://www.objectify.be/wordpress/?p=464
Have you tried these examples: http://www.playframework.org/documentation/2.0.4/ScalaFunctionalTest ?