Home | History | Annotate | Download | only in hosts
      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 
      5 import unittest
      6 
      7 import common
      8 from autotest_lib.server.hosts import host_info
      9 
     10 
     11 class 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 
    107 class 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 
    204 class 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 
    223 class 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 
    254 class 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 
    271 if __name__ == '__main__':
    272     unittest.main()
    273