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