blob: 161fd6a5c5a596629ecf0917877690645e92f520 [file] [log] [blame]
# 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()