You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
136 lines
5.5 KiB
136 lines
5.5 KiB
# Copyright 2017 The Chromium OS Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
from __future__ import print_function
|
|
from __future__ import absolute_import
|
|
|
|
import mock
|
|
import unittest
|
|
|
|
import common
|
|
from autotest_lib.server.hosts import host_info
|
|
from autotest_lib.server.hosts import shadowing_store
|
|
|
|
|
|
class ShadowingStoreTestCase(unittest.TestCase):
|
|
"""Tests shadowing capabilities of ShadowingStore"""
|
|
|
|
def test_init_commits_to_shadow(self):
|
|
"""Initialization updates the shadow store"""
|
|
info = host_info.HostInfo(labels='blah', attributes='boo')
|
|
primary = _FakeRaisingStore(info)
|
|
shadow = _FakeRaisingStore()
|
|
store = shadowing_store.ShadowingStore(primary, shadow)
|
|
self.assertEqual(shadow.get(), info)
|
|
|
|
def test_commit_commits_to_both_stores(self):
|
|
"""Successful commit involves committing to both stores"""
|
|
primary = _FakeRaisingStore()
|
|
shadow = _FakeRaisingStore()
|
|
store = shadowing_store.ShadowingStore(primary, shadow)
|
|
info = host_info.HostInfo(labels='blah', attributes='boo')
|
|
store.commit(info)
|
|
self.assertEqual(primary.get(), info)
|
|
self.assertEqual(shadow.get(), info)
|
|
|
|
def test_commit_ignores_failure_to_commit_to_shadow(self):
|
|
"""Failure to commit to shadow store does not affect the result"""
|
|
init_info = host_info.HostInfo(labels='init')
|
|
primary = _FakeRaisingStore(init_info)
|
|
shadow = _FakeRaisingStore(init_info, raise_on_commit=True)
|
|
store = shadowing_store.ShadowingStore(primary, shadow)
|
|
info = host_info.HostInfo(labels='blah', attributes='boo')
|
|
store.commit(info)
|
|
self.assertEqual(primary.get(), info)
|
|
self.assertEqual(shadow.get(), init_info)
|
|
|
|
def test_refresh_validates_matching_stores(self):
|
|
"""Successful validation on refresh returns the correct info"""
|
|
init_info = host_info.HostInfo(labels='init')
|
|
primary = _FakeRaisingStore(init_info)
|
|
shadow = _FakeRaisingStore(init_info)
|
|
store = shadowing_store.ShadowingStore(primary, shadow)
|
|
got = store.get(force_refresh=True)
|
|
self.assertEqual(got, init_info)
|
|
|
|
def test_refresh_ignores_failed_refresh_from_shadow_store(self):
|
|
"""Failure to refresh from shadow store does not affect the result"""
|
|
init_info = host_info.HostInfo(labels='init')
|
|
primary = _FakeRaisingStore(init_info)
|
|
shadow = _FakeRaisingStore(init_info, raise_on_refresh=True)
|
|
store = shadowing_store.ShadowingStore(primary, shadow)
|
|
got = store.get(force_refresh=True)
|
|
self.assertEqual(got, init_info)
|
|
|
|
def test_refresh_complains_on_mismatching_stores(self):
|
|
"""Store complains on mismatched responses from the primary / shadow"""
|
|
callback = mock.MagicMock()
|
|
p_info = host_info.HostInfo('primary')
|
|
primary = _FakeRaisingStore(p_info)
|
|
shadow = _FakeRaisingStore()
|
|
store = shadowing_store.ShadowingStore(primary, shadow,
|
|
mismatch_callback=callback)
|
|
# ShadowingStore will update shadow on initialization, so we modify it
|
|
# after creating store.
|
|
s_info = host_info.HostInfo('shadow')
|
|
shadow.commit(s_info)
|
|
|
|
got = store.get(force_refresh=True)
|
|
self.assertEqual(got, p_info)
|
|
callback.assert_called_once_with(p_info, s_info)
|
|
|
|
def test_refresh_fixes_mismatch_in_stores(self):
|
|
"""On finding a mismatch, the difference is fixed by the store"""
|
|
callback = mock.MagicMock()
|
|
p_info = host_info.HostInfo('primary')
|
|
primary = _FakeRaisingStore(p_info)
|
|
shadow = _FakeRaisingStore()
|
|
store = shadowing_store.ShadowingStore(primary, shadow,
|
|
mismatch_callback=callback)
|
|
# ShadowingStore will update shadow on initialization, so we modify it
|
|
# after creating store.
|
|
s_info = host_info.HostInfo('shadow')
|
|
shadow.commit(s_info)
|
|
|
|
got = store.get(force_refresh=True)
|
|
self.assertEqual(got, p_info)
|
|
callback.assert_called_once_with(p_info, s_info)
|
|
self.assertEqual(got, shadow.get())
|
|
|
|
got = store.get(force_refresh=True)
|
|
self.assertEqual(got, p_info)
|
|
# No extra calls, just the one we already saw above.
|
|
callback.assert_called_once_with(p_info, s_info)
|
|
|
|
|
|
class _FakeRaisingStore(host_info.InMemoryHostInfoStore):
|
|
"""A fake store that raises an error on refresh / commit if requested"""
|
|
|
|
def __init__(self, info=None, raise_on_refresh=False,
|
|
raise_on_commit=False):
|
|
"""
|
|
@param info: A HostInfo to initialize the store with.
|
|
@param raise_on_refresh: If True, _refresh_impl raises a StoreError.
|
|
@param raise_on_commit: If True, _commit_impl raises a StoreError.
|
|
"""
|
|
super(_FakeRaisingStore, self).__init__(info)
|
|
self._raise_on_refresh = raise_on_refresh
|
|
self._raise_on_commit = raise_on_commit
|
|
|
|
def _refresh_impl(self):
|
|
print('refresh_impl')
|
|
if self._raise_on_refresh:
|
|
raise host_info.StoreError('Test refresh error')
|
|
return super(_FakeRaisingStore, self)._refresh_impl()
|
|
|
|
def _commit_impl(self, info):
|
|
print('commit_impl: %s' % info)
|
|
if self._raise_on_commit:
|
|
raise host_info.StoreError('Test commit error')
|
|
super(_FakeRaisingStore, self)._commit_impl(info)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|