1#!/usr/bin/env python3 2# coding=utf-8 3 4# 5# Copyright (c) 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 os 20import traceback 21import platform 22from xml.etree import ElementTree 23 24from devicetest.core.exception import TestPrepareError 25from devicetest.core.constants import RunResult 26from devicetest.utils.util import get_base_name 27from devicetest.utils.util import import_from_file 28 29 30class PrepareHandler(): 31 32 def __init__(self, log, cur_case, project, configs, devices, run_list): 33 self.log = log 34 self.cur_case = cur_case 35 self.project = project 36 self.configs = configs 37 self.devices = devices 38 self.is_run_prepare = False 39 self.parse_test_list(run_list) 40 41 def parse_prepare_config(self, case_path, xml_path): 42 try: 43 self.log.debug("parse prepare config case path:{}". 44 format(case_path)) 45 case_name = get_base_name(case_path) 46 prepares = ElementTree.parse(xml_path).findall("prepare") 47 for cls in prepares: 48 cls_name = get_base_name(cls.attrib["class"].strip()) 49 for case in cls.findall("testcase"): 50 name = get_base_name(case.attrib["name"].strip()) 51 if name and case_name == name: 52 if self.flash_prepare_config(case_name, cls_name): 53 break 54 except Exception: 55 self.log.debug(traceback.format_exc()) 56 self.log.error("parse prepare config exception error.") 57 58 def flash_prepare_config(self, case_name, cls_name): 59 if cls_name not in self.project.prepare.config.keys(): 60 self.project.prepare.config[cls_name] = {} 61 self.project.prepare.config[cls_name]['status'] = 'unexecuted' 62 self.project.prepare.config[cls_name]['cases'] = [] 63 if case_name not in self.project.prepare.config[cls_name]['cases']: 64 self.project.prepare.config[cls_name]['cases'].append(case_name) 65 return True 66 return False 67 68 def parse_test_list(self, test_list): 69 """Parse user provided test list into internal format for test_runner. 70 """ 71 if not self.project.prepare.path: 72 return 73 xml_path = os.path.join(self.project.prepare.path, 'prepare.xml') 74 self.log.debug("prepare xml path:{}".format(xml_path)) 75 if os.access(xml_path, os.F_OK): 76 for elem in test_list: 77 self._parse_one_test_specifier(elem, xml_path) 78 self.log.debug("prepare config:{}".format( 79 self.project.prepare.config)) 80 if self.project.prepare.config: 81 self.is_run_prepare = True 82 else: 83 self.log.warning( 84 "{} not exists, please check.".format(xml_path)) 85 86 def _parse_one_test_specifier(self, item, xml_path): 87 sys_type = platform.system() 88 if sys_type == "Windows": 89 tokens = item.split(';') 90 elif sys_type == "Linux": 91 tokens = item.split(':') 92 elif sys_type == "Darwin": 93 tokens = item.split(':') 94 else: 95 raise TestPrepareError("sys type error:{}".format(sys_type)) 96 if len(tokens) > 2: 97 raise TestPrepareError( 98 "Syntax error in test specifier {}".format(item)) 99 if len(tokens) == 1: 100 # This should be considered a test class name 101 self.parse_prepare_config(tokens[0], xml_path) 102 elif len(tokens) == 2: 103 test_cls_name, test_case_names = tokens 104 for elem in test_case_names.split(','): 105 self.validate_test_name(elem.strip()) 106 self.parse_prepare_config(test_cls_name, xml_path) 107 108 def validate_test_name(self, name): 109 """Checks if a test name is valid. """ 110 if name == "" or name is None or len(name) < 1: 111 raise TestPrepareError( 112 "Invalid test case name found:{},test method couldn't" 113 " be none.".format(name)) 114 115 def _init_run_prepare(self, test_cls_name): 116 """ 117 prepare变量清理 118 Args: 119 test_cls_name: 120 Returns: 121 """ 122 self.cur_case.log_details_path = "./log/test_run_details.log" 123 self.cur_case.log_path = "./log/test_run_summary.log" 124 self.cur_case.set_case_screenshot_dir(self.project.test_suite_path, 125 self.project.task_report_dir, 126 test_cls_name) 127 self.cur_case.report_path = self.cur_case.case_screenshot_dir + ".html" 128 self.cur_case.case_result = RunResult.PASSED 129 self.cur_case.description = "" 130 self.cur_case.error_msg = "" 131 self.cur_case.status = 0 132 self.cur_case.image_num = 0 133 self.cur_case.dump_xml_num = 0 134 135 def run_prepare(self, is_teardown=False): 136 if not self.is_run_prepare: 137 return 138 func = 'teardown' if is_teardown else 'setup' 139 self.log.debug("in prepare {}".format(func)) 140 error_msg = None 141 try: 142 for cls, val in self.project.prepare.config.items(): 143 if self.project.prepare.path: 144 prepare_path = self.project.prepare.path 145 else: 146 prepare_path = os.path.join( 147 self.project.test_suite_path, 'prepare') 148 149 self.log.debug("prepare path:{}".format(prepare_path)) 150 test_cls_name = os.path.join(prepare_path, cls + '.py') 151 if not os.access(test_cls_name, os.F_OK): 152 test_cls_name = os.path.join(prepare_path, 153 cls + '.pyd') 154 if not os.access(test_cls_name, os.F_OK): 155 err = "Can not find prepare script '{}'.".format( 156 os.path.join(prepare_path, cls + '.py/d')) 157 raise TestPrepareError(err) 158 self.log.info("import prepare script:{}".format(cls)) 159 self.project.cur_case_full_path = test_cls_name 160 test_cls = import_from_file(prepare_path, cls) 161 self.log.debug( 162 "Success to import {}.".format(test_cls_name)) 163 with test_cls(self.configs) as test_instance: 164 if 'setup' == func: 165 if 'unexecuted' == val['status']: 166 self.project.prepare.config[cls][ 167 'status'] = 'executed' 168 result = test_instance._exec_func( 169 test_instance.setup) 170 if not result: 171 raise TestPrepareError( 172 "prepare's setup may be error!") 173 else: 174 if 'executed' == val['status']: 175 self.project.prepare.config[cls][ 176 'status'] = 'finsh' 177 result = test_instance._exec_func( 178 test_instance.teardown) 179 if not result: 180 self.log.warning( 181 "prepare's teardown may be error!") 182 183 except TestPrepareError as err: 184 error_msg = "{}: {}".format(err, traceback.format_exc()) 185 self.log.error(error_msg) 186 187 except Exception: 188 error_msg = "run prepare error! {}".format(traceback.format_exc()) 189 self.log.error(error_msg) 190 self.log.debug(traceback.format_exc()) 191 192 finally: 193 self.log.debug("exit prepare {}".format(func)) 194 if error_msg is not None: 195 raise TestPrepareError(error_msg) 196