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
16 #include <gtest/gtest.h>
17 #include <singleton.h>
18 #include <uv.h>
19 #include "ability_context.h"
20 #include "ability_context_impl.h"
21 #include "ability_business_error.h"
22 #include "errors.h"
23 #include "hilog_wrapper.h"
24 #define private public
25 #define protected public
26 #include "js_ability_context.h"
27 #undef private
28 #undef protected
29 #include "js_runtime_utils.h"
30 #include "native_engine/impl/ark/ark_native_engine.h"
31 #include "native_engine/impl/ark/ark_native_deferred.h"
32 #include "native_engine/native_engine.h"
33 #include "js_runtime_lite.h"
34 #include "napi_common_want.h"
35
36 #include "mock_parse_requestcode.h"
37
38 using namespace testing;
39 using namespace testing::ext;
40 using namespace OHOS::AAFwk;
41 using namespace OHOS::AbilityRuntime;
42
43 namespace OHOS {
44 namespace AbilityRuntime {
45
46 constexpr size_t ARGC_ZERO = 0;
47 constexpr size_t ARGC_ONE = 1;
48 constexpr size_t ARGC_TWO = 2;
49
50 const int USLEEPTIME = 100000;
51
52 napi_env env_ = nullptr;
53 panda::ecmascript::EcmaVM* vm_ = nullptr;
54
55 class MockDeferred : public NativeDeferred {
56 public:
Resolve(napi_value data)57 void Resolve(napi_value data) override
58 {
59 resolved_ = true;
60 if (nref_ != nullptr) {
61 napi_delete_reference(env_, nref_);
62 nref_ = nullptr;
63 }
64 if (data != nullptr) {
65 napi_create_reference(env_, data, 1, &nref_);
66 }
67 }
68
Reject(napi_value reason)69 void Reject(napi_value reason) override
70 {
71 resolved_ = false;
72 }
73
74 public:
GetLastResolveStatus()75 static bool GetLastResolveStatus() { return resolved_; }
GetLastResolveValue()76 static napi_ref GetLastResolveValue() { return nref_; }
Clear()77 static void Clear()
78 {
79 if (nref_) {
80 delete (reinterpret_cast<NativeReference*>(nref_));
81 nref_ = nullptr;
82 }
83 }
84 static bool resolved_;
85 static napi_ref nref_;
86 };
87 bool MockDeferred::resolved_ = false;
88 napi_ref MockDeferred::nref_ = nullptr;
89
90 class MockArkNativeEngine : public ArkNativeEngine {
91 public:
MockArkNativeEngine(EcmaVM * vm,void * jsEngine,bool isLimitedWorker=false)92 MockArkNativeEngine(EcmaVM* vm, void* jsEngine, bool isLimitedWorker = false)
93 :ArkNativeEngine(vm, jsEngine, isLimitedWorker)
94 {}
95
CreatePromise(NativeDeferred ** deferred)96 napi_value CreatePromise(NativeDeferred** deferred) override
97 {
98 napi_value ret = ArkNativeEngine::CreatePromise(deferred);
99 *deferred = new (std::nothrow) MockDeferred;
100 return ret;
101 }
102 };
103
104 class MockAbilityContextImpl : public AbilityContextImpl {
105 public:
ConnectUIServiceExtensionAbility(const AAFwk::Want & want,const sptr<AbilityConnectCallback> & connectCallback)106 virtual ErrCode ConnectUIServiceExtensionAbility(const AAFwk::Want &want,
107 const sptr<AbilityConnectCallback> &connectCallback) override
108 {
109 callback_ = connectCallback;
110 GTEST_LOG_(INFO) << "ConnectAbility, ret " << connectRet_;
111 return connectRet_;
112 }
113
DisconnectAbility(const AAFwk::Want & want,const sptr<AbilityConnectCallback> & connectCallback,int32_t accountId=-1)114 void DisconnectAbility(const AAFwk::Want &want, const sptr<AbilityConnectCallback> &connectCallback,
115 int32_t accountId = -1) override
116 {}
117 public:
DoneConnect(int status)118 static void DoneConnect(int status)
119 {
120 GTEST_LOG_(INFO) << "DoneConnect " << status;
121 AppExecFwk::ElementName element;
122 sptr<IRemoteObject> remoteObject;
123 callback_->OnAbilityConnectDone(element, remoteObject, 0);
124 }
DoneDisconnect(int status)125 static void DoneDisconnect(int status)
126 {
127 GTEST_LOG_(INFO) << "DoneDisconnect " << status;
128 AppExecFwk::ElementName element;
129 callback_->OnAbilityDisconnectDone(element, 0);
130 }
SetConnectResult(ErrCode code)131 void SetConnectResult(ErrCode code) { connectRet_ = code; }
132 protected:
133 static sptr<AbilityConnectCallback> callback_;
134 ErrCode connectRet_ = ERR_OK;
135 };
136
137 sptr<AbilityConnectCallback> MockAbilityContextImpl::callback_;
138
139 class AbilityContextTest : public testing::Test {
140 public:
141 void SetUp();
142 void TearDown();
143 static void SetUpTestCase(void);
144 static void TearDownTestCase(void);
145
RunNowait(uv_loop_t * loop)146 void RunNowait(uv_loop_t* loop)
147 {
148 usleep(USLEEPTIME);
149 uv_run(loop, UV_RUN_NOWAIT);
150 }
151 void Connect(napi_value* argv, int32_t argc);
152 void Disconnect(napi_value* argv, int32_t argc);
153 public:
154 std::shared_ptr<JsAbilityContext> jsAbilityContext_;
155 std::shared_ptr<MockAbilityContextImpl> abilityContextImpl_;
156 };
157
SetUpTestCase()158 void AbilityContextTest::SetUpTestCase()
159 {
160 GTEST_LOG_(INFO) << "SetUpTestCase";
161 panda::RuntimeOption option;
162 option.SetGcType(panda::RuntimeOption::GC_TYPE::GEN_GC);
163 const int64_t poolSize = 0x1000000;
164 option.SetGcPoolSize(poolSize);
165 option.SetLogLevel(panda::RuntimeOption::LOG_LEVEL::ERROR);
166 option.SetDebuggerLibraryPath("");
167 vm_ = panda::JSNApi::CreateJSVM(option);
168 if (vm_ == nullptr) {
169 GTEST_LOG_(INFO) << "Create vm failed.";
170 return;
171 }
172 env_ = reinterpret_cast<napi_env>(new (std::nothrow) MockArkNativeEngine(vm_, nullptr));
173 }
174
TearDownTestCase()175 void AbilityContextTest::TearDownTestCase()
176 {
177 GTEST_LOG_(INFO) << "TearDownTestCase";
178 MockArkNativeEngine* engine = reinterpret_cast<MockArkNativeEngine*>(env_);
179 delete engine;
180 engine = nullptr;
181 if (vm_ != nullptr) {
182 JSNApi::DestroyJSVM(vm_);
183 vm_ = nullptr;
184 }
185 }
186
SetUp()187 void AbilityContextTest::SetUp()
188 {
189 GTEST_LOG_(INFO) << "AbilityContextTest::SetUp";
190 abilityContextImpl_ = std::make_shared<MockAbilityContextImpl>();
191 if (abilityContextImpl_ == nullptr) {
192 GTEST_LOG_(INFO) << "abilityContextImpl is nullptr.";
193 return;
194 }
195 jsAbilityContext_ = std::make_shared<JsAbilityContext>(abilityContextImpl_);
196 }
197
TearDown()198 void AbilityContextTest::TearDown()
199 {
200 GTEST_LOG_(INFO) << "AbilityContextTest::TearDown " << (void*)this;
201 MockDeferred::Clear();
202 abilityContextImpl_.reset();
203 jsAbilityContext_.reset();
204 }
205
Connect(napi_value * argv,int32_t argc)206 void AbilityContextTest::Connect(napi_value* argv, int32_t argc)
207 {
208 GTEST_LOG_(INFO) << "AbilityRuntime_AbilityContext_0100 start";
209 auto func = [](napi_env env, napi_callback_info info) -> napi_value {
210 JsAbilityContext::ConnectUIServiceExtension(env, info);
211 napi_value result = nullptr;
212 napi_get_undefined(env, &result);
213 return result;
214 };
215
216 HandleScope handleScope(env_);
217 napi_value recv = nullptr;
218 napi_create_object(env_, &recv);
219 napi_status wrapret = napi_wrap(env_, recv, jsAbilityContext_.get(),
220 [](napi_env env, void* data, void* hint) {}, nullptr, nullptr);
221 EXPECT_EQ(wrapret, napi_ok);
222
223 napi_value funcValue = nullptr;
224 napi_create_function(env_, "testFunc", NAPI_AUTO_LENGTH, func, nullptr, &funcValue);
225
226 napi_value funcResultValue = nullptr;
227 napi_call_function(env_, recv, funcValue, argc, argv, &funcResultValue);
228 }
229
Disconnect(napi_value * argv,int32_t argc)230 void AbilityContextTest::Disconnect(napi_value* argv, int32_t argc)
231 {
232 auto func = [](napi_env env, napi_callback_info info) -> napi_value {
233 JsAbilityContext::DisconnectUIServiceExtension(env, info);
234 napi_value result = nullptr;
235 napi_get_undefined(env, &result);
236 return result;
237 };
238 HandleScope handleScope(env_);
239 napi_value recv = nullptr;
240 napi_create_object(env_, &recv);
241 napi_status wrapret = napi_wrap(env_, recv, jsAbilityContext_.get(), [](napi_env env, void* data, void* hint) {},
242 nullptr, nullptr);
243 EXPECT_EQ(wrapret, napi_ok);
244
245 napi_value funcResultValue = nullptr;
246 napi_value funcValue = nullptr;
247 napi_create_function(env_, "disconnectFunc", NAPI_AUTO_LENGTH, func, nullptr, &funcValue);
248 napi_call_function(env_, recv, funcValue, argc, argv, &funcResultValue);
249 }
250
251 HWTEST_F(AbilityContextTest, AbilityRuntime_AbilityContext_0100, TestSize.Level1)
252 {
253 GTEST_LOG_(INFO) << "AbilityRuntime_AbilityContext_0100 start";
254 HandleScope handleScope(env_);
255 TryCatch tryCatch(env_);
256 napi_value argv[] = { };
257 Connect(argv, ARGC_ZERO);
258 EXPECT_TRUE(tryCatch.HasCaught());
259 tryCatch.ClearException();
260 ArkNativeEngine* engine = (ArkNativeEngine*)env_;
261 if (!engine->lastException_.IsEmpty()) {
262 engine->lastException_.Empty();
263 }
264
265 GTEST_LOG_(INFO) << "AbilityRuntime_AbilityContext_0100 end";
266 }
267
268 HWTEST_F(AbilityContextTest, AbilityRuntime_AbilityContext_0101, TestSize.Level1)
269 {
270 GTEST_LOG_(INFO) << "AbilityRuntime_AbilityContext_0101 start";
271 HandleScope handleScope(env_);
272 TryCatch tryCatch(env_);
273 napi_value undef = nullptr;
274 napi_get_undefined(env_, &undef);
275 napi_value argv[] = { undef };
276 Connect(argv, ARGC_ONE);
277 EXPECT_TRUE(tryCatch.HasCaught());
278 tryCatch.ClearException();
279 ArkNativeEngine* engine = (ArkNativeEngine*)env_;
280 if (!engine->lastException_.IsEmpty()) {
281 engine->lastException_.Empty();
282 }
283
284 GTEST_LOG_(INFO) << "AbilityRuntime_AbilityContext_0101 end";
285 }
286
287 HWTEST_F(AbilityContextTest, AbilityRuntime_AbilityContext_0102, TestSize.Level1)
288 {
289 GTEST_LOG_(INFO) << "AbilityRuntime_AbilityContext_0102 start";
290 HandleScope handleScope(env_);
291 TryCatch tryCatch(env_);
292 AAFwk::Want want;
293 napi_value jswant = AppExecFwk::CreateJsWant(env_, want);
294 napi_value argv[] = { jswant };
295 Connect(argv, ARGC_ONE);
296 EXPECT_TRUE(tryCatch.HasCaught());
297 tryCatch.ClearException();
298 ArkNativeEngine* engine = (ArkNativeEngine*)env_;
299 if (!engine->lastException_.IsEmpty()) {
300 engine->lastException_.Empty();
301 }
302
303 GTEST_LOG_(INFO) << "AbilityRuntime_AbilityContext_0102 end";
304 }
305
306 HWTEST_F(AbilityContextTest, AbilityRuntime_AbilityContext_0103, TestSize.Level1)
307 {
308 GTEST_LOG_(INFO) << "AbilityRuntime_AbilityContext_0103 start";
309 HandleScope handleScope(env_);
310 TryCatch tryCatch(env_);
311 AAFwk::Want want;
312 napi_value jswant = AppExecFwk::CreateJsWant(env_, want);
313 napi_value callbackObject = nullptr;
314 napi_create_object(env_, &callbackObject);
315 napi_value argv[] = { jswant, callbackObject};
316 Connect(argv, ARGC_TWO);
317 EXPECT_FALSE(tryCatch.HasCaught());
318
319 ArkNativeEngine* engine = (ArkNativeEngine*)env_;
320 uv_loop_t* loop = engine->GetUVLoop();
321 RunNowait(loop);
322 MockAbilityContextImpl::DoneConnect(ERR_OK);
323 RunNowait(loop);
324
325 EXPECT_TRUE(MockDeferred::GetLastResolveStatus());
326 napi_ref nref = MockDeferred::GetLastResolveValue();
327 EXPECT_NE(nref, nullptr);
328 napi_value proxy = (reinterpret_cast<NativeReference*>(nref))->GetNapiValue();
329 napi_value argv2[] = { proxy };
330 Disconnect(argv2, ARGC_ONE);
331 RunNowait(loop);
332
333 MockAbilityContextImpl::DoneDisconnect(0);
334 RunNowait(loop);
335 abilityContextImpl_->SetConnectResult(ERR_OK);
336 GTEST_LOG_(INFO) << "AbilityRuntime_AbilityContext_0103 end";
337 }
338
339 HWTEST_F(AbilityContextTest, AbilityRuntime_AbilityContext_0104, TestSize.Level1)
340 {
341 GTEST_LOG_(INFO) << "AbilityRuntime_AbilityContext_0104 start";
342 HandleScope handleScope(env_);
343 TryCatch tryCatch(env_);
344 napi_value argv[] = {};
345 Disconnect(argv, ARGC_ZERO);
346 EXPECT_TRUE(tryCatch.HasCaught());
347 tryCatch.ClearException();
348 ArkNativeEngine* engine = (ArkNativeEngine*)env_;
349 if (!engine->lastException_.IsEmpty()) {
350 engine->lastException_.Empty();
351 }
352 GTEST_LOG_(INFO) << "AbilityRuntime_AbilityContext_0104 end";
353 }
354
355 HWTEST_F(AbilityContextTest, AbilityRuntime_AbilityContext_0105, TestSize.Level1)
356 {
357 GTEST_LOG_(INFO) << "AbilityRuntime_AbilityContext_0105 start";
358 HandleScope handleScope(env_);
359 TryCatch tryCatch(env_);
360 napi_value proxy = nullptr;
361 napi_create_object(env_, &proxy);
362 napi_value argv[] = {proxy};
363 Disconnect(argv, ARGC_ONE);
364 EXPECT_TRUE(tryCatch.HasCaught());
365 tryCatch.ClearException();
366 ArkNativeEngine* engine = (ArkNativeEngine*)env_;
367 if (!engine->lastException_.IsEmpty()) {
368 engine->lastException_.Empty();
369 }
370 GTEST_LOG_(INFO) << "AbilityRuntime_AbilityContext_0105 end";
371 }
372
373 HWTEST_F(AbilityContextTest, AbilityRuntime_AbilityContext_RequestCodeFromStringToInt64_0100, TestSize.Level1)
374 {
375 // requestCode is too long
376 std::string requestCodeStr1 = "1000000000000001";
377 auto requestCode = RequestCodeFromStringToInt64(requestCodeStr1);
378 EXPECT_EQ(requestCode, 0);
379
380 // requestCode not match
381 std::string requestCodeStr2 = "001000";
382 requestCode = RequestCodeFromStringToInt64(requestCodeStr2);
383 EXPECT_EQ(requestCode, 0);
384
385 std::string requestCodeStr3 = "aaa100";
386 requestCode = RequestCodeFromStringToInt64(requestCodeStr3);
387 EXPECT_EQ(requestCode, 0);
388
389 std::string requestCodeStr4 = "100aaa";
390 requestCode = RequestCodeFromStringToInt64(requestCodeStr4);
391 EXPECT_EQ(requestCode, 0);
392
393 std::string requestCodeStr5 = "-1";
394 requestCode = RequestCodeFromStringToInt64(requestCodeStr5);
395 EXPECT_EQ(requestCode, 0);
396
397 // requestCode is too large
398 std::string requestCodeStr6 = "562949953421312";
399 requestCode = RequestCodeFromStringToInt64(requestCodeStr6);
400 EXPECT_EQ(requestCode, 0);
401
402 // requestCode is valid
403 std::string requestCodeStr7 = "562949953421311";
404 requestCode = RequestCodeFromStringToInt64(requestCodeStr7);
405 EXPECT_EQ(requestCode, 562949953421311);
406
407 std::string requestCodeStr8 = "0";
408 requestCode = RequestCodeFromStringToInt64(requestCodeStr8);
409 EXPECT_EQ(requestCode, 0);
410
411 std::string requestCodeStr9 = "1";
412 requestCode = RequestCodeFromStringToInt64(requestCodeStr9);
413 EXPECT_EQ(requestCode, 1);
414 }
415
416 HWTEST_F(AbilityContextTest, AbilityRuntime_AbilityContext_StartUIServiceExtension_0100, TestSize.Level1)
417 {
418 napi_env env{nullptr};
419 napi_callback_info info{nullptr};
420 jsAbilityContext_->StartUIServiceExtension(env, info);
421 EXPECT_EQ(info, nullptr);
422 }
423
424 HWTEST_F(AbilityContextTest, AbilityRuntime_AbilityContext_OnStartUIServiceExtension_0100, TestSize.Level1)
425 {
426 OHOS::AbilityRuntime::Runtime::Options options;
427 std::shared_ptr<OHOS::JsEnv::JsEnvironment> jsEnv = nullptr;
428 auto err = JsRuntimeLite::GetInstance().CreateJsEnv(options, jsEnv);
429 EXPECT_EQ(err, napi_status::napi_ok);
430 napi_env env = reinterpret_cast<napi_env>(jsEnv->GetNativeEngine());
431
432 NapiCallbackInfo info{1};
433 AAFwk::Want want;
434 info.argv[0] = OHOS::AppExecFwk::WrapWant(env, want);
435 jsAbilityContext_->OnStartUIServiceExtension(env, info);
436
437 JsRuntimeLite::GetInstance().RemoveJsEnv(reinterpret_cast<napi_env>(jsEnv->GetNativeEngine()));
438 }
439
440 } // namespace AAFwk
441 } // namespace OHOS