Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: add coverage for napi_cancel_async_work #12575

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion test/addons-napi/test_async/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ const common = require('../../common');
const assert = require('assert');
const test_async = require(`./build/${common.buildType}/test_async`);

test_async(5, common.mustCall(function(err, val) {
test_async.Test(5, common.mustCall(function(err, val) {
assert.strictEqual(err, null);
assert.strictEqual(val, 10);
process.nextTick(common.mustCall(function() {}));
}));

const cancelSuceeded = function() {};
test_async.TestCancel(common.mustCall(cancelSuceeded));
82 changes: 76 additions & 6 deletions test/addons-napi/test_async/test_async.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
#include <unistd.h>
#endif

// this needs to be greater than the thread pool size
#define MAX_CANCEL_THREADS 6

typedef struct {
int32_t _input;
int32_t _output;
Expand All @@ -15,6 +18,7 @@ typedef struct {
} carrier;

carrier the_carrier;
carrier async_carrier[MAX_CANCEL_THREADS];

struct AutoHandleScope {
explicit AutoHandleScope(napi_env env)
Expand Down Expand Up @@ -74,7 +78,7 @@ void Complete(napi_env env, napi_status status, void* data) {

napi_value result;
NAPI_CALL_RETURN_VOID(env,
napi_call_function(env, global, callback, 2, argv, &result));
napi_make_callback(env, global, callback, 2, argv, &result));

NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, c->_callback));
NAPI_CALL_RETURN_VOID(env, napi_delete_async_work(env, c->_request));
Expand Down Expand Up @@ -111,12 +115,78 @@ napi_value Test(napi_env env, napi_callback_info info) {
return nullptr;
}

void BusyCancelComplete(napi_env env, napi_status status, void* data) {
AutoHandleScope scope(env);
carrier* c = static_cast<carrier*>(data);
NAPI_CALL_RETURN_VOID(env, napi_delete_async_work(env, c->_request));
}

void CancelComplete(napi_env env, napi_status status, void* data) {
AutoHandleScope scope(env);
carrier* c = static_cast<carrier*>(data);

if (status == napi_cancelled) {
// ok we got the status we expected so make the callback to
// indicate the cancel succeeded.
napi_value callback;
NAPI_CALL_RETURN_VOID(env,
napi_get_reference_value(env, c->_callback, &callback));
napi_value global;
NAPI_CALL_RETURN_VOID(env, napi_get_global(env, &global));
napi_value result;
NAPI_CALL_RETURN_VOID(env,
napi_make_callback(env, global, callback, 0, nullptr, &result));
}

NAPI_CALL_RETURN_VOID(env, napi_delete_async_work(env, c->_request));
NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, c->_callback));
}

void CancelExecute(napi_env env, void* data) {
#if defined _WIN32
Sleep(1000);
#else
sleep(1);
#endif
}

napi_value TestCancel(napi_env env, napi_callback_info info) {
size_t argc = 1;
napi_value argv[1];
napi_value _this;
void* data;

// make sure the work we are going to cancel will not be
// able to start by using all the threads in the pool
for (int i = 1; i < MAX_CANCEL_THREADS; i++) {
NAPI_CALL(env, napi_create_async_work(env, CancelExecute,
BusyCancelComplete, &async_carrier[i], &async_carrier[i]._request));
NAPI_CALL(env, napi_queue_async_work(env, async_carrier[i]._request));
}

// now queue the work we are going to cancel and then cancel it.
// cancel will fail if the work has already started, but
// we have prevented it from starting by consuming all of the
// workers above.
NAPI_CALL(env,
napi_get_cb_info(env, info, &argc, argv, &_this, &data));
NAPI_CALL(env, napi_create_async_work(env, CancelExecute,
CancelComplete, &async_carrier[0], &async_carrier[0]._request));
NAPI_CALL(env,
napi_create_reference(env, argv[0], 1, &async_carrier[0]._callback));
NAPI_CALL(env, napi_queue_async_work(env, async_carrier[0]._request));
NAPI_CALL(env, napi_cancel_async_work(env, async_carrier[0]._request));
return nullptr;
}

void Init(napi_env env, napi_value exports, napi_value module, void* priv) {
napi_value test;
NAPI_CALL_RETURN_VOID(env,
napi_create_function(env, "Test", Test, nullptr, &test));
NAPI_CALL_RETURN_VOID(env,
napi_set_named_property(env, module, "exports", test));
napi_property_descriptor properties[] = {
DECLARE_NAPI_PROPERTY("Test", Test),
DECLARE_NAPI_PROPERTY("TestCancel", TestCancel),
};

NAPI_CALL_RETURN_VOID(env, napi_define_properties(
env, exports, sizeof(properties) / sizeof(*properties), properties));
}

NAPI_MODULE(addon, Init)