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 "special_test_flow.h"
17 
18 #include <string>
19 #include "ability_manager_client.h"
20 #include "report.h"
21 #include "string_ex.h"
22 #include "wukong_define.h"
23 
24 namespace OHOS {
25 namespace WuKong {
26 namespace {
27 const std::string SPECIAL_TEST_HELP_MSG =
28     "usage: wukong special [<arguments>]\n"
29     "These are wukong special arguments list:\n"
30     "   -h, --help                 special test help\n"
31     "   -t, --touch[x,y]           touch event \n"
32     "   -c, --count                total count of test\n"
33     "   -i, --interval             interval\n"
34     "   -S, --swap[option]         swap event\n"
35     "                              option is -s| -e| -b\n"
36     "                              -s, --start: the start point of swap\n"
37     "                              -e, --end: the end point of swap\n"
38     "                              -b, --bilateral: swap go and back\n"
39     "   -k, --spec_insomnia        power on/off event\n"
40     "   -T, --time                 total time of test\n"
41     "   -C, --component            component event\n"
42     "   -p, --screenshot           get screenshot(only in componment input)\n"
43     "   -r, --record               record user operation\n"
44     "   -R, --replay               replay user operation\n"
45     "   -u, --uitest               uitest dumpLayout\n";
46 
47 const std::string SHORT_OPTIONS = "c:hi:T:t:kSbs:e:C:pr:R:u:";
48 const struct option LONG_OPTIONS[] = {
49     {"count", required_argument, nullptr, 'c'},      // test count
50     {"help", no_argument, nullptr, 'h'},             // help information
51     {"interval", required_argument, nullptr, 'i'},   // test interval
52     {"touch", required_argument, nullptr, 't'},      // touch
53     {"spec_insomnia", no_argument, nullptr, 'k'},    // sleep and awake
54     {"time", required_argument, nullptr, 'T'},       // test time
55     {"swap", required_argument, nullptr, 'S'},       // swap
56     {"bilateral", no_argument, nullptr, 'b'},        // swap go and back
57     {"start", no_argument, nullptr, 's'},            // the start point of swap
58     {"end", no_argument, nullptr, 'e'},              // the end point of swap
59     {"component", required_argument, nullptr, 'C'},  // the end point of swap
60     {"screenshot", no_argument, nullptr, 'p'},       // get photo of screenshot
61     {"record", required_argument, nullptr, 'r'},     // record user operation
62     {"replay", required_argument, nullptr, 'R'},     // replay user operation
63     {"uitest", no_argument, nullptr, 'u'}            // uitest dumpLayout
64 };
65 const int ONE_MINUTE = 60000;
66 bool g_commandSWAPENABLE = false;
67 bool g_commandHELPENABLE = false;
68 bool g_commandTIMEENABLE = false;
69 bool g_commandTOUCHENABLE = false;
70 bool g_commandPOWERENABLE = false;
71 bool g_commandGOBACKENABLE = false;
72 bool g_commandCOUNTENABLE = false;
73 bool g_commandCOMPONENTENABLE = false;
74 bool g_commandSCREENSHOTENABLE = false;
75 bool g_commandRECORDABLE = false;
76 bool g_commandREPLAYABLE = false;
77 bool g_commandUITEST = false;
78 
79 const int NUMBER_TWO = 2;
80 }  // namespace
81 using namespace std;
82 
SpecialTestFlow(WuKongShellCommand &shellcommand)83 SpecialTestFlow::SpecialTestFlow(WuKongShellCommand &shellcommand) : TestFlow(shellcommand)
84 {
85 }
86 
~SpecialTestFlow()87 SpecialTestFlow::~SpecialTestFlow()
88 {
89     if (timer_ != nullptr) {
90         timer_->Shutdown();
91         timer_->Unregister(timerId_);
92         timer_ = nullptr;
93     }
94 }
95 
EnvInit()96 ErrCode SpecialTestFlow::EnvInit()
97 {
98     ErrCode result = OHOS::ERR_OK;
99     const std::string paramError = "param is incorrect";
100     if (g_commandSWAPENABLE == true) {
101         if (swapStartPoint_.size() == NUMBER_TWO && swapEndPoint_.size() == NUMBER_TWO) {
102             // set the params of touch special test
103             std::shared_ptr<SwapParam> swapParam = std::make_shared<SwapParam>();
104             swapParam->startX_ = stoi(swapStartPoint_[0]);
105             swapParam->startY_ = stoi(swapStartPoint_[1]);
106             swapParam->endX_ = stoi(swapEndPoint_[0]);
107             swapParam->endY_ = stoi(swapEndPoint_[1]);
108             swapParam->isGoBack_ = g_commandGOBACKENABLE;
109             if (specialTestObject_ == nullptr) {
110                 specialTestObject_ = swapParam;
111             }
112         } else {
113             DEBUG_LOG(paramError.c_str());
114             shellcommand_.ResultReceiverAppend(paramError + "\n");
115             result = OHOS::ERR_INVALID_VALUE;
116         }
117     } else if (g_commandTOUCHENABLE == true) {
118         if (touchParam_.size() == NUMBER_TWO) {
119             // set the params of swap special test
120             std::shared_ptr<TouchParam> touchParam = std::make_shared<TouchParam>();
121             touchParam->x_ = stoi(touchParam_[0]);
122             touchParam->y_ = stoi(touchParam_[1]);
123             if (specialTestObject_ == nullptr) {
124                 specialTestObject_ = touchParam;
125             }
126         } else {
127             DEBUG_LOG(paramError.c_str());
128             shellcommand_.ResultReceiverAppend(paramError + "\n");
129             result = OHOS::ERR_INVALID_VALUE;
130         }
131     } else if (g_commandCOMPONENTENABLE == true) {
132         std::shared_ptr<ComponentParam> componentParam = std::make_shared<ComponentParam>();
133         for (auto name : bundleName_) {
134             componentParam->PushBundleName(name);
135         }
136         componentParam->isAllFinished_ = false;
137         specialTestObject_ = componentParam;
138     } else if (g_commandRECORDABLE == true) {
139         std::shared_ptr<RecordParam> recordParam = std::make_shared<RecordParam>();
140         recordParam->recordName_ = specialRecordName_;
141         recordParam->recordStatus_ = true;
142         if (specialTestObject_ == nullptr) {
143             specialTestObject_ = recordParam;
144         }
145     } else if (g_commandREPLAYABLE == true) {
146         std::shared_ptr<RecordParam> replayParam = std::make_shared<RecordParam>();
147         replayParam->recordName_ = specialRecordName_;
148         replayParam->recordStatus_ = false;
149         if (specialTestObject_ == nullptr) {
150             specialTestObject_ = replayParam;
151         }
152     }
153 
154     // if time test flow, register timer.
155     if (g_commandTIMEENABLE) {
156         RegisterTimer();
157     }
158     return result;
159 }
160 
RunStep()161 ErrCode SpecialTestFlow::RunStep()
162 {
163     // control the count test flow
164     if (g_commandCOUNTENABLE == true) {
165         totalCount_--;
166         if (totalCount_ < 0) {
167             isFinished_ = true;
168             return OHOS::ERR_OK;
169         }
170     }
171     // order test
172     ErrCode result;
173     if (g_commandSCREENSHOTENABLE) {
174         std::string screenStorePath;
175         result = WuKongUtil::GetInstance()->WukongScreenCap(screenStorePath, g_commandUITEST);
176         if (result == OHOS::ERR_OK) {
177             Report::GetInstance()->RecordScreenPath(screenStorePath);
178         }
179     }
180     InputType inputTypeId = DistrbuteInputType();
181     std::shared_ptr<InputAction> inputaction = InputFactory::GetInputAction(inputTypeId);
182     if (!inputaction) {
183         WARN_LOG("This test failed, the inputaction is nullptr.");
184         return OHOS::ERR_INVALID_VALUE;
185     }
186     result = inputaction->OrderInput(specialTestObject_);
187     if (result != OHOS::ERR_OK) {
188         WARN_LOG("This test failed");
189     }
190     if (!g_commandPOWERENABLE) {
191         if (ProtectRightAbility() == OHOS::ERR_INVALID_VALUE) {
192             return OHOS::ERR_INVALID_VALUE;
193         }
194     }
195     if (g_commandCOMPONENTENABLE) {
196         if (specialTestObject_->isAllFinished_) {
197             isFinished_ = true;
198         }
199     }
200     if (g_commandRECORDABLE) {
201         isFinished_ = true;
202     }
203     usleep(intervalArgs_ * oneSecond_);
204     return result;
205 }
ProtectRightAbility()206 ErrCode SpecialTestFlow::ProtectRightAbility()
207 {
208     ErrCode result = OHOS::ERR_OK;
209     auto elementName = AAFwk::AbilityManagerClient::GetInstance()->GetTopAbility();
210     auto curBundleName = elementName.GetBundleName();
211     auto static lastBundleName = elementName.GetBundleName();
212     if (curBundleName != lastBundleName) {
213         auto it = find(bundleName_.begin(), bundleName_.end(), curBundleName);
214         if (it == bundleName_.end()) {
215             std::vector<std::string> bundleList(0);
216             std::vector<std::string> abilityList(0);
217             auto util = WuKongUtil::GetInstance();
218             util->GetBundleList(bundleList, abilityList);
219             if (bundleList.size() == 0 || abilityList.size() == 0) {
220                 ERROR_LOG_STR("bundleList (%u) or abilityList (%u) is 0", bundleList.size(), abilityList.size());
221                 return OHOS::ERR_INVALID_VALUE;
222             }
223             uint32_t index = util->FindElement(bundleList, lastBundleName);
224             if (index == INVALIDVALUE) {
225                 ERROR_LOG("not found bundle");
226                 return OHOS::ERR_INVALID_VALUE;
227             }
228             // start ability through bundle information
229             result = AppManager::GetInstance()->StartAbilityByBundleInfo(abilityList[index], bundleList[index]);
230             if (result == OHOS::ERR_OK) {
231                 INFO_LOG_STR("Bundle Name: (%s) startup successful", bundleList[index].c_str());
232                 WuKongUtil::GetInstance()->SetIsFirstStartAppFlag(true);
233             } else {
234                 INFO_LOG_STR("Bundle Name: (%s) startup failed", bundleList[index].c_str());
235             }
236         } else {
237             lastBundleName = curBundleName;
238             DEBUG_LOG_STR("lastBundleName change to : %s", curBundleName.c_str());
239         }
240     }
241     return result;
242 }
243 
DistrbuteInputType()244 InputType SpecialTestFlow::DistrbuteInputType()
245 {
246     InputType iputType = INPUTTYPE_INVALIDINPUT;
247 
248     if (g_commandTOUCHENABLE == true) {
249         iputType = INPUTTYPE_TOUCHINPUT;
250     } else if (g_commandSWAPENABLE) {
251         iputType = INPUTTYPE_SWAPINPUT;
252     } else if (g_commandPOWERENABLE) {
253         iputType = INPUTTYPE_HARDKEYINPUT;
254     } else if (g_commandCOMPONENTENABLE) {
255         iputType = INPUTTYPE_ELEMENTINPUT;
256     } else if (g_commandRECORDABLE) {
257         iputType = INPUTTYPE_RECORDINPUT;
258     } else if (g_commandREPLAYABLE) {
259         iputType = INPUTTYPE_REPPLAYINPUT;
260     }
261     return iputType;
262 }
263 
GetOptionArguments(std::string &shortOpts)264 const struct option *SpecialTestFlow::GetOptionArguments(std::string &shortOpts)
265 {
266     shortOpts = SHORT_OPTIONS;
267     return LONG_OPTIONS;
268 }
269 
HandleUnknownOption(const char optopt)270 ErrCode SpecialTestFlow::HandleUnknownOption(const char optopt)
271 {
272     ErrCode result = OHOS::ERR_OK;
273     switch (optopt) {
274         case 'T':
275         case 'i':
276         case 'c':
277         case 's':
278         case 'e':
279         case 'C':
280             shellcommand_.ResultReceiverAppend("error: option '-");
281             shellcommand_.ResultReceiverAppend(string(1, optopt));
282             shellcommand_.ResultReceiverAppend("' requires a value.\n");
283             result = OHOS::ERR_INVALID_VALUE;
284             break;
285         case 'h': {
286             result = OHOS::ERR_INVALID_VALUE;
287             break;
288         }
289         default: {
290             // 'wukong special' with a unknown option: wukong special -x
291             shellcommand_.ResultReceiverAppend(
292                 "'wukong special' with an unknown option, please reference help information:\n");
293             result = OHOS::ERR_INVALID_VALUE;
294             break;
295         }
296     }
297     shellcommand_.ResultReceiverAppend(SPECIAL_TEST_HELP_MSG);
298     return result;
299 }
300 
HandleNormalOption(const int option)301 ErrCode SpecialTestFlow::HandleNormalOption(const int option)
302 {
303     ErrCode result = OHOS::ERR_OK;
304     if (option == 'c' || option == 'T') {
305         result = CheckArgument(option);
306     } else if (option == 'i' || option == 't' || option == 's' || option == 'e' || option == 'C') {
307         result = SetRunningParam(option);
308     } else if (option == 'S' || option == 'k' || option == 'h' || option == 'b' || option == 'p' ||
309         option == 'r' || option == 'R' || option == 'u') {
310         result = SetRunningIndicator(option);
311     }
312     WuKongUtil::GetInstance()->SetOrderFlag(true);
313     return result;
314 }
315 
CheckArgument(const int option)316 ErrCode SpecialTestFlow::CheckArgument(const int option)
317 {
318     ErrCode result = OHOS::ERR_OK;
319     switch (option) {
320         case 'c': {
321             result = CheckArgumentOptionOfc();
322             break;
323         }
324         case 'T': {
325             result = CheckArgumentOptionOfT();
326             break;
327         }
328         default: {
329             result = OHOS::ERR_INVALID_VALUE;
330             break;
331         }
332     }
333     return result;
334 }
335 
SetRunningParam(const int option)336 ErrCode SpecialTestFlow::SetRunningParam(const int option)
337 {
338     ErrCode result = OHOS::ERR_OK;
339     if (option == 'i') {
340         intervalArgs_ = std::stoi(optarg);
341         TEST_RUN_LOG(("Interval: " + std::to_string(intervalArgs_)).c_str());
342     } else if (option == 't') {
343         SplitStr(optarg, ",", touchParam_);
344         // check if param is valid
345         result = CheckPosition(touchParam_);
346         g_commandTOUCHENABLE = true;
347     } else if (option == 's') {
348         SplitStr(optarg, ",", swapStartPoint_);
349         // check if param is valid
350         result = CheckPosition(swapStartPoint_);
351     } else if (option == 'e') {
352         SplitStr(optarg, ",", swapEndPoint_);
353         // check if param is valid
354         result = CheckPosition(swapEndPoint_);
355     } else if (option == 'C') {
356         SplitStr(optarg, ",", bundleName_);
357         result = WuKongUtil::GetInstance()->CheckArgumentList(bundleName_, true);
358         g_commandCOMPONENTENABLE = true;
359     }
360     return OHOS::ERR_OK;
361 }
362 
SetRunningIndicator(const int option)363 ErrCode SpecialTestFlow::SetRunningIndicator(const int option)
364 {
365     ErrCode result = OHOS::ERR_OK;
366     if (option == 'S') {
367         g_commandSWAPENABLE = true;
368     } else if (option == 'k') {
369         g_commandPOWERENABLE = true;
370     } else if (option == 'h') {
371         shellcommand_.ResultReceiverAppend(SPECIAL_TEST_HELP_MSG);
372         result = ERR_NO_INIT;
373         g_commandHELPENABLE = true;
374     } else if (option == 'b') {
375         g_commandGOBACKENABLE = true;
376     } else if (option == 'p') {
377         g_commandSCREENSHOTENABLE = true;
378     } else if (option == 'r') {
379         g_commandRECORDABLE = true;
380         specialRecordName_ = optarg;
381     } else if (option == 'R') {
382         g_commandREPLAYABLE = true;
383         specialRecordName_ = optarg;
384     } else if (option == 'u') {
385         g_commandUITEST = true;
386     }
387     return OHOS::ERR_OK;
388 }
389 
RegisterTimer()390 void SpecialTestFlow::RegisterTimer()
391 {
392     if (timer_ == nullptr) {
393         timer_ = std::make_shared<Utils::Timer>("wukong");
394         timerId_ = timer_->Register([this] () { SpecialTestFlow::TestTimeout(); }, totalTime_ * ONE_MINUTE, true);
395         timer_->Setup();
396     }
397 }
398 
TestTimeout()399 void SpecialTestFlow::TestTimeout()
400 {
401     g_commandTIMEENABLE = false;
402     isFinished_ = true;
403 }
404 
CheckPosition(std::vector<std::string> argumentlist)405 ErrCode SpecialTestFlow::CheckPosition(std::vector<std::string> argumentlist)
406 {
407     int32_t screenWidth = -1;
408     int32_t screenHeight = -1;
409 
410     // get the size of screen
411     ErrCode result = WuKongUtil::GetInstance()->GetScreenSize(screenWidth, screenHeight);
412     if (result != OHOS::ERR_OK) {
413         return result;
414     }
415     if (argumentlist.size() > 0) {
416         if (stoi(argumentlist[0]) > screenWidth || stoi(argumentlist[1]) > screenHeight || stoi(argumentlist[0]) < 0 ||
417             stoi(argumentlist[1]) < 0) {
418             std::string paramError = "the param of position is incorrect";
419             DEBUG_LOG(paramError.c_str());
420             shellcommand_.ResultReceiverAppend(paramError + "\n");
421             result = OHOS::ERR_NO_INIT;
422         }
423     }
424     return result;
425 }
426 
LauncherApp()427 ErrCode SpecialTestFlow::LauncherApp()
428 {
429     std::shared_ptr<InputAction> inputaction = InputFactory::GetInputAction(INPUTTYPE_APPSWITCHINPUT);
430     if (!inputaction) {
431         return OHOS::ERR_INVALID_VALUE;
432     }
433     ErrCode result = inputaction->OrderInput(specialTestObject_);
434     if (result != OHOS::ERR_OK) {
435         ERROR_LOG("launcher app failed");
436     }
437     return result;
438 }
439 
CheckArgumentOptionOfc()440 ErrCode SpecialTestFlow::CheckArgumentOptionOfc()
441 {
442     // check if the '-c' and 'T' is exist at the same time
443     if (g_commandTIMEENABLE == false) {
444         std::stringstream ss(optarg);
445         if (ss >> countArgs_) {
446             g_commandCOUNTENABLE = true;
447             TEST_RUN_LOG(("Count: " + std::to_string(countArgs_)).c_str());
448             totalCount_ = countArgs_;
449             return OHOS::ERR_OK;
450         } else {
451             ERROR_LOG("Setting -c must follow an interger");
452             return OHOS::ERR_INVALID_VALUE;
453         }
454     } else {
455         DEBUG_LOG(PARAM_COUNT_TIME_ERROR);
456         shellcommand_.ResultReceiverAppend(std::string(PARAM_COUNT_TIME_ERROR) + "\n");
457         return OHOS::ERR_INVALID_VALUE;
458     }
459 }
460 
CheckArgumentOptionOfT()461 ErrCode SpecialTestFlow::CheckArgumentOptionOfT()
462 {
463     // check if the '-c' and 'T' is exist at the same time
464     if (g_commandCOUNTENABLE == false) {
465         std::stringstream ss(optarg);
466         if (ss >> totalTime_) {
467             TEST_RUN_LOG(("Time: " + std::to_string(totalTime_)).c_str());
468             g_commandTIMEENABLE = true;
469             return OHOS::ERR_OK;
470         } else {
471             ERROR_LOG("Setting -T must follow a float");
472             return OHOS::ERR_INVALID_VALUE;
473         }
474     } else {
475         DEBUG_LOG(PARAM_TIME_COUNT_ERROR);
476         shellcommand_.ResultReceiverAppend(std::string(PARAM_TIME_COUNT_ERROR) + "\n");
477         return OHOS::ERR_INVALID_VALUE;
478     }
479 }
480 
481 }  // namespace WuKong
482 }  // namespace OHOS
483