Unit testing redux-saga task cancellation - unit-testing

I was wondering if anyone had any tips on how to unit-test the following redux-saga login/logout flow:
let pollingTask = null
function * handleLogin () {
try {
const token = yield call(loginHandler)
pollingTask = yield fork(handlePolls, token)
yield put('LOGIN_SUCCSES')
} catch (e) {
yield put('LOGIN_FAILURE')
}
}
function * handlePolls (token) {
while (true) {
try {
yield call(pollHandler, token)
yield put('POLL_SUCCESS')
} catch (e) {
yield put('POLL_FAILURE')
} finally {
if (yield cancelled()) {
yield call(pollCancelled)
}
}
}
}
function * handleLogout () {
try {
yield call(logoutHandler)
yield cancel(pollingTask)
yield put('LOGOUT_SUCCESS')
} catch (e) {
yield put('LOGOUT_FAILURE')
}
}
Since I need to cancel the pollingTask on logout, I tried using createMockTask() in my tests but I always get its value as undefined when I invoke the handleLogout() saga, although I know that my handleLogin() would always be started first and it would initialize the pollingTask.
Any help would be much appreciated!

To make the function go to yield cancelled() you call .return() on the iterator.
An example -
//assuming this saga
function* saga() {
try {
const resp = yield call(someApi)
yield put(action(resp))
} finally {
if(yield cancelled()) {
// handle logic specific to cancellation. For example
yield <some effect>
}
}
}
// test
const gen = saga()
expect(gen.next().value).toEqual(call(someApi))
// simulates cancellation
// gen asking for cancel status
expect(gen.return().value).toEqual( cancelled() )
// answer yes, we've been cancelled
expect(gen.next(true).value).toEqual(<some effect>)
Example taken from https://github.com/redux-saga/redux-saga/issues/266#issuecomment-216087030

Related

Problems about using C++ coroutines

I'm experimenting the incoming C++ coroutines with liburing.
I'm a JavaScript developer and trying to implement a function like Promise.all
My first attempt
template <typename T>
task<std::vector<T>> taskAll1(std::vector<task<T>> list) {
std::vector<T> result;
result.reserve(list.size());
for (auto&& t : list) {
result.push_back(co_await t);
}
co_return result;
}
task is modified from gor_task. I mainly make task::promise_type::initial_suspend return suspend_never to let coroutines start by default.
The usage:
// async_delay: https://github.com/CarterLi/liburing-http-demo/blob/12af992d0d87a721bbe67bb67aee8e4b0e965114/async_coro.hpp#L68
// It waits some seconds asynchronously and then prints the number of seconds it waits.
task<bool> start() {
// TODO: less verbose code?
std::vector<task<int>> vec;
vec.emplace_back(async_delay(1));
vec.emplace_back(async_delay(2));
vec.emplace_back(async_delay(3));
co_await taskAll<int>(std::move(vec));
co_return true;
}
The code works as expected. But if I rearrange the order of emplace_backs, for example let async_delay(2) come before async_delay(1), the code still runs but freezes at the end of program. I know it is because the task async_delay(1) is resolved before it's awaited, but I have no idea how to fix it.
The second attempt, what I want to to do is translating following JS code into C++
/** #param {Promise<any>[]} list */
function taskAll(list) {
return new Promise(resolve => {
const result = new Array(list.length);
let left = list.length;
list.forEach((p, i) => {
p.then(x => {
result[i] = x;
left--;
if (!left) resolve(result);
})
});
});
}
The c++ code
// completion: https://github.com/CarterLi/liburing-http-demo/blob/12af992d0d87a721bbe67bb67aee8e4b0e965114/task.hpp#L78
// It's like JS Promise and can be awaited directly without calling an async function
template <typename T>
task<std::vector<T>> taskAll(std::vector<task<T>> list) {
std::vector<T> result(list.size());
size_t left = list.size();
completion<std::vector<T>> promise;
for (size_t i=0; i<list.size(); ++i) {
[&, i]() mutable -> task<bool> {
result[i] = co_await list[i];
left--;
if (!left) promise.resolve(std::move(result));
co_return true;
}();
}
co_await promise;
co_return result;
}
The code crashes immediately. Async code is really hard to debug and I gave up.
Full code can be found in Github, please help.
For 2nd attempt, I found that I forgot to assign the task returned by lambda expression, which make the task destruct immediately after the lambda function returned.

C++ wrap multiple returns

I have the following code which returns ERROR in many lines:
bool func()
{
if (acondition)
{
return 0;
}
return 1;
}
int cmdfun()
{
other_funcs;
if (func()) return ERROR#NUMBER;
other_funcs;
if (func()) return ERROR#NUMBER;
}
But I found its becoming longer and longer. How can I encapsulate return ERROR#NUMBER into func() also? Or any way to encapsulate if (func()) return ERROR; into another independent function?
You can't really achieve this using return on its own.
But you could throw an exception in func which will bubble up the call stack, in the way you seem to want program control to:
struct myexception{}; /*ToDo - inherit from std::exception?*/
bool func()
{
if (acondition){
return 0; /*normal behaviour, perhaps make `func` void if not needed?*/
}
throw myexception();
}
cmdfun then takes the form:
int cmdfun()
{
other_funcs;
func();
other_funcs;
func();
/* don't forget to return something*/
}
Finally, make sure you catch the exception in the caller to cmdfun.
As I said it is not an exception and cannot be handled by std::exception, it is just an error message and ERROR#NUMBER is just another macro. And I cannot access to the caller to cmdfun(). So unable to adopt the first answer. But after asked someone else, it is possible to encapsulate returns and save time when typing them, though it's not recommended, but in this particular case, I can use macro. A complete example is given below:
#include <iostream>
using namespace std;
#define CHECK_VEC(acondition)\
if(checkcondition(acondition)) return -1;
bool checkcondition(bool acondition)
{
if (acondition) return 1;
return 0;
}
int fun_called_by_main()
{
int a = 5 + 4;
bool acondition = a;
CHECK_VEC(acondition);
return 1;
}
int main()
{
int a = fun_called_by_main();
cout << a << endl;
cin.get();
return 0;
}
If I understood corectly your question, you are asking for an 'error reporter' for your own errors. There are 2 solutions for 2 separate cases:
Case 1 - you still want to use a return statement to make an 'error reporter':
To do this, you'll have to make another function or just learn how to use goto. However, you don't need to - your function returns a boolean(bool) - which means you only have 2 possible results: 0 (False) and 1 (True)
bool func()
{
if (acondition)
{
return (bool)0; // False (no error)
}
return (bool)1; // True (error)
// Note: I used (bool)0 and (bool)1 because it is
// more correct because your returning type is bool.
}
void errorcase(bool trueorfalse)
{
switch(trueorfalse)
{
case False:
... // your code (func() returned 0)
break;
default:
... // your code (func() returned 1)
break;
// Note that you will not need to check if an error occurred every time.
}
return;
}
int cmdfun()
{
... // your code
errorcase(func());
... // again - your code
return 0; // I suppouse that you will return 0...
}
But I think that the second case is more interesting (unfortunetly it is also preety hard to understand as a beginner and the first solution might be a lot easier for you):
Case 2 - you decided to do it somehow else - that's by learning throw and catch - I won't repeat the answer because it is already given: #Bathsheba answered preety good...

getting deprecation error, Do not use `.then` on an instance of Ember.Application.(using mocha-adapter and ember 1.7)

I recently upgraded my ember version from 1.5 to 1.7. Everything is working fine, expect for when I run my tests I get this annoying warning message :
DEPRECATION: Do not use `.then` on an instance of Ember.Application. Please use the `.ready` hook instead.
I am using mocha adapter, but I don't think its anyhow related to the adapter because when I created a simple jsbin using this adapter I did not get any messages. This message shows up when ever in my test I use andThen(function(){ .... }). The call that causes this warning message originates from this function:
//IN ember.js file
function wait(app, value) {
return Test.promise(function(resolve) {
// If this is the first async promise, kick off the async test
if (++countAsync === 1) {
Test.adapter.asyncStart();
}
// Every 10ms, poll for the async thing to have finished
var watcher = setInterval(function() {
// 1. If the router is loading, keep polling
var routerIsLoading = !!app.__container__.lookup('router:main').router.activeTransition;
if (routerIsLoading) { return; }
// 2. If there are pending Ajax requests, keep polling
if (Test.pendingAjaxRequests) { return; }
// 3. If there are scheduled timers or we are inside of a run loop, keep polling
if (run.hasScheduledTimers() || run.currentRunLoop) { return; }
if (Test.waiters && Test.waiters.any(function(waiter) {
var context = waiter[0];
var callback = waiter[1];
return !callback.call(context);
})) { return; }
// Stop polling
clearInterval(watcher);
// If this is the last async promise, end the async test
if (--countAsync === 0) {
Test.adapter.asyncEnd();
}
// Synchronously resolve the promise
run(null, resolve, value);//THIS CAUSES THE WARNING MESSAGE
}, 10);
});
}
and then ends up here which finally gives the warning:
//IN ember.js file
__exports__.inspect = inspect;// The following functions are intentionally minified to keep the functions
// below Chrome's function body size inlining limit of 600 chars.
function apply(t /* target */, m /* method */, a /* args */) {
var l = a && a.length;
if (!a || !l) { return m.call(t); }
switch (l) {
case 1: return m.call(t, a[0]);
case 2: return m.call(t, a[0], a[1]);//this is executed with a[0] as a function that seems like a promise
case 3: return m.call(t, a[0], a[1], a[2]);
case 4: return m.call(t, a[0], a[1], a[2], a[3]);
case 5: return m.call(t, a[0], a[1], a[2], a[3], a[4]);
default: return m.apply(t, a);
}
}
the function that is passed as an argument to case 2 is :
function (value) {
if (sealed) { return; }
sealed = true;
if (thenable !== value) {
resolve(promise, value);
} else {
fulfill(promise, value);
}
}
Any idea how I am avoid getting this warning message. thanks.
UPDATE :
I think I found atleast one of the reasons for this issue which was caused by the registerAsyncHelper. We have a helper written as :
Ember.Test.registerAsyncHelper('clickCheckbox', function(app, selector, context) {
var $el = findWithAssert(selector, context);
Ember.run($el, 'mousedown');
Ember.run($el, 'mouseup');
Ember.run($el, 'click');
// Workaround for IE8 because programmatically clicking a checkbox
// does not fire the "change" event
Ember.run($el, 'change');
return wait(app);
});
so if I don't use this helper, the issue seems to disappear! Also if I were to do return wait() instead of wait(app), things work.

Exit workflow early based on the result of an activity

I think my question has a straight forward answer, I just can't seem to find it.
I have a basic workflow:
private void doWorkflow() {
Promise<Boolean> result = activityClient.checkSomething();
if (result.get() == true) {
//exit
}
activityClient.doSomething();
}
The first problem is I cannot seem to get the result within the workflow. I have to go to an #asynchronous method to get the result. Secondly, if I were to use an #asynchronous method to determine if I should exit early then I'm back to square one since #asynchronous methods need to return a promise.
Thanks in advance
I would rewrite your code as:
private void doWorkflow() {
Promise<Boolean> result = activityClient.checkSomething();
doSomething(result);
}
#Asynchronous
private void doSomething(Promise<Boolean> flag) {
if (!flag.get()) {
activityClient.doSomething();
}
}
If you don't want to use #Asynchronous method you can use Task directly:
private void doWorkflow() {
final Promise<Boolean> result = activityClient.checkSomething();
new Task(result) {
public void do Execute() {
if (!result.get()) {
activityClient.doSomething();
}
}
};
}

Understanding an example about resumable functions in proposal N3650 for C++1y

Consider the following example taken from N3650:
int cnt = 0;
do {
cnt = await streamR.read(512, buf);
if (cnt == 0)
break;
cnt = await streamW.write(cnt, buf);
} while (cnt > 0);
I am probably missing something, but if I understood async and await well, what is the point in showing the usefulness of the two constructs with the above example when the effects are equivalent to writing:
int cnt = 0;
do {
cnt = streamR.read(512, buf).get();
if (cnt == 0)
break;
cnt = streamW.write(cnt, buf).get();
} while (cnt > 0);
where both the read().get() and write().get() calls are synchronous?
The await keyword is not equal to calling get on a future. You might look at it more like this, suppose you start from this:
future<T> complex_function()
{
do_some_stuff();
future<Result> x = await some_async_operation();
return do_some_other_stuff(x);
}
This is functionally more or less the same as
future<T> complex_function()
{
do_some_stuff();
return some_async_operation().then([=](future<Result> x) {
return do_some_other_stuff(x);
});
}
Note the more or less, because there are some resource management implications, variables created in do_some_stuff shouldn't be copied to execute do_some_other_stuff like the lambda version will do.
The second variant makes it more clear what will happen upon invocation.
The do_some_stuff() will be invoked synchronously when you call complex_function.
some_async_operation is called asynchronously and results in a future. The exact moment when this operation is executed depends on your actual asynchronous calling implementation, it might be immediate when you use threads, it might be whenever the .get() is called when you use defered execution.
We don't execute do_some_other_stuff immediately, but rather chain it to the future obtained in step 2. This means that it can be executed as soon as the result from some_async_operation is ready but not before. Aside from that, it's moment of execution is determined by the runtime. If the implementation would just wrap the then proposal, this means it would inherit the parent future's executor/launch policy (as per N3558).
The function returns the last future, that represents the eventual result. Note this NEEDS to be a future, as part of the function body is executed asynchronously.
A more complete example (hopefully correct):
future<void> forwardMsgs(istream& streamR, ostream& streamW) async
{
char buf[512];
int cnt = 0;
do {
cnt = await streamR.read(512, buf);
if (cnt == 0)
break;
cnt = await streamW.write(cnt, buf);
} while (cnt > 0);
}
future<void> fut = forwardMsgs(myStreamR, myStreamW);
/* do something */
fut.get();
The important point is (quoting from the draft):
After suspending, a resumable function may be resumed by the scheduling logic of the runtime and will eventually complete its logic, at which point it executes a return statement (explicit or implicit) and sets the function’s result value in the placeholder.
and:
A resumable function may continue execution on another thread after resuming following a suspension of its execution.
That is, the thread who originally called forwardMsgs can return at any of the suspension points. If it does, during the /* do something */ line, the code inside forwardMsgs can be executed by another thread even though the function has been called "synchronously".
This example is very similar to
future<void> fut = std::async(forwardMsgs, myStreamR, myStreamW);
/* do something */
fut.get();
The difference is the resumable function can be executed by different threads: a different thread can resume execution (of the resumable function) after each resumption/suspension point.
I think the idea is that the streamR.read() and streamW.write() calls are asynchronous I/O operations and return futures, which are automatically waited on by the await expressions.
So the equivalent synchronous version would have to call future::get() to obtain the results e.g.
int cnt = 0;
do {
cnt = streamR.read(512, buf).get();
if (cnt == 0)
break;
cnt = streamW.write(cnt, buf).get();
} while (cnt > 0);
You're correct to point out that there is no concurrency here. However in the context of a resumable function the await makes the behaviour different to the snippet above. When the await is reached the function will return a future, so the caller of the function can proceed without blocking even if the resumable function is blocked at an await while waiting for some other result (e.g. in this case the read() or write() calls to finish.) The resumable function might resume running asynchronously, so the result becomes available in the background while the caller is doing something else.
Here's the correct translation of the example function to not use await:
struct Copy$StackFrame {
promise<void> $result;
input_stream& streamR;
output_stream& streamW;
int cnt;
char buf[512];
};
using Copy$StackPtr = std::shared_ptr<Copy$StackFrame>;
future<void> Copy(input_stream& streamR, output_stream& streamW) {
Copy$StackPtr $stack{ new Copy$StackFrame{ {}, streamR, streamW, 0 } };
future<int> f$1 = $stack->streamR.read(512, stack->buf);
f$1.then([$stack](future<int> f) { Copy$Cont1($stack, std::move(f)); });
return $stack->$result.get_future();
}
void Copy$Cont1(Copy$StackPtr $stack, future<int> f$1) {
try {
$stack->cnt = f$1.get();
if ($stack->cnt == 0) {
// break;
$stack->$result.set_value();
return;
}
future<int> f$2 = $stack->streamW.write($stack->cnt, $stack->buf);
f$2.then([$stack](future<int> f) { Copy$Cont2($stack, std::move(f)); });
} catch (...) {
$stack->$result.set_exception(std::current_exception());
}
}
void Copy$Cont2(Copy$StackPtr $stack, future<int> f$2) {
try {
$stack->cnt = f$2.get();
// while (cnt > 0)
if (cnt <= 0) {
$stack->$result.set_value();
return;
}
future<int> f$1 = $stack->streamR.read(512, stack->buf);
f$1.then([$stack](future<int> f) { Copy$Cont1($stack, std::move(f)); });
} catch (...) {
$stack->$result.set_exception(std::current_exception());
}
}
As you can see, the compiler transformation here is quite complex. The key point here is that, unlike the get() version, the original Copy returns its future as soon as the first async call has been made.
I have the same issue with the meaning of the difference between these two code samples. Let's re write them a little to be more complete.
// Having two functions
future<void> f (istream&streamR, ostream&streamW) async
{ int cnt = 0;
do {
cnt = await streamR.read(512, buf);
if (cnt == 0)
break;
cnt = await streamW.write(cnt, buf);
} while (cnt > 0);
}
void g(istream&streamR, ostream&streamW)
{ int cnt = 0;
do {
cnt = streamR.read(512, buf).get();
if (cnt == 0)
break;
cnt = streamW.write(cnt, buf).get();
} while (cnt > 0);
}
// what is the difference between
auto a = f(streamR, streamW);
// and
auto b = async(g, streamR, streamW);
You still need at least three stacks. In both cases main thread is not blocked. Is it assumption that await would be implemented by compiler more efficiently than future<>:get()?. Well, the one without await can be used now.
Thanks
Adam Zielinski