• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2019 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 json
6import logging
7import os
8
9import common
10
11CONFIG_DIR = os.path.join(
12        os.path.dirname(os.path.realpath(__file__)), os.pardir, 'configs')
13
14
15def _get_config_filepath(platform):
16    """Find the JSON file containing the platform's config"""
17    return os.path.join(CONFIG_DIR, '%s.json' % platform)
18
19
20def _has_config_file(platform):
21    """Determine whether the platform has a config file"""
22    return os.path.isfile(_get_config_filepath(platform))
23
24
25def _load_config(platform):
26    """Load the platform's JSON config into a dict"""
27    fp = _get_config_filepath(platform)
28    with open(fp) as config_file:
29        return json.load(config_file)
30
31
32class Config(object):
33    """Configuration for FAFT tests.
34
35    This object is meant to be the interface to all configuration required
36    by FAFT tests, including device specific overrides.
37
38    It gets the values from the JSON files in CONFIG_DIR.
39    Default values are declared in the DEFAULTS.json.
40    Platform-specific overrides come from <platform>.json.
41    If the platform has model-specific overrides, then those take precedence
42    over the platform's config.
43    If the platform inherits overrides from a parent platform, then the child
44    platform's overrides take precedence over the parent's.
45
46    TODO(gredelston): Move the JSON out of this Autotest, as per
47    go/cros-fw-testing-configs
48
49    @ivar platform: string containing the board name being tested.
50    @ivar model: string containing the model name being tested
51    """
52
53    def __init__(self, platform, model=None):
54        """Initialize an object with FAFT settings.
55
56        @param platform: The name of the platform being tested.
57        """
58        # Load JSON in order of importance (model, platform, parent/s, DEFAULTS)
59        self.platform = platform.rsplit('_', 1)[-1].lower().replace("-", "_")
60        self._precedence_list = []
61        self._precedence_names = []
62        if _has_config_file(self.platform):
63            platform_config = _load_config(self.platform)
64            self._add_cfg_to_precedence(self.platform, platform_config)
65            model_configs = platform_config.get('models', {})
66            model_config = model_configs.get(model, None)
67            if model_config is not None:
68                self._add_cfg_to_precedence(
69                        'MODEL:%s' % model, model_config, prepend=True)
70                logging.debug('Using model override for %s', model)
71            parent_platform = self._precedence_list[-1].get('parent', None)
72            while parent_platform is not None:
73                parent_config = _load_config(parent_platform)
74                self._add_cfg_to_precedence(parent_platform, parent_config)
75                parent_platform = self._precedence_list[-1].get('parent', None)
76        else:
77            logging.debug(
78                    'No platform config file found at %s. Using default.',
79                    _get_config_filepath(self.platform))
80        default_config = _load_config('DEFAULTS')
81        self._add_cfg_to_precedence('DEFAULTS', default_config)
82
83        # Set attributes
84        all_attributes = self._precedence_list[-1].keys()
85        self.attributes = {}
86        self.attributes['platform'] = self.platform
87        for attribute in all_attributes:
88            if attribute.endswith('.DOC') or attribute == 'models':
89                continue
90            for config_dict in self._precedence_list:
91                if attribute in config_dict:
92                    self.attributes[attribute] = config_dict[attribute]
93                    break
94
95    def _add_cfg_to_precedence(self, cfg_name, cfg, prepend=False):
96        """Add a configuration to self._precedence_list.
97
98        @ivar cfg_name: The name of the config.
99        @ivar cfg: The config dict.
100        @ivar prepend: If true, add to the beginning of self._precedence_list.
101                       Otherwise, add it to the end.
102        """
103        position = 0 if prepend else len(self._precedence_list)
104        self._precedence_list.insert(position, cfg)
105        self._precedence_names.insert(position, cfg_name)
106
107    def __getattr__(self, attr):
108        if attr in self.attributes:
109            return self.attributes[attr]
110        raise AttributeError('FAFT config has no attribute named %s' % attr)
111
112    def __str__(self):
113        str_list = []
114        str_list.append('----------[ FW Testing Config Variables ]----------')
115        str_list.append('--- Precedence list: %s ---' % self._precedence_names)
116        for attr in sorted(self.attributes):
117            str_list.append('  %s: %s' % (attr, self.attributes[attr]))
118        str_list.append('---------------------------------------------------')
119        return '\n'.join(str_list)
120