diff --git a/rally/benchmark/scenarios/heat/utils.py b/rally/benchmark/scenarios/heat/utils.py index 2a34af2b97..1b49b27f27 100644 --- a/rally/benchmark/scenarios/heat/utils.py +++ b/rally/benchmark/scenarios/heat/utils.py @@ -48,12 +48,6 @@ benchmark_group = cfg.OptGroup(name="benchmark", title="benchmark options") CONF.register_opts(heat_benchmark_opts, group=benchmark_group) -def heat_resource_is(status): - """Check status of stack.""" - - return lambda resource: resource.stack_status.upper() == status.upper() - - class HeatScenario(base.Scenario): """Base class for Heat scenarios with basic atomic actions.""" @@ -94,7 +88,7 @@ class HeatScenario(base.Scenario): stack = bench_utils.wait_for( stack, - is_ready=heat_resource_is("CREATE_COMPLETE"), + is_ready=bench_utils.resource_is("CREATE_COMPLETE"), update_resource=bench_utils.get_from_manager(["CREATE_FAILED"]), timeout=CONF.benchmark.heat_stack_create_timeout, check_interval=CONF.benchmark.heat_stack_create_poll_interval) diff --git a/rally/benchmark/utils.py b/rally/benchmark/utils.py index 3727f58e74..eea8cc03ea 100644 --- a/rally/benchmark/utils.py +++ b/rally/benchmark/utils.py @@ -28,16 +28,23 @@ from rally import exceptions LOG = logging.getLogger(__name__) -def resource_is(status): - return lambda resource: resource.status.upper() == status.upper() - - def get_status(resource): # workaround for heat resources - using stack_status instead of status if ((hasattr(resource, "stack_status") and isinstance(resource.stack_status, six.string_types))): return resource.stack_status.upper() - return resource.status.upper() + return getattr(resource, "status", "NONE").upper() + + +class resource_is(object): + def __init__(self, desired_status): + self.desired_status = desired_status + + def __call__(self, resource): + return get_status(resource) == self.desired_status.upper() + + def __str__(self): + return str(self.desired_status) def get_from_manager(error_statuses=None): @@ -106,7 +113,13 @@ def wait_for(resource, is_ready, update_resource=None, timeout=60, break time.sleep(check_interval) if time.time() - start > timeout: - raise exceptions.TimeoutException() + raise exceptions.TimeoutException( + desired_status=str(is_ready), + resource_name=getattr(resource, "name", repr(resource)), + resource_type=resource.__class__.__name__, + resource_id=getattr(resource, "id", ""), + resource_status=get_status(resource)) + return resource @@ -132,7 +145,12 @@ def wait_for_delete(resource, update_resource=None, timeout=60, break time.sleep(check_interval) if time.time() - start > timeout: - raise exceptions.TimeoutException() + raise exceptions.TimeoutException( + desired_status="deleted", + resource_name=getattr(resource, "name", repr(resource)), + resource_type=resource.__class__.__name__, + resource_id=getattr(resource, "id", ""), + resource_status=get_status(resource)) def format_exc(exc): diff --git a/rally/exceptions.py b/rally/exceptions.py index 4e5841884c..dde1d11542 100644 --- a/rally/exceptions.py +++ b/rally/exceptions.py @@ -169,7 +169,9 @@ class ResourceNotFound(NotFoundException): class TimeoutException(RallyException): - msg_fmt = _("Timeout exceeded.") + msg_fmt = _("Rally tired waiting for %(resource_type)s %(resource_name)s:" + "%(resource_id)s to become %(desired_status)s current " + "status %(resource_status)s") class GetResourceFailure(RallyException): diff --git a/tests/unit/benchmark/scenarios/heat/test_utils.py b/tests/unit/benchmark/scenarios/heat/test_utils.py index 38bb15e70f..ffc2400372 100644 --- a/tests/unit/benchmark/scenarios/heat/test_utils.py +++ b/tests/unit/benchmark/scenarios/heat/test_utils.py @@ -29,7 +29,7 @@ class HeatScenarioTestCase(test.TestCase): def setUp(self): super(HeatScenarioTestCase, self).setUp() self.stack = mock.Mock() - self.res_is = mockpatch.Patch(HEAT_UTILS + ".heat_resource_is") + self.res_is = mockpatch.Patch(BM_UTILS + ".resource_is") self.get_fm = mockpatch.Patch(BM_UTILS + '.get_from_manager') self.wait_for = mockpatch.Patch(HEAT_UTILS + ".bench_utils.wait_for") self.wait_for_delete = mockpatch.Patch( @@ -82,11 +82,6 @@ class HeatScenarioTestCase(test.TestCase): self._test_atomic_action_timer(scenario.atomic_actions(), 'heat.delete_stack') - def test_heat_resource_is(self): - stack = {'stack_status': 'CREATE_COMPLETED'} - status_fn = utils.heat_resource_is('CREATE_COMPLETED') - status_fn(stack) - class HeatScenarioNegativeTestCase(test.TestCase): diff --git a/tests/unit/benchmark/test_utils.py b/tests/unit/benchmark/test_utils.py index 48fa453e11..077188ac28 100644 --- a/tests/unit/benchmark/test_utils.py +++ b/tests/unit/benchmark/test_utils.py @@ -167,7 +167,8 @@ class WaitForTestCase(test.TestCase): def setUp(self): super(WaitForTestCase, self).setUp() - self.resource = object() + + self.resource = fakes.FakeResource() self.load_secs = 0.01 self.fake_checker_delayed = self.get_fake_checker_delayed( seconds=self.load_secs) @@ -196,7 +197,21 @@ class WaitForTestCase(test.TestCase): self.assertEqual(loaded_resource, self.resource) def test_wait_for_timeout_failure(self): - self.assertRaises(exceptions.TimeoutException, utils.wait_for, - self.resource, self.fake_checker_false, - self.fake_updater, self.load_secs, - self.load_secs / 3) + self.resource.name = "fake_name" + self.resource.id = "fake_id" + self.resource.status = "fake_stale_status" + + is_ready = utils.resource_is("fake_new_status") + exc = self.assertRaises( + exceptions.TimeoutException, utils.wait_for, + self.resource, is_ready, + self.fake_updater, self.load_secs, + self.load_secs / 3) + + self.assertEqual(exc.kwargs["resource_name"], "fake_name") + self.assertEqual(exc.kwargs["resource_id"], "fake_id") + self.assertEqual(exc.kwargs["desired_status"], "fake_new_status") + self.assertEqual(exc.kwargs["resource_status"], "FAKE_STALE_STATUS") + + self.assertIn("FakeResource", str(exc)) + self.assertIn("fake_new_status", str(exc))