• 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            self._params_pre_processing(para_list)
322            (options, unparsed) = parser.parse_known_args(para_list)
323            if unparsed:
324                LOG.warning("Unparsed input: %s", " ".join(unparsed))
325            self._params_post_processing(options)
326
327        except SystemExit as _:
328            valid_param = False
329            parser.print_help()
330            LOG.warning("Parameter parsing system exit exception.")
331        return Argument(options, unparsed, valid_param, parser)
332
333    @classmethod
334    def _params_pre_processing(cls, para_list):
335        if len(para_list) <= 1 or (
336                len(para_list) > 1 and "-" in str(para_list[1])):
337            para_list.insert(1, Task.EMPTY_TASK)
338        for index, param in enumerate(para_list):
339            if param == "--retry":
340                if index + 1 == len(para_list):
341                    para_list.append("retry_previous_command")
342                elif "-" in str(para_list[index + 1]):
343                    para_list.insert(index + 1, "retry_previous_command")
344            elif param == "-->":
345                para_list[index] = "!%s" % param
346
347    def _params_post_processing(self, options):
348        # params post-processing
349        if options.task == Task.EMPTY_TASK:
350            setattr(options, ConfigConst.task, "")
351        if options.testargs:
352            if not options.pass_through:
353                test_args = self._parse_combination_param(options.testargs)
354                setattr(options, ConfigConst.testargs, test_args)
355            else:
356                setattr(options, ConfigConst.testargs, {
357                    ConfigConst.pass_through: options.testargs})
358        if not options.resource_path:
359            resource_path = UserConfigManager(
360                config_file=options.config, env=options.test_environment).\
361                get_resource_path()
362            setattr(options, ConfigConst.resource_path, resource_path)
363        if not options.testcases_path:
364            testcases_path = UserConfigManager(
365                config_file=options.config, env=options.test_environment).\
366                get_testcases_dir()
367            setattr(options, ConfigConst.testcases_path, testcases_path)
368        if options.testcases_path:
369            if Scheduler.task_type in ["ets", "hits"]:
370                testcases_path = "".join((options.testcases_path,
371                                          "/special/android-ets/testcases"))
372                setattr(options, "testcases_path", testcases_path)
373        device_log = UserConfigManager(
374            config_file=options.config, env=options.test_environment). \
375            get_device_log_status()
376        if device_log is None or (device_log != ConfigConst.device_log_on
377                                  and device_log != ConfigConst.device_log_off):
378            device_log = ConfigConst.device_log_on
379        setattr(options, ConfigConst.device_log, device_log)
380        if options.subsystems:
381            subsystem_list = str(options.subsystems).split(";")
382            setattr(options, ConfigConst.subsystems, subsystem_list)
383        if options.parts:
384            part_list = str(options.parts).split(";")
385            setattr(options, ConfigConst.parts, part_list)
386
387    def command_parser(self, args):
388        try:
389            Scheduler.command_queue.append(args)
390            LOG.info("Input command: {}".format(args))
391            para_list = args.split()
392            argument = self.argument_parser(para_list)
393            options = argument.options
394            if options is None or not argument.valid_param:
395                LOG.warning("Options is None.")
396                return None
397            if options.action == ToolCommandType.toolcmd_key_run and \
398                    options.retry:
399                options = self._get_retry_options(options, argument.parser)
400                if options.dry_run:
401                    history_report_path = getattr(options,
402                                                  "history_report_path", "")
403                    self._list_retry_case(history_report_path)
404                    return
405            else:
406                from xdevice import SuiteReporter
407                SuiteReporter.clear_failed_case_list()
408                SuiteReporter.clear_report_result()
409
410            command = options.action
411            if command == "":
412                LOG.info("Command is empty.")
413                return
414
415            self._process_command(command, options, para_list, argument.parser)
416        except (ParamError, ValueError, TypeError, SyntaxError,
417                AttributeError) as exception:
418            error_no = getattr(exception, "error_no", "00000")
419            LOG.exception("%s: %s" % (get_instance_name(exception), exception),
420                          exc_info=False, error_no=error_no)
421            if Scheduler.upload_address:
422                Scheduler.upload_unavailable_result(str(exception.args))
423                Scheduler.upload_report_end()
424        finally:
425            if isinstance(Scheduler.command_queue[-1], str):
426                Scheduler.command_queue.pop()
427
428    def _process_command(self, command, options, para_list, parser):
429        if command.startswith(ToolCommandType.toolcmd_key_help):
430            self._process_command_help(parser, para_list)
431        elif command.startswith(ToolCommandType.toolcmd_key_show):
432            self._process_command_show(para_list)
433        elif command.startswith(ToolCommandType.toolcmd_key_run):
434            self._process_command_run(command, options)
435        elif command.startswith(ToolCommandType.toolcmd_key_quit):
436            self._process_command_quit(command)
437        elif command.startswith(ToolCommandType.toolcmd_key_list):
438            self._process_command_list(command, para_list)
439        elif command.startswith(ToolCommandType.toolcmd_key_tool):
440            self._process_command_tool(command, para_list, options)
441        else:
442            LOG.error("Unsupported command action", error_no="00100",
443                      action=command)
444
445    def _get_retry_options(self, options, parser):
446        input_options = copy.deepcopy(options)
447        # get history command, history report path
448        history_command, history_report_path = self._parse_retry_option(
449            options)
450        LOG.info("History command: %s", history_command)
451        if not os.path.exists(history_report_path) and \
452                Scheduler.mode != ModeType.decc:
453            raise ParamError(
454                "history report path %s not exists" % history_report_path)
455
456        # parse history command, set history report path
457        is_dry_run = True if options.dry_run else False
458
459        # clear the content about repeat count in history command
460        if "--repeat" in history_command:
461            split_list = list(history_command.split())
462            if "--repeat" in split_list:
463                pos = split_list.index("--repeat")
464                split_list = split_list[:pos] + split_list[pos + 2:]
465                history_command = " ".join(split_list)
466
467        argument = self.argument_parser(history_command.split())
468        argument.options.dry_run = is_dry_run
469        setattr(argument.options, "history_report_path", history_report_path)
470        # modify history_command -rp param and -sn param
471        for option_tuple in self._get_to_be_replaced_option(parser):
472            history_command = self._replace_history_option(
473                history_command, (input_options, argument.options),
474                option_tuple)
475
476        # add history command to Scheduler.command_queue
477        LOG.info("Retry command: %s", history_command)
478        Scheduler.command_queue[-1] = history_command
479        return argument.options
480
481    @classmethod
482    def _process_command_help(cls, parser, para_list):
483        if para_list[0] == ToolCommandType.toolcmd_key_help:
484            if len(para_list) == 2:
485                cls.display_help_command_info(para_list[1])
486            else:
487                parser.print_help()
488        else:
489            LOG.error("Wrong help command. Use 'help' to print help")
490        return
491
492    @classmethod
493    def _process_command_show(cls, para_list):
494        if para_list[0] == ToolCommandType.toolcmd_key_show:
495            pass
496        else:
497            LOG.error("Wrong show command.")
498        return
499
500    @classmethod
501    def _process_command_run(cls, command, options):
502
503        scheduler = get_plugin(plugin_type=Plugin.SCHEDULER,
504                               plugin_id=SchedulerType.scheduler)[0]
505        if scheduler is None:
506            LOG.error("Can not find the scheduler plugin.")
507        else:
508            scheduler.exec_command(command, options)
509
510        return
511
512    def _process_command_list(self, command, para_list):
513        if command != ToolCommandType.toolcmd_key_list:
514            LOG.error("Wrong list command.")
515            return
516        if len(para_list) > 1:
517            if para_list[1] == "history":
518                self._list_history()
519            elif para_list[1] == "devices" or para_list[1] == Task.EMPTY_TASK:
520                env_manager = EnvironmentManager()
521                env_manager.list_devices()
522            else:
523                self._list_task_id(para_list[1])
524            return
525        # list devices
526        env_manager = EnvironmentManager()
527        env_manager.list_devices()
528        return
529
530    @classmethod
531    def _process_command_quit(cls, command):
532        if command == ToolCommandType.toolcmd_key_quit:
533            env_manager = EnvironmentManager()
534            env_manager.env_stop()
535            sys.exit(0)
536        else:
537            LOG.error("Wrong exit command. Use 'quit' to quit program")
538        return
539
540    def _process_command_tool(cls, command, para_list, options):
541        if not command.startswith(ToolCommandType.toolcmd_key_tool):
542            LOG.error("Wrong tool command.")
543            return
544        if len(para_list) > 2:
545            if para_list[1] == ConfigConst.renew_report:
546                if options.report_path:
547                    report_list = str(options.report_path).split(";")
548                    cls._renew_report(report_list)
549
550    @staticmethod
551    def _parse_combination_param(combination_value):
552        # sample: size:xxx1;exclude-annotation:xxx
553        parse_result = {}
554        key_value_pairs = str(combination_value).split(";")
555        for key_value_pair in key_value_pairs:
556            key, value = key_value_pair.split(":", 1)
557            if not value:
558                raise ParamError("'%s' no value" % key)
559            value_list = str(value).split(",")
560            exist_list = parse_result.get(key, [])
561            exist_list.extend(value_list)
562            parse_result[key] = exist_list
563        return parse_result
564
565    @classmethod
566    def _list_history(cls):
567        print("Command history:")
568        print("{0:<16}{1:<50}{2:<50}".format(
569            "TaskId", "Command", "ReportPath"))
570        for command_info in Scheduler.command_queue[:-1]:
571            command, report_path = command_info[1], command_info[2]
572            if len(command) > MAX_VISIBLE_LENGTH:
573                command = "%s..." % command[:MAX_RESERVED_LENGTH]
574            if len(report_path) > MAX_VISIBLE_LENGTH:
575                report_path = "%s..." % report_path[:MAX_RESERVED_LENGTH]
576            print("{0:<16}{1:<50}{2:<50}".format(
577                command_info[0], command, report_path))
578
579    @classmethod
580    def _list_task_id(cls, task_id):
581        print("List task:")
582        task_id, command, report_path = task_id, "", ""
583        for command_info in Scheduler.command_queue[:-1]:
584            if command_info[0] != task_id:
585                continue
586            task_id, command, report_path = command_info
587            break
588        print("{0:<16}{1:<100}".format("TaskId:", task_id))
589        print("{0:<16}{1:<100}".format("Command:", command))
590        print("{0:<16}{1:<100}".format("ReportPath:", report_path))
591
592    @classmethod
593    def _list_retry_case(cls, history_path):
594        params = ResultReporter.get_task_info_params(history_path)
595        if not params:
596            raise ParamError("no retry case exists")
597        session_id, command, report_path, failed_list = \
598            params[ReportConst.session_id], params[ReportConst.command], \
599            params[ReportConst.report_path], \
600            [(module, failed) for module, case_list in params[ReportConst.unsuccessful_params].items()
601             for failed in case_list]
602        if Scheduler.mode == ModeType.decc:
603            from xdevice import SuiteReporter
604            SuiteReporter.failed_case_list = failed_list
605            return
606
607        # draw tables in console
608        left, middle, right = 23, 49, 49
609        two_segments = "{0:-<%s}{1:-<%s}+" % (left, middle + right)
610        two_rows = "|{0:^%s}|{1:^%s}|" % (left - 1, middle + right - 1)
611
612        three_segments = "{0:-<%s}{1:-<%s}{2:-<%s}+" % (left, middle, right)
613        three_rows = "|{0:^%s}|{1:^%s}|{2:^%s}|" % \
614                     (left - 1, middle - 1, right - 1)
615        if len(session_id) > middle + right - 1:
616            session_id = "%s..." % session_id[:middle + right - 4]
617        if len(command) > middle + right - 1:
618            command = "%s..." % command[:middle + right - 4]
619        if len(report_path) > middle + right - 1:
620            report_path = "%s..." % report_path[:middle + right - 4]
621
622        print(two_segments.format("+", '+'))
623        print(two_rows.format("SessionId", session_id))
624        print(two_rows.format("Command", command))
625        print(two_rows.format("ReportPath", report_path))
626
627        print(three_segments.format("+", '+', '+'))
628        print(three_rows.format("Module", "Testsuite", "Testcase"))
629        print(three_segments.format("+", '+', '+'))
630        for module, failed in failed_list:
631            # all module is failed
632            if "#" not in failed:
633                class_name = "-"
634                test = "-"
635            # others, get failed cases info
636            else:
637                pos = failed.rfind("#")
638                class_name = failed[:pos]
639                test = failed[pos + 1:]
640            if len(module) > left - 1:
641                module = "%s..." % module[:left - 4]
642            if len(class_name) > middle - 1:
643                class_name = "%s..." % class_name[:middle - 4]
644            if len(test) > right - 1:
645                test = "%s..." % test[:right - 4]
646            print(three_rows.format(module, class_name, test))
647        print(three_segments.format("+", '+', '+'))
648
649    @classmethod
650    def _find_history_path(cls, session):
651        from xdevice import Variables
652        if os.path.isdir(session):
653            return session
654
655        target_path = os.path.join(
656            Variables.exec_dir, Variables.report_vars.report_dir, session)
657        if not os.path.isdir(target_path):
658            raise ParamError("session '%s' is invalid!" % session)
659
660        return target_path
661
662    def _parse_retry_option(self, options):
663        if Scheduler.mode == ModeType.decc:
664            if len(Scheduler.command_queue) < 2:
665                raise ParamError("no previous command executed")
666            _, history_command, history_report_path = \
667                Scheduler.command_queue[-2]
668            return history_command, history_report_path
669
670        # get history_command, history_report_path
671        if options.retry == "retry_previous_command":
672            from xdevice import Variables
673            history_path = os.path.join(
674                Variables.exec_dir, Variables.report_vars.report_dir, "latest")
675            if options.session:
676                history_path = self._find_history_path(options.session)
677
678            params = ResultReporter.get_task_info_params(history_path)
679            if not params:
680                error_msg = "no previous command executed" if not \
681                    options.session else "'%s' has no command executed" % \
682                                         options.session
683                raise ParamError(error_msg)
684            history_command, history_report_path = params[ReportConst.command], params[ReportConst.report_path]
685        else:
686            history_command, history_report_path = "", ""
687            for command_tuple in Scheduler.command_queue[:-1]:
688                if command_tuple[0] != options.retry:
689                    continue
690                history_command, history_report_path = \
691                    command_tuple[1], command_tuple[2]
692                break
693            if not history_command:
694                raise ParamError("wrong task id input: %s" % options.retry)
695        return history_command, history_report_path
696
697    @classmethod
698    def display_help_command_info(cls, command):
699        if command == ToolCommandType.toolcmd_key_run:
700            print(RUN_INFORMATION)
701        elif command == ToolCommandType.toolcmd_key_list:
702            print(LIST_INFORMATION)
703        elif command == "empty":
704            print(GUIDE_INFORMATION)
705        else:
706            print("'%s' command no help information." % command)
707
708    @classmethod
709    def _replace_history_option(cls, history_command, options_tuple,
710                                target_option_tuple):
711        input_options, history_options = options_tuple
712        option_name, short_option_str, full_option_str = target_option_tuple
713        history_value = getattr(history_options, option_name, "")
714        input_value = getattr(input_options, option_name, "")
715        if history_value:
716            if input_value:
717                history_command = history_command.replace(history_value,
718                                                          input_value)
719                setattr(history_options, option_name, input_value)
720            else:
721                history_command = str(history_command).replace(
722                    history_value, "").replace(full_option_str, "").\
723                    replace(short_option_str, "")
724        else:
725            if input_value:
726                history_command = "{}{}".format(
727                    history_command, " %s %s" % (short_option_str,
728                                                 input_value))
729                setattr(history_options, option_name, input_value)
730
731        return history_command.strip()
732
733    @classmethod
734    def _get_to_be_replaced_option(cls, parser):
735        name_list = ["report_path", "device_sn"]
736        option_str_list = list()
737        action_list = getattr(parser, "_actions", [])
738        if action_list:
739            for action in action_list:
740                if action.dest not in name_list:
741                    continue
742                option_str_list.append((action.dest, action.option_strings[0],
743                                        action.option_strings[1]))
744        else:
745            option_str_list = [("report_path", "-rp", "--reportpath"),
746                               ("device_sn", "-sn", "--device_sn")]
747        return option_str_list
748
749    @classmethod
750    def _renew_report(cls, report_list):
751        from _core.report.__main__ import main_report
752        for report in report_list:
753            run_command = Scheduler.command_queue.pop()
754            Scheduler.command_queue.append(("", run_command, report))
755            sys.argv.insert(1, report)
756            main_report()
757            sys.argv.pop(1)
758
759
760RUN_INFORMATION = """run:
761    This command is used to execute the selected testcases.
762    It includes a series of processes such as use case compilation, \
763execution, and result collection.
764
765usage: run [-l TESTLIST [TESTLIST ...] | -tf TESTFILE
766           [TESTFILE ...]] [-tc TESTCASE] [-c CONFIG] [-sn DEVICE_SN]
767           [-rp REPORT_PATH [REPORT_PATH ...]]
768           [-respath RESOURCE_PATH [RESOURCE_PATH ...]]
769           [-tcpath TESTCASES_PATH [TESTCASES_PATH ...]]
770           [-ta TESTARGS [TESTARGS ...]] [-pt]
771           [-env TEST_ENVIRONMENT [TEST_ENVIRONMENT ...]]
772           [-e EXECTYPE] [-t [TESTTYPE [TESTTYPE ...]]]
773           [-td TESTDRIVER] [-tl TESTLEVEL] [-bv BUILD_VARIANT]
774           [-cov COVERAGE] [--retry RETRY] [--session SESSION]
775           [--dryrun] [--reboot-per-module] [--check-device]
776           [--repeat REPEAT]
777           action task
778
779Specify tests to run.
780
781positional arguments:
782  action                Specify action
783  task                  Specify task name,such as "ssts", "acts", "hits"
784
785optional arguments:
786    -h, --help            show this help message and exit
787    -l TESTLIST [TESTLIST ...], --testlist TESTLIST [TESTLIST ...]
788                        Specify test list
789    -tf TESTFILE [TESTFILE ...], --testfile TESTFILE [TESTFILE ...]
790                        Specify test list file
791    -tc TESTCASE, --testcase TESTCASE
792                        Specify test case
793    -c CONFIG, --config CONFIG
794                        Specify config file path
795    -sn DEVICE_SN, --device_sn DEVICE_SN
796                        Specify device serial number
797    -rp REPORT_PATH [REPORT_PATH ...], --reportpath REPORT_PATH [REPORT_PATH \
798...]
799                        Specify test report path
800    -respath RESOURCE_PATH [RESOURCE_PATH ...], --resourcepath RESOURCE_PATH \
801[RESOURCE_PATH ...]
802                        Specify test resource path
803    -tcpath TESTCASES_PATH [TESTCASES_PATH ...], --testcasespath \
804TESTCASES_PATH [TESTCASES_PATH ...]
805                        Specify testcases path
806    -ta TESTARGS [TESTARGS ...], --testargs TESTARGS [TESTARGS ...]
807                        Specify test arguments
808    -pt, --passthrough    Pass through test arguments
809    -env TEST_ENVIRONMENT [TEST_ENVIRONMENT ...], --environment \
810TEST_ENVIRONMENT [TEST_ENVIRONMENT ...]
811                        Specify test environment
812    -e EXECTYPE, --exectype EXECTYPE
813                        Specify test execute type
814    -t [TESTTYPE [TESTTYPE ...]], --testtype [TESTTYPE [TESTTYPE ...]]
815                        Specify test type(UT,MST,ST,PERF,SEC,RELI,DST,ALL)
816    -td TESTDRIVER, --testdriver TESTDRIVER
817                        Specify test driver id
818    -tl TESTLEVEL, --testlevel TESTLEVEL
819                        Specify test level
820    -bv BUILD_VARIANT, --build_variant BUILD_VARIANT
821                        Specify build variant(release,debug)
822    -cov COVERAGE, --coverage COVERAGE
823                        Specify coverage
824    --retry RETRY         Specify retry command
825    --session SESSION     retry task by session id
826    --dryrun              show retry test case list
827    --reboot-per-module   reboot devices before executing each module
828    --check-device        check the test device meets the requirements
829    --repeat REPEAT       number of times that a task is executed repeatedly
830
831Examples:
832    run -l <module name>;<module name>
833    run -tf test/resource/<test file name>.txt
834
835    run –l <module name> -sn <device serial number>;<device serial number>
836    run –l <module name> -respath <path of resource>
837    run –l <module name> -ta size:large
838    run –l <module name> –ta class:<package>#<class>#<method>
839    run –l <module name> -ta size:large -pt
840    run –l <module name> –env <the content string of user_config.xml>
841    run –l <module name> –e device
842    run –l <module name> –t ALL
843    run –l <module name> –td CppTest
844    run –l <module name> -tcpath resource/testcases
845
846    run ssts
847    run ssts –tc <python script name>;<python script name>
848    run ssts -sn <device serial number>;<device serial number>
849    run ssts -respath <path of resource>
850    ... ...
851
852    run acts
853    run acts –tc <python script name>;<python script name>
854    run acts -sn <device serial number>;<device serial number>
855    run acts -respath <path of resource>
856    ... ...
857
858    run hits
859    ... ...
860
861    run --retry
862    run --retry --session <report folder name>
863    run --retry --dryrun
864"""
865
866LIST_INFORMATION = "list:" + """
867    This command is used to display device list and task record.\n
868usage:
869    list
870    list history
871    list <id>
872
873Introduction:
874    list:         display device list
875    list history: display history record of a serial of tasks
876    list <id>:    display history record about task what contains specific id
877
878Examples:
879    list
880    list history
881    list 6e****90
882"""
883
884
885GUIDE_INFORMATION = """help:
886    use help to get  information.
887
888usage:
889    run:  Display a list of supported run command.
890    list: Display a list of supported device and task record.
891
892Examples:
893    help run
894    help list
895"""
896