• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2016 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 unittest
6
7import common
8from autotest_lib.server.hosts import host_info
9
10
11class HostInfoTest(unittest.TestCase):
12    """Tests the non-trivial attributes of HostInfo."""
13
14    def setUp(self):
15        self.info = host_info.HostInfo()
16
17
18    def test_build_needs_prefix(self):
19        """The build prefix is of the form '<type>-version:'"""
20        self.info.labels = ['cros-version', 'ab-version', 'testbed-version',
21                            'fwrw-version', 'fwro-version']
22        self.assertIsNone(self.info.build)
23
24
25    def test_build_prefix_must_be_anchored(self):
26        """Ensure that build ignores prefixes occuring mid-string."""
27        self.info.labels = ['not-at-start-cros-version:cros1',
28                            'not-at-start-ab-version:ab1',
29                            'not-at-start-testbed-version:testbed1']
30        self.assertIsNone(self.info.build)
31
32
33    def test_build_ignores_firmware(self):
34        """build attribute should ignore firmware versions."""
35        self.info.labels = ['fwrw-version:fwrw1', 'fwro-version:fwro1']
36        self.assertIsNone(self.info.build)
37
38
39    def test_build_returns_first_match(self):
40        """When multiple labels match, first one should be used as build."""
41        self.info.labels = ['cros-version:cros1', 'cros-version:cros2']
42        self.assertEqual(self.info.build, 'cros1')
43        self.info.labels = ['ab-version:ab1', 'ab-version:ab2']
44        self.assertEqual(self.info.build, 'ab1')
45        self.info.labels = ['testbed-version:tb1', 'testbed-version:tb2']
46        self.assertEqual(self.info.build, 'tb1')
47
48
49    def test_build_prefer_cros_over_others(self):
50        """When multiple versions are available, prefer cros."""
51        self.info.labels = ['testbed-version:tb1', 'ab-version:ab1',
52                            'cros-version:cros1']
53        self.assertEqual(self.info.build, 'cros1')
54        self.info.labels = ['cros-version:cros1', 'ab-version:ab1',
55                            'testbed-version:tb1']
56        self.assertEqual(self.info.build, 'cros1')
57
58
59    def test_build_prefer_ab_over_testbed(self):
60        """When multiple versions are available, prefer ab over testbed."""
61        self.info.labels = ['testbed-version:tb1', 'ab-version:ab1']
62        self.assertEqual(self.info.build, 'ab1')
63        self.info.labels = ['ab-version:ab1', 'testbed-version:tb1']
64        self.assertEqual(self.info.build, 'ab1')
65
66
67    def test_os_no_match(self):
68        """Use proper prefix to search for os information."""
69        self.info.labels = ['something_else', 'cros-version:hana',
70                            'os_without_colon']
71        self.assertEqual(self.info.os, '')
72
73
74    def test_os_returns_first_match(self):
75        """Return the first matching os label."""
76        self.info.labels = ['os:linux', 'os:windows', 'os_corrupted_label']
77        self.assertEqual(self.info.os, 'linux')
78
79
80    def test_board_no_match(self):
81        """Use proper prefix to search for board information."""
82        self.info.labels = ['something_else', 'cros-version:hana', 'os:blah',
83                            'board_my_board_no_colon']
84        self.assertEqual(self.info.board, '')
85
86
87    def test_board_returns_first_match(self):
88        """Return the first matching board label."""
89        self.info.labels = ['board_corrupted', 'board:walk', 'board:bored']
90        self.assertEqual(self.info.board, 'walk')
91
92
93    def test_pools_no_match(self):
94        """Use proper prefix to search for pool information."""
95        self.info.labels = ['something_else', 'cros-version:hana', 'os:blah',
96                            'board_my_board_no_colon', 'board:my_board']
97        self.assertEqual(self.info.pools, set())
98
99
100    def test_pools_returns_all_matches(self):
101        """Return all matching pool labels."""
102        self.info.labels = ['board_corrupted', 'board:walk', 'board:bored',
103                            'pool:first_pool', 'pool:second_pool']
104        self.assertEqual(self.info.pools, {'second_pool', 'first_pool'})
105
106
107class InMemoryHostInfoStoreTest(unittest.TestCase):
108    """Basic tests for CachingHostInfoStore using InMemoryHostInfoStore."""
109
110    def setUp(self):
111        self.store = host_info.InMemoryHostInfoStore()
112
113
114    def _verify_host_info_data(self, host_info, labels, attributes):
115        """Verifies the data in the given host_info."""
116        self.assertListEqual(host_info.labels, labels)
117        self.assertDictEqual(host_info.attributes, attributes)
118
119
120    def test_first_get_refreshes_cache(self):
121        """Test that the first call to get gets the data from store."""
122        self.store.info = host_info.HostInfo(['label1'], {'attrib1': 'val1'})
123        got = self.store.get()
124        self._verify_host_info_data(got, ['label1'], {'attrib1': 'val1'})
125
126
127    def test_repeated_get_returns_from_cache(self):
128        """Tests that repeated calls to get do not refresh cache."""
129        self.store.info = host_info.HostInfo(['label1'], {'attrib1': 'val1'})
130        got = self.store.get()
131        self._verify_host_info_data(got, ['label1'], {'attrib1': 'val1'})
132
133        self.store.info = host_info.HostInfo(['label1', 'label2'], {})
134        got = self.store.get()
135        self._verify_host_info_data(got, ['label1'], {'attrib1': 'val1'})
136
137
138    def test_get_uncached_always_refreshes_cache(self):
139        """Tests that calling get_uncached always refreshes the cache."""
140        self.store.info = host_info.HostInfo(['label1'], {'attrib1': 'val1'})
141        got = self.store.get(force_refresh=True)
142        self._verify_host_info_data(got, ['label1'], {'attrib1': 'val1'})
143
144        self.store.info = host_info.HostInfo(['label1', 'label2'], {})
145        got = self.store.get(force_refresh=True)
146        self._verify_host_info_data(got, ['label1', 'label2'], {})
147
148
149    def test_commit(self):
150        """Test that commit sends data to store."""
151        info = host_info.HostInfo(['label1'], {'attrib1': 'val1'})
152        self._verify_host_info_data(self.store.info, [], {})
153        self.store.commit(info)
154        self._verify_host_info_data(self.store.info, ['label1'],
155                                    {'attrib1': 'val1'})
156
157
158    def test_commit_then_get(self):
159        """Test a commit-get roundtrip."""
160        got = self.store.get()
161        self._verify_host_info_data(got, [], {})
162
163        info = host_info.HostInfo(['label1'], {'attrib1': 'val1'})
164        self.store.commit(info)
165        got = self.store.get()
166        self._verify_host_info_data(got, ['label1'], {'attrib1': 'val1'})
167
168
169    def test_commit_then_get_uncached(self):
170        """Test a commit-get_uncached roundtrip."""
171        got = self.store.get()
172        self._verify_host_info_data(got, [], {})
173
174        info = host_info.HostInfo(['label1'], {'attrib1': 'val1'})
175        self.store.commit(info)
176        got = self.store.get(force_refresh=True)
177        self._verify_host_info_data(got, ['label1'], {'attrib1': 'val1'})
178
179
180    def test_commit_deepcopies_data(self):
181        """Once commited, changes to HostInfo don't corrupt the store."""
182        info = host_info.HostInfo(['label1'], {'attrib1': {'key1': 'data1'}})
183        self.store.commit(info)
184        info.labels.append('label2')
185        info.attributes['attrib1']['key1'] = 'data2'
186        self._verify_host_info_data(self.store.info,
187                                    ['label1'], {'attrib1': {'key1': 'data1'}})
188
189
190    def test_get_returns_deepcopy(self):
191        """The cached object is protected from |get| caller modifications."""
192        self.store.info = host_info.HostInfo(['label1'],
193                                             {'attrib1': {'key1': 'data1'}})
194        got = self.store.get()
195        self._verify_host_info_data(got,
196                                    ['label1'], {'attrib1': {'key1': 'data1'}})
197        got.labels.append('label2')
198        got.attributes['attrib1']['key1'] = 'data2'
199        got = self.store.get()
200        self._verify_host_info_data(got,
201                                    ['label1'], {'attrib1': {'key1': 'data1'}})
202
203
204class ExceptionRaisingStore(host_info.CachingHostInfoStore):
205    """A test class that always raises on refresh / commit."""
206
207    def __init__(self):
208        super(ExceptionRaisingStore, self).__init__()
209        self.refresh_raises = True
210        self.commit_raises = True
211
212
213    def _refresh_impl(self):
214        if self.refresh_raises:
215            raise host_info.StoreError('no can do')
216        return host_info.HostInfo()
217
218    def _commit_impl(self, _):
219        if self.commit_raises:
220            raise host_info.StoreError('wont wont wont')
221
222
223class CachingHostInfoStoreErrorTest(unittest.TestCase):
224    """Tests error behaviours of CachingHostInfoStore."""
225
226    def setUp(self):
227        self.store = ExceptionRaisingStore()
228
229
230    def test_failed_refresh_cleans_cache(self):
231        """Sanity checks return values when refresh raises."""
232        with self.assertRaises(host_info.StoreError):
233            self.store.get()
234        # Since |get| hit an error, a subsequent get should again hit the store.
235        with self.assertRaises(host_info.StoreError):
236            self.store.get()
237
238
239    def test_failed_commit_cleans_cache(self):
240        """Check that a failed commit cleanes cache."""
241        # Let's initialize the store without errors.
242        self.store.refresh_raises = False
243        self.store.get(force_refresh=True)
244        self.store.refresh_raises = True
245
246        with self.assertRaises(host_info.StoreError):
247            self.store.commit(host_info.HostInfo())
248        # Since |commit| hit an error, a subsequent get should again hit the
249        # store.
250        with self.assertRaises(host_info.StoreError):
251            self.store.get()
252
253
254class GetStoreFromMachineTest(unittest.TestCase):
255    """Tests the get_store_from_machine function."""
256
257    def test_machine_is_dict(self):
258        machine = {
259                'something': 'else',
260                'host_info_store': 5
261        }
262        self.assertEqual(host_info.get_store_from_machine(machine), 5)
263
264
265    def test_machine_is_string(self):
266        machine = 'hostname'
267        self.assertTrue(isinstance(host_info.get_store_from_machine(machine),
268                                   host_info.InMemoryHostInfoStore))
269
270
271if __name__ == '__main__':
272    unittest.main()
273