Integration testing with Akka-Camel - akka

I started on a new akka project and having an issue with akka-camel integration testing..
So I have a consumer actor and am trying to test if it is receiving the message I send
Here is the test
#Test
public void testConsumer() {
final String testXml = "<user>" +
"<firstName>First</firstName>" +
"<lastName>Last</lastName>" +
"</user>";
new JavaTestKit(_system) {{
final JavaTestKit probe = new JavaTestKit(_system);
final ActorRef subject2 = _system.actorOf(Consumer.mkProps(probe.getRef(), endPoint, "testConsumerActor"));
camel.template().sendBody(endPoint, testXml);
}};
}
The test fails with the following exception
15:15:02.442 [Camel (test-cdr) thread #0 - seda://testRecords] WARN o.a.c.component.seda.SedaConsumer - Error processing exchange. Exchange[Message: <user><firstName>First</firstName><lastName>Last</lastName></user>]. Caused by: [akka.camel.ActorNotRegisteredException - Actor [akka://test-cdr/user/$a] doesn't exist]
akka.camel.ActorNotRegisteredException: Actor [akka://test-cdr/user/$a] doesn't exist
at akka.camel.internal.component.ActorProducer$$anonfun$actorFor$1.apply(ActorComponent.scala:182) ~[akka-camel_2.10-2.2.3.jar:na]
at akka.camel.internal.component.ActorProducer$$anonfun$actorFor$1.apply(ActorComponent.scala:182) ~[akka-camel_2.10-2.2.3.jar:na]
at scala.Option.getOrElse(Option.scala:120) ~[scala-library-2.10.3.jar:na]
at akka.camel.internal.component.ActorProducer.actorFor(ActorComponent.scala:182) ~[akka-camel_2.10-2.2.3.jar:na]
When I debug through my test, I notice that before the constructor for my consumer is called, camel is sending the message. How do I prevent this? or am I missing anything?
SD

I had issue with Akka-Camel which seemed to be problem with Camel initialization. I had to wait for Camel to initialize before I could send messages.
It's descibed in Akka Camel - JMS messages lost - should wait for initialization of Camel?
Java version for Camel initialization was:
ActorRef producer = system.actorOf(new Props(SimpleProducer.class), "simpleproducer");
Timeout timeout = new Timeout(Duration.create(15, SECONDS));
Future<ActorRef> activationFuture = camel.activationFutureFor(producer,timeout, system.dispatcher());
activationFuture.onComplete(new OnComplete<ActorRef>() {
#Override
public void onComplete(Throwable arg0, ActorRef arg1)
throws Throwable {
producer.tell("First!!");
}
},system.dispatcher());
Are you performing any sort of Camel initialization in your test? If not, adding something like this may help.

Related

Sending message on Actor startup with real (non-temp) sender ActorRef?

I'd like an actor to send a message on startup and receive a reply later.
Sending the message from within preStart results in a temporary sender reference (because the Actor hasn't yet started?). So the reply will likely be a dead letter.
Any tips would be appreciated. Apologies if my premise is mis-informed - I am new to Akka.
One approach is to send a message to self in preStart:
class MyActor extends Actor {
def preStart(): Unit = {
self ! CallService
}
def receive = {
case CallService =>
(service ? ServiceRequest).mapTo[ServiceResponse].pipeTo(self)
case ServiceResponse =>
// do something with the response
}
}
As described in this answer, if you want the actor to send the message before it processes all other messages, then you could stash the other messages:
class MyActor extends Actor with Stash {
def preStart(): Unit = {
self ! CallService
}
def uninitialized: Receive = {
case CallService =>
(service ? ServiceRequest).mapTo[ServiceResponse].pipeTo(self)
unstashAll()
context.become(initialized)
case _ => stash() // if we get a message other than CallService, stash it
}
def initialized: Receive = {
case ServiceResponse =>
// do something with the response from the service
case ...
}
def receive = uninitialized
}
Your premise is indeed not correct: when preStart runs the actor is already fully started, it's self reference never is a temporary one. Without code it is impossible to help you further, though.
The sender should always be considered "temporary" -- cf. this blog post, for example:
The rule is simply never close over the sender method in a block of
code that is potentially executed in another thread, such as a
scheduled task or a Future. The trick is to capture the current sender
in a val, as illustrated below...
-- Closing Over An Akka Actor Sender In The Receive
Make a copy of sender, and then later when you are ready to reply, reply to that copy of the actorRef and not to "sender".

Program termination during quartz scheduler verification using power mockito

I am trying to verify the quartz scheduler process by mocking System.currentTimeMillis() using PowerMockito .
Scenario :
I have scheduled a job for May 6th 2016 12 hrs .For verification I am trying to mock the System.currentTimeMillis() to scheduled time. So, the quartz will trigger on that particular time.
Test Case :
#RunWith(PowerMockRunner.class)
#PrepareForTest({ QuartzSchedulerThread.class })
public class SampleExampleTest {
#Test
public void test() {
/**
* mock the system.current milliseconds
*/
PowerMockito.mockStatic(System.class);
long value=getMockedMilliseconds();
PowerMockito.when(System.currentTimeMillis()).thenReturn(value);
System.out.println("Mocked milliseconds"+value);
try {
SchedulerFactory sf = new StdSchedulerFactory(getProperties());
Scheduler sched = sf.getScheduler();
sched.start();
} catch (SchedulerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public long getMockedMilliseconds() {
Date expectedDate=new Date(116, 4, 6 , 11, 57);
long mokedMilliSeconds = expectedDate.getTime();
return mokedMilliSeconds;
}
public Properties getProperties(){
Properties properties = new Properties();
properties.setProperty("org.quartz.scheduler.skipUpdateCheck", "true");
// set other properties ...such as
properties.setProperty("org.quartz.jobStore.class",
"org.quartz.impl.jdbcjobstore.JobStoreTX");
properties.setProperty("org.quartz.jobStore.driverDelegateClass",
"org.quartz.impl.jdbcjobstore.PostgreSQLDelegate");
properties.setProperty("org.quartz.jobStore.tablePrefix", "QRTZ_");
properties.setProperty("org.quartz.jobStore.dataSource", "obulis");
//properties.setProperty("org.quartz.jobStore.misfireThreshold", "1000");
// Datasource configurations
properties.setProperty("org.quartz.dataSource.obulis.driver",
"org.postgresql.Driver");
properties.setProperty("org.quartz.dataSource.obulis.URL",
"jdbc:postgresql://192.168.27.43:5433/obulis");
properties.setProperty("org.quartz.dataSource.obulis.user", "postgres");
properties.setProperty("org.quartz.dataSource.obulis.password",
"Nuwaza123");
properties.setProperty("org.quartz.dataSource.obulis.maxConnections",
"5");
properties.setProperty("rg.quartz.dataSource.obulis.validationQuery",
"select 0");
properties.setProperty("org.quartz.threadPool.class",
"org.quartz.simpl.SimpleThreadPool");
properties.setProperty("org.quartz.threadPool.threadCount", "4");
return properties;
}
}
Problem:
While executing the test case the program terminates abruptly before starting the scheduler. If the PowerMock is removed it is starting the scheduler.
console:
Mocked milliseconds1462516020000
INFO [main] (MLog.java:80) - MLog clients using log4j logging.
INFO [main] (C3P0Registry.java:204) - Initializing c3p0-0.9.1.1 [built 15- March-2007 01:32:31; debug? true; trace: 10]
Picked up _JAVA_OPTIONS: -Djava.net.preferIPv4Stack=true
What will be the cause of it? How to mock and verify whether the job will trigger on that particular time ?
I think you're going down a very bad way... You shouldn't mock the types you don't own: https://github.com/mockito/mockito/wiki/How-to-write-good-tests#dont-mock-type-you-dont-own .
What exactly do you want to verify? That Quartz is working? Makes no sense - if it didn't the library wouldn't be released ;) If you do want to plug it in in the integration test, just run a normal Quartz job. Let that job do sth (produce an output) and then check if this output is present.

Akka Fault handling and Scheduler

What will happen, when I schedule a message in the constructor of my Actor and the actor fails (Exception) before the message was send?
When the actor is resumed or restarted, will the message send like nothing has happened?
When the actor is stopped, will the message send to the dead letter box?
When I start the timer in preStart(), will I have two scheduled message when the actor restarts after a failure?
The answers to your questions are as follows:
1) Yes, the actor will receive the message as long as you used the scheduler scheduleOnce variant that takes an ActorRef as an arg. Because an ActorRef is just a lightweight proxy based on an actor address, it can survive failures of the target actor and still route messages to it as long as it successfully restarts back up and re-binds to the address that the ActorRef represents/
2) Yes, if the ActorRef is for a path that is no longer represented in the ActorSystem then the message will be sent to deadletter instead.
3) Yes you will. If you do it in preStart or in the body of the actor (constructor) and the actor fails and restarts, then the scheduled will now have two jobs to do for the same ActorRef and thus two requests will eventually be received.
A little code to show all of this in action. Consider the following actor:
class TestSchedActor extends Actor{
import context._
override def preStart = {
context.system.scheduler.scheduleOnce(1 second, self, "bar")
}
def receive = {
case "foo" =>
val s:String = null
s.length
case "baz" =>
context stop self
case other =>
println(s"Got $other")
}
}
If you tested it in this way:
val system = ActorSystem("schedtest")
val ref = system.actorOf(Props[TestSchedActor])
ref ! "foo"
Then the output would be:
[ERROR] [04/03/2014 07:58:24.988] [schedtest-akka.actor.default-dispatcher-2] [ akka://schedtest/user/$a] null
java.lang.NullPointerException
at code.TestSchedActor$$anonfun$receive$1.applyOrElse(Asking.scala:27)
at akka.actor.ActorCell.receiveMessage(ActorCell.scala:498)
at akka.actor.ActorCell.invoke(ActorCell.scala:456)
at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:237)
at akka.dispatch.Mailbox.run(Mailbox.scala:219)
at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:386)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:262)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:975)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1478)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:104)
Got bar
Got bar
This shows both #1 and #3 as the actor still received the message after failure and actually received 2 as it re-scheduled again when it was restarted.
If you tested the actor like this:
val system = ActorSystem("schedtest")
val ref = system.actorOf(Props[TestSchedActor])
ref ! "baz"
Then you would see the following output:
[INFO] [04/03/2014 08:01:14.199] [schedtest-akka.actor.default-dispatcher-2] [akka://schedtest/user/$a] Message [java.lang.String] from
Actor[akka://schedtest/user/$a#687201705] to Actor[akka://schedtest/user/$a#687201705] was
not delivered. [1] dead letters encountered. This logging can be turned off or adjusted
with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
Provided you had not disabled deadletter logging.
I assume that your actor sends a message (using a scheduled task) to itself (using something like system.actorSelection to resolve self address).
Then:
1) Yes;
2) Yes;
3) Yes (moreover, if you start the timer in the constructor you'll get the same behavior).
To avoid all such issues you can start the timer in preStart(), save the received Cancellable into a local variable inside the Actor and then cancel it in postStop(). postStop() / preStart() are called from preRestart() / postRestart(), so your scheduled task will be rescheduled on Actor restarts and cancelled on Actor stop.

JMS Testing - JMSTemplate send not executed

I have code piece sending jms messages via Spring JMSTemplate. For testing the the method i use Mockito.
My code looks like following.... publishDialogueServiceMessage()->
brokerUrl = jmsQueueProperties.getProperty(MessageRouterConstants.JMS_QUEUE_URL);
LOG.info("The broker url is : {}", brokerUrl);
jmsTemplate.send(jmsQueueProperties.getProperty(MessageRouterConstants.QUEUE), new MessageCreator() {
#Override
public Message createMessage(Session session) throws JMSException {
ObjectMessage obj = session.createObjectMessage(serviceResponse);
messageSent = true;
return obj;
}
});
In above code to i set boolean variable true, to check that if the message is sent
My Test looks following,
#Before
public void setUp() throws Exception {
connectionFactory = Mockito.spy(new ActiveMQConnectionFactory(
"vm://localhost?broker.persistent=false"));
conn = connectionFactory.createConnection();
conn.start();
}
#After
public void cleanUp() throws Exception{
conn.stop();
}
#Test
public void testPublishDialogueServiceMessage()
{
ServiceResponse response = Mockito.mock(
ServiceResponse.class, Mockito.withSettings()
.serializable());
JmsTemplate mockTemplate = Mockito.mock(JmsTemplate.class);
java.util.Properties p = Mockito.mock(java.util.Properties.class);
Mockito.when(p.getProperty(MessageRouterConstants.QUEUE))
.thenReturn("outbound.request.queue");
mockTemplate.setConnectionFactory(connectionFactory);
mockTemplate.setDeliveryPersistent(true);
mockTemplate.setSessionAcknowledgeMode(2);
mockTemplate.setSessionTransacted(true);
ReflectionTestUtils.setField(publisher, "jmsQueueProperties", p);
ReflectionTestUtils.setField(publisher, "jmsTemplate", mockTemplate);
// test
publisher.publishDialogueServiceMessage(response);
ArgumentCaptor<MessageCreator> msgCreator = ArgumentCaptor.forClass(MessageCreator.class);
Mockito.verify(p, Mockito.times(2))
.getProperty(Mockito.anyString());
Mockito.verify(mockTemplate, Mockito.times(1)).send(
Mockito.anyString(), Mockito.any(MessageCreator.class));
//MessageCreator msgCrt = Mockito.spy(msgCreator.getValue());
//Assert.notNull(msgCrt);
Assert.isTrue(publisher.isMessageSent());
}
In test i facing an interesting problem as publisher.isMessageSent() always returns me FALSE indicating that send message seems not executed(?). but Mockito.verify(mockTemplate, Mockito.times(1)).send(Mockito.anyString(), Mockito.any(MessageCreator.class)); goes fine.
I am wondering what is the cause that my messageSent variable not setting. Can anyone shed some light what I might be doing wrong.
Simple, you have a mock for the jmsTemplate (your mockTemplate). When a method is invoked on a mock it doesn't do anything other than record the call to the mock. So the mock doesn't know that it should attempt to invoke the msgCreator.
Looking at your test I see some obvious issues that suggest a lack of knowledge of Mockito. Why are you setting all of those fields on mockTemplate? It is a mock, it will not use those fields anyway. This also suggests that you don't need the code in your #Before and #After.
If you REALLY want your test to send a message via JMS (and thereby invoke the message createor) you should use a spy on JmsTemplate instead of a mock. However, I would highly discourage this as your test will be dependent on an external system and you would in effect be testing JsmTemplate. The fact that your mock gets invoked properly is sufficient. The only additional thing I think you need to do is to invoke the message creator being passed to the mock to verify that it creates the message correctly.

Sending + processing multiple messages with Actors

When working with Actors, if an Actor needs to co-operate with multiple other Actors to fulfil a request then what's the recommended approach here? To be more precise, if Actor A (through processing message M) needs to retrieve information from Actor B + Actor C, then it can send messages asynchronously to Actor B + C, but how should it correlate the responses from Actor B + C to the original message M ?
I've looked at the Akka framework and can't see how this is done so have had to implement something myself whereby an Actor keeps track of what messages have been sent and attempts to correlate their responses back to the source message. I must be missing something as I would've thought that this type of behaviour would already be built into various Actor frameworks
Generally if you need to send a message and get a correlated response, you end up having to send some kind of nonce in the original message that the responder must return with its reply. This can be explicit or it can be supported in the messaging layer. Not sure about Akka, but that's how Erlang handles RPCs in OTP.
Just create a new actor and use that to preserve the context and stop it after a timeout or when it has performed the "join".
You can also use Future-composition instead of spawning an actor:
class A extends Actor {
def receive = {
case DoX(x) =>
val b = actorB ? DoYourPartOf(x) mapTo manifest[BResult]
val c = actorC ? DoYourPartOf(x) mapTo manifest[CResult]
b zip c map { case (b,c) => merge(b,c) } pipeTo sender
}
}
}
Or Dataflow:
class A extends Actor {
def receive = {
case DoX(x) => flow {
val b = actorB ? DoYourPartOf(x) mapTo manifest[BResult]
val c = actorC ? DoYourPartOf(x) mapTo manifest[CResult]
merge(b(),c())
} pipeTo sender
}
}
}