1*9c5db199SXin Li# Copyright 2017 The Chromium OS Authors. All rights reserved. 2*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be 3*9c5db199SXin Li# found in the LICENSE file. 4*9c5db199SXin Li 5*9c5db199SXin Liimport importlib 6*9c5db199SXin Liimport logging 7*9c5db199SXin Liimport os 8*9c5db199SXin Liimport re 9*9c5db199SXin Li 10*9c5db199SXin Liimport yaml 11*9c5db199SXin Li 12*9c5db199SXin Lifrom autotest_lib.client.common_lib import error 13*9c5db199SXin Li 14*9c5db199SXin Liclass DeviceCapability(object): 15*9c5db199SXin Li """ 16*9c5db199SXin Li Generate capabilities status on DUT from yaml files in a given path. 17*9c5db199SXin Li Answer from the capabilities whether some capability is satisfied on DUT. 18*9c5db199SXin Li """ 19*9c5db199SXin Li 20*9c5db199SXin Li def __init__(self, settings_path='/usr/local/etc/autotest-capability'): 21*9c5db199SXin Li """ 22*9c5db199SXin Li @param settings_path: string, the base directory for autotest 23*9c5db199SXin Li capability. There should be yaml files. 24*9c5db199SXin Li """ 25*9c5db199SXin Li self.capabilities = self.__get_autotest_capability(settings_path) 26*9c5db199SXin Li logging.info("Capabilities:\n%r", self.capabilities) 27*9c5db199SXin Li 28*9c5db199SXin Li 29*9c5db199SXin Li def __get_autotest_capability(self, settings_path): 30*9c5db199SXin Li """ 31*9c5db199SXin Li Generate and summarize capabilities from yaml files in 32*9c5db199SXin Li settings_path with detectors. 33*9c5db199SXin Li 34*9c5db199SXin Li @param settings_path: string, the base directory for autotest 35*9c5db199SXin Li capability. There should be yaml files. 36*9c5db199SXin Li @returns dict: 37*9c5db199SXin Li The capabilities on DUT. 38*9c5db199SXin Li Its key is string denoting a capability. Its value is 'yes', 'no' or 39*9c5db199SXin Li 'disable.' 40*9c5db199SXin Li """ 41*9c5db199SXin Li 42*9c5db199SXin Li def run_detector(name): 43*9c5db199SXin Li """ 44*9c5db199SXin Li Run a detector in the detector directory. (i.e. 45*9c5db199SXin Li autotest/files/client/cros/video/detectors) 46*9c5db199SXin Li Return the result of the detector. 47*9c5db199SXin Li 48*9c5db199SXin Li @param name: string, the name of running detector. 49*9c5db199SXin Li @returns string, a result of detect() in the detector script. 50*9c5db199SXin Li """ 51*9c5db199SXin Li if name not in detect_results: 52*9c5db199SXin Li detector = importlib.import_module( 53*9c5db199SXin Li "autotest_lib.client.cros.video.detectors.%s" 54*9c5db199SXin Li % name) 55*9c5db199SXin Li detect_results[name] = detector.detect() 56*9c5db199SXin Li logging.info("Detector result (%s): %s", 57*9c5db199SXin Li name, detect_results[name]) 58*9c5db199SXin Li return detect_results[name] 59*9c5db199SXin Li 60*9c5db199SXin Li managed_cap_fpath = os.path.join(settings_path, 61*9c5db199SXin Li 'managed-capabilities.yaml') 62*9c5db199SXin Li if not os.path.exists(managed_cap_fpath): 63*9c5db199SXin Li raise error.TestFail("%s is not installed" % managed_cap_fpath) 64*9c5db199SXin Li managed_caps = yaml.safe_load(open(managed_cap_fpath)) 65*9c5db199SXin Li 66*9c5db199SXin Li cap_files = [f for f in os.listdir(settings_path) 67*9c5db199SXin Li if re.match(r'^[0-9]+-.*\.yaml$', f)] 68*9c5db199SXin Li cap_files.sort(key=lambda f: int(f.split('-', 1)[0])) 69*9c5db199SXin Li 70*9c5db199SXin Li detect_results = {} 71*9c5db199SXin Li autotest_caps = dict.fromkeys(managed_caps, 'no') 72*9c5db199SXin Li for fname in cap_files: 73*9c5db199SXin Li logging.debug('Processing caps: %s', fname) 74*9c5db199SXin Li fname = os.path.join(settings_path, fname) 75*9c5db199SXin Li for rule in yaml.safe_load(open(fname)): 76*9c5db199SXin Li # The type of rule is string or dict 77*9c5db199SXin Li # If the type is a string, it is a capability (e.g. webcam). 78*9c5db199SXin Li # If a specific condition (e.g. kepler, cpu type) is required, 79*9c5db199SXin Li # rule would be dict, for example, 80*9c5db199SXin Li # {'detector': 'intel_cpu', 81*9c5db199SXin Li # 'match': ['intel_celeron_1007U'], 82*9c5db199SXin Li # 'capabilities': ['no hw_h264_enc_1080_30'] }. 83*9c5db199SXin Li logging.debug("%r", rule) 84*9c5db199SXin Li caps = [] 85*9c5db199SXin Li if isinstance(rule, dict): 86*9c5db199SXin Li if run_detector(rule['detector']) in rule['match']: 87*9c5db199SXin Li caps = rule['capabilities'] 88*9c5db199SXin Li else: 89*9c5db199SXin Li caps = [rule] 90*9c5db199SXin Li 91*9c5db199SXin Li for capability in caps: 92*9c5db199SXin Li m = re.match(r'(?:(disable|no)\s+)?([\w\-]+)$', capability) 93*9c5db199SXin Li prefix, capability = m.groups() 94*9c5db199SXin Li if capability in managed_caps: 95*9c5db199SXin Li autotest_caps[capability] = prefix or 'yes' 96*9c5db199SXin Li else: 97*9c5db199SXin Li raise error.TestFail( 98*9c5db199SXin Li "Unexpected capability: %s" % capability) 99*9c5db199SXin Li 100*9c5db199SXin Li return autotest_caps 101*9c5db199SXin Li 102*9c5db199SXin Li 103*9c5db199SXin Li def get_managed_caps(self): 104*9c5db199SXin Li return self.capabilities.keys() 105*9c5db199SXin Li 106*9c5db199SXin Li 107*9c5db199SXin Li def get_capability_results(self): 108*9c5db199SXin Li return self.capabilities 109*9c5db199SXin Li 110*9c5db199SXin Li 111*9c5db199SXin Li def get_capability(self, cap): 112*9c5db199SXin Li """ 113*9c5db199SXin Li Decide if a device satisfies a required capability for an autotest. 114*9c5db199SXin Li 115*9c5db199SXin Li @param cap: string, denoting one capability. It must be one in 116*9c5db199SXin Li settings_path + 'managed-capabilities.yaml.' 117*9c5db199SXin Li @returns 'yes', 'no', or 'disable.' 118*9c5db199SXin Li """ 119*9c5db199SXin Li try: 120*9c5db199SXin Li return self.capabilities[cap] 121*9c5db199SXin Li except KeyError: 122*9c5db199SXin Li raise error.TestFail("Unexpected capability: %s" % cap) 123*9c5db199SXin Li 124*9c5db199SXin Li 125*9c5db199SXin Li def ensure_capability(self, cap): 126*9c5db199SXin Li """ 127*9c5db199SXin Li Raise TestNAError if a device doesn't satisfy cap. 128*9c5db199SXin Li """ 129*9c5db199SXin Li if self.get_capability(cap) != 'yes': 130*9c5db199SXin Li raise error.TestNAError("Missing Capability: %s" % cap) 131*9c5db199SXin Li 132*9c5db199SXin Li 133*9c5db199SXin Li def have_capability(self, cap): 134*9c5db199SXin Li """ 135*9c5db199SXin Li Return whether cap is available. 136*9c5db199SXin Li """ 137*9c5db199SXin Li return self.get_capability(cap) == 'yes' 138