From 6f54a3cec3619801c0d125e1a4082c8852587366 Mon Sep 17 00:00:00 2001 From: Angus Salkeld Date: Mon, 2 Feb 2015 18:09:26 +1000 Subject: [PATCH] Change to basic notification unit tests part of blueprint decouple-nested Change-Id: I0932abc6ed410739263d5ef8b5d5aaf57def1d10 --- heat/tests/test_notifications.py | 348 ++++++++----------------------- 1 file changed, 87 insertions(+), 261 deletions(-) diff --git a/heat/tests/test_notifications.py b/heat/tests/test_notifications.py index 68faaa7f01..fc33ce93dc 100644 --- a/heat/tests/test_notifications.py +++ b/heat/tests/test_notifications.py @@ -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(), - '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) - - -class ScaleNotificationTest(common.HeatTestCase): - - def setUp(self): - super(ScaleNotificationTest, self).setUp() - self.ctx = utils.dummy_context() - self.ctx.tenant_id = 'test_tenant' - - def create_autoscaling_stack_and_get_group(self): - - 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 - - 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.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, - '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', - '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'}) - ] + 'stack_identity': 'hay-are-en', + 'stack_name': 'fred', + 'tenant_id': 'test_tenant_id', + 'create_at': timeutils.isotime(created_time), + 'state': 'x_f'}) - 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) +class AutoScaleTest(common.HeatTestCase): + def setUp(self): + super(AutoScaleTest, self).setUp() + self.ctx = utils.dummy_context() - 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) + 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' - @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() + notify = self.patchobject(notification, 'notify') - err_message = 'Boooom' - m_as = self.patchobject(aws_asg.AutoScalingGroup, 'resize') - m_as.side_effect = exception.Error(err_message) + 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': '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'}) - 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]) + 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': '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'})