Using akka typed: 2.6.10. My parent generates child actors to do some work as you can see below (note this is part of event sourced actor). Is there a way to acquire reference to internally created child actor using possibly name during testing time?
For example, below we have child actor provider_1 which is created at initialization time and I am hoping to acquire a reference to TestProbe using this name from outside. I am reluctant to change the way code is structured for sake of testing, for example in here there are some reference to passing in ref/factory or re-constructing parent in test in order to test this, which I would like to avoid.
def commandHandler(
ctx: ActorContext[Command]
): (State, Command) => Effect[Event, State] = { (state, cmd) =>
cmd match {
case Init =>
ctx.spawn(Provider(ctx.self), "provider_1")
Effect.none
}
}
If you're using the BehaviorTestKit to test the actor, the actor gets run with an alternative ActorContext implementation.
So the following should work (note that akka.actor.testkit.typed.Effect has little relation to Effect in persistence), using scalatest matchers:
import akka.actor.testkit.typed.Effect.Spawned
val testKit = BehaviorTestKit(behaviorUnderTest)
testKit.run(Init)
val effect = testKit.retrieveEffect : akka.actor.testkit.typed.Effect
val childActorRef =
effect match {
case s: Spawned if s.childName == "provider_1" => s.ref
case _ => fail()
}
val childInbox = testKit.childInbox(childActorRef)
testKit.run(SendMessageToYourChild("hello"))
childInbox.hasMessages shouldBe true
childInbox.receiveMessage shouldBe MessageFromParent("hello")
akka.actor.testkit.typed.scaladsl.TestInbox is intended to be the synchronous behavior testing analogue to the asynchronous TestProbe.
I'm not aware of an analogous method for the asynchronous ActorTestKit, where a child actor will actually be spawned.
Related
I hope it is ok to ask this. I am using akka and have two actors, where one is initiated/created fast and the other much slower. The rapidly created one asks the other for something (ask-pattern), and the message is sent to dead letters since the other is not initiated yet. What is the preferred way of making an actor waiting with sending it´s message? I am not so eager to make an actor sleep or something without knowing there is no other way.
I would use the functionality become()/unbecome() Akka provides for Actors. I am assuming in the following code that the slowActor gets created by the fastActor. The trick here is that the fastActor will have two behaviors: one for when the slowActor is getting initiated and the other for when it's ready to do some work. When slowActor is ready, it will send a message to the fastActor to advertise that is able to receive messages. fastActor will be watching slowActor and if it gets terminated, it will change its behavior again. What to do next would be up to your solution.
Here is a mock code as a guide (I have not compiled the code and it might contain some errors):
case object Ready
case object DoWork
case object WorkDone
class FastActor extends Actor with ActorLogging {
val slowActor = context.actorOf(SlowActor.props)
context.watch(slowActor)
def receive = slowActorNotReadyBehavior
def slowActorNotReadyBehavior = {
case DoWork => log.warning("Slow actor in not ready, I am sorry...")
case Ready => context.become(slowActorReadyBehavior)
}
def slowActorReadyBehavior = {
case DoWork => (slowActor ? DoWork).pipeTo(self)
case Terminated(ref) =>
log.error("Slow actor terminated")
context.unbecome()
//... do something with slowActor
}
}
class SlowActor extends Actor {
override def preStart = {
context.parent ! Ready
}
def receive = {
case DoWork =>
//do something
sender ! WorkDone
}
}
In book of akka in actor's chapter three. It use a message event to test silent actor's state.
The actor as this:
object SilentActorProtocol {
case class SilentMessage(data: String)
case class GetState(receiver: ActorRef)
}
class SilentActor extends Actor {
import SilentActorProtocol._
var internalState = Vector[String]()
def receive = {
case SilentMessage(data) =>
internalState = internalState :+ data
case GetState(receiver) => receiver ! internalState
}
}
Test code as this:
"change internal state when it receives a message, multi" in {
import SilentActorProtocol._
val silentActor = system.actorOf(Props[SilentActor], "s3")
silentActor ! SilentMessage("whisper1")
silentActor ! SilentMessage("whisper2")
silentActor ! GetState(testActor)
expectMsg(Vector("whisper1", "whisper2"))
}
Inner the test code why use GetState get result of above SilentMessage event.
Why not use slientActor.internalState get the result straightly?
Update
Some friends seems mislead my problem.For detail,
The books said
use the internalState variable will encounter concurrency problem, so there should use a GetState event tell actor to get the actor's inner state rather then use internalState straightly.
I don't know why it should encounter concurrency problem and why use GetState can fix the problem
Explain
slientActor.internalState can't get inner variable straightly , instand, use silentActor.underlyingActor.internalState can get it.So sorry for the terrible question.
If I understand your question correctly, the answer is that the silentActor in the test code is not the actor, it is the ActorRef instance, therefore it does not have the internalState var to be referenced.
If you want to write unit tests for specific variables and methods on the ActorRef, you need to use the underlyingActor technique as described (with its caveats) in the documentation. (see section on TestActorRef.
I am brand new to Akka but my understanding about the Stop directive is that it is used inside of SupervisorStrategies when the child should be considered permanently out of service, but there is a way to handle the total outage.
If that understanding is correct, then what I would like to do is have some kind of a “backup actor” that should be engaged after the normal/primary child is stopped and used from that point forward as a fallback. For example, say I have a parent actor who has a child actor - Notifier - whose job it is to send emails. If the Notifier truly dies (say, the underlying mail server goes offline), a backup to this actor might be another actor, say, QueueClient, that sends the notification request to a message broker, where the message will be queued up and replayed at a later time.
How can I define such a SupervisorStrategy to have this built in fault tolerance/actor backup inside of it? Please show code examples, its the only way I will learn!
Overriding Supervisor Strategies beyond the default directives is not commonly done, and not really necessary in your case. A solution would be to watch the child actor from the parent, and when the parent finds that the child is stopped, engage the backup actor.
import akka.actor.SupervisorStrategy.Stop
import akka.actor._
class Parent extends Actor {
var child: ActorRef = context.actorOf(Props[DefaultChild])
context.watch(child)
def receive = {
case Terminated(actor) if actor == child =>
child = context.actorOf(Props[BackupChild])
}
override def supervisorStrategy = OneForOneStrategy() {
case ex: IllegalStateException => Stop
}
}
class DefaultChild extends Actor {
def receive = { case _ => throw new IllegalStateException("whatever") }
}
class BackupChild extends Actor {
def receive = { case _ => }
}
Is it possible to bind a set of AKKA actors to a certain context?
E.g. I have three actors and each of them are implementing a state machine. These actors send messages to each other on certain state transitions. Now I want to bind these state to a context, e.g. a user context. So I have a user (represented by an userId) who has a set of actors bound in certain states. As long as this user context exists these actors (or at least their states) must be bound to the user's context. Is this possible per se in AKKA or do I have to persist the state of the different actors user-wise? Or are actors not designed for these use cases?
I'm not 100% sure that I get what you are asking, but I'll take a shot at an answer anyway. The actor system itself is heirarchical. Parent/child relationships exist in the heirarchy and the parent will be the owner (and supervisor) to the children. If you modeled your system with a UserContext actor being the parent to three child actors (your FSM actors) then I suppose the children will be bound to this UserContext actor instance. Consider this simplified example model:
class UserContext extends Actor{
val stateA = context.actorOf(Props[StateA])
val stateB = context.actorOf(Props[StateB])
val stateC = context.actorOf(Props[StateC])
def receive = {
case _ =>
}
}
class StateA extends Actor{
def receive = {
case _ =>
}
}
class StateB extends Actor{
def receive = {
case _ =>
}
}
class StateC extends Actor{
def receive = {
case _ =>
}
}
If you set things up this way, the state children will be started up when this user context instance is created and will also be stopped when the user context instance is stopped. Now all you need is a little code to make sure only one user context per user exists in the system. You could do something like this to assure that:
object UserContext{
def apply(username:String)(implicit system:ActorSystem):ActorRef = {
val ctx = system.actorFor("/user/" + username)
if (ctx.isTerminated){
try{
system.actorOf(Props[UserContext], username)
}
catch{
case InvalidActorNameException(msg) if msg.contains("unique") => apply(username)
}
}
else
ctx
}
}
This factory object makes sure the user context actor for the supplied username is not currently running. If it is, it just returns that ref. If not, it starts it up and binds it to the name of the user for later lookups.
Once you do things like this, just use the factory to lookup the UserContext for a supplied username and then route all messages through it and let it delegate messages to the correct child state actor. This is obviously quite simplified, but I think it might be something similar to what you want.
Anyone know of a good way to unit test Scala actors? In the general sense I have an actor that receives a message and will send out other messages in response. This is done on multiple threads, and an actor that is not correct may either send the wrong messages or no message at all. I need a simple way of creating a mockup actor that send and receives messages to the actor being tested. Any experiences in this area?
Because of the dynamic nature of actor-style message passing, mocking actors is usually no trouble at all. Just create an actor which receives the desired message and you're home free. You will of course need to ensure that this mock actor is the one to which messages are passed, but that shouldn't be a problem as long as the actor you are attempting to test is reentrant.
I think the complexity depends on a couple factors...
How stateful is the actor?
If it behaves like a idempotent function, only asynchronous, then it should be a simple matter of mocking up an actor that sends a message and then checks that it receives the expected messages back. You probably want to use a react/receiveWithin on the mock actor in case there is response within a reasonable period of time you can fail rather than hanging.
However if the messages aren't independent of one another, then you should test it with various sequences of messages and expected results.
How many actors will the actor being tested interact with?
If an actor is expected to interact with many others, and it is stateful, then it should be tested with several actors sending/receiving messages. Since you probably have no guarantee of the order in which the messages will arrive, you should be sure to either permute the orders in which the actors send the messages or introduce random pauses in the actors generating messages and run the test many times.
I'm not aware of any prebuilt frameworks for testing actors, but you could possibly look to Erlang for inspiration.
http://svn.process-one.net/contribs/trunk/eunit/doc/overview-summary.html
I have been wondering about how to test Actors myself.
Here is what I came up with, does anybody see problems with this approach?
Rather than send messages directly, what if your actor delegated message sending to a function?
Then your tests can swap out the function with one that tracks the number of times called and/or the arguments with which the method was called:
class MyActor extends Actor {
var sendMessage:(Actor, ContactMsg) => Unit = {
(contactActor, msg) => {
Log.trace("real sendMessage called")
contactActor ! msg
}
}
var reactImpl:PartialFunction(Any, Unit) = {
case INCOMING(otherActor1, otherActor2, args) => {
/* logic to test */
if(args){
sendMessage(otherActor1, OUTGOING_1("foo"))
} else {
sendMessage(otherActor2, OUTGOING_2("bar"))
}
}
}
final def act = loop {
react {
reactImpl
}
}
Your test case might contain code like:
// setup the test
var myActor = new MyActor
var target1 = new MyActor
var target2 = new MyActor
var sendMessageCalls:List[(Actor, String)] = Nil
/*
* Create a fake implementation of sendMessage
* that tracks the arguments it was called with
* in the sendMessageCalls list:
*/
myActor.sendMessage = (actor, message) => {
Log.trace("fake sendMessage called")
message match {
case OUTGOING_1(payload) => {
sendMessageCalls = (actor, payload) :: sendMessageCalls
}
case _ => { fail("Unexpected Message sent:"+message) }
}
}
// run the test
myActor.start
myActor.reactImpl(Incoming(target1, target2, true))
// assert the results
assertEquals(1, sendMessageCalls.size)
val(sentActor, sentPayload) = sendMessageCalls(0)
assertSame(target1, sentActor)
assertEquals("foo", sentPayload)
// .. etc.
My attempt at unit testing an actor (it works). I'm using Specs as a framework.
object ControllerSpec extends Specification {
"ChatController" should{
"add a listener and respond SendFriends" in{
var res = false
val a = actor{}
val mos = {ChatController !? AddListener(a)}
mos match{
case SendFriends => res = true
case _ => res = false
}
res must beTrue
}
How this works is by sending a synchronous call to the singleton ChatController. ChatController responds by use of reply(). The response is sent as a return of the called function, which gets stored into mos. Then a match is applied to mos getting the case class that was sent from ChatController. If the result is what is expected (SendFriends) set res to true. The res must beTrue assertion determines the success or failure of test.
My actor singleton that I'm testing
import ldc.socialirc.model._
import scala.collection.mutable.{HashMap, HashSet}
import scala.actors.Actor
import scala.actors.Actor._
import net.liftweb.util.Helpers._
//Message types
case class AddListener(listener: Actor)
case class RemoveListener(listener: Actor)
case class SendFriends
//Data Types
case class Authority(usr: Actor, role: String)
case class Channel(channelName: String, password: String, creator: String, motd: String, users: HashSet[Authority])
object ChatController extends Actor {
// The Channel List - Shows what actors are in each Chan
val chanList = new HashMap[String, Channel]
// The Actor List - Shows what channels its in
val actorList = new HashMap[Actor, HashSet[String]]
def notifyListeners = {
}
def act = {
loop {
react {
case AddListener(listener: Actor)=>
actorList += listener -> new HashSet[String]
reply(SendFriends)
}
}
}
start //Dont forget to start
}
Though its not complete it does return the Sendfriends case class as expected.
Suite for unit testing of Actors has recently been added to Akka. You can find some information and code snippets in this blogpost.