Instantiating Akka actors in a Play application with Subcut - scala

I have a Play 2.1 application. I am also using Subcut for dependency injection, which is already set up and working for most parts of the application, except for one.
Say I have the following snippet of actor-related code:
import akka.actor._
import com.typesafe.plugin._
import play.api.Play.current
import play.api.libs.concurrent.Akka
class FoobarActor extends Actor {
def receive = {
// do stuff here
}
}
object Foobar {
val actor = Akka.system.actorOf(Props[FoobarActor])
}
Now, say I would like to inject some objects into each instance of the FoobarActor using Subcut. This would require the actor class to extend Injectable, with the BindingModule passed into the constructor, like this:
import akka.actor._
import com.typesafe.plugin._
import play.api.Play.current
import play.api.libs.concurrent.Akka
import com.escalatesoft.subcut.inject.{Injectable, BindingModule}
class FoobarActor(implicit val bindingModule: BindingModule) extends Actor
with Injectable {
val bazProvider = inject[BazProvider]
val quuxProvider = inject[QuuxProvider]
def receive = {
// do stuff here
}
}
The question is: how is such an actor instantiated?
Typically, objects managed by Subcut are constructed in Subcut's configuration objects (i.e., objects that extend NewBindingModule), or in the case of Play's controllers, in the Global object (see play-subcut on github).
What would I replace Akka.system.actorOf(Props[FoobarActor]) with in order to override the instantiation of actors in order to pass in the binding module?
object Foobar {
val actor = /* what goes here? */
}

As Roland mentioned, this should be as simple as just instantiating the actor with a constructor argument. I wasn't sure the implicit would work with Akka's way of doing actor instantiation with constructor args but it seems to work okay. The code should look something like this:
class FoobarActor(implicit val bindingModule: BindingModule) extends Actor
with Injectable {
val bazProvider = inject[BazProvider]
val quuxProvider = inject[QuuxProvider]
def receive = {
// do stuff here
}
}
object FoobarActor {
def apply(implicit bindingModule:BindingModule) = {
Akka.system.actorOf(Props(classOf[FoobarActor], bindingModule))
}
}
Then, if you wanted to instantiate the FoobarActor, as long as you had an implicit BindingModule in scope, you could just do:
val ref = FoobarActor()

Related

Illegal inheritance, superclass X not a subclass of the superclass Y of the mixin trait Z - Scala

I am trying to execute a akka-http which is a scala program. My KISS code is as follows:-
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.{HttpRequest, HttpResponse}
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.directives.BasicDirectives
import akka.stream.ActorMaterializer
import akka.stream.scaladsl.Flow
import com.typesafe.config.ConfigFactory
object MyBoot02 extends SprayCanBoot02 with RestInterface02 with App {
}
abstract class SprayCanBoot02 {
val config = ConfigFactory.load()
val host = config.getString("http.host")
val port = config.getInt("http.port")
implicit val system = ActorSystem("My-ActorSystem")
implicit val executionContext = system.dispatcher
implicit val materializer = ActorMaterializer()
//implicit val timeout = Timeout(10 seconds)
implicit val routes: Flow[HttpRequest, HttpResponse, Any]
Http().bindAndHandle(routes, host, port) map {
binding => println(s"The binding local address is ${binding.localAddress}")
}
}
trait RestInterface02 extends AncileDemoGateway02 with Resource02 {
implicit val routes = questionroutes
val buildMetadataConfig = "this is a build metadata route"
}
trait Resource02 extends QuestionResource02
trait QuestionResource02 {
val questionroutes = {
path("hi") {
get {
complete("questionairre created")
}
}
}
}
class AncileDemoGateway02 {
println("Whatever")
}
The error that I get is because of how I am wiring stuff when trying to execute MyBoot02. The error is as follows:
Error:(58, 41) illegal inheritance; superclass SprayCanBoot is not a
subclass of the superclass AncileDemoGateway of the mixin trait
RestInterface object MyBoot extends SprayCanBoot with RestInterface
with App
Why does the error state 'SprayCanBoot is not a subclass of the superclass AncileDemoGateway'. In my code SprayCanBoot and AncileDemoGateway are 2 separate entities then why such an error?
Thanks
Unfortunately, for some mysterious reason, that's probably inherited from the wonderful design of Java, you cannot extend more than one class either directly or indirectly.
It is possible to mix in as many traits as you want, but you can only have one superclass in the hierarchy (ok, technically, you can have more than one, but they all must be extending each other - that's why your error message is complaining about SprayBoot not being a subclass).
In your case, you are extending SprayCanBoot02, which is a class, and also RestInterface02, that extends AncileDemoGateway02, which is also a class. So MyBoot02 is trying to extend two different classes at once, which is illegal.
Making AncileDemoGateway02 a trait should fix the error.
In general, a trait inheriting from a class is commonly used to limit the classes a trait can be mixed into.
In your case, the MyBoot02 class can’t extend the RestInterface02 trait, because MyBoot02 and RestInterface02 don’t share the same superclass.

Check what the method of mocked object receives

In my project, whenever a class produces some output, instead of doing println it calls OutputStore.write, which is a class and method I defined.
I am trying to test the output of another class so I mocked OutputStore. I want to see what parameters it receives to OutputStore.write.
val mockOutputStore = mock[OutputStore]
I would like to do something like this:
val argument = ArgumentCaptor.forClass(classOf[OutputStore])
verify(mockOutputStore).write(argument.capture())
assertEquals("some parameter", argument.getValue())
However, this doesn't compile as verify is not even recognized.
The signature of my test class is this:
class SomeUnitTestSet extends org.scalatest.FunSuite with MockitoSugar with PropertyChecks
Any idea how to check what parameters a mocked object's method receives?
Here is a translation of what #JBNizet suggested into a Scala code
Assuming you have your OutputStore class
class OutputStore {
def write(msg: String) = {
println(msg)
}
}
and some OutputStoreApiUser class
class OutputStoreApiUser(val outputStore: OutputStore) {
def foo(): Unit = {
outputStore.write("some parameter")
outputStore.write("some parameter2")
}
}
Then your test might be something like this (in real life you probably #Inject outputStore but this is not relevant here):
import org.mockito.Mockito.verify // static import!
import org.scalatest.mockito.MockitoSugar
import org.scalatest.prop.PropertyChecks
class SomeUnitTestSet extends org.scalatest.FunSuite with MockitoSugar with PropertyChecks {
test("Capture calls"){
val mockOutputStore = mock[OutputStore]
val apiUser = new OutputStoreApiUser(mockOutputStore)
apiUser.foo()
verify(mockOutputStore).write("some parameter")
verify(mockOutputStore).write("some parameter2")
}
}
This one compiles and works for me as I would expect

How to mock using external call in Akka Actor using ScalaTest

I am new to entire ecosystem including Scala, Akka and ScalaTest
I am working on a problem where my Actor gives call to external system.
case object LogProcessRequest
class LProcessor extends Actor {
val log = Logging(context.system, this)
def receive = {
case LogProcessRequest =>
log.debug("starting log processing")
LogReaderDisruptor main(Array())
}
}
The LogReaderDisruptor main(Array()) is a Java class that does many other things.
The test I have currently looks like
class LProcessorSpec extends UnitTestSpec("testSystem") {
"A mocked log processor" should {
"be called" in {
val logProcessorActor = system.actorOf(Props[LProcessor])
logProcessorActor ! LogProcessRequest
}
}
}
where UnitTestSpec looks like (and inspired from here)
import akka.actor.ActorSystem
import akka.testkit.{ImplicitSender, TestKit}
import org.scalatest.matchers.MustMatchers
import org.scalatest.{BeforeAndAfterAll, WordSpecLike}
abstract class UnitTestSpec(name: String)
extends TestKit(ActorSystem(name))
with WordSpecLike
with MustMatchers
with BeforeAndAfterAll
with ImplicitSender {
override def afterAll() {
system.shutdown()
}
}
Question
How can I mock the call to LogReaderDisruptor main(Array()) and verify that it was called?
I am coming from Java, JUnit, Mockito land and something that I would have done here would be
doNothing().when(logReaderDisruptor).main(Matchers.<String>anyVararg())
verify(logReaderDisruptor, times(1)).main(Matchers.<String>anyVararg())
I am not sure how to translate that with ScalaTest here.
Also, This code may not be idiomatic, since I am very new and learning
There are a few ways to do this. The kind of OO way is to wrap logDisrupter as an object and pass it in. I would set up a companion object to instantiate the actor. Something like below. Then you can pass alternate implementation. You can also achieve a similar approach by using traits and mixing in an alternative logDisrupter only as needed.
object LProcessor {
def props(logDisrupter : LogDisrupter) = Props(new LProcessor(logDisrupter))
}
class LProcessor(logDisrupter : LogDisrupter) extends Actor {
val log = Logging(context.system, this)
def receive = {
case LogProcessRequest =>
log.debug("starting log processing")
logDisrupter.doSomething();
}
}
Then instatiate as
val logProcessorActor = system.actorOf(LProcessor.props(logDisrupter))

Serialize class as its one member with Jackson

Sometimes the class has only one member to serialize (other members are transient), and I would like to serialize and deserialize this class as its only member.
Consider following code:
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper
case class Content(i:Seq[Int])
case class Wrap(content:Content)
object Main extends App {
val om = new ObjectMapper() with ScalaObjectMapper {
registerModule(new DefaultScalaModule)
}
val roots = Wrap(Content(Seq(1,2,3)))
val out = om.writeValueAsString(roots)
println(out)
val test = om.readValue(out, classOf[Wrap])
println(test)
}
The result of serialization of Wrapis {"content":{"i":[1,2,3]}}.
I would like to get {"i":[1,2,3]} only. I guess I could do this with custom serializer/deserializer, but given in real case the content is a complex class, this would mean I would have to serialize the content manually, if I am not mistaken. I would prefer some more straightforward solution.
Is it possible to "delegate" the serialization/deserialization to a member/constructor parameter?
It can be done using converters, which can be used to modify Jackson behaviour using JsonSerialize and JsonDeserialize properties.
import com.fasterxml.jackson.databind.annotation.{JsonSerialize, JsonDeserialize}
import com.fasterxml.jackson.databind.util.StdConverter
#JsonDeserialize(converter=classOf[WrapConverterDeserialize])
#JsonSerialize(converter=classOf[WrapConverterSerialize])
case class Wrap(content:Content)
class WrapConverterDeserialize extends StdConverter[Content,Wrap] {
override def convert(value: Content) = new Wrap(value)
}
class WrapConverterSerialize extends StdConverter[Wrap,Content] {
override def convert(value: Wrap) = value.content
}

How to test a public method in an akka actor?

I have an akka actor:
class MyActor extends Actor {
def recieve { ... }
def getCount(id: String): Int = {
//do a lot of stuff
proccess(id)
//do more stuff and return
}
}
I am trying to create a unit test for the getCount method:
it should "count" in {
val system = ActorSystem("Test")
val myActor = system.actorOf(Props(classOf[MyActor]), "MyActor")
myActor.asInstanceOf[MyActor].getCount("1522021") should be >= (28000)
}
But it is not working:
java.lang.ClassCastException: akka.actor.RepointableActorRef cannot be cast to com.playax.MyActor
How could I test this method?
Do something like this:
import org.scalatest._
import akka.actor.ActorSystem
import akka.testkit.TestActorRef
import akka.testkit.TestKit
class YourTestClassTest extends TestKit(ActorSystem("Testsystem")) with FlatSpecLike with Matchers {
it should "count plays" in {
val actorRef = TestActorRef(new MyActor)
val actor = actorRef.underlyingActor
actor.getCount("1522021") should be >= (28000)
}
}
I generally recommend factoring any "business logic" that is executed by an Actor into a separate class that is supplied as a constructor parameter or provided via a Cake component. Doing this simplifies the Actor, leaving it only the responsibility to protect long-lived mutable state and handle incoming messages. It also facilitates testing both the business logic (by making it separately available for unit tests) and how the Actor interacts with that logic by supplying a mock / spy instance or component when testing the Actor itself.