Testing akka FSM with futures - intellij-idea

I have an akka FSM actor which uses futures in states. For example:
when(StateA) {
case Event(str: String, _) =>
if (str == "ping") {
Future("await-ping").pipeTo(self)(sender)
goto(AwaitStateA)
} else {
stay() replying "stay-ping"
}
}
when(AwaitStateA) {
case Event(str: String, _) =>
goto(StateA) replying str
}
Tests for actor above using akka testkit:
val adaptation: TestFSMRef[State, Data, _ <: Actor]
"Switch between states A" must {
"should return `await-ping`" in {
adaptation ! "ping"
expectMsg("await-ping")
adaptation.stateName should be(StateA)
}
"should return `stay-ping`" in {
adaptation ! "pong"
expectMsg("stay-ping")
adaptation.stateName should be(StateA)
}
}
Full code for tests you can find on github: https://github.com/azhur/fsmtest
The Problem is that tests failed randomly (sometimes they all passed).
Failures appear in test "should return await-ping" -> "AwaitStateA was not equal to StateA".
Please help to find where am I mistaken.
I try to run tests from command line and from IDE (Intellij IDEA). Results are the same. When I run each test separately, is hard to catch failure.

The future is running on the global ExecutionContext (that you have imported) and there is a race between that and the calling thread dispatcher that is used by TestFSMRef.
I would not use TestFSMRef here. If it is important to verify the state transitions you can use the FSM transition listener instead. Something like this:
val adaptation: ActorRef = system.actorOf(Props[FsmSwitcher1])
"should return `await-ping`" in {
val transitionListener = TestProbe()
adaptation ! SubscribeTransitionCallBack(transitionListener.ref)
transitionListener.expectMsg(CurrentState(adaptation, StateA))
adaptation ! "ping"
expectMsg("await-ping")
transitionListener.expectMsg(Transition(adaptation, StateA, AwaitStateA))
transitionListener.expectMsg(Transition(adaptation, AwaitStateA, StateA))
}

Related

How iterate until the condition is met using kotlin and functional programming?

I'm using an API that returns a text like this:
BW3511,HGP,ITP,Canceled,32.
I have to continue fetching until I get a response that is not "Canceled".
this code fetches the data:
val flightResponse = async {
println("Started fetching Flight info.")
client.get<String>(FLIGHT_ENDPOINT).also {
println("Finished fetching Flight info.")
}
}
the client.get can only be called within The coroutineScope body, also the flightResponse type is Deferred<String>.
check if it is canceled:
fun isCanceled(
flightResponse: String
) : Boolean {
val (_, _, _, status, _) = flightResponse.split(",")
return status == "Canceled"
}
how can I repeat client.get<String>(FLIGHT_ENDPOINT) until my condition is met using Functional Programming style?
I tried using takeIf but I have to get at least one result and it cannot be a nullable type.
As said in the comment by #Jorn, this looks like an overuse of functional style. It can be implemented by a simple loop and this way it will be probably more clear to the reader:
fun getNextNotCancelled() {
while (true) {
val response = client.get<String>(FLIGHT_ENDPOINT)
if (!isCanceled(response)) return response
}
}
If your real case is more complex, so you have several filters, etc. or for any other reason you really need to do this declaratively, then you need to create some kind of an infinite generator. For classic synchronous code that means sequence and for asynchronous - flow.
Example using a sequence:
generateSequence { client.get<String>(FLIGHT_ENDPOINT) }
.first { !isCanceled(it) }
Flow:
flow {
while (true) {
emit(client.get<String>(FLIGHT_ENDPOINT))
}
}.first { !isCanceled(it) }
As you said you use coroutines, I assume you would like to go for the latter. And as you can see, it is pretty similar to our initial loop-based approach, only more complicated. Of course, we can create a similar generateFlow() utility function and then it would be shorter.

Kotlin: retain coroutine context in scenario with nested runBlocking

I'm fairly new to kotlin coroutines, and I have what I think is a somewhat esoteric use case related to how runBlocking and coroutine contexts interact.
To start with, a simple example. Let's say I've got a dead simple context element. Nothing fancy.
class ExampleContext(val s: String) : AbstractCoroutineContextElement(Key) {
companion object Key : CoroutineContext.Key<ExampleContext>
}
When I run these examples, they behave exactly the way I'd expect them to:
runBlocking(ExampleContext("foo")) {
println(coroutineContext[ExampleContext.Key]?.s) // prints "foo
}
runBlocking(ExampleContext("foo")) {
launch {
println(coroutineContext[ExampleContext.Key]?.s) // prints "foo"
}
}
runBlocking(ExampleContext("foo")) {
launch(ExampleContext("bar")) {
println(coroutineContext[ExampleContext.Key]?.s) // prints "bar"
}
}
When I do this it prints null (as I would expect it to, because it runBlocking defaults to having EmptyContext in its constructor):
runBlocking(ExampleContext("foo")) {
runBlocking {
println(coroutineContext[ExampleContext.Key]?.s) // prints null
}
}
So here's my conundrum. The docs (and all the guidance I've found on the web) basically say don't do this: runBlocking is supposed to be run at the outermost layer of the coroutine logic and that's it. No nesting. What I'm working on is a library that needs to populate some context for access inside code that I don't own that gets called later (basically, you can think of it like an interceptor). The rough pseudocode looks a little like this:
class MyLibrary(otherPeoplesLogic: OtherPeoplesBusinessLogic) {
fun <IN, OUT> execute(input: IN): OUT {
... do my library's thing, including adding in a custom context element ...
try {
return otherPeoplesLogic.execute(input)
} finally {
... do my library's cleanup ...
}
}
}
To support coroutines in OtherPeoplesBusinessLogic, all I'd really have to do is add runBlocking like this:
class MyLibrary(otherPeoplesLogic: OtherPeoplesBusinessLogic) {
fun <IN, OUT> execute(input: IN): OUT {
... do my library's thing ...
runBlocking(myCustomContext) {
try {
return otherPeoplesLogic.execute(input)
} finally {
... do my library's cleanup ...
}
}
}
}
So long as all OtherPeoplesBusinessLogic::execute does is launch/async/etc, everything is fine: myCustomContext will be accessible. What I'm worried about is what happens if OtherPeoplesBusinessLogic::execute (which I'm not in control of) misbehaves and does its own runBlocking call with no context argument passed at all: what I think will happen is that myCustomContext will just silently get dropped like the example above. Not good, because it needs to be accessible.
Phew. A lot of explanation. Thanks for bearing with me. :)
So my ultimate question here is this: is there anything I can do (outside of scolding the users of my library to not call runBlocking) to prevent an accidental nested runBlocking call from dropping my context? Or am I just out of luck here and should scrap the whole idea?

Why is the value not entering the list?

At 'urichecking2' log, I can see there is value. But in 'uriChecking' the uriList is null.
why the uriList.add not work??
private fun getPhotoList() {
val fileName = intent.getStringExtra("fileName")
Log.d("fileNameChecking", "$fileName")
val listRef = FirebaseStorage.getInstance().reference.child("image").child(fileName!!)
var tmpUrl:Uri = Uri.parse(fileName)
Log.d("firstTmpUri","$tmpUrl")
listRef.listAll()
.addOnSuccessListener { listResult ->
for (item in listResult.items) {
item.downloadUrl.addOnCompleteListener { task ->
if (task.isSuccessful) {
tmpUrl = task.result
Log.d("secondTmpUri","$tmpUrl")
Log.d("urichecking2","$task.result")
uriList.add(task.result)
} else {
}
}.addOnFailureListener {
// Uh-oh, an error occurred!
}
}
}
Log.d("thirdTmpUri","$tmpUrl")
Log.d("urichecking", "$uriList")
}
If I do this, the log is output in the order of first, third, and second, and the desired value is in second, but when third comes out, it returns to the value of first.
The listAll method (like most cloud APIs these days, including downloadUrl which you also use) is asynchronous, since it needs to make a call to the server - which may take time. This means the code executes in a different order than you may expect, which is easiest to see if you add some logging:
Log.d("Firebase","Before starting listAll")
listRef.listAll()
.addOnSuccessListener { listResult ->
Log.d("Firebase","Got listResult")
}
Log.d("Firebase","After starting listAll")
When you run this code it outputs:
Before starting listAll
After starting listAll
Got listResult
This is probably not the order you expected, but it perfectly explains why you can't see the list result. By the time your Log.d("urichecking", "$uriList") runs, none of the uriList.add(task.result) has been called yet.
The solution for this is always the same: any code that needs the list result, has to be inside the addOnCompleteListener callback, be called from there, or be otherwise synchronized.
So in its simplest way:
listRef.listAll()
.addOnSuccessListener { listResult ->
for (item in listResult.items) {
item.downloadUrl.addOnCompleteListener { task ->
if (task.isSuccessful) {
uriList.add(task.result)
Log.d("urichecking", "$uriList")
}
}
}
}
This is an incredibly common mistake to make if you're new to programming with asynchronous APIs, so I recommend checking out
Asynchronous programming techniques in the Kotlin language guide
How to get URL from Firebase Storage getDownloadURL
Can someone help me with logic of the firebase on success listener
Why does my function that calls an API or launches a coroutine return an empty or null value?

Unpredictable coroutines execution order?

This is what I thought:
When using coroutines you go piling up async ops and once you are done with synchronous op..call them in FIFO order..but that's not always true
In this example you get what I expected:
fun main() = runBlocking {
launch {
println("1")
}
launch {
println("2")
}
println("0")
}
Also here(with nested launch):
fun main() = runBlocking {
launch {
println("1")
}
launch {
launch {
println("3")
}
println("2")
}
println("0")
}
Now in this example with a scope builder and creating another "pile"(not the real term) the order changes but still..you get as expected
fun main() = runBlocking {
launch {
println("2")
}
// replacing launch
coroutineScope {
println("0")
}
println("1")
}
Finally..the reason of this question..example 2 with scope builder:
fun main() = runBlocking {
launch {
println("3")
}
coroutineScope {
launch {
println("1")
}
println("0")
}
println("2")
}
I get this:
0
3
1
2
Why??
Was my assumption wrong and that's not how coroutines work
If so..then how should I determine the correct order when coding
edited: I've tried running the same code on different machines and different platforms but always got the same result..also tried more complicated nesting to prove non-variability of results
And digging the documentation found that coroutines are just code transformation(as I initially thought)
Remember that even if the like to call them 'light-weight' threads they run in a single 'real' thread(note: without newSingleThreadContext)
Thus I chose to believe execution order is pre-established at compile-time and not decided at runtime
After all..I still can't anticipate the order..and that's what I want
Don't assume coroutines will be run in a specific order, the runtime will decide what's best to run when and in what order. What you may be interested in that will help is the kotlinx.coroutines documentation. It does a great job of explaining how they work and also provides some handy abstractions to help managing coroutines make more sense. I personally recommend checking out channels, jobs, and Deferred (async/await).
For example, if I wanted things done in a certain order by number, I'd use channels to ensure things arrived in the order I wanted.
runBlocking {
val channel = Channel<Int>()
launch {
for (x in 0..5) channel.send(x * x)
channel.close()
}
for (msg in channel) {
// Pretend we're doing some work with channel results
println("Message: $msg")
}
}
Hopefully that can give you more context or what coroutines are and what they're good for.

How can I silently catch panics in QuickCheck tests?

In the tests of my overflower_support crate, I have found that I get a lot of spurious reports of panics which are already handled using std::panic::catch_unwind(_). This is a bit unfortunate, as it obscures the real errors that may happen. The messages look like:
thread 'safe' panicked at 'arithmetic overflow', src/lib.rs:56
To quell those distracting messages, I introduced the dont_panic(..) function, which hijacks the panic handler, calls a closure and resets the panic handler when done, returning the closures result. It looks like this:
fn dont_panic<F, A, R>(args: A, f: F) -> R
where F: Fn(A) -> R
{
let p = panic::take_hook();
panic::set_hook(Box::new(|_| ()));
let result = f(args);
panic::set_hook(p);
result
}
However, using this function within the function to check somewhat surprisingly not only quells the desired messages, but also quickcheck's error output, which is obviously valuable to me. This occurs even when limiting tests to one thread.
#[test]
fn test_some_panic() {
fn check(x: usize) -> bool {
let expected = if x < 256 { Some(x) } else { None };
let actual = dont_panic(|| panic::catch_unwind(|| { assert!(x < 256); x }).ok());
expected == actual
}
quickcheck(check as fn(usize) -> bool);
}
How can I hide the caught panics from my code while keeping QuickCheck's panics visible?
The default panic handler is printing panic information unconditionally on stderr.
You want to register your own handler.
I've met the same problem and a few others, and I ended up writing a crate to solve them:
panic-control
With it, your example might be solved by running in a "quiet" thread (assuming you weren't interested in using catch_unwind specifically):
use panic_control::spawn_quiet;
#[test]
fn test_some_panic() {
fn check(x: usize) -> bool {
let expected = if x < 256 { Some(x) } else { None };
let h = spawn_quiet(|| { assert!(x < 256); x });
let actual = h.join().ok();
expected == actual
}
quickcheck(check as fn(usize) -> bool);
}
There were two problems with my approach:
The tests run in parallel (and quickcheck appears to add some parallelism of
its own, as -j 1 appears ineffective to quell the panic messages).
The message gets written (or otherwise suppressed by set_hook(_)) no
matter if there's a catch_unwind(_) or not.
However, dpc.pw's idea to distinguish based on files in the panic handler was
spot-on. I changed my approach to call an install_handler() function before
calling quickcheck(_), which I reproduce here in full:
use std::panic;
use std::sync::{Once, ONCE_INIT};
static HANDLER : Once = ONCE_INIT;
fn install_handler() {
HANDLER.call_once(|| {
let p = panic::take_hook();
panic::set_hook(Box::new(move|info| {
if info.location().map_or(false, |l| l.file() != "src/lib.rs" &&
!l.file().ends_with("/num/mod.rs")) {
p(info);
}
}));
})
}
This will quell the panic messages if the panic came from src/lib.rs (which
is my overflower_support code) or somewhere from /num/mod.rs (because the
Rust libcore code may panic, too).
Note that you could omit the Once, but this would add the handler multiple
times and increase the size of stack traces considerably while exacerbating
test performance.