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