Testing stop behavior of an EventSourcedBehavior in akka - akka

I have an EventSourcedBehavior that will eventually get a message which leads to one last event and then stops itself. Implementing this is not the problem, but when I want to test it I get a DeadLetter Message because the EventSourcedBehaviorTestKit sends a "GetState" message right after the runCommand. Problem is: the behavior stopped itself and cannot respond anymore.
I have looked into the api docs of EventSourcedBehaviorTestKit but cannot find a suitable method to achieve my goal.
Here is a simple test that showcases my problem:
"test behavior stop" in {
sealed trait Command
case object Hi extends Command
sealed trait Event
sealed trait State
case object Empty extends State
val behavior = EventSourcedBehavior[Command, Event, State](
PersistenceId.ofUniqueId("1"),
Empty,
(_,_) => Effect.none.thenStop(),
(_,_) => Empty)
val kit = EventSourcedBehaviorTestKit[Command, Event, State](system, behavior)
kit.runCommand(Hi)
}
[2022-10-31 19:30:30,059] [INFO] [akka.actor.LocalActorRef] [SomeSpec-akka.actor.default-dispatcher-3] [akka://SomeSpec/system/test/$a] - Message [akka.persistence.typed.internal.EventSourcedBehaviorImpl$GetState] to Actor[akka://SomeSpec/system/test/$a#-553414380] was not delivered. [1] dead letters encountered. If this is not an expected behavior then Actor[akka://SomeSpec/system/test/$a#-553414380] may have terminated unexpectedly. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
- must test behavior stop *** FAILED ***
[info] java.lang.AssertionError: Timeout (3 seconds) during receiveMessage while waiting for message.
[...]
build.sbt
---------
...
lazy val akkaVersion = 2.6.19
"com.typesafe.akka" %% "akka-actor-testkit-typed" % akkaVersion % Test,
"com.typesafe.akka" %% "akka-persistence-testkit" % akkaVersion % Test,
"org.scalatest" %% "scalatest" % "3.1.4" % Test
...
How can I setup the test so that I can run this command and then expect the behavior to stop?

Stopping is not testable with the EventSourcedBehaviorTestKit.
You can leverage the PersistentTestKit's in-memory journal and snapshot store and test using the ActorTestKit.
Alternatively, as of Akka 2.7.0, there's the ability to turn an EventSourcedBehavior into one that doesn't persist but exposes events and snapshots on probes (instead of the secret GetState command as the EventSourcedBehaviorTestkit does) and is testable using the BehaviorTestkit or ActorTestkit (though the ergonomics favor the former).

Related

Cypress | Chai assertions executes outside if else condition. Assertions are mentioned inside if condition

I am writing a cypress custom command, which fetches a json response from an API end point. I am writing some assertions on the json response. However, I have a if-else condition to be executed. See below.
cy.getReportJson('84b636f4-c8f0-4aa4-bdeb-15abf811d432',user).then(report=> {
if(services.request_criminal_record_check.include){
console.log('inside if')
cy.wait(30000)
expect(report.report_summary.rcmp_result.status).equal(data.expected_result.rcmp_result.status)
expect(report.report_summary.rcmp_result.overall_score).equal(data.expected_result.rcmp_result.overall_score)
expect(report.report_summary.rcmp_result.result).equal(data.expected_result.rcmp_result.result)
}
})
When I run this code in a spec file, the Output I get is as follows.
As you can see, the assertions are running, before the wait command is triggered.
I want cypress to wait for 30 seconds, so that the back-end runs its magic and generates a report and after 30 seconds, i wanna assert on the report json.
Even the console.log is printed after the assertions are executed.
Is this something related to the async nature of Cypress?
You need to queue the assertions. expect()... runs immediately, but cy.wait() is pausing the queue exection.
cy.wait(30000)
cy.then(() => {
expect(...).equal(...)
expect(...).equal(...)
expect(...).equal(...)
})

rxjava testScheduler race condition

I stumbled upon a weird testScheduler behavior that I cannot wrap my head around. The code below is greatly simplified, but it origins in a real life issue.
Consider this test:
#Test
fun testSchedulerFun(){
val testScheduler = TestScheduler()
val stringsProcessor = PublishProcessor.create<String>()
val completable = Completable.complete()
completable
.doOnComplete { stringsProcessor.onNext("onComplete") }
.subscribeOn(testScheduler)
.subscribe()
val testSubscriber = stringsProcessor
.subscribeOn(testScheduler) //this line of code messes the test
.test()
testScheduler.triggerActions()
testSubscriber
.assertValues("onComplete")
}
**When I subscribe the tested stringsProcessor on testScheduler, the test fails. When I remove that line it succeeds. **
The flow of events as I see it is:
triggerActions
completable and stringsProcessor are being subscribed and propagate their events downstream.
And apparently the stringsProcessor.onNext("onComplete") is evaluated after the testSubscriber has finished.
I want to know why
The reason the test fails is because stringProcessor has no subscriber the time you call onNext on it. That subscriber only comes after because you added the "this line messes up" subscribeOn.
There is no race condition involved because everything runs on the same thread in a deterministic order:
when the code executes completable ... subscribe() part, a task is queued with testScheduler that will perform the doOnComplete call.
when the code executes the test part, another task is queued with testScheduler that will observe the processor.
triggerActions executes task 1, which emits the value to no subscribers, then executes task 2 and now ready to observe the processor, but nothing comes.

Assertions in kotlin coroutines / callback

Fairly new to kotlin.
I'm testing a http client which executes the calls asynchronously and takes a callback as argument from the caller.
Now, let's assume the caller is a unit test. Asserting INSIDE the callback doesn't work obviously because it runs in some kind of background io thread (using Kluent for asserts, I really like the syntax).
client.query(identifier, uiCallback = {
System.out.println("Found a total of ${it.total} entries with identifier!")
signal.countDown()
it.total shouldBe 1
})
I could defer the assert to outside of the callback, but i think that's not very elegant.
In an android context with java i would have done something like "runOnUIThread" (before RX). I also have to use that api in android, so I'll run into that problem anyways.
I must be missing sg. very basic. Is is state of the art to use junit for kotlin anyways or is there a better way to go?
EDIT: That "signal" there is a CountdownLatch to wait for the asynchronous execution.
EDIT 2: Retrofit service definition:
#GET("Entity")
fun query(#Query("identifier") identifier: Array<String?> = arrayOfNulls(0),
#Query("_count") count:Int = 10): Call<ResponseBody>

How to unit test an Akka actor that sends a message to itself, without using Thread.sleep

I have a Scala unit test for an Akka actor. The actor is designed to poll a remote system and update a local cache. Part of the actor's design is that it doesn't attempt to poll while it's still processing or awaiting the result of the last poll, to avoid flooding the remote system when it experiences a slowdown.
I have a test case (shown below) which uses Mockito to simulate a slow network call, and checks that when the actor is told to update, it won't make another network call until the current one is complete. It checks the actor has not made another call by verifying a lack of interactions with the remote service.
I want to eliminate the call to Thread.sleep. I want to test the functionality of the actor without relying on waiting for a hardcoded time, in every test run, which is brittle, and wastes time. The test can poll or block, waiting for a condition, with a timeout. This will be more robust, and will not waste time when the test is passing. I also have the added constraint that I want to keep the state used to prevent extra polling var allowPoll limited in scope, to the internals of the PollingActor.
is there a way force a wait until the actor is finished messaging itself? If there's a way I can wait until then before trying to assert.
is it necessary to send the internal message at all? Couldn't I maintain the internal state with a threadsafe datastructure, such as java.util.concurrent.AtomicBoolean. I have done this and the code appears to work, but I'm not knowledgeable enough about Akka to know if it's discouraged -- a colleague recommended the self message style.
is there better, out-of-the-box functionality with the same semantics? Then I would opt for an integration test instead of a unit test, though I'm not sure if it would solve this problem.
The current actor looks something like this:
class PollingActor(val remoteService: RemoteServiceThingy) extends ActWhenActiveActor {
private var allowPoll: Boolean = true
def receive = {
case PreventFurtherPolling => {
allowPoll = false
}
case AllowFurtherPolling => {
allowPoll = true
}
case UpdateLocalCache => {
if (allowPoll) {
self ! PreventFurtherPolling
remoteService.makeNetworkCall.onComplete {
result => {
self ! AllowFurtherPolling
// process result
}
}
}
}
}
}
trait RemoteServiceThingy {
def makeNetworkCall: Future[String]
}
private case object PreventFurtherPolling
private case object AllowFurtherPolling
case object UpdateLocalCache
And the unit test, in specs2, looks like this:
"when request has finished a new requests can be made" ! {
val remoteService = mock[RemoteServiceThingy]
val actor = TestActorRef(new PollingActor(remoteService))
val slowRequest = new DefaultPromise[String]()
remoteService.makeNetworkCall returns slowRequest
actor.receive(UpdateLocalCache)
actor.receive(UpdateLocalCache)
slowRequest.complete(Left(new Exception))
// Although the test calls the actor synchronously, the actor calls *itself* asynchronously, so we must wait.
Thread.sleep(1000)
actor.receive(UpdateLocalCache)
there was two(remoteService).makeNetworkCall
}
The way we have chosen to solve this for now is to inject the equivalent of an observer into the actor (piggybacking on an existing logger which wasn't included in the listing in the question). The actor can then tell the observer when it has transitioned from various states. In the test code we perform an action then wait for the relevant notification from the actor, before continuing and making assertions.
In the test we have something like this:
actor.receive(UpdateLocalCache)
observer.doActionThenWaitForEvent(
{ actor.receive(UpdateLocalCache) }, // run this action
"IgnoredUpdateLocalCache" // then wait for the actor to emit an event
}
// assert on number of calls to remote service
I don't know if there's a more idiomatic way, this seems like a reasonable suggestion to me.

Does the child actor know that he is being resumed?

Imagine a straight-forward supervision hierarchy. The child dies. The father decides to Restart the child. When Restarted, the postRestart and friends are called, but what if the father had decided to resume the child? Does the child actor know that he is being resumed? And btw. does the father have access to the message that caused the exception in his child?
Resume means “nothing really happened, carry on” and in this spirit the child is not even informed. It is a directive which should rarely be used.
The parent does only get the failure itself (i.e. the Throwable), not the message which caused the problem, because that would invite you to entangle the logic of parent and child beyond what is healthy.
The term resume means continue processing messages and is referred to at two points in the documentation.
The first is used in response to an exception state:
As per akka documentation:
As described in Actor Systems supervision describes a dependency relationship between actors: the supervisor delegates tasks to subordinates and therefore must respond to their failures. When a subordinate detects a failure (i.e. throws an exception), it suspends itself and all its subordinates and sends a message to its supervisor, signaling failureDepending on the nature of the work to be supervised and the nature of the failure, the supervisor has a choice of the following four options:
Resume the subordinate, keeping its accumulated internal state
Restart the subordinate, clearing out its accumulated internal state
Terminate the subordinate permanently
Escalate the failure, thereby failing itself
Note that RESTART actually KILLS the original actor. The term resume is used again here meaning to continue processing messages.
As per the akka documentation.
The precise sequence of events during a restart is the following:
- suspend the actor (which means that it will not process normal messages until resumed), and recursively suspend all children
- call the old instance’s preRestart hook (defaults to sending termination requests to all children and calling postStop)
- wait for all children which were requested to terminate (using context.stop()) during preRestart to actually terminate; this—like all actor operations—is non-blocking, the termination notice from the last killed child will effect the progression to the next step
- create new actor instance by invoking the originally provided factory again
- invoke postRestart on the new instance (which by default also calls preStart)
- send restart request to all children which were not killed in step 3; restarted children will follow the same process recursively, from step 2
- resume the actor
You can have the failure bubble up to the Supervisor if you properly set up that kind of behavior in the supervisorStrategy of the supervisor. A little example to show that behavior:
import akka.actor.Actor
import akka.actor.Props
import akka.actor.ActorSystem
object SupervisorTest {
def main(args: Array[String]) {
val system = ActorSystem("test")
val master = system.actorOf(Props[Master], "master")
master ! "foo"
Thread.sleep(500)
val worker = system.actorFor("/user/master/foo")
worker ! "bar"
}
}
class Master extends Actor{
import akka.actor.OneForOneStrategy
import akka.actor.SupervisorStrategy._
import scala.concurrent.duration._
override val supervisorStrategy =
OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
case _: Exception => Escalate
Escalate
}
override def preRestart(ex:Throwable, msg:Option[Any]) = {
println("In master restart: " + msg)
}
def receive = {
case msg:String =>
context.actorOf(Props[Worker], msg)
}
}
class Worker extends Actor{
override def preRestart(ex:Throwable, msg:Option[Any]) = {
println("In worker restart: " + msg)
}
def receive = {
case _ =>
throw new Exception("error!!")
}
}
You can see in the Master actor (the supervisor in my example), I am choosing to Escalate a failure of type Exception. This will cause the failure to bubble up to the preRestart in the Master actor. Now I was expecting the msg param to preRestart to be the original offending message that went to the worker actor, but it wasn't. The only way I got that to show was be also overriding the preRestart of the child actor. In my example, you will see the print outs from both the supervisor and child, in that order.