Merge pull request #114 from fnordahl/issue/113

Fix race in `test_utils.config_change()`
This commit is contained in:
Frode Nordahl
2018-08-16 14:54:59 +02:00
committed by GitHub
3 changed files with 65 additions and 0 deletions

View File

@@ -91,6 +91,8 @@ class TestModel(ut_utils.BaseTestCase):
self.unit2.run_action.side_effect = _run_action
self.unit1.is_leader_from_status.side_effect = _is_leader(False)
self.unit2.is_leader_from_status.side_effect = _is_leader(True)
self.unit1.data = {'agent-status': {'current': 'idle'}}
self.unit2.data = {'agent-status': {'current': 'idle'}}
self.units = [self.unit1, self.unit2]
self.relation1 = mock.MagicMock()
self.relation1.id = 42
@@ -893,6 +895,29 @@ disk_formats = ami,ari,aki,vhd,vmdk,raw,qcow2,vdi,iso,root-tar
'active',
timeout=0.1)
def test_wait_for_agent_status(self):
async def _block_until(f, timeout=None):
if not f():
raise asyncio.futures.TimeoutError
self.patch_object(model, 'get_juju_model', return_value='mname')
self.patch_object(model, 'Model')
self.unit1.data = {'agent-status': {'current': 'idle'}}
self.unit2.data = {'agent-status': {'current': 'executing'}}
self.Model.return_value = self.Model_mock
self.Model_mock.block_until.side_effect = _block_until
model.wait_for_agent_status(timeout=0.1)
def test_wait_for_agent_status_timeout(self):
async def _block_until(f, timeout=None):
if not f():
raise asyncio.futures.TimeoutError
self.patch_object(model, 'get_juju_model', return_value='mname')
self.patch_object(model, 'Model')
self.Model.return_value = self.Model_mock
self.Model_mock.block_until.side_effect = _block_until
with self.assertRaises(asyncio.futures.TimeoutError):
model.wait_for_agent_status(timeout=0.1)
class AsyncModelTests(aiounittest.AsyncTestCase):

View File

@@ -77,6 +77,10 @@ class OpenStackBaseTest(unittest.TestCase):
alternate_config,
model_name=self.model_name)
logging.debug(
'Waiting for units to execute config-changed hook')
model.wait_for_agent_status(model_name=self.model_name)
logging.debug(
'Waiting for units to reach target states')
model.wait_for_application_states(

View File

@@ -606,6 +606,42 @@ def check_unit_workload_status_message(model, unit, message=None,
raise ValueError("Must be called with message or prefixes")
async def async_wait_for_agent_status(model_name=None, status='executing',
timeout=60):
"""Wait for at least one unit to enter a specific agent status.
This is useful for awaiting execution after mutating charm configuration.
:param model_name: Name of model to query.
:type model_name: str
:param status: The desired agent status we are looking for.
:type status: str
:param timeout: Time to wait for status to be achieved.
:type timeout: int
"""
def one_agent_status(model, status):
check_model_for_hard_errors(model)
for app in model.applications:
for unit in model.applications[app].units:
agent_status = unit.data.get('agent-status', {})
if agent_status.get('current', None) == status:
break
else:
continue
break
else:
return False
return True
async with run_in_model(model_name) as model:
logging.info('Waiting for at least one unit with agent status "{}"'
.format(status))
await model.block_until(
lambda: one_agent_status(model, status), timeout=timeout)
wait_for_agent_status = sync_wrapper(async_wait_for_agent_status)
async def async_wait_for_application_states(model_name=None, states=None,
timeout=2700):
"""Wait for model to achieve the desired state.