xref: /aosp_15_r20/external/autotest/server/cros/faft/utils/config_unittest.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1#!/usr/bin/python3
2#
3# Copyright 2019 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7import json
8import os
9import tempfile
10import unittest
11
12import common
13
14from autotest_lib.client.common_lib import error
15from autotest_lib.server.cros.faft.utils import config
16
17
18class CanLoadDefaultTestCase(unittest.TestCase):
19    """Ensure that configs can load the default JSON"""
20
21    def runTest(self):
22        """Main test logic"""
23        platform = "foo"
24        cfg = config.Config(platform)
25        self.assertIsInstance(cfg.has_keyboard, bool)
26
27
28class _MockConfigTestCaseBaseClass(unittest.TestCase):
29    """
30    Base class which handles the setup/teardown of mock config files.
31
32    Sub-classes should declare a class attribute, mock_configs,
33    as a dict representing all platforms to be written as JSON files.
34    This class writes those JSON files during setUp() and deletes them
35    during tearDown().
36    During runTest(), sub-classes can create config.Config instances by name
37    and run assertions as normal.
38
39    """
40
41    mock_configs = None
42
43    def setUp(self):
44        """Set up a tempfile containing the test data"""
45        if self.mock_configs is None:
46            return
47
48        # Setup mock config._CONFIG_DIR, but remember the original.
49        self.mock_config_dir = tempfile.mkdtemp()
50        self.original_config_dir = config._CONFIG_DIR
51        config._CONFIG_DIR = self.mock_config_dir
52
53        # Write mock config file.
54        with open(config._consolidated_json_fp(), 'w') as f:
55            json.dump(self.mock_configs, f)
56
57    def tearDown(self):
58        """After tests are complete, delete the tempfile"""
59        if self.mock_configs is None:
60            return
61        os.remove(config._consolidated_json_fp())
62        os.rmdir(self.mock_config_dir)
63        config._CONFIG_DIR = self.original_config_dir
64
65
66class InheritanceTestCase(_MockConfigTestCaseBaseClass):
67    """Ensure that platforms inherit attributes correctly"""
68
69    mock_configs = {
70            'DEFAULTS': {
71                    'no_override': 'default',
72                    'parent_override': 'default',
73                    'child_override': 'default',
74                    'both_override': 'default',
75                    'parent': None
76            },
77            'childboard': {
78                    'child_override': 'child',
79                    'both_override': 'child',
80                    'parent': 'parentboard'
81            },
82            'parentboard': {
83                    'parent_override': 'parent',
84                    'both_override': 'parent'
85            }
86    }
87
88    def runTest(self):
89        """
90        Verify that the following situations resolve correctly:
91            A platform that inherit some overridess from another platform
92            A platform that does not inherit from another platform
93            A platform not found in the config file
94        """
95        child_config = config.Config('childboard')
96        #print(child_config)
97        self.assertEqual(child_config.no_override, 'default')
98        self.assertEqual(child_config.parent_override, 'parent')
99        self.assertEqual(child_config.child_override, 'child')
100        self.assertEqual(child_config.both_override, 'child')
101        with self.assertRaises(AttributeError):
102            child_config.foo  # pylint: disable=pointless-statement
103
104        parent_config = config.Config('parentboard')
105        self.assertEqual(parent_config.no_override, 'default')
106        self.assertEqual(parent_config.parent_override, 'parent')
107        self.assertEqual(parent_config.child_override, 'default')
108        self.assertEqual(parent_config.both_override, 'parent')
109
110        foo_config = config.Config('foo')
111        self.assertEqual(foo_config.no_override, 'default')
112        self.assertEqual(foo_config.parent_override, 'default')
113        self.assertEqual(foo_config.child_override, 'default')
114        self.assertEqual(foo_config.both_override, 'default')
115
116        # While we're here, verify that str(config) doesn't break
117        str(child_config)  # pylint: disable=pointless-statement
118
119
120class ModelOverrideTestCase(_MockConfigTestCaseBaseClass):
121    """Verify that models of boards inherit overrides with proper precedence"""
122    mock_configs = {
123            'parentboard': {
124                    'attr1': 'parent_attr1',
125                    'attr2': 'parent_attr2',
126                    'models': {
127                            'modelA': {
128                                    'attr1': 'parent_modelA_attr1'
129                            }
130                    }
131            },
132            'childboard': {
133                    'parent': 'parentboard',
134                    'attr1': 'child_attr1',
135                    'models': {
136                            'modelA': {
137                                    'attr1': 'child_modelA_attr1'
138                            }
139                    }
140            },
141            'DEFAULTS': {
142                    'models': None,
143                    'attr1': 'default',
144                    'attr2': 'default'
145            }
146    }
147
148    def runTest(self):
149        """Run assertions on test data"""
150        child_config = config.Config('childboard')
151        child_modelA_config = config.Config('childboard', 'modelA')
152        child_modelB_config = config.Config('childboard', 'modelB')
153        parent_config = config.Config('parentboard')
154        parent_modelA_config = config.Config('parentboard', 'modelA')
155        parent_modelB_config = config.Config('parentboard', 'modelB')
156
157        self.assertEqual(child_config.attr1, 'child_attr1')
158        self.assertEqual(child_config.attr2, 'parent_attr2')
159        self.assertEqual(child_modelA_config.attr1, 'child_modelA_attr1')
160        self.assertEqual(child_modelA_config.attr2, 'parent_attr2')
161        self.assertEqual(child_modelB_config.attr1, 'child_attr1')
162        self.assertEqual(child_modelB_config.attr2, 'parent_attr2')
163        self.assertEqual(parent_config.attr1, 'parent_attr1')
164        self.assertEqual(parent_config.attr2, 'parent_attr2')
165        self.assertEqual(parent_modelA_config.attr1, 'parent_modelA_attr1')
166        self.assertEqual(parent_modelA_config.attr2, 'parent_attr2')
167        self.assertEqual(parent_modelB_config.attr1, 'parent_attr1')
168        self.assertEqual(parent_modelB_config.attr2, 'parent_attr2')
169
170
171class DirectSelfInheritanceTestCase(_MockConfigTestCaseBaseClass):
172    """Ensure that a config which inherits from itself raises an error."""
173
174    mock_configs = {
175        'selfloop': {
176            'parent': 'selfloop',
177        },
178    }
179
180    def runTest(self):
181        """Run assertions on test data."""
182        with self.assertRaises(error.TestError):
183            config.Config('selfloop')
184
185
186class IndirectSelfInheritanceTestCase(_MockConfigTestCaseBaseClass):
187    """Ensure that configs which inherit from each other raise an error."""
188
189    mock_configs = {
190        'indirectloop1': {
191            'parent': 'indirectloop2',
192        },
193        'indirectloop2': {
194            'parent': 'indirectloop1',
195        },
196        'indirectloop3': {
197            'parent': 'indirectloop1',
198        },
199    }
200
201    def runTest(self):
202        """Run assertions on test data."""
203        with self.assertRaises(error.TestError):
204            config.Config('indirectloop1')
205        with self.assertRaises(error.TestError):
206            config.Config('indirectloop3')
207
208
209class FindMostSpecificConfigTestCase(_MockConfigTestCaseBaseClass):
210    """Ensure that configs named like $BOARD-kernelnext load $BOARD.json."""
211
212    mock_configs = {
213            'DEFAULTS': {},
214            'samus': {},
215            'veyron': {},
216            'minnie': {'parent': 'veyron'},
217    }
218
219    def runTest(self):
220        cfg = config.Config('samus-kernelnext')
221        self.assertEqual(config.Config('samus-kernelnext').platform, 'samus')
222        self.assertEqual(config.Config('samus-arc-r').platform, 'samus')
223        self.assertEqual(config.Config('veyron_minnie').platform, 'minnie')
224        self.assertEqual(config.Config('veyron_monroe').platform, 'veyron')
225        self.assertEqual(config.Config('veyron_minnie-arc-r').platform, 'minnie')
226        self.assertEqual(config.Config('veyron_monroe-arc-r').platform, 'veyron')
227
228
229if __name__ == '__main__':
230    unittest.main()
231