Skip to content

Commit 793268c

Browse files
authored
test: Add test case for canceling async worker tasks (#1202)
* test: Add test case for canceling async worker tasks
1 parent 1331856 commit 793268c

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

test/async_worker.cc

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#include <chrono>
2+
#include <thread>
3+
#include "assert.h"
14
#include "napi.h"
25

36
using namespace Napi;
@@ -95,12 +98,81 @@ class TestWorkerNoCallback : public AsyncWorker {
9598
bool _succeed;
9699
};
97100

101+
class EchoWorker : public AsyncWorker {
102+
public:
103+
EchoWorker(Function& cb, std::string& echo) : AsyncWorker(cb), echo(echo) {}
104+
~EchoWorker() {}
105+
106+
void Execute() override {
107+
// Simulate cpu heavy task
108+
std::this_thread::sleep_for(std::chrono::milliseconds(30));
109+
}
110+
111+
void OnOK() override {
112+
HandleScope scope(Env());
113+
Callback().Call({Env().Null(), String::New(Env(), echo)});
114+
}
115+
116+
private:
117+
std::string echo;
118+
};
119+
120+
class CancelWorker : public AsyncWorker {
121+
public:
122+
CancelWorker(Function& cb) : AsyncWorker(cb) {}
123+
~CancelWorker() {}
124+
125+
static void DoWork(const CallbackInfo& info) {
126+
Function cb = info[0].As<Function>();
127+
std::string echo = info[1].As<String>();
128+
int threadNum = info[2].As<Number>().Uint32Value();
129+
130+
for (int i = 0; i < threadNum; i++) {
131+
AsyncWorker* worker = new EchoWorker(cb, echo);
132+
worker->Queue();
133+
assert(worker->Env() == info.Env());
134+
}
135+
136+
AsyncWorker* cancelWorker = new CancelWorker(cb);
137+
cancelWorker->Queue();
138+
139+
#ifdef NAPI_CPP_EXCEPTIONS
140+
try {
141+
cancelWorker->Cancel();
142+
} catch (Napi::Error& e) {
143+
Napi::Error::New(info.Env(), "Unable to cancel async worker tasks")
144+
.ThrowAsJavaScriptException();
145+
}
146+
#else
147+
cancelWorker->Cancel();
148+
#endif
149+
}
150+
151+
void Execute() override {
152+
// Simulate cpu heavy task
153+
std::this_thread::sleep_for(std::chrono::milliseconds(100));
154+
}
155+
156+
void OnOK() override {
157+
Napi::Error::New(this->Env(),
158+
"OnOk should not be invoked on successful cancellation")
159+
.ThrowAsJavaScriptException();
160+
}
161+
162+
void OnError(const Error&) override {
163+
Napi::Error::New(this->Env(),
164+
"OnError should not be invoked on successful cancellation")
165+
.ThrowAsJavaScriptException();
166+
}
167+
};
168+
98169
Object InitAsyncWorker(Env env) {
99170
Object exports = Object::New(env);
100171
exports["doWork"] = Function::New(env, TestWorker::DoWork);
101172
exports["doWorkNoCallback"] =
102173
Function::New(env, TestWorkerNoCallback::DoWork);
103174
exports["doWorkWithResult"] =
104175
Function::New(env, TestWorkerWithResult::DoWork);
176+
exports["tryCancelQueuedWork"] = Function::New(env, CancelWorker::DoWork);
105177
return exports;
106178
}

test/async_worker.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ function installAsyncHooksForTest () {
6363
}
6464

6565
async function test (binding) {
66+
const libUvThreadCount = Number(process.env.UV_THREADPOOL_SIZE || 4);
67+
binding.asyncworker.tryCancelQueuedWork(() => {}, 'echoString', libUvThreadCount);
68+
6669
if (!checkAsyncHooks()) {
6770
await new Promise((resolve) => {
6871
binding.asyncworker.doWork(true, {}, function (e) {

0 commit comments

Comments
 (0)