| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- # Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # http:#www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- """ Test Env, manages DUT, App and EnvConfig, interface for test cases to access these components """
- import functools
- import os
- import threading
- import traceback
- import netifaces
- from . import EnvConfig
- def _synced(func):
- @functools.wraps(func)
- def decorator(self, *args, **kwargs):
- with self.lock:
- ret = func(self, *args, **kwargs)
- return ret
- decorator.__doc__ = func.__doc__
- return decorator
- class Env(object):
- """
- test env, manages DUTs and env configs.
- :keyword app: class for default application
- :keyword dut: class for default DUT
- :keyword env_tag: test env tag, used to select configs from env config file
- :keyword env_config_file: test env config file path
- :keyword test_name: test suite name, used when generate log folder name
- """
- CURRENT_LOG_FOLDER = ''
- def __init__(self,
- app=None,
- dut=None,
- env_tag=None,
- env_config_file=None,
- test_suite_name=None,
- **kwargs):
- self.app_cls = app
- self.default_dut_cls = dut
- self.config = EnvConfig.Config(env_config_file, env_tag)
- self.log_path = self.app_cls.get_log_folder(test_suite_name)
- if not os.path.exists(self.log_path):
- os.makedirs(self.log_path)
- Env.CURRENT_LOG_FOLDER = self.log_path
- self.allocated_duts = dict()
- self.lock = threading.RLock()
- @_synced
- def get_dut(self, dut_name, app_path, dut_class=None, app_class=None, app_config_name=None, **dut_init_args):
- """
- get_dut(dut_name, app_path, dut_class=None, app_class=None)
- :param dut_name: user defined name for DUT
- :param app_path: application path, app instance will use this path to process application info
- :param dut_class: dut class, if not specified will use default dut class of env
- :param app_class: app class, if not specified will use default app of env
- :param app_config_name: app build config
- :keyword dut_init_args: extra kwargs used when creating DUT instance
- :return: dut instance
- """
- if dut_name in self.allocated_duts:
- dut = self.allocated_duts[dut_name]['dut']
- else:
- if dut_class is None:
- dut_class = self.default_dut_cls
- if app_class is None:
- app_class = self.app_cls
- app_target = dut_class.TARGET
- detected_target = None
- try:
- port = self.config.get_variable(dut_name)
- if not app_target:
- result, detected_target = dut_class.confirm_dut(port)
- except ValueError:
- # try to auto detect ports
- allocated_ports = [self.allocated_duts[x]['port'] for x in self.allocated_duts]
- available_ports = dut_class.list_available_ports()
- for port in available_ports:
- if port not in allocated_ports:
- result, detected_target = dut_class.confirm_dut(port)
- if result:
- break
- else:
- port = None
- if not app_target:
- app_target = detected_target
- if not app_target:
- raise ValueError("DUT class doesn't specify the target, and autodetection failed")
- app_inst = app_class(app_path, app_config_name, app_target)
- if port:
- try:
- dut_config = self.get_variable(dut_name + '_port_config')
- except ValueError:
- dut_config = dict()
- dut_config.update(dut_init_args)
- dut = dut_class(dut_name, port,
- os.path.join(self.log_path, dut_name + '.log'),
- app_inst,
- **dut_config)
- self.allocated_duts[dut_name] = {'port': port, 'dut': dut}
- else:
- raise ValueError('Failed to get DUT')
- return dut
- @_synced
- def close_dut(self, dut_name):
- """
- close_dut(dut_name)
- close one DUT by name if DUT name is valid (the name used by ``get_dut``). otherwise will do nothing.
- :param dut_name: user defined name for DUT
- :return: None
- """
- try:
- dut = self.allocated_duts.pop(dut_name)['dut']
- dut.close()
- except KeyError:
- pass
- @_synced
- def get_variable(self, variable_name):
- """
- get_variable(variable_name)
- get variable from config file. If failed then try to auto-detected it.
- :param variable_name: name of the variable
- :return: value of variable if successfully found. otherwise None.
- """
- return self.config.get_variable(variable_name)
- PROTO_MAP = {
- 'ipv4': netifaces.AF_INET,
- 'ipv6': netifaces.AF_INET6,
- 'mac': netifaces.AF_LINK,
- }
- @_synced
- def get_pc_nic_info(self, nic_name='pc_nic', proto='ipv4'):
- """
- get_pc_nic_info(nic_name="pc_nic")
- try to get info of a specified NIC and protocol.
- :param nic_name: pc nic name. allows passing variable name, nic name value.
- :param proto: "ipv4", "ipv6" or "mac"
- :return: a dict of nic info if successfully found. otherwise None.
- nic info keys could be different for different protocols.
- key "addr" is available for both mac, ipv4 and ipv6 pic info.
- """
- interfaces = netifaces.interfaces()
- if nic_name in interfaces:
- # the name is in the interface list, we regard it as NIC name
- if_addr = netifaces.ifaddresses(nic_name)
- else:
- # it's not in interface name list, we assume it's variable name
- _nic_name = self.get_variable(nic_name)
- if_addr = netifaces.ifaddresses(_nic_name)
- return if_addr[self.PROTO_MAP[proto]][0]
- @_synced
- def close(self, dut_debug=False):
- """
- close()
- close all DUTs of the Env.
- :param dut_debug: if dut_debug is True, then print all dut expect failures before close it
- :return: exceptions during close DUT
- """
- dut_close_errors = []
- for dut_name in self.allocated_duts:
- dut = self.allocated_duts[dut_name]['dut']
- try:
- if dut_debug:
- dut.print_debug_info()
- dut.close()
- except Exception as e:
- traceback.print_exc()
- dut_close_errors.append(e)
- self.allocated_duts = dict()
- return dut_close_errors
|