• 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#
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