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