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
This commit is contained in:
parent
adb6adb516
commit
8f1de0c11a
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
self.greenpool.spawn_n(stack.create)
|
||||
eventlet.sleep(1)
|
||||
self.assertEqual(stack.resources['WaitForTheHandle'].state,
|
||||
'IN_PROGRESS')
|
||||
t = json.loads(test_template_waitcondition)
|
||||
stack = self.create_stack('test_stack', t, {})
|
||||
|
||||
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.greenpool.waitall()
|
||||
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.m.VerifyAll()
|
||||
|
||||
# allows testing of the test directly
|
||||
if __name__ == '__main__':
|
||||
|
|
Loading…
Reference in New Issue