Ensure that c.c.unitdata.kv is properly mocked out
As unit tests run concurrently, it's important that all tests use a mocked out version of the kv() store. Otherwise, unit tests can race and fail due to SQLite lock erros. See linked bug for details. Change-Id: I7e16a566531a7faf9d3a960c3df524fd46976a2a Closes-Bug: #1905760
This commit is contained in:
parent
da304cbea6
commit
2962cc9a9a
|
@ -9,9 +9,8 @@ import yaml
|
|||
|
||||
import charmhelpers.contrib.openstack.ha.utils as ch_ha_utils
|
||||
from charmhelpers.contrib.database.mysql import PerconaClusterHelper
|
||||
from charmhelpers.core.unitdata import kv
|
||||
|
||||
from test_utils import CharmTestCase
|
||||
from test_utils import CharmTestCase, FakeKvStore
|
||||
|
||||
sys.modules['MySQLdb'] = mock.Mock()
|
||||
# python-apt is not installed as part of test-requirements but is imported by
|
||||
|
@ -24,7 +23,8 @@ with mock.patch('charmhelpers.contrib.hardening.harden.harden') as mock_dec:
|
|||
import percona_hooks as hooks
|
||||
|
||||
|
||||
TO_PATCH = ['log', 'config',
|
||||
TO_PATCH = ['log',
|
||||
'config',
|
||||
'get_db_helper',
|
||||
'relation_ids',
|
||||
'relation_set',
|
||||
|
@ -52,7 +52,8 @@ TO_PATCH = ['log', 'config',
|
|||
'client_node_is_ready',
|
||||
'relation_set',
|
||||
'relation_get',
|
||||
'install_mysql_ocf']
|
||||
'install_mysql_ocf',
|
||||
'kv']
|
||||
|
||||
|
||||
class TestSharedDBRelation(CharmTestCase):
|
||||
|
@ -763,6 +764,8 @@ class TestUpgradeCharm(CharmTestCase):
|
|||
'leader_get',
|
||||
'notify_bootstrapped',
|
||||
'mark_seeded',
|
||||
'kv',
|
||||
'is_unit_upgrading_set',
|
||||
]
|
||||
|
||||
def print_log(self, msg, level=None):
|
||||
|
@ -773,6 +776,7 @@ class TestUpgradeCharm(CharmTestCase):
|
|||
self.config.side_effect = self.test_config.get
|
||||
self.log.side_effect = self.print_log
|
||||
self.tmpdir = tempfile.mkdtemp()
|
||||
self.is_unit_upgrading_set.return_value = False
|
||||
|
||||
def tearDown(self):
|
||||
CharmTestCase.tearDown(self)
|
||||
|
@ -853,6 +857,7 @@ class TestConfigs(CharmTestCase):
|
|||
default_config[k] = None
|
||||
return default_config
|
||||
|
||||
@mock.patch.object(hooks, 'is_unit_upgrading_set')
|
||||
@mock.patch.object(os, 'makedirs')
|
||||
@mock.patch.object(hooks, 'get_cluster_host_ip')
|
||||
@mock.patch.object(hooks, 'get_wsrep_provider_options')
|
||||
|
@ -867,7 +872,9 @@ class TestConfigs(CharmTestCase):
|
|||
parse_config,
|
||||
get_wsrep_provider_options,
|
||||
get_cluster_host_ip,
|
||||
makedirs):
|
||||
makedirs,
|
||||
mock_is_unit_upgrading_set):
|
||||
mock_is_unit_upgrading_set.return_value = False
|
||||
parse_config.return_value = {'key_buffer': '32M'}
|
||||
get_cluster_host_ip.return_value = '10.1.1.1'
|
||||
get_wsrep_provider_options.return_value = None
|
||||
|
@ -905,6 +912,7 @@ class TestConfigs(CharmTestCase):
|
|||
context,
|
||||
perms=0o444)
|
||||
|
||||
@mock.patch.object(hooks, 'is_unit_upgrading_set')
|
||||
@mock.patch.object(os, 'makedirs')
|
||||
@mock.patch.object(hooks, 'get_cluster_host_ip')
|
||||
@mock.patch.object(hooks, 'get_wsrep_provider_options')
|
||||
|
@ -919,7 +927,9 @@ class TestConfigs(CharmTestCase):
|
|||
parse_config,
|
||||
get_wsrep_provider_options,
|
||||
get_cluster_host_ip,
|
||||
makedirs):
|
||||
makedirs,
|
||||
mock_is_unit_upgrading_set):
|
||||
mock_is_unit_upgrading_set.return_value = False
|
||||
parse_config.return_value = {'key_buffer': '32M'}
|
||||
get_cluster_host_ip.return_value = '10.1.1.1'
|
||||
get_wsrep_provider_options.return_value = None
|
||||
|
@ -960,6 +970,7 @@ class TestConfigs(CharmTestCase):
|
|||
context,
|
||||
perms=0o444)
|
||||
|
||||
@mock.patch.object(hooks, 'is_unit_upgrading_set')
|
||||
@mock.patch.object(os, 'makedirs')
|
||||
@mock.patch.object(hooks, 'get_cluster_host_ip')
|
||||
@mock.patch.object(hooks, 'get_wsrep_provider_options')
|
||||
|
@ -975,7 +986,9 @@ class TestConfigs(CharmTestCase):
|
|||
parse_config,
|
||||
get_wsrep_provider_options,
|
||||
get_cluster_host_ip,
|
||||
makedirs):
|
||||
makedirs,
|
||||
mock_is_unit_upgrading_set):
|
||||
mock_is_unit_upgrading_set.return_value = False
|
||||
parse_config.return_value = {'key_buffer': '32M'}
|
||||
get_cluster_host_ip.return_value = '10.1.1.1'
|
||||
get_wsrep_provider_options.return_value = None
|
||||
|
@ -1025,9 +1038,11 @@ class TestClusterRelation(CharmTestCase):
|
|||
CharmTestCase.setUp(self, hooks, TO_PATCH)
|
||||
self.config.side_effect = self.test_config.get
|
||||
self.is_leader.return_value = False
|
||||
kvstore = kv()
|
||||
kvstore.set('initial_client_update_done', True)
|
||||
self.kvstore = FakeKvStore()
|
||||
self.kvstore.set('initial_client_update_done', True)
|
||||
self.kv.return_value = self.kvstore
|
||||
|
||||
@mock.patch('percona_utils.kv')
|
||||
@mock.patch.object(hooks, 'config_changed')
|
||||
@mock.patch.object(hooks, 'get_cluster_host_ip')
|
||||
@mock.patch('percona_utils.notify_bootstrapped')
|
||||
|
@ -1044,13 +1059,15 @@ class TestClusterRelation(CharmTestCase):
|
|||
mock_leader_get, mock_get_wsrep_value,
|
||||
mock_notify_bootstrapped,
|
||||
mock_cluster_host_ip,
|
||||
mock_config_changed):
|
||||
mock_config_changed,
|
||||
mock_kv):
|
||||
def fake_leader_get(k):
|
||||
return {
|
||||
'bootstrap-uuid': '1-2-3-4',
|
||||
'wsrep_cluster_state_uuid': '1-2-3-4',
|
||||
}[k]
|
||||
|
||||
mock_kv.return_value = self.kvstore
|
||||
mock_leader_get.side_effect = fake_leader_get
|
||||
mock_get_wsrep_value.side_effect = fake_leader_get
|
||||
mock_is_bootstrapped.return_value = True
|
||||
|
|
|
@ -8,7 +8,7 @@ from charmhelpers.fetch import SourceConfigError
|
|||
|
||||
import percona_utils
|
||||
|
||||
from test_utils import CharmTestCase, patch_open
|
||||
from test_utils import CharmTestCase, patch_open, FakeKvStore
|
||||
|
||||
os.environ['JUJU_UNIT_NAME'] = 'percona-cluster/2'
|
||||
|
||||
|
@ -556,10 +556,16 @@ class UtilsTestsStatus(CharmTestCase):
|
|||
'distributed_wait',
|
||||
'cluster_ready',
|
||||
'seeded',
|
||||
'kv',
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
super(UtilsTestsStatus, self).setUp(percona_utils, self.TO_PATCH)
|
||||
self._kvstore = FakeKvStore()
|
||||
self.kv.return_value = self._kvstore
|
||||
_m = mock.patch("charmhelpers.core.unitdata.kv")
|
||||
self.mock_kv = _m.start()
|
||||
self.addCleanup(_m.stop)
|
||||
|
||||
@mock.patch.object(percona_utils, 'seeded')
|
||||
def test_single_unit(self, mock_seeded):
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import io
|
||||
import os
|
||||
import logging
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
import yaml
|
||||
|
@ -8,6 +9,8 @@ import yaml
|
|||
from contextlib import contextmanager
|
||||
from mock import patch, MagicMock
|
||||
|
||||
from charmhelpers.core.unitdata import Record
|
||||
|
||||
|
||||
def load_config():
|
||||
'''
|
||||
|
@ -143,3 +146,55 @@ def patch_open():
|
|||
|
||||
with patch('builtins.open', stub_open):
|
||||
yield mock_open, mock_file
|
||||
|
||||
|
||||
class FakeKvStore():
|
||||
|
||||
def __init__(self):
|
||||
self._store = {}
|
||||
self._closed = False
|
||||
self._flushed = False
|
||||
|
||||
def close(self):
|
||||
self._closed = True
|
||||
self._flushed = True
|
||||
|
||||
def get(self, key, default=None, record=False):
|
||||
if key not in self._store:
|
||||
return default
|
||||
if record:
|
||||
return Record(self._store[key])
|
||||
return self._store[key]
|
||||
|
||||
def getrange(self, *args, **kwargs):
|
||||
raise NotImplementedError
|
||||
|
||||
def update(self, mapping, prefix=""):
|
||||
for k, v in mapping.items():
|
||||
self.set("%s%s" % (prefix, k), v)
|
||||
|
||||
def unset(self, key):
|
||||
if key in self._store:
|
||||
del self._store[key]
|
||||
|
||||
def unsetrange(self, keys=None, prefix=""):
|
||||
raise NotImplementedError
|
||||
|
||||
def set(self, key, value):
|
||||
self._store[key] = value
|
||||
return value
|
||||
|
||||
def delta(self, mapping, prefix):
|
||||
raise NotImplementedError
|
||||
|
||||
def hook_scope(self, name=""):
|
||||
raise NotImplementedError
|
||||
|
||||
def flush(self, save=True):
|
||||
self._flushed = True
|
||||
|
||||
def gethistory(self, key, deserialize=False):
|
||||
raise NotImplementedError
|
||||
|
||||
def debug(self, fh=sys.stderr):
|
||||
raise NotImplementedError
|
||||
|
|
Loading…
Reference in New Issue