• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 
16 #include "test.h"
17 
18 #include "native_engine/impl/ark/ark_native_engine.h"
19 #include "utils/log.h"
20 
21 #include <unistd.h>
22 
23 using ArkIdleMonitor = panda::ecmascript::ArkIdleMonitor;
24 using panda::RuntimeOption;
25 
26 struct ThreadArgs {
27     NativeEngine* engine = nullptr;
28     bool initialState = false;
29     bool suspendState = false;
30     bool resumeState = false;
31 };
32 
33 static NativeEngine* g_nativeEngine = nullptr;
34 LoggerCollector* LoggerCollector::last_ = nullptr;
35 
NativeEngineTest()36 NativeEngineTest::NativeEngineTest()
37 {
38     engine_ = g_nativeEngine;
39 }
40 
~NativeEngineTest()41 NativeEngineTest::~NativeEngineTest()
42 {}
43 
Run(void * args)44 void *NativeEngineTest::Run(void *args)
45 {
46     ThreadArgs* threadArgs = reinterpret_cast<ThreadArgs*>(args);
47     NativeEngine* engine = threadArgs->engine;
48     threadArgs->initialState = engine->IsSuspended();
49     engine->SuspendVM();
50     threadArgs->suspendState = engine->IsSuspended();
51     engine->ResumeVM();
52     sleep(1);
53     threadArgs->resumeState = engine->IsSuspended();
54     return nullptr;
55 }
56 
Run()57 void DeathTest::Run()
58 {
59     size_t stackSize = GetCurrentStackSize();
60     ASSERT_NE(pipe(coutPipe_), -1);
61     ASSERT_NE(pipe(cerrPipe_), -1);
62 
63     // Malloc stack of child process
64     ASSERT_FALSE(stackSize < 0 || stackSize > MAX_ALLOWED_CHILD_PROCESS_STACK_SIZE);
65     char* childStack = new char[stackSize];
66     ASSERT_NE(childStack, nullptr);
67 
68     pid_t childPid = clone(RunInChild, childStack + stackSize, SIGCHLD, (void*)this);
69     if (childPid != -1) {
70         int status = 0;
71         ASSERT_EQ(waitpid(childPid, &status, 0), childPid);
72 
73         isExit_ = WIFEXITED(status);
74         exitCode_ = WEXITSTATUS(status);
75         isSignal_ = WIFSIGNALED(status);
76         signal_ = WTERMSIG(status);
77 
78         coutResult_ = ReadFd(coutPipe_[0]);
79         cerrResult_ = ReadFd(cerrPipe_[0]);
80         AssertResult();
81     }
82 
83     close(coutPipe_[0]);
84     close(cerrPipe_[0]);
85 
86     free(childStack);
87     ASSERT_NE(childPid, -1);
88 }
89 
GetCurrentStackSize()90 size_t DeathTest::GetCurrentStackSize()
91 {
92     //  Get stack size of current thread
93     pthread_attr_t attr;
94     size_t stackSize = 0;
95     pthread_getattr_np(pthread_self(), &attr);
96     pthread_attr_getstacksize(&attr, &stackSize);
97     pthread_attr_destroy(&attr);
98     return stackSize;
99 }
100 
RunInChild(void * arg)101 int DeathTest::RunInChild(void* arg)
102 {
103     // block to generate cppcrash log
104     if (signal(SIGABRT, SIG_IGN) == SIG_ERR) {
105         std::cerr << "Failed to register abort signal handler." << std::endl;
106     }
107 
108     DeathTest* that = reinterpret_cast<DeathTest*>(arg);
109     // close unused write pipe port
110     close(that->coutPipe_[0]);
111     close(that->cerrPipe_[0]);
112     // redirect cout/cerr to pipe
113     dup2(that->coutPipe_[1], STDOUT_FILENO);
114     dup2(that->cerrPipe_[1], STDERR_FILENO);
115 
116     // redirect hilog to stdout
117     LOG_SetCallback(RedirectHilog);
118 
119     // execute test case.
120     that->TestBody();
121 
122     // close read pipe port
123     close(that->coutPipe_[1]);
124     close(that->cerrPipe_[1]);
125     return 0;
126 }
127 
RedirectHilog(const LogType,const LogLevel level,const unsigned int,const char *,const char * msg)128 void DeathTest::RedirectHilog(const LogType, const LogLevel level, const unsigned int, const char*, const char* msg)
129 {
130     if (level >= LogLevel::LOG_WARN) {
131         std::cerr << msg << std::endl;
132     } else {
133         std::cout << msg << std::endl;
134     }
135 }
136 
ReadFd(int fd)137 std::string DeathTest::ReadFd(int fd)
138 {
139     std::string result;
140     // set pipe to non-block mode
141     if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) == -1) {
142         std::cerr << "Failed to set fd to non-block mode" << std::endl;
143         return result;
144     }
145     constexpr int bufferSize = 64;
146     char buffer[bufferSize];
147     ssize_t readSize = 0;
148     while ((readSize = read(fd, buffer, sizeof(buffer))) > 0) {
149         result += std::string(buffer, readSize);
150     };
151     return result;
152 }
153 
main(int argc,char ** argv)154 int main(int argc, char** argv)
155 {
156     testing::GTEST_FLAG(output) = "xml:./";
157     testing::InitGoogleTest(&argc, argv);
158 
159     // Setup
160     RuntimeOption option;
161     option.SetGcType(RuntimeOption::GC_TYPE::GEN_GC);
162     const int64_t poolSize = 0x1000000;  // 16M
163     option.SetGcPoolSize(poolSize);
164     option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR);
165     option.SetDebuggerLibraryPath("");
166     EcmaVM* vm = panda::JSNApi::CreateJSVM(option);
167     if (vm == nullptr) {
168         return 0;
169     }
170 
171     g_nativeEngine = new ArkNativeEngine(vm, nullptr);
172 
173     int ret = testing::UnitTest::GetInstance()->Run();
174 
175     g_nativeEngine->Loop(LOOP_NOWAIT);
176 
177     delete g_nativeEngine;
178     g_nativeEngine = nullptr;
179     panda::JSNApi::DestroyJSVM(vm);
180     vm = nullptr;
181 
182     return ret;
183 }
184 
185 HWTEST_F(NativeEngineTest, SuspendVM001, testing::ext::TestSize.Level0)
186 {
187     pthread_t tids;
188     struct ThreadArgs *args = new ThreadArgs;
189     args->engine = engine_;
190     int res = pthread_create(&tids, NULL, Run, (void*)args);
191     if (res != 0) {
192         std::cout << "thread create failed";
193         return;
194     }
195     for (int i = 0; i < 3; ++i) { // 3:Loop 3 times
196         std::this_thread::sleep_for(std::chrono::milliseconds(100));
197         engine_->CheckSafepoint();
198     }
199     ASSERT_TRUE(!args->initialState);
200     ASSERT_TRUE(args->suspendState);
201     ASSERT_TRUE(!args->resumeState);
202     delete args;
203     args = nullptr;
204 }
205 
206 HWTEST_F(NativeEngineTest, CreateRuntimeFunc001, testing::ext::TestSize.Level0)
207 {
__anon64adc9040102() 208     std::thread t([this]() {
209         auto result = engine_->CreateRuntime(true);
210         ASSERT_TRUE(result);
211         delete reinterpret_cast<NativeEngine *>(result);
212     });
213     t.join();
214 }
215 
216 HWTEST_F(NativeEngineTest, ExecuteTranslateBySourceMapFunc001, testing::ext::TestSize.Level0)
217 {
218     std::string stack = engine_->ExecuteTranslateBySourceMap("test1/test2/test3/test.ts");
219     ASSERT_EQ(stack, "test1/test2/test3/test.ts");
220 }
221 
222 HWTEST_F(NativeEngineTest, NapiErrorManagerTest001, testing::ext::TestSize.Level0)
223 {
224     auto onWorkerErrorCallback =
__anon64adc9040202(napi_env env, napi_value exception, std::string vm_name, uint32_t type) 225         [] (napi_env env, napi_value exception, std::string vm_name, uint32_t type) -> bool {
226         EXPECT_EQ(type, 2);
227         EXPECT_EQ(vm_name, "test");
228         return true;
229     };
230     auto onMainThreadErrorCallback =
231         [] (napi_env env, std::string summary, std::string name,
__anon64adc9040302(napi_env env, std::string summary, std::string name, std::string message, std::string stack) 232             std::string message, std::string stack) -> bool {
233         EXPECT_EQ(name, "name");
234         EXPECT_EQ(message, "message");
235         return true;
236     };
__anon64adc9040402() 237     auto hasOnErrorCb = [] () -> bool {
238         return true;
239     };
240     NapiErrorManager::GetInstance()->RegisterHasOnErrorCallback(hasOnErrorCb);
241     NapiErrorManager::GetInstance()->RegisterOnErrorCallback(onWorkerErrorCallback, onMainThreadErrorCallback);
242     ASSERT_NE(NapiErrorManager::GetInstance()->GetOnWorkerErrorCallback(), nullptr);
243     ASSERT_NE(NapiErrorManager::GetInstance()->GetOnMainThreadErrorCallback(), nullptr);
244     napi_value exception = nullptr;
245     NapiErrorManager::GetInstance()->NotifyUncaughtException(reinterpret_cast<napi_env>(engine_),
246         exception, "test", 2);
247     ASSERT_EQ(NapiErrorManager::GetInstance()->NotifyUncaughtException(reinterpret_cast<napi_env>(engine_),
248         "", "name", "message", ""), true);
249 }
250 
251 HWTEST_F(NativeEngineTest, NapiErrorManagerTest002, testing::ext::TestSize.Level0)
252 {
253     auto allUnhandledRejectionCallbackTest =
__anon64adc9040502(napi_env env, napi_value* exception, std::string vm_name, uint32_t type) 254         [] (napi_env env, napi_value* exception, std::string vm_name, uint32_t type) -> bool {
255         EXPECT_EQ(type, 0);
256         EXPECT_EQ(vm_name, "test");
257         return true;
258     };
__anon64adc9040602() 259     auto hasAllUnhandledRejectionCb = [] () -> bool {
260         return false;
261     };
262 
263     NapiErrorManager::GetInstance()->RegisterHasAllUnhandledRejectionCallback(hasAllUnhandledRejectionCb);
264     napi_value* exception = nullptr;
265     NapiErrorManager::GetInstance()->RegisterAllUnhandledRejectionCallback(allUnhandledRejectionCallbackTest);
266     ASSERT_NE(NapiErrorManager::GetInstance()->GetAllUnhandledRejectionCallback(), nullptr);
267     NapiErrorManager::GetInstance()->NotifyUnhandledRejection(reinterpret_cast<napi_env>(engine_),
268         exception, "test", 0);
269 }
270 
271 HWTEST_F(NativeEngineTest, NapiErrorManagerTest003, testing::ext::TestSize.Level0)
272 {
__anon64adc9040702() 273     auto hasOnErrorCb = [] () -> bool {
274         return true;
275     };
276 
277     NapiErrorManager::GetInstance()->RegisterHasOnErrorCallback(hasOnErrorCb);
278     auto callback = NapiErrorManager::GetInstance()->GetHasErrorCallback();
279     ASSERT_NE(callback, nullptr);
280     ASSERT_EQ(callback(), true);
281 }
282 
283 HWTEST_F(NativeEngineTest, NapiErrorManagerTest004, testing::ext::TestSize.Level0)
284 {
__anon64adc9040802() 285     auto hasAllUnhandledRejectionCb = [] () -> bool {
286         return false;
287     };
288 
289     NapiErrorManager::GetInstance()->RegisterHasAllUnhandledRejectionCallback(hasAllUnhandledRejectionCb);
290     auto callback = NapiErrorManager::GetInstance()->GetHasAllUnhandledRejectionCallback();
291     ASSERT_NE(callback, nullptr);
292     ASSERT_EQ(callback(), false);
293 }
294 
295 HWTEST_F(NativeEngineTest, FinalizersCallbackTest001, testing::ext::TestSize.Level0)
296 {
297     ASSERT_NE(engine_, nullptr);
298     napi_env env = (napi_env)engine_;
299     const EcmaVM *vm = reinterpret_cast<ArkNativeEngine*>(engine_)->GetEcmaVm();
300 
301     const char *str = "FinalizersCallbackTest001";
302     size_t size = 2 * ArkNativeEngine::FINALIZERS_PACK_PENDING_NATIVE_BINDING_SIZE_THRESHOLD;
303     static bool finalizersCallbackDone[2] = {false, false};
304 
305     for (int i = 0; i < 2; ++i) {
306         {
307             panda::LocalScope scope(vm);
308             napi_value object = nullptr;
309             napi_create_object(env, &object);
__anon64adc9040902(napi_env env, void *data, void *hint) 310             napi_wrap_with_size(env, object, (void*)str, [](napi_env env, void *data, void *hint) {
311                 bool *result = reinterpret_cast<bool*>(hint);
312                 ASSERT_FALSE(*result);
313                 *result = true;
314             }, reinterpret_cast<void*>(&finalizersCallbackDone[i]), nullptr, size);
315         }
316         panda::JSNApi::TriggerGC(vm, panda::ecmascript::GCReason::OTHER, panda::JSNApi::TRIGGER_GC_TYPE::FULL_GC);
317     }
318 
319     ASSERT_FALSE(finalizersCallbackDone[0]);
320     ASSERT_TRUE(finalizersCallbackDone[1]);
321 }
322 
323 /**
324  * @tc.name: SetMainThreadEcmaVMTest
325  * @tc.desc: Test interface of ArkIdleMonitor
326  * @tc.type: FUNC
327  */
328 HWTEST_F(NativeEngineTest, SetMainThreadEcmaVMTest001, testing::ext::TestSize.Level0)
329 {
330     ASSERT_NE(engine_, nullptr);
331     EcmaVM *vm = const_cast<EcmaVM*>(reinterpret_cast<ArkNativeEngine*>(engine_)->GetEcmaVm());
332 
333     auto arkIdleMonitor = ArkIdleMonitor::GetInstance();
334     arkIdleMonitor->SetMainThreadEcmaVM(vm);
335 
336     int64_t oldIdleDuration = arkIdleMonitor->GetTotalIdleDuration();
337     for (int i = 0; i < 10; i++) {
338         arkIdleMonitor->NotifyLooperIdleStart(i * 500, 20);
339         ASSERT_EQ(arkIdleMonitor->IsIdleState(), true);
340         arkIdleMonitor->NotifyLooperIdleEnd(i * 500 + 250);
341         ASSERT_EQ(arkIdleMonitor->IsIdleState(), false);
342     }
343 
344     arkIdleMonitor->SetMainThreadEcmaVM(nullptr);
345 
346     for (int i = 10; i < 20; i++) {
347         arkIdleMonitor->NotifyLooperIdleStart(i * 500, 20);
348         ASSERT_EQ(arkIdleMonitor->IsIdleState(), true);
349         arkIdleMonitor->NotifyLooperIdleEnd(i * 500 + 250);
350         ASSERT_EQ(arkIdleMonitor->IsIdleState(), false);
351     }
352 
353     int64_t newIdleDuration = arkIdleMonitor->GetTotalIdleDuration();
354     ASSERT_TRUE(newIdleDuration > oldIdleDuration);
355     ASSERT_TRUE(arkIdleMonitor->GetIdleNotifyCount() > 0);
356 }
357 
358 /**
359  * @tc.name: NotifyChangeBackgroundStateTest
360  * @tc.desc: Test interface of ArkIdleMonitor
361  * @tc.type: FUNC
362  */
363 HWTEST_F(NativeEngineTest, NotifyChangeBackgroundStateTest001, testing::ext::TestSize.Level0)
364 {
365     ASSERT_NE(engine_, nullptr);
366     EcmaVM *vm = const_cast<EcmaVM*>(reinterpret_cast<ArkNativeEngine*>(engine_)->GetEcmaVm());
367 
368     auto arkIdleMonitor = ArkIdleMonitor::GetInstance();
369     arkIdleMonitor->SetMainThreadEcmaVM(vm);
370     arkIdleMonitor->SetStartTimerCallback();
371     arkIdleMonitor->NotifyChangeBackgroundState(true);
372     ASSERT_TRUE(arkIdleMonitor->IsInBackground() == true);
373     arkIdleMonitor->NotifyChangeBackgroundState(false);
374     ASSERT_TRUE(arkIdleMonitor->IsInBackground() == false);
375 }
376 
377 /**
378  * @tc.name: RegisterWorkerEnvTest
379  * @tc.desc: Test interface of ArkIdleMonitor
380  * @tc.type: FUNC
381  */
382 HWTEST_F(NativeEngineTest, RegisterWorkerEnvTest001, testing::ext::TestSize.Level0)
383 {
384     ASSERT_NE(engine_, nullptr);
385     EcmaVM *vm = const_cast<EcmaVM*>(reinterpret_cast<ArkNativeEngine*>(engine_)->GetEcmaVm());
386 
387     auto arkIdleMonitor = ArkIdleMonitor::GetInstance();
388     arkIdleMonitor->SetMainThreadEcmaVM(vm);
389 
__anon64adc9040a02() 390     std::thread t([&arkIdleMonitor]() {
391         RuntimeOption option;
392         option.SetGcType(RuntimeOption::GC_TYPE::GEN_GC);
393         const int64_t poolSize = 0x1000000;  // 16M
394         option.SetGcPoolSize(poolSize);
395         option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR);
396         option.SetDebuggerLibraryPath("");
397         auto workerVM1 = panda::JSNApi::CreateJSVM(option);
398         auto workerVM2 = panda::JSNApi::CreateJSVM(option);
399         ArkNativeEngine *workerEngine1 = new ArkNativeEngine(workerVM1, nullptr);
400         ArkNativeEngine *workerEngine2 = new ArkNativeEngine(workerVM2, nullptr);
401         napi_env wokerEnv1 = reinterpret_cast<napi_env>(workerEngine1);
402         napi_env wokerEnv2 = reinterpret_cast<napi_env>(workerEngine2);
403 
404         arkIdleMonitor->UnregisterWorkerEnv(wokerEnv1);
405         arkIdleMonitor->UnregisterWorkerEnv(wokerEnv2);
406 
407         arkIdleMonitor->RegisterWorkerEnv(wokerEnv1);
408         arkIdleMonitor->RegisterWorkerEnv(wokerEnv2);
409 
410         arkIdleMonitor->UnregisterWorkerEnv(wokerEnv1);
411         arkIdleMonitor->UnregisterWorkerEnv(wokerEnv2);
412 
413         delete workerEngine1;
414         delete workerEngine2;
415     });
416     t.join();
417 }
418 
419 /**
420  * @tc.name: SetRawHeapTrimLevel
421  * @tc.desc: Test interface of SetRawHeapTrimLevel
422  * @tc.type: FUNC
423  */
424 HWTEST_F(NativeEngineTest, SetRawHeapTrimLevelTest001, testing::ext::TestSize.Level0)
425 {
426     ASSERT_NE(engine_, nullptr);
427     EcmaVM *vm = const_cast<EcmaVM*>(reinterpret_cast<ArkNativeEngine*>(engine_)->GetEcmaVm());
428 
429     auto arkIdleMonitor = ArkIdleMonitor::GetInstance();
430     arkIdleMonitor->SetMainThreadEcmaVM(vm);
431 
432     engine_->SetRawHeapTrimLevel(1); // test value
433 }
434