1 /*
2  * Copyright (c) 2022-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 <regex>
17 
18 #include "ability_delegator_registry.h"
19 #include "hilog_tag_wrapper.h"
20 #include "js_runtime_utils.h"
21 #include "runner_runtime/js_test_runner.h"
22 
23 namespace OHOS {
24 namespace RunnerRuntime {
25 namespace {
26 const std::string CAPITALTESTRUNNER = "/ets/TestRunner/";
27 const std::string LOWERCASETESTRUNNER = "/ets/testrunner/";
28 }  // namespace
29 
Create(const std::unique_ptr<Runtime> & runtime,const std::shared_ptr<AbilityDelegatorArgs> & args,const AppExecFwk::BundleInfo & bundleInfo,bool isFaJsModel)30 std::unique_ptr<TestRunner> JsTestRunner::Create(const std::unique_ptr<Runtime> &runtime,
31     const std::shared_ptr<AbilityDelegatorArgs> &args, const AppExecFwk::BundleInfo &bundleInfo, bool isFaJsModel)
32 {
33     if (!runtime) {
34         TAG_LOGE(AAFwkTag::DELEGATOR, "invalid runtime");
35         return nullptr;
36     }
37 
38     if (!args) {
39         TAG_LOGE(AAFwkTag::DELEGATOR, "invalid args");
40         return nullptr;
41     }
42 
43     auto pTestRunner = new (std::nothrow) JsTestRunner(static_cast<JsRuntime &>(*runtime), args, bundleInfo,
44         isFaJsModel);
45     if (!pTestRunner) {
46         TAG_LOGE(AAFwkTag::DELEGATOR, "create testrunner failed");
47         return nullptr;
48     }
49 
50     return std::unique_ptr<JsTestRunner>(pTestRunner);
51 }
52 
JsTestRunner(JsRuntime & jsRuntime,const std::shared_ptr<AbilityDelegatorArgs> & args,const AppExecFwk::BundleInfo & bundleInfo,bool isFaJsModel)53 JsTestRunner::JsTestRunner(
54     JsRuntime &jsRuntime, const std::shared_ptr<AbilityDelegatorArgs> &args, const AppExecFwk::BundleInfo &bundleInfo,
55     bool isFaJsModel)
56     : jsRuntime_(jsRuntime), isFaJsModel_(isFaJsModel)
57 {
58     std::string moduleName;
59     if (args) {
60         std::string srcPath;
61         if (bundleInfo.hapModuleInfos.back().isModuleJson) {
62             srcPath.append(args->GetTestModuleName());
63             if (args->GetTestRunnerClassName().find("/") == std::string::npos) {
64                 srcPath.append(LOWERCASETESTRUNNER);
65             }
66             moduleName = args->GetTestModuleName();
67         } else {
68             srcPath.append(args->GetTestPackageName());
69             srcPath.append("/assets/js/TestRunner/");
70             moduleName = args->GetTestPackageName();
71         }
72         srcPath.append(args->GetTestRunnerClassName());
73         srcPath.append(".abc");
74         srcPath_ = srcPath;
75     }
76     TAG_LOGD(AAFwkTag::DELEGATOR, "srcPath: %{public}s", srcPath_.c_str());
77 
78     if (!moduleName.empty()) {
79         for (auto hapModuleInfo : bundleInfo.hapModuleInfos) {
80             if ((hapModuleInfo.isModuleJson && hapModuleInfo.name == moduleName) ||
81                 hapModuleInfo.package == moduleName) {
82                 hapPath_ = hapModuleInfo.hapPath;
83                 break;
84             }
85         }
86     } else {
87         hapPath_ = bundleInfo.hapModuleInfos.back().hapPath;
88     }
89     TAG_LOGD(AAFwkTag::DELEGATOR, "hapPath: %{public}s", hapPath_.c_str());
90 
91     if (isFaJsModel) {
92         return;
93     }
94 
95     moduleName.append("::").append("TestRunner");
96     jsTestRunnerObj_ = jsRuntime_.LoadModule(moduleName, srcPath_, hapPath_,
97         bundleInfo.hapModuleInfos.back().compileMode == AppExecFwk::CompileMode::ES_MODULE);
98     if (!jsTestRunnerObj_ && srcPath_.find(LOWERCASETESTRUNNER) != std::string::npos) {
99         TAG_LOGI(AAFwkTag::DELEGATOR, "not found %{public}s , retry load capital address", srcPath_.c_str());
100         std::regex src_pattern(LOWERCASETESTRUNNER);
101         srcPath_ = std::regex_replace(srcPath_, src_pattern, CAPITALTESTRUNNER);
102         TAG_LOGD(AAFwkTag::DELEGATOR, "capital address is %{public}s", srcPath_.c_str());
103         jsTestRunnerObj_ = jsRuntime_.LoadModule(moduleName, srcPath_, hapPath_,
104             bundleInfo.hapModuleInfos.back().compileMode == AppExecFwk::CompileMode::ES_MODULE);
105     }
106 }
107 
108 JsTestRunner::~JsTestRunner() = default;
109 
Initialize()110 bool JsTestRunner::Initialize()
111 {
112     if (isFaJsModel_) {
113         if (!jsRuntime_.RunScript("/system/etc/strip.native.min.abc", "")) {
114             TAG_LOGE(AAFwkTag::DELEGATOR, "runscript err");
115             return false;
116         }
117 
118         if (!jsRuntime_.RunScript("/system/etc/abc/ability/delegator_mgmt.abc", "")) {
119             TAG_LOGE(AAFwkTag::DELEGATOR, "run delegator failed");
120             return false;
121         }
122 
123         if (!jsRuntime_.RunSandboxScript(srcPath_, hapPath_)) {
124             TAG_LOGE(AAFwkTag::DELEGATOR, "runScript srcPath_ err");
125             return false;
126         }
127 
128         napi_env env = jsRuntime_.GetNapiEnv();
129         napi_value object = nullptr;
130         napi_get_global(env, &object);
131         if (object == nullptr) {
132             TAG_LOGE(AAFwkTag::DELEGATOR, "get globalobject get");
133             return false;
134         }
135         napi_value mainEntryFunc = nullptr;
136         napi_get_named_property(env, object, "___mainEntry___", &mainEntryFunc);
137         if (mainEntryFunc == nullptr) {
138             TAG_LOGE(AAFwkTag::DELEGATOR, "get mainEntryFunc failed");
139             return false;
140         }
141         napi_value value = nullptr;
142         napi_get_global(env, &value);
143         if (value == nullptr) {
144             TAG_LOGE(AAFwkTag::DELEGATOR, "get global failed");
145             return false;
146         }
147         napi_call_function(env, value, mainEntryFunc, 1, &value, nullptr);
148     }
149     return true;
150 }
151 
Prepare()152 void JsTestRunner::Prepare()
153 {
154     TAG_LOGI(AAFwkTag::DELEGATOR, "Enter");
155     TestRunner::Prepare();
156     CallObjectMethod("onPrepare");
157 }
158 
Run()159 void JsTestRunner::Run()
160 {
161     TAG_LOGI(AAFwkTag::DELEGATOR, "Enter");
162     TestRunner::Run();
163     CallObjectMethod("onRun");
164 }
165 
CallObjectMethod(const char * name,napi_value const * argv,size_t argc)166 void JsTestRunner::CallObjectMethod(const char *name, napi_value const *argv, size_t argc)
167 {
168     TAG_LOGI(AAFwkTag::DELEGATOR, "callJsMethod(%{public}s)", name);
169     auto env = jsRuntime_.GetNapiEnv();
170     if (isFaJsModel_) {
171         napi_value global = nullptr;
172         napi_get_global(env, &global);
173         napi_value exportObject = nullptr;
174         napi_get_named_property(env, global, "exports", &exportObject);
175         if (!CheckTypeForNapiValue(env, exportObject, napi_object)) {
176             TAG_LOGE(AAFwkTag::DELEGATOR, "get exportObject failed");
177             return;
178         }
179 
180         napi_value defaultObject = nullptr;
181         napi_get_named_property(env, exportObject, "default", &defaultObject);
182         if (!CheckTypeForNapiValue(env, defaultObject, napi_object)) {
183             TAG_LOGE(AAFwkTag::DELEGATOR, "get defaultObject failed");
184             return;
185         }
186 
187         napi_value func = nullptr;
188         napi_get_named_property(env, defaultObject, name, &func);
189         if (!CheckTypeForNapiValue(env, func, napi_function)) {
190             TAG_LOGE(AAFwkTag::DELEGATOR, "callRequest func:%{public}s", func == nullptr ? "nullptr" : "not func");
191             return;
192         }
193         napi_call_function(env, CreateJsUndefined(env), func, argc, argv, nullptr);
194         return;
195     }
196 
197     if (!jsTestRunnerObj_) {
198         TAG_LOGE(AAFwkTag::DELEGATOR, "not found %{public}s", srcPath_.c_str());
199         ReportFinished("Not found " + srcPath_);
200         return;
201     }
202 
203     HandleScope handleScope(jsRuntime_);
204     napi_value obj = jsTestRunnerObj_->GetNapiValue();
205     if (!CheckTypeForNapiValue(env, obj, napi_object)) {
206         TAG_LOGE(AAFwkTag::DELEGATOR, "get TestRunner object failed");
207         ReportFinished("Failed to get Test Runner object");
208         return;
209     }
210 
211     napi_value methodOnCreate = nullptr;
212     napi_get_named_property(env, obj, name, &methodOnCreate);
213     if (methodOnCreate == nullptr) {
214         TAG_LOGE(AAFwkTag::DELEGATOR, "get '%{public}s' from TestRunner object failed", name);
215         ReportStatus("Failed to get " + std::string(name) + " from Test Runner object");
216         return;
217     }
218     napi_call_function(env, obj, methodOnCreate, argc, argv, nullptr);
219 }
220 
ReportFinished(const std::string & msg)221 void JsTestRunner::ReportFinished(const std::string &msg)
222 {
223     TAG_LOGI(AAFwkTag::DELEGATOR, "enter");
224     auto delegator = AbilityDelegatorRegistry::GetAbilityDelegator();
225     if (!delegator) {
226         TAG_LOGE(AAFwkTag::DELEGATOR, "null delegator");
227         return;
228     }
229 
230     delegator->FinishUserTest(msg, -1);
231 }
232 
ReportStatus(const std::string & msg)233 void JsTestRunner::ReportStatus(const std::string &msg)
234 {
235     TAG_LOGI(AAFwkTag::DELEGATOR, "enter");
236     auto delegator = AbilityDelegatorRegistry::GetAbilityDelegator();
237     if (!delegator) {
238         TAG_LOGE(AAFwkTag::DELEGATOR, "null delegator");
239         return;
240     }
241 
242     delegator->Print(msg);
243 }
244 }  // namespace RunnerRuntime
245 }  // namespace OHOS
246