From: Steve Baker Date: Mon, 24 Sep 2012 23:46:08 +0000 (+1200) Subject: Fix test_waitcondition.py race by converting to mox. X-Git-Tag: 2014.1~1354 X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=8f1de0c11ae7d2c357656f73590f9e3b3f73c990;p=openstack-build%2Fheat-build.git Fix test_waitcondition.py race by converting to mox. Eventlet calls and metadata state changes are now mocked, so there are no sleeps, and in theory no chance of races. Change-Id: I05fee73a8cefafe1f2bb5a4ca65c585933497475 --- diff --git a/heat/engine/wait_condition.py b/heat/engine/wait_condition.py index 73512130..179a467f 100644 --- a/heat/engine/wait_condition.py +++ b/heat/engine/wait_condition.py @@ -14,7 +14,6 @@ # under the License. import eventlet -import json from heat.common import exception from heat.engine import resources @@ -80,23 +79,26 @@ class WaitCondition(resources.Resource): self.resource_id = handle_url.split('/')[-1] return self.resource_id + def _get_status_reason(self, handle): + return (handle.metadata.get('Status', WAITING), + handle.metadata.get('Reason', 'Reason not provided')) + + def _create_timeout(self): + return eventlet.Timeout(self.timeout) + def handle_create(self): tmo = None try: # keep polling our Metadata to see if the cfn-signal has written # it yet. The execution here is limited by timeout. - with eventlet.Timeout(self.timeout) as tmo: + with self._create_timeout() as tmo: handle = self.stack[self._get_handle_resource_id()] - status = WAITING - reason = '' + (status, reason) = (WAITING, '') sleep_time = 1 while status == WAITING: - meta = handle.metadata - status = meta.get('Status', WAITING) - reason = meta.get('Reason', 'Reason not provided') - logger.debug('got %s' % json.dumps(meta)) + (status, reason) = self._get_status_reason(handle) if status == WAITING: logger.debug('Waiting for the Metadata[Status]') eventlet.sleep(sleep_time) @@ -107,8 +109,7 @@ class WaitCondition(resources.Resource): # not my timeout raise else: - status = TIMEDOUT - reason = 'Timed out waiting for instance' + (status, reason) = (TIMEDOUT, 'Timed out waiting for instance') if status != SUCCESS: raise exception.Error(reason) diff --git a/heat/tests/test_waitcondition.py b/heat/tests/test_waitcondition.py index 15f2421a..5307f214 100644 --- a/heat/tests/test_waitcondition.py +++ b/heat/tests/test_waitcondition.py @@ -13,20 +13,19 @@ # under the License. -from datetime import datetime -import eventlet import json import logging -import os +import mox import sys +import eventlet import nose import unittest from nose.plugins.attrib import attr -from nose import with_setup import heat.db as db_api from heat.engine import parser +from heat.engine import wait_condition as wc from heat.common import context logger = logging.getLogger('test_waitcondition') @@ -56,7 +55,15 @@ test_template_waitcondition = ''' @attr(speed='slow') class stacksTest(unittest.TestCase): def setUp(self): - self.greenpool = eventlet.GreenPool() + self.m = mox.Mox() + self.m.StubOutWithMock(wc.WaitCondition, + '_get_status_reason') + self.m.StubOutWithMock(wc.WaitCondition, + '_create_timeout') + self.m.StubOutWithMock(eventlet, 'sleep') + + def tearDown(self): + self.m.UnsetStubs() def create_stack(self, stack_name, temp, params): template = parser.Template(temp) @@ -68,33 +75,62 @@ class stacksTest(unittest.TestCase): return stack def test_post_success_to_handle(self): - params = {} + t = json.loads(test_template_waitcondition) - stack = self.create_stack('test_stack', t, params) + stack = self.create_stack('test_stack', t, {}) - self.greenpool.spawn_n(stack.create) - eventlet.sleep(1) - self.assertEqual(stack.resources['WaitForTheHandle'].state, - 'IN_PROGRESS') + wc.WaitCondition._create_timeout().AndReturn(eventlet.Timeout(5)) + wc.WaitCondition._get_status_reason( + mox.IgnoreArg()).AndReturn(('WAITING', '')) + eventlet.sleep(1).AndReturn(None) + wc.WaitCondition._get_status_reason( + mox.IgnoreArg()).AndReturn(('WAITING', '')) + eventlet.sleep(1).AndReturn(None) + wc.WaitCondition._get_status_reason( + mox.IgnoreArg()).AndReturn(('SUCCESS', 'woot toot')) + + self.m.ReplayAll() + + stack.create() + + resource = stack.resources['WaitForTheHandle'] + self.assertEqual(resource.state, + 'CREATE_COMPLETE') r = db_api.resource_get_by_name_and_stack(None, 'WaitHandle', stack.id) self.assertEqual(r.name, 'WaitHandle') - metadata = {"Status": "SUCCESS", - "Reason": "woot toot", - "Data": "Application has completed configuration.", - "UniqueId": "00000"} + self.m.VerifyAll() - r.update_and_save({'rsrc_metadata': metadata}) + def test_timeout(self): - eventlet.sleep(2) + t = json.loads(test_template_waitcondition) + stack = self.create_stack('test_stack', t, {}) - logger.debug('state %s' % stack.resources['WaitForTheHandle'].state) - self.assertEqual(stack.resources['WaitForTheHandle'].state, - 'CREATE_COMPLETE') + tmo = eventlet.Timeout(6) + wc.WaitCondition._create_timeout().AndReturn(tmo) + wc.WaitCondition._get_status_reason( + mox.IgnoreArg()).AndReturn(('WAITING', '')) + eventlet.sleep(1).AndReturn(None) + wc.WaitCondition._get_status_reason( + mox.IgnoreArg()).AndReturn(('WAITING', '')) + eventlet.sleep(1).AndRaise(tmo) + + self.m.ReplayAll() + + stack.create() + + resource = stack.resources['WaitForTheHandle'] + + self.assertEqual(resource.state, + 'CREATE_FAILED') + self.assertEqual(wc.WaitCondition.UPDATE_REPLACE, + resource.handle_update()) + + stack.delete() - self.greenpool.waitall() + self.m.VerifyAll() # allows testing of the test directly if __name__ == '__main__':