Merge "Change to basic notification unit tests"
This commit is contained in:
@@ -14,281 +14,107 @@
|
||||
import mock
|
||||
from oslo.utils import timeutils
|
||||
|
||||
from heat.common import exception
|
||||
from heat.common import grouputils
|
||||
from heat.common import template_format
|
||||
from heat.engine.clients.os import glance
|
||||
from heat.engine.clients.os import nova
|
||||
from heat.engine import environment
|
||||
from heat.engine import parser
|
||||
from heat.engine import resource
|
||||
# imports for mocking
|
||||
from heat.engine.resources.aws import autoscaling_group as aws_asg
|
||||
from heat.engine.resources.aws import wait_condition as aws_wc
|
||||
from heat.engine.resources import instance
|
||||
from heat.engine.resources import loadbalancer
|
||||
from heat.engine.resources import user
|
||||
from heat.engine import signal_responder as signal
|
||||
from heat.engine import stack_resource
|
||||
from heat.engine import notification
|
||||
from heat.tests import common
|
||||
from heat.tests import generic_resource
|
||||
# reuse the same template than autoscaling tests
|
||||
from heat.tests import test_autoscaling as test_as
|
||||
from heat.tests import utils
|
||||
|
||||
|
||||
class NotificationTest(common.HeatTestCase):
|
||||
class StackTest(common.HeatTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(NotificationTest, self).setUp()
|
||||
resource._register_class('GenericResource',
|
||||
generic_resource.ResourceWithProps)
|
||||
|
||||
def create_test_stack(self):
|
||||
test_template = {'HeatTemplateFormatVersion': '2012-12-12',
|
||||
'Parameters': {'Foo': {'Type': 'String'},
|
||||
'Pass': {'Type': 'String',
|
||||
'NoEcho': True}},
|
||||
'Resources':
|
||||
{'TestResource': {'Type': 'GenericResource',
|
||||
'Properties': {'Foo': 'abc'}}},
|
||||
'Outputs': {'food':
|
||||
{'Value':
|
||||
{'Fn::GetAtt': ['TestResource',
|
||||
'foo']}}}}
|
||||
template = parser.Template(test_template)
|
||||
super(StackTest, self).setUp()
|
||||
self.ctx = utils.dummy_context()
|
||||
self.ctx.tenant_id = 'test_tenant'
|
||||
|
||||
env = environment.Environment()
|
||||
env.load({u'parameters':
|
||||
{u'Foo': 'user_data', u'Pass': 'secret'}})
|
||||
self.stack_name = utils.random_name()
|
||||
stack = parser.Stack(self.ctx, self.stack_name, template,
|
||||
env=env, disable_rollback=True)
|
||||
self.stack = stack
|
||||
stack.store()
|
||||
self.created_time = stack.created_time
|
||||
self.create_at = timeutils.isotime(self.created_time)
|
||||
stack.create()
|
||||
def test_send(self):
|
||||
created_time = timeutils.utcnow()
|
||||
st = mock.Mock()
|
||||
st.state = ('x', 'f')
|
||||
st.status = st.state[0]
|
||||
st.action = st.state[1]
|
||||
st.name = 'fred'
|
||||
st.status_reason = 'this is why'
|
||||
st.created_time = created_time
|
||||
st.context = self.ctx
|
||||
st.identifier.return_value.arn.return_value = 'hay-are-en'
|
||||
|
||||
self.expected = {}
|
||||
for action in ('create', 'suspend', 'delete'):
|
||||
self.make_mocks(action)
|
||||
notify = self.patchobject(notification, 'notify')
|
||||
|
||||
def make_mocks(self, action):
|
||||
stack_arn = self.stack.identifier().arn()
|
||||
self.expected[action] = [
|
||||
mock.call(self.ctx,
|
||||
'orchestration.stack.%s.start' % action,
|
||||
{'state_reason': 'Stack %s started' % action.upper(),
|
||||
notification.stack.send(st)
|
||||
notify.assert_called_once_with(
|
||||
self.ctx, 'stack.f.error', 'ERROR',
|
||||
{'state_reason': 'this is why',
|
||||
'user_id': 'test_username',
|
||||
'stack_identity': stack_arn,
|
||||
'tenant_id': 'test_tenant',
|
||||
'create_at': self.create_at,
|
||||
'stack_name': self.stack_name,
|
||||
'state': '%s_IN_PROGRESS' % action.upper()}),
|
||||
mock.call(self.ctx,
|
||||
'orchestration.stack.%s.end' % action,
|
||||
{'state_reason':
|
||||
'Stack %s completed successfully' % action.upper(),
|
||||
'user_id': 'test_username',
|
||||
'stack_identity': stack_arn,
|
||||
'tenant_id': 'test_tenant',
|
||||
'create_at': self.create_at,
|
||||
'stack_name': self.stack_name,
|
||||
'state': '%s_COMPLETE' % action.upper()})]
|
||||
|
||||
@mock.patch('oslo.messaging.notify.notifier.Notifier.info')
|
||||
def test_create_stack(self, mock_notify):
|
||||
self.create_test_stack()
|
||||
self.assertEqual((self.stack.CREATE, self.stack.COMPLETE),
|
||||
self.stack.state)
|
||||
|
||||
self.assertEqual(self.expected['create'],
|
||||
mock_notify.call_args_list)
|
||||
|
||||
@mock.patch('oslo.messaging.notify.notifier.Notifier.info')
|
||||
def test_create_and_suspend_stack(self, mock_notify):
|
||||
self.create_test_stack()
|
||||
self.assertEqual((self.stack.CREATE, self.stack.COMPLETE),
|
||||
self.stack.state)
|
||||
|
||||
self.assertEqual(self.expected['create'],
|
||||
mock_notify.call_args_list)
|
||||
self.stack.suspend()
|
||||
self.assertEqual((self.stack.SUSPEND, self.stack.COMPLETE),
|
||||
self.stack.state)
|
||||
|
||||
expected = self.expected['create'] + self.expected['suspend']
|
||||
self.assertEqual(expected, mock_notify.call_args_list)
|
||||
|
||||
@mock.patch('oslo.messaging.notify.notifier.Notifier.info')
|
||||
def test_create_and_delete_stack(self, mock_notify):
|
||||
self.create_test_stack()
|
||||
self.assertEqual((self.stack.CREATE, self.stack.COMPLETE),
|
||||
self.stack.state)
|
||||
|
||||
self.assertEqual(self.expected['create'],
|
||||
mock_notify.call_args_list)
|
||||
self.stack.delete()
|
||||
self.assertEqual((self.stack.DELETE, self.stack.COMPLETE),
|
||||
self.stack.state)
|
||||
expected = self.expected['create'] + self.expected['delete']
|
||||
|
||||
self.assertEqual(expected, mock_notify.call_args_list)
|
||||
'stack_identity': 'hay-are-en',
|
||||
'stack_name': 'fred',
|
||||
'tenant_id': 'test_tenant_id',
|
||||
'create_at': timeutils.isotime(created_time),
|
||||
'state': 'x_f'})
|
||||
|
||||
|
||||
class ScaleNotificationTest(common.HeatTestCase):
|
||||
|
||||
class AutoScaleTest(common.HeatTestCase):
|
||||
def setUp(self):
|
||||
super(ScaleNotificationTest, self).setUp()
|
||||
super(AutoScaleTest, self).setUp()
|
||||
self.ctx = utils.dummy_context()
|
||||
self.ctx.tenant_id = 'test_tenant'
|
||||
|
||||
def create_autoscaling_stack_and_get_group(self):
|
||||
def test_send(self):
|
||||
created_time = timeutils.utcnow()
|
||||
st = mock.Mock()
|
||||
st.state = ('x', 'f')
|
||||
st.status = st.state[0]
|
||||
st.action = st.state[1]
|
||||
st.name = 'fred'
|
||||
st.status_reason = 'this is why'
|
||||
st.created_time = created_time
|
||||
st.context = self.ctx
|
||||
st.identifier.return_value.arn.return_value = 'hay-are-en'
|
||||
|
||||
env = environment.Environment()
|
||||
env.load({u'parameters':
|
||||
{u'KeyName': 'foo', 'ImageId': 'cloudimage'}})
|
||||
t = template_format.parse(test_as.as_template)
|
||||
template = parser.Template(t)
|
||||
self.stack_name = utils.random_name()
|
||||
stack = parser.Stack(self.ctx, self.stack_name, template,
|
||||
env=env, disable_rollback=True)
|
||||
stack.store()
|
||||
self.created_time = stack.created_time
|
||||
self.create_at = timeutils.isotime(self.created_time)
|
||||
self.stub_SnapshotConstraint_validate()
|
||||
self.m.ReplayAll()
|
||||
stack.create()
|
||||
self.stack = stack
|
||||
group = stack['WebServerGroup']
|
||||
self.assertEqual((group.CREATE, group.COMPLETE), group.state)
|
||||
self.m.VerifyAll()
|
||||
return group
|
||||
notify = self.patchobject(notification, 'notify')
|
||||
|
||||
def mock_stack_except_for_group(self):
|
||||
self.m_validate = self.patchobject(parser.Stack, 'validate')
|
||||
self.patchobject(nova.KeypairConstraint, 'validate')
|
||||
self.patchobject(glance.ImageConstraint, 'validate')
|
||||
self.patchobject(nova.FlavorConstraint, 'validate')
|
||||
self.patchobject(instance.Instance, 'handle_create'
|
||||
).return_value = True
|
||||
self.patchobject(instance.Instance, 'check_create_complete'
|
||||
).return_value = True
|
||||
self.patchobject(stack_resource.StackResource,
|
||||
'check_update_complete').return_value = True
|
||||
|
||||
self.patchobject(loadbalancer.LoadBalancer, 'handle_update')
|
||||
self.patchobject(user.User, 'handle_create')
|
||||
self.patchobject(user.AccessKey, 'handle_create')
|
||||
self.patchobject(aws_wc.WaitCondition, 'handle_create')
|
||||
self.patchobject(aws_wc.WaitCondition,
|
||||
'check_create_complete').return_value = True
|
||||
self.patchobject(signal.SignalResponder, 'handle_create')
|
||||
|
||||
def expected_notifs_calls(self, group, adjust,
|
||||
start_capacity, end_capacity=None,
|
||||
with_error=None):
|
||||
|
||||
stack_arn = self.stack.identifier().arn()
|
||||
expected = [mock.call(
|
||||
self.ctx,
|
||||
'orchestration.autoscaling.start',
|
||||
{'state_reason': 'Stack CREATE completed successfully',
|
||||
notification.autoscaling.send(st, adjustment='x',
|
||||
adjustment_type='y',
|
||||
capacity='5',
|
||||
groupname='c',
|
||||
message='fred',
|
||||
suffix='the-end')
|
||||
notify.assert_called_once_with(
|
||||
self.ctx, 'autoscaling.the-end', 'INFO',
|
||||
{'state_reason': 'this is why',
|
||||
'user_id': 'test_username',
|
||||
'stack_identity': stack_arn,
|
||||
'tenant_id': 'test_tenant',
|
||||
'create_at': self.create_at,
|
||||
'adjustment_type': 'ChangeInCapacity',
|
||||
'groupname': group.FnGetRefId(),
|
||||
'capacity': start_capacity,
|
||||
'adjustment': adjust,
|
||||
'stack_name': self.stack_name,
|
||||
'message': 'Start resizing the group %s' %
|
||||
group.FnGetRefId(),
|
||||
'state': 'CREATE_COMPLETE'})
|
||||
]
|
||||
if with_error:
|
||||
expected += [mock.call(
|
||||
self.ctx,
|
||||
'orchestration.autoscaling.error',
|
||||
{'state_reason':
|
||||
'Stack CREATE completed successfully',
|
||||
'stack_identity': 'hay-are-en',
|
||||
'stack_name': 'fred',
|
||||
'tenant_id': 'test_tenant_id',
|
||||
'create_at': timeutils.isotime(created_time),
|
||||
'state': 'x_f', 'adjustment_type': 'y',
|
||||
'groupname': 'c', 'capacity': '5',
|
||||
'message': 'fred', 'adjustment': 'x'})
|
||||
|
||||
def test_send_error(self):
|
||||
created_time = timeutils.utcnow()
|
||||
st = mock.Mock()
|
||||
st.state = ('x', 'f')
|
||||
st.status = st.state[0]
|
||||
st.action = st.state[1]
|
||||
st.name = 'fred'
|
||||
st.status_reason = 'this is why'
|
||||
st.created_time = created_time
|
||||
st.context = self.ctx
|
||||
st.identifier.return_value.arn.return_value = 'hay-are-en'
|
||||
|
||||
notify = self.patchobject(notification, 'notify')
|
||||
|
||||
notification.autoscaling.send(st, adjustment='x',
|
||||
adjustment_type='y',
|
||||
capacity='5',
|
||||
groupname='c',
|
||||
suffix='error')
|
||||
notify.assert_called_once_with(
|
||||
self.ctx, 'autoscaling.error', 'ERROR',
|
||||
{'state_reason': 'this is why',
|
||||
'user_id': 'test_username',
|
||||
'stack_identity': stack_arn,
|
||||
'tenant_id': 'test_tenant',
|
||||
'create_at': self.create_at,
|
||||
'adjustment_type': 'ChangeInCapacity',
|
||||
'groupname': group.FnGetRefId(),
|
||||
'capacity': start_capacity,
|
||||
'adjustment': adjust,
|
||||
'stack_name': self.stack_name,
|
||||
'message': with_error,
|
||||
'state': 'CREATE_COMPLETE'})
|
||||
]
|
||||
else:
|
||||
expected += [mock.call(
|
||||
self.ctx,
|
||||
'orchestration.autoscaling.end',
|
||||
{'state_reason':
|
||||
'Stack CREATE completed successfully',
|
||||
'user_id': 'test_username',
|
||||
'stack_identity': stack_arn,
|
||||
'tenant_id': 'test_tenant',
|
||||
'create_at': self.create_at,
|
||||
'adjustment_type': 'ChangeInCapacity',
|
||||
'groupname': group.FnGetRefId(),
|
||||
'capacity': end_capacity,
|
||||
'adjustment': adjust,
|
||||
'stack_name': self.stack_name,
|
||||
'message': 'End resizing the group %s' %
|
||||
group.FnGetRefId(),
|
||||
'state': 'CREATE_COMPLETE'})
|
||||
]
|
||||
|
||||
return expected
|
||||
|
||||
@mock.patch('heat.engine.notification.stack.send')
|
||||
@mock.patch('oslo.messaging.notify.notifier.Notifier.info')
|
||||
def test_scale_success(self, mock_notify, mock_send):
|
||||
self.mock_stack_except_for_group()
|
||||
group = self.create_autoscaling_stack_and_get_group()
|
||||
expected = self.expected_notifs_calls(group,
|
||||
adjust=1,
|
||||
start_capacity=1,
|
||||
end_capacity=2,
|
||||
)
|
||||
group.adjust(1)
|
||||
self.assertEqual(2, grouputils.get_size(group))
|
||||
mock_notify.assert_has_calls(expected)
|
||||
|
||||
expected = self.expected_notifs_calls(group,
|
||||
adjust=-1,
|
||||
start_capacity=2,
|
||||
end_capacity=1,
|
||||
)
|
||||
group.adjust(-1)
|
||||
self.assertEqual(1, grouputils.get_size(group))
|
||||
mock_notify.assert_has_calls(expected)
|
||||
|
||||
@mock.patch('heat.engine.notification.stack.send')
|
||||
@mock.patch('oslo.messaging.notify.notifier.Notifier.info')
|
||||
@mock.patch('oslo.messaging.notify.notifier.Notifier.error')
|
||||
def test_scaleup_failure(self, mock_error, mock_info, mock_send):
|
||||
self.mock_stack_except_for_group()
|
||||
group = self.create_autoscaling_stack_and_get_group()
|
||||
|
||||
err_message = 'Boooom'
|
||||
m_as = self.patchobject(aws_asg.AutoScalingGroup, 'resize')
|
||||
m_as.side_effect = exception.Error(err_message)
|
||||
|
||||
info, error = self.expected_notifs_calls(group,
|
||||
adjust=2,
|
||||
start_capacity=1,
|
||||
with_error=err_message)
|
||||
self.assertRaises(exception.Error, group.adjust, 2)
|
||||
self.assertEqual(1, grouputils.get_size(group))
|
||||
mock_error.assert_has_calls([error])
|
||||
mock_info.assert_has_calls([info])
|
||||
'stack_identity': 'hay-are-en',
|
||||
'stack_name': 'fred',
|
||||
'tenant_id': 'test_tenant_id',
|
||||
'create_at': timeutils.isotime(created_time),
|
||||
'state': 'x_f', 'adjustment_type': 'y',
|
||||
'groupname': 'c', 'capacity': '5',
|
||||
'message': 'error', 'adjustment': 'x'})
|
||||
|
||||
Reference in New Issue
Block a user