• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# coding=utf-8
3
4#
5# Copyright (c) 2020-2022 Huawei Device Co., Ltd.
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10#     http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17#
18
19import argparse
20import os
21import platform
22import signal
23import sys
24import threading
25import copy
26from collections import namedtuple
27
28from _core.config.config_manager import UserConfigManager
29from _core.constants import SchedulerType
30from _core.constants import ConfigConst
31from _core.constants import ReportConst
32from _core.constants import ModeType
33from _core.constants import ToolCommandType
34from _core.environment.manager_env import EnvironmentManager
35from _core.exception import ParamError
36from _core.exception import ExecuteTerminate
37from _core.executor.request import Task
38from _core.executor.scheduler import Scheduler
39from _core.logger import platform_logger
40from _core.plugin import Plugin
41from _core.plugin import get_plugin
42from _core.utils import SplicingAction
43from _core.utils import get_instance_name
44from _core.utils import is_python_satisfied
45from _core.report.result_reporter import ResultReporter
46
47__all__ = ["Console"]
48
49LOG = platform_logger("Console")
50try:
51    if platform.system() != 'Windows':
52        import readline
53except (ModuleNotFoundError, ImportError):  # pylint:disable=undefined-variable
54    LOG.warning("Readline module is not exist.")
55
56MAX_VISIBLE_LENGTH = 49
57MAX_RESERVED_LENGTH = 46
58Argument = namedtuple('Argument', 'options unparsed valid_param parser')
59
60
61class Console(object):
62    """
63    Class representing an console for executing test.
64    Main xDevice console providing user with the interface to interact
65    """
66    __instance = None
67
68    def __new__(cls, *args, **kwargs):
69        """
70        Singleton instance
71        """
72        if cls.__instance is None:
73            cls.__instance = super(Console, cls).__new__(cls, *args, **kwargs)
74        return cls.__instance
75
76    def __init__(self):
77        pass
78
79    @classmethod
80    def handler_terminate_signal(cls, signalnum, frame):
81        # ctrl+c
82        del signalnum, frame
83        if not Scheduler.is_execute:
84            return
85        LOG.info("Get terminate input")
86        terminate_thread = threading.Thread(
87            target=Scheduler.terminate_cmd_exec)
88        terminate_thread.setDaemon(True)
89        terminate_thread.start()
90
91    def console(self, args):
92        """
93        Main xDevice console providing user with the interface to interact
94        """
95        if not is_python_satisfied():
96            sys.exit(0)
97
98        if args is None or len(args) < 2:
99            # init environment manager
100            EnvironmentManager()
101            # Enter xDevice console
102            self._console()
103        else:
104            # init environment manager
105            EnvironmentManager()
106            # Enter xDevice command parser
107            self.command_parser(" ".join(args[1:]))
108
109    def _console(self):
110        # Enter xDevice console
111        signal.signal(signal.SIGINT, self.handler_terminate_signal)
112
113        while True:
114            try:
115                usr_input = input(">>> ")
116                if usr_input == "":
117                    continue
118
119                self.command_parser(usr_input)
120
121            except SystemExit as _:
122                LOG.info("Program exit normally!")
123                break
124            except ExecuteTerminate as _:
125                LOG.info("Execution terminated")
126            except (IOError, EOFError, KeyboardInterrupt) as error:
127                LOG.exception("Input Error: {}".format(error),
128                              exc_info=False)
129
130    def argument_parser(self, para_list):
131        """
132        Argument parser
133        """
134        options = None
135        unparsed = []
136        valid_param = True
137        parser = None
138
139        try:
140            parser = argparse.ArgumentParser(
141                description="Specify tests to run.")
142            group = parser.add_mutually_exclusive_group()
143            parser.add_argument("action",
144                                type=str.lower,
145                                help="Specify action")
146            parser.add_argument("task",
147                                type=str,
148                                default=None,
149                                help="Specify task name")
150            group.add_argument("-l", "--testlist",
151                               action=SplicingAction,
152                               type=str,
153                               nargs='+',
154                               dest=ConfigConst.testlist,
155                               default="",
156                               help="Specify test list"
157                               )
158            group.add_argument("-tf", "--testfile",
159                               action=SplicingAction,
160                               type=str,
161                               nargs='+',
162                               dest=ConfigConst.testfile,
163                               default="",
164                               help="Specify test list file"
165                               )
166            parser.add_argument("-tc", "--testcase",
167                                action="store",
168                                type=str,
169                                dest=ConfigConst.testcase,
170                                default="",
171                                help="Specify test case"
172                                )
173            parser.add_argument("-c", "--config",
174                                action=SplicingAction,
175                                type=str,
176                                nargs='+',
177                                dest=ConfigConst.configfile,
178                                default="",
179                                help="Specify config file path"
180                                )
181            parser.add_argument("-sn", "--device_sn",
182                                action="store",
183                                type=str,
184                                dest=ConfigConst.device_sn,
185                                default="",
186                                help="Specify device serial number"
187                                )
188            parser.add_argument("-rp", "--reportpath",
189                                action=SplicingAction,
190                                type=str,
191                                nargs='+',
192                                dest=ConfigConst.report_path,
193                                default="",
194                                help="Specify test report path"
195                                )
196            parser.add_argument("-respath", "--resourcepath",
197                                action=SplicingAction,
198                                type=str,
199                                nargs='+',
200                                dest=ConfigConst.resource_path,
201                                default="",
202                                help="Specify test resource path"
203                                )
204            parser.add_argument("-tcpath", "--testcasespath",
205                                action=SplicingAction,
206                                type=str,
207                                nargs='+',
208                                dest=ConfigConst.testcases_path,
209                                default="",
210                                help="Specify testcases path"
211                                )
212            parser.add_argument("-ta", "--testargs",
213                                action=SplicingAction,
214                                type=str,
215                                nargs='+',
216                                dest=ConfigConst.testargs,
217                                default={},
218                                help="Specify test arguments"
219                                )
220            parser.add_argument("-pt", "--passthrough",
221                                action="store_true",
222                                dest=ConfigConst.pass_through,
223                                help="Pass through test arguments"
224                                )
225            parser.add_argument("-env", "--environment",
226                                action=SplicingAction,
227                                type=str,
228                                nargs='+',
229                                dest=ConfigConst.test_environment,
230                                default="",
231                                help="Specify test environment"
232                                )
233            parser.add_argument("-e", "--exectype",
234                                action="store",
235                                type=str,
236                                dest=ConfigConst.exectype,
237                                default="device",
238                                help="Specify test execute type"
239                                )
240            parser.add_argument("-t", "--testtype",
241                                nargs='*',
242                                dest=ConfigConst.testtype,
243                                default=[],
244                                help="Specify test type" +
245                                     "(UT,MST,ST,PERF,SEC,RELI,DST,ALL)"
246                                )
247            parser.add_argument("-td", "--testdriver",
248                                action="store",
249                                type=str,
250                                dest=ConfigConst.testdriver,
251                                default="",
252                                help="Specify test driver id"
253                                )
254            parser.add_argument("-tl", "--testlevel",
255                                action="store",
256                                type=str,
257                                dest="testlevel",
258                                default="",
259                                help="Specify test level"
260                                )
261            parser.add_argument("-bv", "--build_variant",
262                                action="store",
263                                type=str,
264                                dest="build_variant",
265                                default="release",
266                                help="Specify build variant(release,debug)"
267                                )
268            parser.add_argument("-cov", "--coverage",
269                                action="store",
270                                type=str,
271                                dest="coverage",
272                                default="",
273                                help="Specify coverage"
274                                )
275            parser.add_argument("--retry",
276                                action="store",
277                                type=str,
278                                dest=ConfigConst.retry,
279                                default="",
280                                help="Specify retry command"
281                                )
282            parser.add_argument("--session",
283                                action=SplicingAction,
284                                type=str,
285                                nargs='+',
286                                dest=ConfigConst.session,
287                                help="retry task by session id")
288            parser.add_argument("--dryrun",
289                                action="store_true",
290                                dest=ConfigConst.dry_run,
291                                help="show retry test case list")
292            parser.add_argument("--reboot-per-module",
293                                action="store_true",
294                                dest=ConfigConst.reboot_per_module,
295                                help="reboot devices before executing each "
296                                     "module")
297            parser.add_argument("--check-device",
298                                action="store_true",
299                                dest=ConfigConst.check_device,
300                                help="check the test device meets the "
301                                     "requirements")
302            parser.add_argument("--repeat",
303                                type=int,
304                                default=0,
305                                dest=ConfigConst.repeat,
306                                help="number of times that a task is executed"
307                                     " repeatedly")
308            parser.add_argument("-le", "--local_execution_log_path",
309                                dest="local_execution_log_path",
310                                help="- The local execution log path.")
311            parser.add_argument("-s", "--subsystem",
312                                dest="subsystems",
313                                action="store",
314                                type=str,
315                                help="- Specify the list of subsystem")
316            parser.add_argument("-p", "--part",
317                                dest="parts",
318                                action="store",
319                                type=str,
320                                help="- Specify the list of part")
321            parser.add_argument("-kim", "--kits_in_module",
322                                dest=ConfigConst.kits_in_module,
323                                action=SplicingAction,
324                                type=str,
325                                nargs='+',
326                                default="",
327                                help="- kits that are used for specify module")
328            parser.add_argument("--kp", "--kits_params",
329                                dest=ConfigConst.kits_params,
330                                action=SplicingAction,
331                                type=str,
332                                nargs='+',
333                                default="",
334                                help="- the params of kits that related to module")
335            parser.add_argument("--auto_retry",
336                                dest=ConfigConst.auto_retry,
337                                type=int,
338                                default=0,
339                                help="- the count of auto retry")
340            self._params_pre_processing(para_list)
341            (options, unparsed) = parser.parse_known_args(para_list)
342            if unparsed:
343                LOG.warning("Unparsed input: %s", " ".join(unparsed))
344            self._params_post_processing(options)
345
346        except SystemExit as _:
347            valid_param = False
348            parser.print_help()
349            LOG.warning("Parameter parsing system exit exception.")
350        return Argument(options, unparsed, valid_param, parser)
351
352    @classmethod
353    def _params_pre_processing(cls, para_list):
354        if len(para_list) <= 1 or (
355                len(para_list) > 1 and "-" in str(para_list[1])):
356            para_list.insert(1, Task.EMPTY_TASK)
357        for index, param in enumerate(para_list):
358            if param == "--retry":
359                if index + 1 == len(para_list):
360                    para_list.append("retry_previous_command")
361                elif "-" in str(para_list[index + 1]):
362                    para_list.insert(index + 1, "retry_previous_command")
363            elif param == "-->":
364                para_list[index] = "!%s" % param
365
366    def _params_post_processing(self, options):
367        # params post-processing
368        if options.task == Task.EMPTY_TASK:
369            setattr(options, ConfigConst.task, "")
370        if options.testargs:
371            if not options.pass_through:
372                test_args = self._parse_combination_param(options.testargs)
373                setattr(options, ConfigConst.testargs, test_args)
374            else:
375                setattr(options, ConfigConst.testargs, {
376                    ConfigConst.pass_through: options.testargs})
377        if not options.resource_path:
378            resource_path = UserConfigManager(
379                config_file=options.config, env=options.test_environment).\
380                get_resource_path()
381            setattr(options, ConfigConst.resource_path, resource_path)
382        if not options.testcases_path:
383            testcases_path = UserConfigManager(
384                config_file=options.config, env=options.test_environment).\
385                get_testcases_dir()
386            setattr(options, ConfigConst.testcases_path, testcases_path)
387        if options.testcases_path:
388            if Scheduler.task_type in ["ets", "hits"]:
389                testcases_path = "".join((options.testcases_path,
390                                          "/special/android-ets/testcases"))
391                setattr(options, "testcases_path", testcases_path)
392        device_log_dict = UserConfigManager(
393            config_file=options.config, env=options.test_environment). \
394            get_device_log_status()
395        setattr(options, ConfigConst.device_log, device_log_dict)
396        if options.subsystems:
397            subsystem_list = str(options.subsystems).split(";")
398            setattr(options, ConfigConst.subsystems, subsystem_list)
399        if options.parts:
400            part_list = str(options.parts).split(";")
401            setattr(options, ConfigConst.parts, part_list)
402
403    def command_parser(self, args):
404        try:
405            Scheduler.command_queue.append(args)
406            LOG.info("Input command: {}".format(args))
407            para_list = args.split()
408            argument = self.argument_parser(para_list)
409            options = argument.options
410            if options is None or not argument.valid_param:
411                LOG.warning("Options is None.")
412                return None
413            if options.action == ToolCommandType.toolcmd_key_run and \
414                    options.retry:
415                if hasattr(options, ConfigConst.auto_retry):
416                    setattr(options, ConfigConst.auto_retry, 0)
417                options = self._get_retry_options(options, argument.parser)
418                if options.dry_run:
419                    history_report_path = getattr(options,
420                                                  "history_report_path", "")
421                    self._list_retry_case(history_report_path)
422                    return
423            else:
424                from xdevice import SuiteReporter
425                SuiteReporter.clear_failed_case_list()
426                SuiteReporter.clear_report_result()
427
428            command = options.action
429            if command == "":
430                LOG.info("Command is empty.")
431                return
432
433            self._process_command(command, options, para_list, argument.parser)
434        except (ParamError, ValueError, TypeError, SyntaxError,
435                AttributeError) as exception:
436            error_no = getattr(exception, "error_no", "00000")
437            LOG.exception("%s: %s" % (get_instance_name(exception), exception),
438                          exc_info=False, error_no=error_no)
439            if Scheduler.upload_address:
440                Scheduler.upload_unavailable_result(str(exception.args))
441                Scheduler.upload_report_end()
442        finally:
443            if isinstance(Scheduler.command_queue[-1], str):
444                Scheduler.command_queue.pop()
445
446    def _process_command(self, command, options, para_list, parser):
447        if command.startswith(ToolCommandType.toolcmd_key_help):
448            self._process_command_help(parser, para_list)
449        elif command.startswith(ToolCommandType.toolcmd_key_show):
450            self._process_command_show(para_list)
451        elif command.startswith(ToolCommandType.toolcmd_key_run):
452            self._process_command_run(command, options)
453        elif command.startswith(ToolCommandType.toolcmd_key_quit):
454            self._process_command_quit(command)
455        elif command.startswith(ToolCommandType.toolcmd_key_list):
456            self._process_command_list(command, para_list)
457        elif command.startswith(ToolCommandType.toolcmd_key_tool):
458            self._process_command_tool(command, para_list, options)
459        else:
460            LOG.error("Unsupported command action", error_no="00100",
461                      action=command)
462
463    def _get_retry_options(self, options, parser):
464        input_options = copy.deepcopy(options)
465        # get history command, history report path
466        history_command, history_report_path = self._parse_retry_option(
467            options)
468        LOG.info("History command: %s", history_command)
469        if not os.path.exists(history_report_path) and \
470                Scheduler.mode != ModeType.decc:
471            raise ParamError(
472                "history report path %s not exists" % history_report_path)
473
474        # parse history command, set history report path
475        is_dry_run = True if options.dry_run else False
476
477        history_command = self._wash_history_command(history_command)
478
479        argument = self.argument_parser(history_command.split())
480        argument.options.dry_run = is_dry_run
481        setattr(argument.options, "history_report_path", history_report_path)
482        # modify history_command -rp param and -sn param
483        for option_tuple in self._get_to_be_replaced_option(parser):
484            history_command = self._replace_history_option(
485                history_command, (input_options, argument.options),
486                option_tuple)
487
488        # add history command to Scheduler.command_queue
489        LOG.info("Retry command: %s", history_command)
490        Scheduler.command_queue[-1] = history_command
491        return argument.options
492
493    @classmethod
494    def _process_command_help(cls, parser, para_list):
495        if para_list[0] == ToolCommandType.toolcmd_key_help:
496            if len(para_list) == 2:
497                cls.display_help_command_info(para_list[1])
498            else:
499                parser.print_help()
500        else:
501            LOG.error("Wrong help command. Use 'help' to print help")
502        return
503
504    @classmethod
505    def _process_command_show(cls, para_list):
506        if para_list[0] == ToolCommandType.toolcmd_key_show:
507            pass
508        else:
509            LOG.error("Wrong show command.")
510        return
511
512    @classmethod
513    def _process_command_run(cls, command, options):
514
515        scheduler = get_plugin(plugin_type=Plugin.SCHEDULER,
516                               plugin_id=SchedulerType.scheduler)[0]
517        if scheduler is None:
518            LOG.error("Can not find the scheduler plugin.")
519        else:
520            scheduler.exec_command(command, options)
521
522        return
523
524    def _process_command_list(self, command, para_list):
525        if command != ToolCommandType.toolcmd_key_list:
526            LOG.error("Wrong list command.")
527            return
528        if len(para_list) > 1:
529            if para_list[1] == "history":
530                self._list_history()
531            elif para_list[1] == "devices" or para_list[1] == Task.EMPTY_TASK:
532                env_manager = EnvironmentManager()
533                env_manager.list_devices()
534            else:
535                self._list_task_id(para_list[1])
536            return
537        # list devices
538        env_manager = EnvironmentManager()
539        env_manager.list_devices()
540        return
541
542    @classmethod
543    def _process_command_quit(cls, command):
544        if command == ToolCommandType.toolcmd_key_quit:
545            env_manager = EnvironmentManager()
546            env_manager.env_stop()
547            sys.exit(0)
548        else:
549            LOG.error("Wrong exit command. Use 'quit' to quit program")
550        return
551
552    def _process_command_tool(cls, command, para_list, options):
553        if not command.startswith(ToolCommandType.toolcmd_key_tool):
554            LOG.error("Wrong tool command.")
555            return
556        if len(para_list) > 2:
557            if para_list[1] == ConfigConst.renew_report:
558                if options.report_path:
559                    report_list = str(options.report_path).split(";")
560                    cls._renew_report(report_list)
561
562    @staticmethod
563    def _parse_combination_param(combination_value):
564        # sample: size:xxx1;exclude-annotation:xxx
565        parse_result = {}
566        key_value_pairs = str(combination_value).split(";")
567        for key_value_pair in key_value_pairs:
568            key, value = key_value_pair.split(":", 1)
569            if not value:
570                raise ParamError("'%s' no value" % key)
571            value_list = str(value).split(",")
572            exist_list = parse_result.get(key, [])
573            exist_list.extend(value_list)
574            parse_result[key] = exist_list
575        return parse_result
576
577    @classmethod
578    def _list_history(cls):
579        print("Command history:")
580        print("{0:<16}{1:<50}{2:<50}".format(
581            "TaskId", "Command", "ReportPath"))
582        for command_info in Scheduler.command_queue[:-1]:
583            command, report_path = command_info[1], command_info[2]
584            if len(command) > MAX_VISIBLE_LENGTH:
585                command = "%s..." % command[:MAX_RESERVED_LENGTH]
586            if len(report_path) > MAX_VISIBLE_LENGTH:
587                report_path = "%s..." % report_path[:MAX_RESERVED_LENGTH]
588            print("{0:<16}{1:<50}{2:<50}".format(
589                command_info[0], command, report_path))
590
591    @classmethod
592    def _list_task_id(cls, task_id):
593        print("List task:")
594        task_id, command, report_path = task_id, "", ""
595        for command_info in Scheduler.command_queue[:-1]:
596            if command_info[0] != task_id:
597                continue
598            task_id, command, report_path = command_info
599            break
600        print("{0:<16}{1:<100}".format("TaskId:", task_id))
601        print("{0:<16}{1:<100}".format("Command:", command))
602        print("{0:<16}{1:<100}".format("ReportPath:", report_path))
603
604    @classmethod
605    def _list_retry_case(cls, history_path):
606        params = ResultReporter.get_task_info_params(history_path)
607        if not params:
608            raise ParamError("no retry case exists")
609        session_id, command, report_path, failed_list = \
610            params[ReportConst.session_id], params[ReportConst.command], \
611            params[ReportConst.report_path], \
612            [(module, failed) for module, case_list in params[ReportConst.unsuccessful_params].items()
613             for failed in case_list]
614        if Scheduler.mode == ModeType.decc:
615            from xdevice import SuiteReporter
616            SuiteReporter.failed_case_list = failed_list
617            return
618
619        # draw tables in console
620        left, middle, right = 23, 49, 49
621        two_segments = "{0:-<%s}{1:-<%s}+" % (left, middle + right)
622        two_rows = "|{0:^%s}|{1:^%s}|" % (left - 1, middle + right - 1)
623
624        three_segments = "{0:-<%s}{1:-<%s}{2:-<%s}+" % (left, middle, right)
625        three_rows = "|{0:^%s}|{1:^%s}|{2:^%s}|" % \
626                     (left - 1, middle - 1, right - 1)
627        if len(session_id) > middle + right - 1:
628            session_id = "%s..." % session_id[:middle + right - 4]
629        if len(command) > middle + right - 1:
630            command = "%s..." % command[:middle + right - 4]
631        if len(report_path) > middle + right - 1:
632            report_path = "%s..." % report_path[:middle + right - 4]
633
634        print(two_segments.format("+", '+'))
635        print(two_rows.format("SessionId", session_id))
636        print(two_rows.format("Command", command))
637        print(two_rows.format("ReportPath", report_path))
638
639        print(three_segments.format("+", '+', '+'))
640        print(three_rows.format("Module", "Testsuite", "Testcase"))
641        print(three_segments.format("+", '+', '+'))
642        for module, failed in failed_list:
643            # all module is failed
644            if "#" not in failed:
645                class_name = "-"
646                test = "-"
647            # others, get failed cases info
648            else:
649                pos = failed.rfind("#")
650                class_name = failed[:pos]
651                test = failed[pos + 1:]
652            if len(module) > left - 1:
653                module = "%s..." % module[:left - 4]
654            if len(class_name) > middle - 1:
655                class_name = "%s..." % class_name[:middle - 4]
656            if len(test) > right - 1:
657                test = "%s..." % test[:right - 4]
658            print(three_rows.format(module, class_name, test))
659        print(three_segments.format("+", '+', '+'))
660
661    @classmethod
662    def _find_history_path(cls, session):
663        from xdevice import Variables
664        if os.path.isdir(session):
665            return session
666
667        target_path = os.path.join(
668            Variables.exec_dir, Variables.report_vars.report_dir, session)
669        if not os.path.isdir(target_path):
670            raise ParamError("session '%s' is invalid!" % session)
671
672        return target_path
673
674    def _parse_retry_option(self, options):
675        if Scheduler.mode == ModeType.decc:
676            if len(Scheduler.command_queue) < 2:
677                raise ParamError("no previous command executed")
678            _, history_command, history_report_path = \
679                Scheduler.command_queue[-2]
680            return history_command, history_report_path
681
682        # get history_command, history_report_path
683        if options.retry == "retry_previous_command":
684            from xdevice import Variables
685            history_path = os.path.join(Variables.temp_dir, "latest")
686            if options.session:
687                history_path = self._find_history_path(options.session)
688
689            params = ResultReporter.get_task_info_params(history_path)
690            if not params:
691                error_msg = "no previous command executed" if not \
692                    options.session else "'%s' has no command executed" % \
693                                         options.session
694                raise ParamError(error_msg)
695            history_command, history_report_path = params[ReportConst.command], params[ReportConst.report_path]
696        else:
697            history_command, history_report_path = "", ""
698            for command_tuple in Scheduler.command_queue[:-1]:
699                if command_tuple[0] != options.retry:
700                    continue
701                history_command, history_report_path = \
702                    command_tuple[1], command_tuple[2]
703                break
704            if not history_command:
705                raise ParamError("wrong task id input: %s" % options.retry)
706        return history_command, history_report_path
707
708    @classmethod
709    def display_help_command_info(cls, command):
710        if command == ToolCommandType.toolcmd_key_run:
711            print(RUN_INFORMATION)
712        elif command == ToolCommandType.toolcmd_key_list:
713            print(LIST_INFORMATION)
714        elif command == "empty":
715            print(GUIDE_INFORMATION)
716        else:
717            print("'%s' command no help information." % command)
718
719    @classmethod
720    def _replace_history_option(cls, history_command, options_tuple,
721                                target_option_tuple):
722        input_options, history_options = options_tuple
723        option_name, short_option_str, full_option_str = target_option_tuple
724        history_value = getattr(history_options, option_name, "")
725        input_value = getattr(input_options, option_name, "")
726        if history_value:
727            if input_value:
728                history_command = history_command.replace(history_value,
729                                                          input_value)
730                setattr(history_options, option_name, input_value)
731            else:
732                history_command = str(history_command).replace(
733                    history_value, "").replace(full_option_str, "").\
734                    replace(short_option_str, "")
735        else:
736            if input_value:
737                history_command = "{}{}".format(
738                    history_command, " %s %s" % (short_option_str,
739                                                 input_value))
740                setattr(history_options, option_name, input_value)
741
742        return history_command.strip()
743
744    @classmethod
745    def _get_to_be_replaced_option(cls, parser):
746        name_list = ["report_path", "device_sn"]
747        option_str_list = list()
748        action_list = getattr(parser, "_actions", [])
749        if action_list:
750            for action in action_list:
751                if action.dest not in name_list:
752                    continue
753                option_str_list.append((action.dest, action.option_strings[0],
754                                        action.option_strings[1]))
755        else:
756            option_str_list = [("report_path", "-rp", "--reportpath"),
757                               ("device_sn", "-sn", "--device_sn")]
758        return option_str_list
759
760    @classmethod
761    def _renew_report(cls, report_list):
762        from _core.report.__main__ import main_report
763        for report in report_list:
764            run_command = Scheduler.command_queue.pop()
765            Scheduler.command_queue.append(("", run_command, report))
766            sys.argv.insert(1, report)
767            main_report()
768            sys.argv.pop(1)
769
770    @classmethod
771    def _wash_history_command(cls, history_command):
772        # clear redundant content in history command. e.g. repeat,sn
773        if "--repeat" in history_command or "-sn" in history_command\
774                or "--auto_retry" in history_command:
775            split_list = list(history_command.split())
776            if "--repeat" in split_list:
777                pos = split_list.index("--repeat")
778                split_list = split_list[:pos] + split_list[pos + 2:]
779            if "-sn" in split_list:
780                pos = split_list.index("-sn")
781                split_list = split_list[:pos] + split_list[pos + 2:]
782            if "--auto_retry" in split_list:
783                pos = split_list.index("--auto_retry")
784                split_list = split_list[:pos] + split_list[pos + 2:]
785            return " ".join(split_list)
786        else:
787            return history_command
788
789
790RUN_INFORMATION = """run:
791    This command is used to execute the selected testcases.
792    It includes a series of processes such as use case compilation, \
793execution, and result collection.
794
795usage: run [-l TESTLIST [TESTLIST ...] | -tf TESTFILE
796           [TESTFILE ...]] [-tc TESTCASE] [-c CONFIG] [-sn DEVICE_SN]
797           [-rp REPORT_PATH [REPORT_PATH ...]]
798           [-respath RESOURCE_PATH [RESOURCE_PATH ...]]
799           [-tcpath TESTCASES_PATH [TESTCASES_PATH ...]]
800           [-ta TESTARGS [TESTARGS ...]] [-pt]
801           [-env TEST_ENVIRONMENT [TEST_ENVIRONMENT ...]]
802           [-e EXECTYPE] [-t [TESTTYPE [TESTTYPE ...]]]
803           [-td TESTDRIVER] [-tl TESTLEVEL] [-bv BUILD_VARIANT]
804           [-cov COVERAGE] [--retry RETRY] [--session SESSION]
805           [--dryrun] [--reboot-per-module] [--check-device]
806           [--repeat REPEAT]
807           action task
808
809Specify tests to run.
810
811positional arguments:
812  action                Specify action
813  task                  Specify task name,such as "ssts", "acts", "hits"
814
815optional arguments:
816    -h, --help            show this help message and exit
817    -l TESTLIST [TESTLIST ...], --testlist TESTLIST [TESTLIST ...]
818                        Specify test list
819    -tf TESTFILE [TESTFILE ...], --testfile TESTFILE [TESTFILE ...]
820                        Specify test list file
821    -tc TESTCASE, --testcase TESTCASE
822                        Specify test case
823    -c CONFIG, --config CONFIG
824                        Specify config file path
825    -sn DEVICE_SN, --device_sn DEVICE_SN
826                        Specify device serial number
827    -rp REPORT_PATH [REPORT_PATH ...], --reportpath REPORT_PATH [REPORT_PATH \
828...]
829                        Specify test report path
830    -respath RESOURCE_PATH [RESOURCE_PATH ...], --resourcepath RESOURCE_PATH \
831[RESOURCE_PATH ...]
832                        Specify test resource path
833    -tcpath TESTCASES_PATH [TESTCASES_PATH ...], --testcasespath \
834TESTCASES_PATH [TESTCASES_PATH ...]
835                        Specify testcases path
836    -ta TESTARGS [TESTARGS ...], --testargs TESTARGS [TESTARGS ...]
837                        Specify test arguments
838    -pt, --passthrough    Pass through test arguments
839    -env TEST_ENVIRONMENT [TEST_ENVIRONMENT ...], --environment \
840TEST_ENVIRONMENT [TEST_ENVIRONMENT ...]
841                        Specify test environment
842    -e EXECTYPE, --exectype EXECTYPE
843                        Specify test execute type
844    -t [TESTTYPE [TESTTYPE ...]], --testtype [TESTTYPE [TESTTYPE ...]]
845                        Specify test type(UT,MST,ST,PERF,SEC,RELI,DST,ALL)
846    -td TESTDRIVER, --testdriver TESTDRIVER
847                        Specify test driver id
848    -tl TESTLEVEL, --testlevel TESTLEVEL
849                        Specify test level
850    -bv BUILD_VARIANT, --build_variant BUILD_VARIANT
851                        Specify build variant(release,debug)
852    -cov COVERAGE, --coverage COVERAGE
853                        Specify coverage
854    --retry RETRY         Specify retry command
855    --session SESSION     retry task by session id
856    --dryrun              show retry test case list
857    --reboot-per-module   reboot devices before executing each module
858    --check-device        check the test device meets the requirements
859    --repeat REPEAT       number of times that a task is executed repeatedly
860
861Examples:
862    run -l <module name>;<module name>
863    run -tf test/resource/<test file name>.txt
864
865    run –l <module name> -sn <device serial number>;<device serial number>
866    run –l <module name> -respath <path of resource>
867    run –l <module name> -ta size:large
868    run –l <module name> –ta class:<package>#<class>#<method>
869    run –l <module name> -ta size:large -pt
870    run –l <module name> –env <the content string of user_config.xml>
871    run –l <module name> –e device
872    run –l <module name> –t ALL
873    run –l <module name> –td CppTest
874    run –l <module name> -tcpath resource/testcases
875
876    run ssts
877    run ssts –tc <python script name>;<python script name>
878    run ssts -sn <device serial number>;<device serial number>
879    run ssts -respath <path of resource>
880    ... ...
881
882    run acts
883    run acts –tc <python script name>;<python script name>
884    run acts -sn <device serial number>;<device serial number>
885    run acts -respath <path of resource>
886    ... ...
887
888    run hits
889    ... ...
890
891    run --retry
892    run --retry --session <report folder name>
893    run --retry --dryrun
894"""
895
896LIST_INFORMATION = "list:" + """
897    This command is used to display device list and task record.\n
898usage:
899    list
900    list history
901    list <id>
902
903Introduction:
904    list:         display device list
905    list history: display history record of a serial of tasks
906    list <id>:    display history record about task what contains specific id
907
908Examples:
909    list
910    list history
911    list 6e****90
912"""
913
914
915GUIDE_INFORMATION = """help:
916    use help to get  information.
917
918usage:
919    run:  Display a list of supported run command.
920    list: Display a list of supported device and task record.
921
922Examples:
923    help run
924    help list
925"""
926