I have refactored a bunch of email sending code in a play application to do that asynchronously using an actor.
When I need to send an email, I now have an injection of an EmailActor and I call emailActor ? EmailRequest(from, to, ...) to send it.
My question is, how can I unit test that the actor is actually called ?
I read the documentation of Akka regarding tests, but it seems to me it focuses on testing the actor themselves, not their invocation, and it is not clear at all where I should start.
You can use a TestProbe and inject it into your email service. Check out this simple test case
import akka.actor.{ActorRef, ActorSystem}
import akka.pattern.ask
import akka.testkit.{TestKit, TestProbe}
import akka.util.Timeout
import org.scalatest.flatspec.AsyncFlatSpecLike
import scala.concurrent.Future
import scala.concurrent.duration._
class TestProbeActorExample
extends TestKit(ActorSystem("test"))
with AsyncFlatSpecLike {
class MyService(actorRef: ActorRef) {
def sendEmail(email: String): Future[Int] = {
implicit val timeout: Timeout = 1.second
(actorRef ? email).mapTo[Int]
}
}
it should "test an actor" in {
val testProbe = TestProbe()
val service = new MyService(testProbe.ref)
val statusCode = service.sendEmail("email")
testProbe.expectMsg("email")
testProbe.reply(10)
statusCode.map(r => assert(r == 10))
}
}
Please note if you use ask pattern you need to assert that a message has been received with expectMsg and then you have to send a reply back with reply
Related
Using below code I'm attempting to limit the amount of messages send to an actor within a specified time frame. But the messages are not being throttled and are being sent as quickly as possible. The downstream actor just makes a http request to the Google home page.
The throttler code where I attempt to limit 3 messages to be sent within 3 seconds :
val throttler: ActorRef =
Source.actorRef(bufferSize = 1000, OverflowStrategy.dropNew)
.throttle(3, 1.second)
.to(Sink.actorRef(printer, NotUsed))
.run()
How can I limit the number of messages sent within loop :
for( a <- 1 to 10000){
// Create the 'greeter' actors
val howdyGreeter: ActorRef =
system.actorOf(Greeter.props(String.valueOf(a), printer), String.valueOf(a))
howdyGreeter ! RequestActor("RequestActor")
howdyGreeter ! Greet
}
to 3 per second ?
entire code :
//https://developer.lightbend.com/guides/akka-quickstart-scala/full-example.html
import akka.NotUsed
import akka.stream.{OverflowStrategy, ThrottleMode}
import akka.stream.scaladsl.{Sink, Source}
import org.apache.http.client.methods.HttpGet
import org.apache.http.entity.StringEntity
import org.apache.http.impl.client.DefaultHttpClient
import net.liftweb.json._
import net.liftweb.json.Serialization.write
import org.apache.http.util.EntityUtils
//import akka.contrib.throttle.TimerBasedThrottler
import akka.actor.{Actor, ActorLogging, ActorRef, ActorSystem, Props}
import scala.concurrent.duration._
import akka.NotUsed
import akka.actor.ActorRef
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import akka.stream.OverflowStrategy
import akka.stream.ThrottleMode
import akka.stream.scaladsl.Sink
import akka.stream.scaladsl.Source
object Greeter {
def props(message: String, printerActor: ActorRef): Props = Props(new Greeter(message, printerActor))
final case class RequestActor(who: String)
case object Greet
}
class Greeter(message: String, printerActor: ActorRef) extends Actor {
import Greeter._
import Printer._
var greeting = ""
def receive = {
case RequestActor(who) =>
val get = new HttpGet("http://www.google.com")
val response = (new DefaultHttpClient).execute(get)
// val responseString = EntityUtils.toString(response.getEntity, "UTF-8")
// System.out.println(responseString)
greeting = String.valueOf(response.getStatusLine.getStatusCode)
println("message is "+message)
// greeting = message + ", " + who
case Greet =>
printerActor ! Greeting(greeting)
}
}
object Printer {
def props: Props = Props[Printer]
final case class Greeting(greeting: String)
}
class Printer extends Actor with ActorLogging {
import Printer._
def receive = {
case Greeting(greeting) =>
log.info("Greeting received (from " + sender() + "): " + greeting)
}
}
object AkkaQuickstart extends App {
import Greeter._
// Create the 'helloAkka' actor system
val system: ActorSystem = ActorSystem("helloAkka")
// Create the printer actor,this is also the target actor
val printer: ActorRef = system.actorOf(Printer.props, "printerActor")
implicit val materializer = ActorMaterializer.create(system)
val throttler: ActorRef =
Source.actorRef(bufferSize = 1000, OverflowStrategy.dropNew)
.throttle(3, 1.second)
.to(Sink.actorRef(printer, NotUsed))
.run()
//Create a new actor for each request thread
for( a <- 1 to 10000){
// Create the 'greeter' actors
val howdyGreeter: ActorRef =
system.actorOf(Greeter.props(String.valueOf(a), printer), String.valueOf(a))
howdyGreeter ! RequestActor("RequestActor")
howdyGreeter ! Greet
}
}
An actor cannot influence what other actors do, in particular it has no control over who puts messages in its mailbox and when — this is how the actor model works. An actor only gets to decide what to do with the messages it finds in its mailbox, and over this it has full control. It can for example drop them, send back error replies, buffer them, etc.
If you want throttling and back-pressure, I recommend not using Actors at all for this part, but only use Akka Streams. The code that generates your request messages should be a Source, not a for-loop. Which source is most appropriate depends entirely on your real use-case, e.g. creating a stream from a strict collection with Source.from() or asynchronously pulling new elements out of a data structure with Source.unfoldAsync plus many more. Doing it this way ensures that the requests are only emitted when the time is right according to the downstream capacity or rate throttling.
It does not appear to me that you're actually using the throttler:
val throttler: ActorRef =
Source.actorRef(bufferSize = 1000, OverflowStrategy.dropNew)
.throttle(3, 1.second)
.to(Sink.actorRef(printer, NotUsed))
.run()
But I don't see any messages being sent to throttler in your code: throttler will only throttle messages sent to throttler.
I have an actor whose sole responsibility is to forward messages it receives from external interfaces (command-line, user, etc.) to appropriate topics. I want to test that it correctly publishes these messages.
I will need to create some dummy subscriber who will expect messages published to a certain topic and make assertions about the messages it receives.
Here's my code that I attempted to realize that:
Messages.scala
case class Foo(foo: String)
InterfaceForwardingActor.scala
import akka.actor.{Actor, ActorLogging}
import akka.cluster.pubsub.{DistributedPubSub, DistributedPubSubMediator}
import com.typesafe.config.Config
/** Actor responsible for forwarding stimuli external to the system.
* For instance, messages from the command-line interface or from a UI.
*
*/
class InterfaceForwardingActor extends Actor with ActorLogging {
import DistributedPubSubMediator.Publish
protected val mediator = DistributedPubSub(context.system).mediator
log.info(s"Hello from interface forwarder.")
final val topic = "info"
def receive = {
case foo: Foo => {
log.info("Forwarding a Foo message")
mediator ! Publish(topic, foo)
}
}
}
and the test code
InterfaceForwardingActorTest.scala
import akka.actor.{ActorSystem, Props}
import akka.cluster.client.ClusterClient.Publish
import akka.cluster.pubsub.DistributedPubSub
import akka.testkit.{ImplicitSender, TestKit, TestProbe}
import com.typesafe.config.ConfigFactory
import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike}
class InterfaceForwardingActorTest extends
TestKit(ActorSystem("InterfaceForwardingActorSpec")) with ImplicitSender with
WordSpecLike with Matchers with BeforeAndAfterAll {
override def afterAll {
TestKit.shutdownActorSystem(system)
}
"An InterfaceForwardingActor" must {
val interfaceForwardingActor = system.actorOf(Props[InterfaceForwardingActor])
val probe = TestProbe()
val mediator = DistributedPubSub(system).mediator
// subscribe the test probe to the "info" topic
mediator ! Publish("info", probe.ref)
"publish a Foo message" in {
val msg = Foo("test")
interfaceForwardingActor ! msg
probe.expectMsg(msg)
}
}
}
What I find is that the probe, which is subscribed to the info topic, doesn't receive the message within the default timeout period of 3 seconds and the assertion fails. The interesting part, however, is that I do see the log message stating that the interface forwarding actor is indeed forwarding a Foo message.
What am I doing wrong in my test?
The TestProbe should be subscribed to the topic in the the test code:
mediator ! Subscribe("info", probe.ref)
instead of
mediator ! Publish("info", probe.ref)
Documentation page of distributed pub-sub is here, for reference.
MyService.scala:33: could not find implicit value for parameter eh: spray.routing.ExceptionHandler
I have run into a "missing implicit" compilation error using Akka, in spray.io code that makes an http call to a separate back-end server, as part of responding to an http get. The code needs to import quite a lot of Spray and Akka libraries, so it's a bit hard figuring whether there may be some library conflicts causing this, and I'd rather figure how to logically trace this sort of problem for this and other cases.
The missing implicit is encountered on calling runRoute(myRoute)
Here's the code:
import spray.routing._
import akka.actor.Actor
import akka.actor.ActorSystem
import spray.http._
import MediaTypes._
import akka.io.IO
import spray.httpx.RequestBuilding._
import scala.concurrent.Future
import spray.can.Http
import spray.http._
import akka.util.Timeout
import HttpMethods._
import akka.pattern.ask
import akka.event.Logging
import scala.concurrent.duration._
// we don't implement our route structure directly in the service actor because
// we want to be able to test it independently, without having to spin up an actor
class MyServiceActor extends Actor with MyService with akka.actor.ActorLogging {
log.info("Starting")
// the HttpService trait defines only one abstract member, which
// connects the services environment to the enclosing actor or test
def actorRefFactory = context
// this actor only runs our route, but you could add
// other things here, like request stream processing
// or timeout handling
def receive = runRoute(myRoute)
}
// this trait defines our service behavior independently from the service actor
trait MyService extends HttpService {
implicit val system: ActorSystem = ActorSystem()
implicit val timeout: Timeout = Timeout(15.seconds)
import system.dispatcher // implicit execution context
//val logger = context.actorSelection("/user/logger")
val logger = actorRefFactory.actorSelection("../logger")
val myRoute =
{
def forward(): String = {
logger ! Log("forwarding to backend")
val response: Future[HttpResponse] =
(IO(Http) ? Get("http:3080//localhost/backend")).mapTo[HttpResponse]
"<html><body><h1>api response after backend processing</h1></body></html>"
}
path("") {
get {
respondWithMediaType(`text/html`) { // XML is marshalled to `text/xml` by default, so we simply override here
complete(forward)
}
}
}
}
}
I am wondering what's the best way to solve this, hopefully providing insight into how to solve similar problems with implicits being missing, as they are somehow inherently not straightforward to track down.
EDIT: when trying to directly pass implicits as in #christian's answer below, I get:
MyService.scala:35: ambiguous implicit values:
both value context in trait Actor of type => akka.actor.ActorContext
and value system in trait MyService of type => akka.actor.ActorSystem
match expected type akka.actor.ActorRefFactory
RoutingSettings.default, LoggingContext.fromActorRefFactory)
^
Not quite sure why being specific as in #christian's answer leaves room for ambiguity for the compiler...
I ran into the same "could not find implicit value for parameter eh: spray.routing.ExceptionHandler" error earlier today. I tried #Christian's approach but saw a few "implicit values for xxx" creeping up. After scouting the error message a little I found adding implicit val system = context.system to the actor that runRoute solved the problem.
runRoute expects a few implicits. You are missing an import:
import spray.routing.RejectionHandler.Default
Update:
I think we also did have some problems with runRoute because we are supplying the implicit parameters explicitly:
runRoute(route)(ExceptionHandler.default, RejectionHandler.Default, context,
RoutingSettings.default, LoggingContext.fromActorRefFactory)
Update2:
To fix the last error, remove the creation of the ActorSystem (in MyService you get the actor system from MyServiceActor - therefore you have to use a self type annotation). This compiles:
import akka.actor.Actor
import akka.io.IO
import spray.httpx.RequestBuilding._
import spray.http.MediaTypes._
import spray.routing.{RoutingSettings, RejectionHandler, ExceptionHandler, HttpService}
import spray.util.LoggingContext
import scala.concurrent.Future
import spray.can.Http
import spray.http._
import akka.util.Timeout
import HttpMethods._
import akka.pattern.ask
import akka.event.Logging
import scala.concurrent.duration._
// we don't implement our route structure directly in the service actor because
// we want to be able to test it independently, without having to spin up an actor
class MyServiceActor extends Actor with MyService with akka.actor.ActorLogging {
log.info("Starting")
// the HttpService trait defines only one abstract member, which
// connects the services environment to the enclosing actor or test
implicit def actorRefFactory = context
// this actor only runs our route, but you could add
// other things here, like request stream processing
// or timeout handling
def receive = runRoute(myRoute)(ExceptionHandler.default, RejectionHandler.Default, context,
RoutingSettings.default, LoggingContext.fromActorRefFactory)
}
// this trait defines our service behavior independently from the service actor
trait MyService extends HttpService { this: MyServiceActor =>
implicit val timeout: Timeout = Timeout(15.seconds)
implicit val system = context.system
//val logger = context.actorSelection("/user/logger")
val logger = actorRefFactory.actorSelection("../logger")
val myRoute =
{
def forward(): String = {
//logger ! Log("forwarding to backend")
val response: Future[HttpResponse] =
(IO(Http) ? Get("http:3080//localhost/backend")).mapTo[HttpResponse]
"<html><body><h1>api response after backend processing</h1></body></html>"
}
path("") {
get {
respondWithMediaType(`text/html`) { // XML is marshalled to `text/xml` by default, so we simply override here
complete(forward)
}
}
}
}
}
I created the following Akka Actor code in Scala. Code works fine when a single workerActor is created. But code silently fails when I try to create a pool of worker actors using round robin logic. Any idea how to fix this? How do I get more debug info to be printed?
import scala.collection.immutable.Map
import scala.collection.mutable.ArrayBuffer
import akka.actor.actorRef2Scala
import akka.actor.ActorSystem
import akka.actor.Props
import scala.concurrent.Await
import scala.concurrent.duration._
import akka.pattern.ask
import akka.util.Timeout
import akka.actor._
import org.junit._
import org.junit.Assert._
import messaging.actors._
import akka.routing.RoundRobinRouter
import akka.routing._
class MainEngineActorTest {
#Test
def testMainActor () = {
val _system = ActorSystem("MainEngineActor")
val master = _system.actorOf(Props[MainEngineActor], name = "EngineActor")
println ("Created Main Engine Actor")
implicit val timeout = Timeout(5 seconds)
val userID = new UserID ("test1")
println ("Sending messages")
for (i <- ( 1 to 10)) {
master ! "Hello"
master ! "World"
}
}
}
class MainEngineActor extends Actor with ActorLogging{
// works if we create only a single workerActor
//val workerActors = context.actorOf(Props[WorkerActor], name = "WorkerActors")
// Doesn't work when we create a pool of worker actors - how do we fix this?
// why doesn't this work and why aren't any error messages printed?
val workerActors = context.actorOf(RoundRobinPool(5).props(Props[WorkerActor]), name = "WorkerActors")
def receive: Receive = {
case request => {
workerActors forward request
}
}
}
class WorkerActor extends Actor {
def receive: Receive = {
case request => {
println ("RequestReceived =" + request)
}
}
}
Try creating your pool like this instead:
val workerActors = context.actorOf(Props[WorkerActor].withRouter(RoundRobinPool(5)), name = "WorkerActors")
In addition, when running this as a Junit test, the program is terminating before the child actors have a chance to receive the message. I verified this by adding a Thread.sleep(5000) after the loop that is sending the Hello and World messages to master. I then tweaked your code a little bit to use Akka's TestActorRef from akka-testkit which will force everything to use the CallingThreadDispatcher to get synchronous execution throughout the test and everything works as expected. The two lines I changed are:
implicit val _system = ActorSystem("MainEngineActor")
val master = TestActorRef(new MainEngineActor())
I'm looking for some easy and short example how to connect and make interaction (two-ways) with tcp socket. In other words, how to write a scala 2.10 application (using akka-camel or netty library) to communicate with a tcp process (socket).
I found a lot of literature on Internet, but everything was old (looking for scala 2.10) and/or deprecated.
Thanks in advance!
hmm I was looking for something like this:
1. server:
import akka.actor._
import akka.camel.{ Consumer, CamelMessage }
class Ser extends Consumer {
def endpointUri = "mina2:tcp://localhost:9002"
def receive = {
case message: CamelMessage => {
//log
println("looging, question:" + message)
sender ! "server response to request: " + message.bodyAs[String] + ", is NO"
}
case _ => println("I got something else!??!!")
}
}
object server extends App {
val system = ActorSystem("some")
val spust = system.actorOf(Props[Ser])
}
2. Client:
import akka.actor._
import akka.camel._
import akka.pattern.ask
import scala.concurrent.duration._
import akka.util.Timeout
import scala.concurrent.Await
class Producer1 extends Actor with Producer {
def endpointUri = "mina2:tcp://localhost:9002"
}
object Client extends App {
implicit val timeout = Timeout(10 seconds)
val system2 = ActorSystem("some-system")
val producer = system2.actorOf(Props[Producer1])
val future = producer.ask("Hello, can I go to cinema?")
val result = Await.result(future, timeout.duration)
println("Is future over?="+future.isCompleted+";;result="+result)
println("Ende!!!")
system2.shutdown
println("system2 ended:"+system2.isTerminated)
I know it is everything written and well-described in http://doc.akka.io/docs/akka/2.1.0/scala/camel.html. But if you are novice you need to read it all and several times in order to build very simple client-server application. I think some kind of "motivation example" would be more than welcome.
I assume you have checked the Akka documentation? http://doc.akka.io/docs/akka/2.1.0/scala/camel.html
In Akka 2.1.0 they have improved the akka-camel module so its fully up to date (was a bit outdated before).
There is also a camel-akka video presentation, covering a real-life use case: http://www.davsclaus.com/2012/04/great-akka-and-camel-presentation-video.html