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# 18import json 19import threading 20 21from _core.config.config_manager import UserConfigManager 22from _core.logger import platform_logger 23from _core.logger import change_logger_level 24from _core.plugin import Plugin 25from _core.plugin import get_plugin 26from _core.utils import convert_serial 27from _core.constants import ProductForm 28from _core.constants import ConfigConst 29from _core.constants import DeviceResult 30from _core.environment.device_state import DeviceAllocationState 31from _core.utils import get_current_time 32from _core.utils import check_mode_in_sys 33 34__all__ = ["EnvironmentManager", "DeviceSelectionOption", "Environment"] 35 36LOG = platform_logger("ManagerEnv") 37 38 39class Environment(object): 40 """ 41 Environment required for each dispatch 42 """ 43 device_mapper = { 44 ProductForm.phone: "Phone", 45 ProductForm.tablet: "Tablet", 46 ProductForm.car: "Car", 47 ProductForm.television: "Tv", 48 ProductForm.watch: "Watch", 49 } 50 51 def __init__(self): 52 self.devices = [] 53 self.phone = 0 54 self.wifiiot = 0 55 self.ipcamera = 0 56 self.device_recorder = dict() 57 58 def __get_serial__(self): 59 device_serials = [] 60 for device in self.devices: 61 device_serials.append(convert_serial(device.__get_serial__())) 62 return ";".join(device_serials) 63 64 def get_devices(self): 65 return self.devices 66 67 def get_description(self): 68 descriptions = [] 69 for d in self.devices: 70 try: 71 descriptions.append(d.device_description) 72 except Exception as e: 73 LOG.error(f"get device description error: {e}") 74 return descriptions 75 76 def check_serial(self): 77 if self.__get_serial__(): 78 return True 79 return False 80 81 def add_device(self, device, index=None): 82 label = self.device_mapper.get(device.label, "DUT") 83 if index: 84 current = index 85 else: 86 current = self.device_recorder.get(label, 0) + 1 87 device.device_id = "%s%s" % (label, current) if not device.device_id else device.device_id 88 LOG.debug("add_device, sn: {}, id: {}".format(device.device_sn, 89 device.device_id)) 90 self.device_recorder.update({label: current}) 91 self.devices.append(device) 92 93 94class EnvironmentManager(object): 95 """ 96 Class representing environment manager that 97 managing the set of available devices for testing 98 """ 99 __instance = None 100 __init_flag = False 101 102 test_devices = { 103 DeviceResult.code: -1, 104 DeviceResult.date: get_current_time(), 105 DeviceResult.msg: "no mobile device", 106 DeviceResult.result: "false", 107 DeviceResult.data: [] 108 } 109 110 def __new__(cls, *args, **kwargs): 111 """ 112 Singleton instance 113 """ 114 del args, kwargs 115 if cls.__instance is None: 116 cls.__instance = super(EnvironmentManager, cls).__new__(cls) 117 return cls.__instance 118 119 def __init__(self, environment="", user_config_file=""): 120 if EnvironmentManager.__init_flag: 121 return 122 self.managers = {} 123 self.used_devices = [] 124 self.environment_enable = True 125 self.env_start(environment, user_config_file) 126 self.lock_con = threading.Condition() 127 128 EnvironmentManager.__init_flag = True 129 130 def env_start(self, environment="", user_config_file=""): 131 user_config_manager = UserConfigManager( 132 config_file=user_config_file, env=environment) 133 log_level_dict = user_config_manager.loglevel 134 if log_level_dict: 135 # change log level when load or reset EnvironmentManager object 136 change_logger_level(log_level_dict) 137 138 self.environment_enable = user_config_manager.environment_enable() 139 if not self.environment_enable: 140 LOG.warning("The device element may not exist in user_config.xml! " 141 "If this is not what you need, please check it") 142 return 143 144 manager_plugins = get_plugin(Plugin.MANAGER) 145 for manager_plugin in manager_plugins: 146 try: 147 manager_instance = manager_plugin.__class__() 148 if manager_instance.init_environment(environment, user_config_file): 149 self.managers[manager_instance.__class__.__name__] = manager_instance 150 except Exception as error: 151 LOG.debug("Env start error: %s" % error) 152 # 倒序排列, 优先加载OH设备 153 if self.managers: 154 self.managers = dict(sorted(self.managers.items(), reverse=True)) 155 156 def env_stop(self): 157 for manager in self.managers.values(): 158 manager.env_stop() 159 manager.devices_list = [] 160 self.managers = {} 161 162 EnvironmentManager.__init_flag = False 163 164 def apply_environment(self, device_options): 165 environment = Environment() 166 for device_option in device_options: 167 LOG.debug("Visit options to find device") 168 device = self.apply_device(device_option) 169 if device is not None: 170 index = self.get_config_device_index(device) 171 environment.add_device(device, index) 172 device.extend_value = device_option.extend_value 173 LOG.debug("Device %s: extend value: %s", convert_serial( 174 device.device_sn), device.extend_value) 175 if hasattr(device, "extend_device_props"): 176 device.extend_device_props() 177 device.init_description() 178 else: 179 LOG.debug("Require label is '%s', then next" % 180 device_option.label) 181 return environment 182 183 def release_environment(self, environment): 184 self.lock_con.acquire() 185 for device in environment.devices: 186 device.extend_value = {} 187 self.release_device(device) 188 if device in self.used_devices: 189 LOG.debug("Device in used_devices, remove it.") 190 self.used_devices.remove(device) 191 self.lock_con.release() 192 193 def reset_environment(self, used_devices): 194 for _, device in used_devices.items(): 195 self.reset_device(device) 196 197 def apply_device(self, device_option, timeout=3): 198 LOG.debug("Apply device from managers:%s" % self.managers) 199 for manager_type, manager in self.managers.items(): 200 support_labels = getattr(manager, "support_labels", []) 201 support_types = getattr(manager, "support_types", []) 202 if device_option.required_manager not in support_types: 203 LOG.warning("'%s' not in %s's support types" % ( 204 device_option.required_manager, manager_type)) 205 continue 206 if not support_labels: 207 continue 208 if device_option.label is None: 209 if manager_type != "ManagerDevice": 210 continue 211 else: 212 if support_labels and \ 213 device_option.label not in support_labels: 214 continue 215 device = manager.apply_device(device_option, timeout) 216 if hasattr(device, "env_index"): 217 device.env_index = device_option.get_env_index() 218 if device: 219 has_allocated = False 220 self.lock_con.acquire() 221 for dev in self.used_devices: 222 if hasattr(dev, "device_sn") and dev.device_sn == device.device_sn: 223 has_allocated = True 224 break 225 if has_allocated: 226 self.lock_con.release() 227 continue 228 else: 229 self.used_devices.append(device) 230 self.lock_con.release() 231 return device 232 233 else: 234 return None 235 236 def get_config_device_index(self, device): 237 if device and hasattr(device, "device_sn"): 238 sn = device.device_sn 239 for manager in self.managers.items(): 240 if hasattr(manager[1], "global_device_filter"): 241 index = 1 242 for s in manager[1].global_device_filter: 243 if s == sn: 244 return index 245 else: 246 index += 1 247 return None 248 249 def check_device_exist(self, device_options): 250 """ 251 Check if there are matched devices which can be allocated or available. 252 """ 253 devices = [] 254 for device_option in device_options: 255 for manager_type, manager in self.managers.items(): 256 support_labels = getattr(manager, "support_labels", []) 257 support_types = getattr(manager, "support_types", []) 258 if device_option.required_manager not in support_types: 259 continue 260 if device_option.label is None: 261 if manager_type != "ManagerDevice": 262 continue 263 else: 264 if support_labels and \ 265 device_option.label not in support_labels: 266 continue 267 for device in manager.devices_list: 268 if device.device_sn in devices: 269 continue 270 if device_option.matches(device, False): 271 devices.append(device.device_sn) 272 break 273 else: 274 continue 275 break 276 else: 277 return False 278 return True 279 280 def release_device(self, device): 281 for manager in self.managers.values(): 282 if device in manager.devices_list: 283 manager.release_device(device) 284 285 def reset_device(self, device): 286 for manager in self.managers.values(): 287 if device in manager.devices_list: 288 manager.reset_device(device) 289 290 def list_devices(self): 291 if check_mode_in_sys(ConfigConst.app_test): 292 for manager in self.managers.values(): 293 devices = manager.list_devices() 294 if devices and isinstance(devices, list): 295 for device in devices: 296 self.test_devices.get(DeviceResult.data).append(device) 297 if self.test_devices.get(DeviceResult.data): 298 self.test_devices[DeviceResult.code] = 0 299 self.test_devices[DeviceResult.result] = "true" 300 self.test_devices[DeviceResult.msg] = "" 301 302 print(json.dumps(self.test_devices, sort_keys=False, 303 separators=(',', ':'))) 304 else: 305 LOG.info("List devices.") 306 for manager in self.managers.values(): 307 manager.list_devices() 308 309 310class DeviceSelectionOption(object): 311 """ 312 Class representing device selection option 313 """ 314 315 def __init__(self, options, label=None, test_source=None): 316 self.device_sn = [x for x in options[ConfigConst.device_sn].split(";") if x] 317 self.device_info = options.get(ConfigConst.device_info) 318 self.label = label 319 self.test_driver = test_source.test_type if test_source else None 320 self.source_file = "" 321 self.extend_value = {} 322 self.required_manager = "" 323 self.required_component = "" 324 self.env_index = None 325 326 def get_label(self): 327 return self.label 328 329 def get_env_index(self): 330 return self.env_index 331 332 def matches(self, device, allocate=True): 333 LOG.debug("Do matches, device:{state:%s, sn:%s, label:%s}, selection " 334 "option:{device sn:%s, label:%s}" % ( 335 device.device_allocation_state, 336 convert_serial(device.device_sn), 337 device.label, 338 [convert_serial(sn) if sn else "" for sn in self.device_sn], 339 self.label)) 340 if not getattr(device, "task_state", True): 341 return False 342 if allocate and device.device_allocation_state != \ 343 DeviceAllocationState.available: 344 return False 345 346 if not allocate: 347 if device.device_allocation_state != \ 348 DeviceAllocationState.available and \ 349 device.device_allocation_state != \ 350 DeviceAllocationState.allocated: 351 return False 352 353 if len(self.device_sn) != 0 and device.device_sn not in self.device_sn: 354 return False 355 356 if self.label and self.label != device.label: 357 return False 358 359 # 匹配设备额外参数 360 if not device.check_advance_option(self.extend_value, device_info=self.device_info): 361 return False 362 363 if self.required_component and \ 364 hasattr(device, ConfigConst.support_component): 365 subsystems, parts = getattr(device, ConfigConst.support_component) 366 required_subsystems, require_part = self.required_component 367 if required_subsystems not in subsystems and \ 368 require_part not in parts: 369 return False 370 return True 371