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
24namespace OHOS {
25namespace WuKong {
26namespace {
27const 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
47const std::string SHORT_OPTIONS = "c:hi:T:t:kSbs:e:C:pr:R:u:";
48const 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};
65const int ONE_MINUTE = 60000;
66bool g_commandSWAPENABLE = false;
67bool g_commandHELPENABLE = false;
68bool g_commandTIMEENABLE = false;
69bool g_commandTOUCHENABLE = false;
70bool g_commandPOWERENABLE = false;
71bool g_commandGOBACKENABLE = false;
72bool g_commandCOUNTENABLE = false;
73bool g_commandCOMPONENTENABLE = false;
74bool g_commandSCREENSHOTENABLE = false;
75bool g_commandRECORDABLE = false;
76bool g_commandREPLAYABLE = false;
77bool g_commandUITEST = false;
78
79const int NUMBER_TWO = 2;
80}  // namespace
81using namespace std;
82
83SpecialTestFlow::SpecialTestFlow(WuKongShellCommand &shellcommand) : TestFlow(shellcommand)
84{
85}
86
87SpecialTestFlow::~SpecialTestFlow()
88{
89    if (timer_ != nullptr) {
90        timer_->Shutdown();
91        timer_->Unregister(timerId_);
92        timer_ = nullptr;
93    }
94}
95
96ErrCode 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
161ErrCode 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}
206ErrCode 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
244InputType 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
264const struct option *SpecialTestFlow::GetOptionArguments(std::string &shortOpts)
265{
266    shortOpts = SHORT_OPTIONS;
267    return LONG_OPTIONS;
268}
269
270ErrCode 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
301ErrCode 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
316ErrCode 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
336ErrCode 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
363ErrCode 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
390void 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
399void SpecialTestFlow::TestTimeout()
400{
401    g_commandTIMEENABLE = false;
402    isFinished_ = true;
403}
404
405ErrCode 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
427ErrCode 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
440ErrCode 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
461ErrCode 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