1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include <unistd.h>
16 #include <sys/syscall.h>
17
18 #include <ctime>
19 #include <latch>
20 #include <thread>
21 #include <gtest/gtest.h>
22
23 #include "ark_native_engine.h"
24 #include "condition/condition_manager.h"
25 #include "condition/condition_variable.h"
26
27 using namespace Commonlibrary::Concurrent::Condition;
28
29 class ConditionTest : public testing::Test {
30 public:
SetUpTestSuite()31 static void SetUpTestSuite()
32 {
33 InitializeEngine();
34 }
35
TearDownTestSuite()36 static void TearDownTestSuite()
37 {
38 DestroyEngine();
39 }
40
InitializeEngine()41 static void InitializeEngine()
42 {
43 panda::RuntimeOption option;
44 option.SetGcType(panda::RuntimeOption::GC_TYPE::GEN_GC);
45
46 const int64_t poolSize = 0x1000000; // 16M
47 option.SetGcPoolSize(poolSize);
48
49 option.SetLogLevel(panda::RuntimeOption::LOG_LEVEL::ERROR);
50 option.SetDebuggerLibraryPath("");
51 vm_ = panda::JSNApi::CreateJSVM(option);
52 ASSERT_TRUE(vm_ != nullptr);
53
54 engine_ = new ArkNativeEngine(vm_, nullptr);
55 }
56
DestroyEngine()57 static void DestroyEngine()
58 {
59 delete engine_;
60 engine_ = nullptr;
61 panda::JSNApi::DestroyJSVM(vm_);
62 }
63
GetEnv()64 static napi_env GetEnv()
65 {
66 return reinterpret_cast<napi_env>(engine_);
67 }
68
CreateFunction(const char * name,napi_value (* callback)(napi_env,napi_callback_info),void * data=nullptr)69 static napi_value CreateFunction(const char *name, napi_value (*callback)(napi_env, napi_callback_info),
70 void *data = nullptr)
71 {
72 napi_value result;
73 napi_status status = napi_create_function(GetEnv(), name, NAPI_AUTO_LENGTH, callback, data, &result);
74 EXPECT_EQ(status, napi_ok);
75 return result;
76 }
77
78 protected:
79 static thread_local NativeEngine *engine_;
80 static thread_local EcmaVM *vm_;
81 };
82
83 thread_local NativeEngine *ConditionTest::engine_ = nullptr;
84 thread_local EcmaVM *ConditionTest::vm_ = nullptr;
85
CreateConditionVariableInstances(napi_env env)86 static napi_value CreateConditionVariableInstances(napi_env env)
87 {
88 napi_value exports;
89 napi_create_object(env, &exports);
90 napi_value exportsResult = Commonlibrary::Concurrent::Condition::ConditionManager::Init(env, exports);
91 napi_value locks;
92 napi_status status = napi_get_named_property(env, exportsResult, "locks", &locks);
93 if (status != napi_ok) {
94 return nullptr;
95 }
96
97 napi_value conditionClass;
98 status = napi_get_named_property(env, locks, "ConditionVariable", &conditionClass);
99 if (status != napi_ok) {
100 return nullptr;
101 }
102
103 napi_value instance;
104 status = napi_new_instance(env, conditionClass, 0, nullptr, &instance);
105 if (status != napi_ok) {
106 return nullptr;
107 }
108
109 napi_ref napi_ref;
110 status = napi_create_reference(env, instance, 1, &napi_ref);
111 if (status != napi_ok) {
112 return nullptr;
113 }
114
115 napi_value thisVar;
116 status = napi_get_reference_value(env, napi_ref, &thisVar);
117 if (status != napi_ok) {
118 return nullptr;
119 }
120
121 return thisVar;
122 }
123
TEST_F(ConditionTest,WaitTest)124 TEST_F(ConditionTest, WaitTest)
125 {
126 ConditionTest::InitializeEngine();
127 napi_env env = ConditionTest::GetEnv();
128 ASSERT_NE(env, nullptr);
129 napi_value thisVar = CreateConditionVariableInstances(env);
130 ASSERT_NE(thisVar, nullptr);
131
132 // 调用 wait 方法
133 napi_value waitFn;
134 napi_status status = napi_get_named_property(env, thisVar, "wait", &waitFn);
135 ASSERT_EQ(status, napi_ok);
136 napi_value promise;
137 status = napi_call_function(env, thisVar, waitFn, 0, nullptr, &promise);
138 ASSERT_EQ(status, napi_ok);
139 ASSERT_TRUE(promise != nullptr);
140 bool isPromise = false;
141 napi_is_promise(env, promise, &isPromise);
142 ASSERT_TRUE(isPromise);
143
144 // 调用notify 方法
145 napi_value notifyFn;
146 status = napi_get_named_property(env, thisVar, "notifyAll", ¬ifyFn);
147 ASSERT_EQ(status, napi_ok);
148 status = napi_call_function(env, thisVar, notifyFn, 0, nullptr, nullptr);
149 ASSERT_EQ(status, napi_ok);
150
151 // 调用notify 方法
152 status = napi_call_function(env, thisVar, notifyFn, 0, nullptr, nullptr);
153 ASSERT_EQ(status, napi_ok);
154 }
155
TEST_F(ConditionTest,WaitForTest)156 TEST_F(ConditionTest, WaitForTest)
157 {
158 ConditionTest::InitializeEngine();
159 napi_env env = ConditionTest::GetEnv();
160 ASSERT_NE(env, nullptr);
161 napi_value thisVar = CreateConditionVariableInstances(env);
162 ASSERT_NE(thisVar, nullptr);
163
164 // 调用 wait 方法
165 napi_value waitFn;
166 napi_status status = napi_get_named_property(env, thisVar, "waitFor", &waitFn);
167 ASSERT_EQ(status, napi_ok);
168 napi_value promise;
169 napi_value milliseconds = nullptr;
170 double millis = 3000;
171 napi_create_double(env, millis, &milliseconds);
172 napi_value argv[] = {milliseconds};
173 status = napi_call_function(env, thisVar, waitFn, 1, argv, &promise);
174 ASSERT_EQ(status, napi_ok);
175 ASSERT_TRUE(promise != nullptr);
176 bool isPromise = false;
177 napi_is_promise(env, promise, &isPromise);
178 ASSERT_TRUE(isPromise);
179
180 // 调用notifyOne 方法
181 napi_value notifyFn;
182 status = napi_get_named_property(env, thisVar, "notifyOne", ¬ifyFn);
183 ASSERT_EQ(status, napi_ok);
184 status = napi_call_function(env, thisVar, notifyFn, 0, nullptr, nullptr);
185 ASSERT_EQ(status, napi_ok);
186
187 // 调用notifyOne 方法
188 status = napi_call_function(env, thisVar, notifyFn, 0, nullptr, nullptr);
189 ASSERT_EQ(status, napi_ok);
190 }
191
TEST_F(ConditionTest,NotifyOneTest)192 TEST_F(ConditionTest, NotifyOneTest)
193 {
194 ConditionTest::InitializeEngine();
195 napi_env env = ConditionTest::GetEnv();
196 ASSERT_NE(env, nullptr);
197 napi_value thisVar = CreateConditionVariableInstances(env);
198 ASSERT_NE(thisVar, nullptr);
199
200 // 调用notify 方法
201 napi_value notifyFn;
202 napi_status status = napi_get_named_property(env, thisVar, "notifyOne", ¬ifyFn);
203 ASSERT_EQ(status, napi_ok);
204 status = napi_call_function(env, thisVar, notifyFn, 0, nullptr, nullptr);
205 ASSERT_EQ(status, napi_ok);
206
207 // 调用notify 方法
208 status = napi_call_function(env, thisVar, notifyFn, 0, nullptr, nullptr);
209 ASSERT_EQ(status, napi_ok);
210 }
211
TEST_F(ConditionTest,NotifyAllTest)212 TEST_F(ConditionTest, NotifyAllTest)
213 {
214 ConditionTest::InitializeEngine();
215 napi_env env = ConditionTest::GetEnv();
216 ASSERT_NE(env, nullptr);
217 napi_value thisVar = CreateConditionVariableInstances(env);
218 ASSERT_NE(thisVar, nullptr);
219
220 // 调用notify 方法
221 napi_value notifyFn;
222 napi_status status = napi_get_named_property(env, thisVar, "notifyAll", ¬ifyFn);
223 ASSERT_EQ(status, napi_ok);
224 status = napi_call_function(env, thisVar, notifyFn, 0, nullptr, nullptr);
225 ASSERT_EQ(status, napi_ok);
226
227 // 调用notify 方法
228 status = napi_call_function(env, thisVar, notifyFn, 0, nullptr, nullptr);
229 ASSERT_EQ(status, napi_ok);
230 }
231
TEST_F(ConditionTest,ConstructorTest)232 TEST_F(ConditionTest, ConstructorTest)
233 {
234 ConditionTest::InitializeEngine();
235 napi_env env = ConditionTest::GetEnv();
236 ASSERT_NE(env, nullptr);
237 napi_value thisVar = CreateConditionVariableInstances(env);
238 ASSERT_NE(thisVar, nullptr);
239 }
240
TEST_F(ConditionTest,ConstructorTest2)241 TEST_F(ConditionTest, ConstructorTest2)
242 {
243 ConditionTest::InitializeEngine();
244 napi_env env = ConditionTest::GetEnv();
245 ASSERT_NE(env, nullptr);
246 ConditionVariable *cond = new ConditionVariable();
247 ASSERT_NE(cond, nullptr);
248 }
249
TEST_F(ConditionTest,RquestTest)250 TEST_F(ConditionTest, RquestTest)
251 {
252 ConditionTest::InitializeEngine();
253 napi_env env = ConditionTest::GetEnv();
254 ASSERT_NE(env, nullptr);
255 napi_value exports;
256 napi_create_object(env, &exports);
257 napi_value exportsResult = Commonlibrary::Concurrent::Condition::ConditionManager::Init(env, exports);
258 napi_value locks;
259 napi_status status = napi_get_named_property(env, exportsResult, "locks", &locks);
260 ASSERT_EQ(status, napi_ok);
261 napi_value conditionClass;
262 status = napi_get_named_property(env, locks, "ConditionVariable", &conditionClass);
263 ASSERT_EQ(status, napi_ok);
264
265 napi_value constructorArgs1[1] = { 0 };
266 std::string name = "condName1";
267 napi_create_string_utf8(env, name.c_str(), name.size(), &constructorArgs1[0]);
268
269 // 调用request 方法
270 napi_value notifyFn;
271 status = napi_get_named_property(env, conditionClass, "request", ¬ifyFn);
272 ASSERT_EQ(status, napi_ok);
273 napi_value condRequest = nullptr;
274 napi_value undefine = nullptr;
275 status = napi_call_function(env, undefine, notifyFn, 1, constructorArgs1, &condRequest);
276 ASSERT_EQ(status, napi_ok);
277 ASSERT_NE(condRequest, nullptr);
278 napi_ref napi_ref;
279 status = napi_create_reference(env, condRequest, 1, &napi_ref);
280 ASSERT_EQ(status, napi_ok);
281 napi_value thisVar;
282 status = napi_get_reference_value(env, napi_ref, &thisVar);
283 ASSERT_EQ(status, napi_ok);
284
285 // 调用 wait 方法
286 napi_value waitFn;
287 status = napi_get_named_property(env, thisVar, "wait", &waitFn);
288 ASSERT_EQ(status, napi_ok);
289 napi_value promise;
290 status = napi_call_function(env, thisVar, waitFn, 0, nullptr, &promise);
291 ASSERT_EQ(status, napi_ok);
292 ASSERT_TRUE(promise != nullptr);
293 bool isPromise = false;
294 napi_is_promise(env, promise, &isPromise);
295 ASSERT_TRUE(isPromise);
296
297 // 调用notify 方法
298 status = napi_get_named_property(env, thisVar, "notifyAll", ¬ifyFn);
299 ASSERT_EQ(status, napi_ok);
300 status = napi_call_function(env, thisVar, notifyFn, 0, nullptr, nullptr);
301 ASSERT_EQ(status, napi_ok);
302 }
303
TEST_F(ConditionTest,NotifyAfterEnvDestroyedTest)304 TEST_F(ConditionTest, NotifyAfterEnvDestroyedTest)
305 {
306 ConditionTest::InitializeEngine();
307 napi_env env = ConditionTest::GetEnv();
308 ASSERT_NE(env, nullptr);
309 napi_value thisVar = CreateConditionVariableInstances(env);
310 ASSERT_NE(thisVar, nullptr);
311
312 // 调用 wait 方法
313 napi_value waitFn;
314 napi_status status = napi_get_named_property(env, thisVar, "wait", &waitFn);
315 ASSERT_EQ(status, napi_ok);
316 napi_value promise;
317 status = napi_call_function(env, thisVar, waitFn, 0, nullptr, &promise);
318 ASSERT_EQ(status, napi_ok);
319 ASSERT_TRUE(promise != nullptr);
320 bool isPromise = false;
321 napi_is_promise(env, promise, &isPromise);
322 ASSERT_TRUE(isPromise);
323
324 std::thread t([&thisVar]() {
325 ConditionTest::InitializeEngine();
326 napi_env env = ConditionTest::GetEnv();
327 napi_value notifyFn;
328 napi_status status = napi_get_named_property(env, thisVar, "notifyOne", ¬ifyFn);
329 ASSERT_EQ(status, napi_ok);
330 napi_value result;
331 status = napi_call_function(env, thisVar, notifyFn, 0, nullptr, &result);
332 ASSERT_EQ(status, napi_ok);
333 ConditionTest::DestroyEngine();
334 });
335 t.join();
336
337 napi_value notifyFn;
338 status = napi_get_named_property(env, thisVar, "notifyAll", ¬ifyFn);
339 ASSERT_EQ(status, napi_ok);
340 status = napi_call_function(env, thisVar, notifyFn, 0, nullptr, nullptr);
341 ASSERT_EQ(status, napi_ok);
342 }
343
TEST_F(ConditionTest,NotifyOneAfterEnvDestroyedTest)344 TEST_F(ConditionTest, NotifyOneAfterEnvDestroyedTest)
345 {
346 ConditionTest::InitializeEngine();
347 napi_env env = ConditionTest::GetEnv();
348 ASSERT_NE(env, nullptr);
349 napi_value thisVar = CreateConditionVariableInstances(env);
350 ASSERT_NE(thisVar, nullptr);
351
352 // 调用 wait 方法
353 napi_value waitFn;
354 napi_status status = napi_get_named_property(env, thisVar, "waitFor", &waitFn);
355 ASSERT_EQ(status, napi_ok);
356 napi_value promise;
357 napi_value milliseconds = nullptr;
358 double millis = 500;
359 napi_create_double(env, millis, &milliseconds);
360 napi_value argv[] = {milliseconds};
361 status = napi_call_function(env, thisVar, waitFn, 1, argv, &promise);
362 ASSERT_EQ(status, napi_ok);
363 ASSERT_TRUE(promise != nullptr);
364 bool isPromise = false;
365 napi_is_promise(env, promise, &isPromise);
366 ASSERT_TRUE(isPromise);
367
368 std::thread t([&thisVar]() {
369 ConditionTest::InitializeEngine();
370 napi_env env = ConditionTest::GetEnv();
371 napi_value notifyFn;
372 napi_status status = napi_get_named_property(env, thisVar, "notifyOne", ¬ifyFn);
373 ASSERT_EQ(status, napi_ok);
374 napi_value result;
375 status = napi_call_function(env, thisVar, notifyFn, 0, nullptr, &result);
376 ASSERT_EQ(status, napi_ok);
377 ConditionTest::DestroyEngine();
378 });
379 t.join();
380 }
381