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