From e8a777fd1a5e5e5de7bb59d47df49e3687755457 Mon Sep 17 00:00:00 2001 From: tengqm Date: Mon, 13 Jul 2015 04:19:28 -0400 Subject: [PATCH] Split engine service test cases (8) This patch splits the stack watch related unit tests into a separate module. Some mox calls are replaced with mock calls where approriate. It also moves the existing modules related to engine service tests into a separate subdirectory. This is to make room for other unit tests that are coming in. Change-Id: I7ea61c22e017785c480d78d6c07132164ed0b889 --- heat/tests/engine/service/__init__.py | 0 .../{ => service}/test_service_engine.py | 0 .../{ => service}/test_software_config.py | 0 .../engine/{ => service}/test_stack_action.py | 0 .../engine/{ => service}/test_stack_create.py | 0 .../engine/{ => service}/test_stack_delete.py | 0 .../engine/{ => service}/test_stack_events.py | 0 .../{ => service}/test_stack_snapshot.py | 0 heat/tests/engine/service/test_stack_watch.py | 265 ++++++++++++++++++ .../{ => service}/test_threadgroup_mgr.py | 0 heat/tests/test_engine_service.py | 231 --------------- 11 files changed, 265 insertions(+), 231 deletions(-) create mode 100644 heat/tests/engine/service/__init__.py rename heat/tests/engine/{ => service}/test_service_engine.py (100%) rename heat/tests/engine/{ => service}/test_software_config.py (100%) rename heat/tests/engine/{ => service}/test_stack_action.py (100%) rename heat/tests/engine/{ => service}/test_stack_create.py (100%) rename heat/tests/engine/{ => service}/test_stack_delete.py (100%) rename heat/tests/engine/{ => service}/test_stack_events.py (100%) rename heat/tests/engine/{ => service}/test_stack_snapshot.py (100%) create mode 100644 heat/tests/engine/service/test_stack_watch.py rename heat/tests/engine/{ => service}/test_threadgroup_mgr.py (100%) diff --git a/heat/tests/engine/service/__init__.py b/heat/tests/engine/service/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/heat/tests/engine/test_service_engine.py b/heat/tests/engine/service/test_service_engine.py similarity index 100% rename from heat/tests/engine/test_service_engine.py rename to heat/tests/engine/service/test_service_engine.py diff --git a/heat/tests/engine/test_software_config.py b/heat/tests/engine/service/test_software_config.py similarity index 100% rename from heat/tests/engine/test_software_config.py rename to heat/tests/engine/service/test_software_config.py diff --git a/heat/tests/engine/test_stack_action.py b/heat/tests/engine/service/test_stack_action.py similarity index 100% rename from heat/tests/engine/test_stack_action.py rename to heat/tests/engine/service/test_stack_action.py diff --git a/heat/tests/engine/test_stack_create.py b/heat/tests/engine/service/test_stack_create.py similarity index 100% rename from heat/tests/engine/test_stack_create.py rename to heat/tests/engine/service/test_stack_create.py diff --git a/heat/tests/engine/test_stack_delete.py b/heat/tests/engine/service/test_stack_delete.py similarity index 100% rename from heat/tests/engine/test_stack_delete.py rename to heat/tests/engine/service/test_stack_delete.py diff --git a/heat/tests/engine/test_stack_events.py b/heat/tests/engine/service/test_stack_events.py similarity index 100% rename from heat/tests/engine/test_stack_events.py rename to heat/tests/engine/service/test_stack_events.py diff --git a/heat/tests/engine/test_stack_snapshot.py b/heat/tests/engine/service/test_stack_snapshot.py similarity index 100% rename from heat/tests/engine/test_stack_snapshot.py rename to heat/tests/engine/service/test_stack_snapshot.py diff --git a/heat/tests/engine/service/test_stack_watch.py b/heat/tests/engine/service/test_stack_watch.py new file mode 100644 index 0000000000..614ef0cb33 --- /dev/null +++ b/heat/tests/engine/service/test_stack_watch.py @@ -0,0 +1,265 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import mock +from oslo_messaging.rpc import dispatcher + +from heat.common import exception +from heat.engine import service +from heat.engine import service_stack_watch +from heat.engine import stack +from heat.engine import watchrule +from heat.objects import stack as stack_object +from heat.objects import watch_data as watch_data_object +from heat.objects import watch_rule as watch_rule_object +from heat.rpc import api as rpc_api +from heat.tests import common +from heat.tests.engine import tools +from heat.tests import utils + + +class StackWatchTest(common.HeatTestCase): + + def setUp(self): + super(StackWatchTest, self).setUp() + + self.ctx = utils.dummy_context(tenant_id='stack_watch_test_tenant') + self.eng = service.EngineService('a-host', 'a-topic') + self.eng.create_periodic_tasks() + # self.eng.engine_id = 'engine-fake-uuid' + + @mock.patch.object(service_stack_watch.StackWatch, 'start_watch_task') + @mock.patch.object(stack_object.Stack, 'get_all') + @mock.patch.object(service.service.Service, 'start') + def test_start_watches_all_stacks(self, mock_super_start, mock_get_all, + start_watch_task): + s1 = mock.Mock(id=1) + s2 = mock.Mock(id=2) + mock_get_all.return_value = [s1, s2] + start_watch_task.return_value = None + + self.eng.thread_group_mgr = None + self.eng.create_periodic_tasks() + + mock_get_all.assert_called_once_with(mock.ANY, tenant_safe=False, + show_hidden=True) + calls = start_watch_task.call_args_list + self.assertEqual(2, start_watch_task.call_count) + self.assertIn(mock.call(1, mock.ANY), calls) + self.assertIn(mock.call(2, mock.ANY), calls) + + @tools.stack_context('service_show_watch_test_stack', False) + def test_show_watch(self): + # Insert two dummy watch rules into the DB + rule = {u'EvaluationPeriods': u'1', + u'AlarmActions': [u'WebServerRestartPolicy'], + u'AlarmDescription': u'Restart the WikiDatabase', + u'Namespace': u'system/linux', + u'Period': u'300', + u'ComparisonOperator': u'GreaterThanThreshold', + u'Statistic': u'SampleCount', + u'Threshold': u'2', + u'MetricName': u'ServiceFailure'} + self.wr = [] + self.wr.append(watchrule.WatchRule(context=self.ctx, + watch_name='show_watch_1', + rule=rule, + watch_data=[], + stack_id=self.stack.id, + state='NORMAL')) + self.wr[0].store() + + self.wr.append(watchrule.WatchRule(context=self.ctx, + watch_name='show_watch_2', + rule=rule, + watch_data=[], + stack_id=self.stack.id, + state='NORMAL')) + self.wr[1].store() + + # watch_name=None should return all watches + result = self.eng.show_watch(self.ctx, watch_name=None) + result_names = [r.get('name') for r in result] + self.assertIn('show_watch_1', result_names) + self.assertIn('show_watch_2', result_names) + + result = self.eng.show_watch(self.ctx, watch_name="show_watch_1") + self.assertEqual(1, len(result)) + self.assertIn('name', result[0]) + self.assertEqual('show_watch_1', result[0]['name']) + + result = self.eng.show_watch(self.ctx, watch_name="show_watch_2") + self.assertEqual(1, len(result)) + self.assertIn('name', result[0]) + self.assertEqual('show_watch_2', result[0]['name']) + + ex = self.assertRaises(dispatcher.ExpectedException, + self.eng.show_watch, + self.ctx, watch_name="nonexistent") + self.assertEqual(exception.WatchRuleNotFound, ex.exc_info[0]) + + # Check the response has all keys defined in the engine API + for key in rpc_api.WATCH_KEYS: + self.assertIn(key, result[0]) + + @tools.stack_context('service_show_watch_metric_test_stack', False) + def test_show_watch_metric(self): + # Insert dummy watch rule into the DB + rule = {u'EvaluationPeriods': u'1', + u'AlarmActions': [u'WebServerRestartPolicy'], + u'AlarmDescription': u'Restart the WikiDatabase', + u'Namespace': u'system/linux', + u'Period': u'300', + u'ComparisonOperator': u'GreaterThanThreshold', + u'Statistic': u'SampleCount', + u'Threshold': u'2', + u'MetricName': u'ServiceFailure'} + self.wr = watchrule.WatchRule(context=self.ctx, + watch_name='show_watch_metric_1', + rule=rule, + watch_data=[], + stack_id=self.stack.id, + state='NORMAL') + self.wr.store() + + # And add a metric datapoint + watch = watch_rule_object.WatchRule.get_by_name(self.ctx, + 'show_watch_metric_1') + self.assertIsNotNone(watch) + values = {'watch_rule_id': watch.id, + 'data': {u'Namespace': u'system/linux', + u'ServiceFailure': { + u'Units': u'Counter', u'Value': 1}}} + watch_data_object.WatchData.create(self.ctx, values) + + # Check there is one result returned + result = self.eng.show_watch_metric(self.ctx, + metric_namespace=None, + metric_name=None) + self.assertEqual(1, len(result)) + + # Create another metric datapoint and check we get two + watch_data_object.WatchData.create(self.ctx, values) + result = self.eng.show_watch_metric(self.ctx, + metric_namespace=None, + metric_name=None) + self.assertEqual(2, len(result)) + + # Check the response has all keys defined in the engine API + for key in rpc_api.WATCH_DATA_KEYS: + self.assertIn(key, result[0]) + + @tools.stack_context('service_show_watch_state_test_stack') + @mock.patch.object(stack.Stack, 'resource_by_refid') + def test_set_watch_state(self, mock_ref): + # Insert dummy watch rule into the DB + rule = {u'EvaluationPeriods': u'1', + u'AlarmActions': [u'WebServerRestartPolicy'], + u'AlarmDescription': u'Restart the WikiDatabase', + u'Namespace': u'system/linux', + u'Period': u'300', + u'ComparisonOperator': u'GreaterThanThreshold', + u'Statistic': u'SampleCount', + u'Threshold': u'2', + u'MetricName': u'ServiceFailure'} + self.wr = watchrule.WatchRule(context=self.ctx, + watch_name='OverrideAlarm', + rule=rule, + watch_data=[], + stack_id=self.stack.id, + state='NORMAL') + self.wr.store() + + class DummyAction(object): + def signal(self): + return "dummyfoo" + + dummy_action = DummyAction() + mock_ref.return_value = dummy_action + + # Replace the real stack threadgroup with a dummy one, so we can + # check the function returned on ALARM is correctly scheduled + dtg = tools.DummyThreadGroup() + self.eng.thread_group_mgr.groups[self.stack.id] = dtg + + state = watchrule.WatchRule.NODATA + result = self.eng.set_watch_state(self.ctx, + watch_name="OverrideAlarm", + state=state) + self.assertEqual(state, result[rpc_api.WATCH_STATE_VALUE]) + self.assertEqual( + [], self.eng.thread_group_mgr.groups[self.stack.id].threads) + + state = watchrule.WatchRule.NORMAL + result = self.eng.set_watch_state(self.ctx, + watch_name="OverrideAlarm", + state=state) + self.assertEqual(state, result[rpc_api.WATCH_STATE_VALUE]) + self.assertEqual( + [], self.eng.thread_group_mgr.groups[self.stack.id].threads) + + state = watchrule.WatchRule.ALARM + result = self.eng.set_watch_state(self.ctx, + watch_name="OverrideAlarm", + state=state) + self.assertEqual(state, result[rpc_api.WATCH_STATE_VALUE]) + self.assertEqual( + [dummy_action.signal], + self.eng.thread_group_mgr.groups[self.stack.id].threads) + + mock_ref.assert_called_once_with('WebServerRestartPolicy') + + @tools.stack_context('service_show_watch_state_badstate_test_stack') + @mock.patch.object(watchrule.WatchRule, 'set_watch_state') + def test_set_watch_state_badstate(self, mock_set): + mock_set.side_effect = ValueError + # Insert dummy watch rule into the DB + rule = {u'EvaluationPeriods': u'1', + u'AlarmActions': [u'WebServerRestartPolicy'], + u'AlarmDescription': u'Restart the WikiDatabase', + u'Namespace': u'system/linux', + u'Period': u'300', + u'ComparisonOperator': u'GreaterThanThreshold', + u'Statistic': u'SampleCount', + u'Threshold': u'2', + u'MetricName': u'ServiceFailure'} + self.wr = watchrule.WatchRule(context=self.ctx, + watch_name='OverrideAlarm2', + rule=rule, + watch_data=[], + stack_id=self.stack.id, + state='NORMAL') + self.wr.store() + + for state in ["HGJHGJHG", "1234", "!\*(&%"]: + self.assertRaises(ValueError, + self.eng.set_watch_state, + self.ctx, watch_name="OverrideAlarm2", + state=state) + + calls = [mock.call("HGJHGJHG"), + mock.call("1234"), + mock.call("!\*(&%")] + mock_set.assert_has_calls(calls) + + @mock.patch.object(watchrule.WatchRule, 'load') + def test_set_watch_state_noexist(self, mock_load): + state = watchrule.WatchRule.ALARM # State valid + mock_load.side_effect = exception.WatchRuleNotFound(watch_name='test') + + ex = self.assertRaises(dispatcher.ExpectedException, + self.eng.set_watch_state, + self.ctx, watch_name="nonexistent", + state=state) + self.assertEqual(exception.WatchRuleNotFound, ex.exc_info[0]) + mock_load.assert_called_once_with(self.ctx, "nonexistent") diff --git a/heat/tests/engine/test_threadgroup_mgr.py b/heat/tests/engine/service/test_threadgroup_mgr.py similarity index 100% rename from heat/tests/engine/test_threadgroup_mgr.py rename to heat/tests/engine/service/test_threadgroup_mgr.py diff --git a/heat/tests/test_engine_service.py b/heat/tests/test_engine_service.py index e05f1dde92..9fc31b38a3 100644 --- a/heat/tests/test_engine_service.py +++ b/heat/tests/test_engine_service.py @@ -33,14 +33,10 @@ from heat.engine.hot import functions as hot_functions from heat.engine.hot import template as hottemplate from heat.engine import resource as res from heat.engine import service -from heat.engine import service_stack_watch from heat.engine import stack as parser from heat.engine import stack_lock from heat.engine import template as templatem -from heat.engine import watchrule from heat.objects import stack as stack_object -from heat.objects import watch_data as watch_data_object -from heat.objects import watch_rule as watch_rule_object from heat.rpc import api as rpc_api from heat.tests import common from heat.tests.engine import tools @@ -1104,26 +1100,6 @@ class StackServiceTest(common.HeatTestCase): self.eng.engine_id = 'engine-fake-uuid' cfg.CONF.set_default('heat_stack_user_role', 'stack_user_role') - @mock.patch.object(service_stack_watch.StackWatch, 'start_watch_task') - @mock.patch.object(stack_object.Stack, 'get_all') - @mock.patch.object(service.service.Service, 'start') - def test_start_watches_all_stacks(self, mock_super_start, mock_get_all, - start_watch_task): - s1 = mock.Mock(id=1) - s2 = mock.Mock(id=2) - mock_get_all.return_value = [s1, s2] - start_watch_task.return_value = None - - self.eng.thread_group_mgr = None - self.eng.create_periodic_tasks() - - mock_get_all.assert_called_once_with(mock.ANY, tenant_safe=False, - show_hidden=True) - calls = start_watch_task.call_args_list - self.assertEqual(2, start_watch_task.call_count) - self.assertIn(mock.call(1, mock.ANY), calls) - self.assertIn(mock.call(2, mock.ANY), calls) - @tools.stack_context('service_identify_test_stack', False) def test_stack_identify(self): self.m.StubOutWithMock(parser.Stack, 'load') @@ -2060,213 +2036,6 @@ class StackServiceTest(common.HeatTestCase): self.assertEqual(test_metadata, md) self.m.VerifyAll() - @tools.stack_context('service_show_watch_test_stack', False) - def test_show_watch(self): - # Insert two dummy watch rules into the DB - rule = {u'EvaluationPeriods': u'1', - u'AlarmActions': [u'WebServerRestartPolicy'], - u'AlarmDescription': u'Restart the WikiDatabase', - u'Namespace': u'system/linux', - u'Period': u'300', - u'ComparisonOperator': u'GreaterThanThreshold', - u'Statistic': u'SampleCount', - u'Threshold': u'2', - u'MetricName': u'ServiceFailure'} - self.wr = [] - self.wr.append(watchrule.WatchRule(context=self.ctx, - watch_name='show_watch_1', - rule=rule, - watch_data=[], - stack_id=self.stack.id, - state='NORMAL')) - self.wr[0].store() - - self.wr.append(watchrule.WatchRule(context=self.ctx, - watch_name='show_watch_2', - rule=rule, - watch_data=[], - stack_id=self.stack.id, - state='NORMAL')) - self.wr[1].store() - - # watch_name=None should return all watches - result = self.eng.show_watch(self.ctx, watch_name=None) - result_names = [r.get('name') for r in result] - self.assertIn('show_watch_1', result_names) - self.assertIn('show_watch_2', result_names) - - result = self.eng.show_watch(self.ctx, watch_name="show_watch_1") - self.assertEqual(1, len(result)) - self.assertIn('name', result[0]) - self.assertEqual('show_watch_1', result[0]['name']) - - result = self.eng.show_watch(self.ctx, watch_name="show_watch_2") - self.assertEqual(1, len(result)) - self.assertIn('name', result[0]) - self.assertEqual('show_watch_2', result[0]['name']) - - ex = self.assertRaises(dispatcher.ExpectedException, - self.eng.show_watch, - self.ctx, watch_name="nonexistent") - self.assertEqual(exception.WatchRuleNotFound, ex.exc_info[0]) - - # Check the response has all keys defined in the engine API - for key in rpc_api.WATCH_KEYS: - self.assertIn(key, result[0]) - - @tools.stack_context('service_show_watch_metric_test_stack', False) - def test_show_watch_metric(self): - # Insert dummy watch rule into the DB - rule = {u'EvaluationPeriods': u'1', - u'AlarmActions': [u'WebServerRestartPolicy'], - u'AlarmDescription': u'Restart the WikiDatabase', - u'Namespace': u'system/linux', - u'Period': u'300', - u'ComparisonOperator': u'GreaterThanThreshold', - u'Statistic': u'SampleCount', - u'Threshold': u'2', - u'MetricName': u'ServiceFailure'} - self.wr = watchrule.WatchRule(context=self.ctx, - watch_name='show_watch_metric_1', - rule=rule, - watch_data=[], - stack_id=self.stack.id, - state='NORMAL') - self.wr.store() - - # And add a metric datapoint - watch = watch_rule_object.WatchRule.get_by_name(self.ctx, - 'show_watch_metric_1') - self.assertIsNotNone(watch) - values = {'watch_rule_id': watch.id, - 'data': {u'Namespace': u'system/linux', - u'ServiceFailure': { - u'Units': u'Counter', u'Value': 1}}} - watch_data_object.WatchData.create(self.ctx, values) - - # Check there is one result returned - result = self.eng.show_watch_metric(self.ctx, - metric_namespace=None, - metric_name=None) - self.assertEqual(1, len(result)) - - # Create another metric datapoint and check we get two - watch_data_object.WatchData.create(self.ctx, values) - result = self.eng.show_watch_metric(self.ctx, - metric_namespace=None, - metric_name=None) - self.assertEqual(2, len(result)) - - # Check the response has all keys defined in the engine API - for key in rpc_api.WATCH_DATA_KEYS: - self.assertIn(key, result[0]) - - @tools.stack_context('service_show_watch_state_test_stack') - def test_set_watch_state(self): - self.eng.thread_group_mgr = tools.DummyThreadGroupMgrLogStart() - # Insert dummy watch rule into the DB - rule = {u'EvaluationPeriods': u'1', - u'AlarmActions': [u'WebServerRestartPolicy'], - u'AlarmDescription': u'Restart the WikiDatabase', - u'Namespace': u'system/linux', - u'Period': u'300', - u'ComparisonOperator': u'GreaterThanThreshold', - u'Statistic': u'SampleCount', - u'Threshold': u'2', - u'MetricName': u'ServiceFailure'} - self.wr = watchrule.WatchRule(context=self.ctx, - watch_name='OverrideAlarm', - rule=rule, - watch_data=[], - stack_id=self.stack.id, - state='NORMAL') - self.wr.store() - - class DummyAction(object): - def signal(self): - return "dummyfoo" - - dummy_action = DummyAction() - self.m.StubOutWithMock(parser.Stack, 'resource_by_refid') - parser.Stack.resource_by_refid( - 'WebServerRestartPolicy').AndReturn(dummy_action) - - self.m.ReplayAll() - - state = watchrule.WatchRule.NODATA - result = self.eng.set_watch_state(self.ctx, - watch_name="OverrideAlarm", - state=state) - self.assertEqual(state, result[rpc_api.WATCH_STATE_VALUE]) - self.assertEqual([], self.eng.thread_group_mgr.started) - - state = watchrule.WatchRule.NORMAL - result = self.eng.set_watch_state(self.ctx, - watch_name="OverrideAlarm", - state=state) - self.assertEqual(state, result[rpc_api.WATCH_STATE_VALUE]) - self.assertEqual([], self.eng.thread_group_mgr.started) - - state = watchrule.WatchRule.ALARM - result = self.eng.set_watch_state(self.ctx, - watch_name="OverrideAlarm", - state=state) - self.assertEqual(state, result[rpc_api.WATCH_STATE_VALUE]) - self.assertEqual([(self.stack.id, dummy_action.signal)], - self.eng.thread_group_mgr.started) - - self.m.VerifyAll() - - @tools.stack_context('service_show_watch_state_badstate_test_stack') - def test_set_watch_state_badstate(self): - # Insert dummy watch rule into the DB - rule = {u'EvaluationPeriods': u'1', - u'AlarmActions': [u'WebServerRestartPolicy'], - u'AlarmDescription': u'Restart the WikiDatabase', - u'Namespace': u'system/linux', - u'Period': u'300', - u'ComparisonOperator': u'GreaterThanThreshold', - u'Statistic': u'SampleCount', - u'Threshold': u'2', - u'MetricName': u'ServiceFailure'} - self.wr = watchrule.WatchRule(context=self.ctx, - watch_name='OverrideAlarm2', - rule=rule, - watch_data=[], - stack_id=self.stack.id, - state='NORMAL') - self.wr.store() - - self.m.StubOutWithMock(watchrule.WatchRule, 'set_watch_state') - for state in ["HGJHGJHG", "1234", "!\*(&%"]: - watchrule.WatchRule.set_watch_state( - state).InAnyOrder().AndRaise(ValueError) - self.m.ReplayAll() - - for state in ["HGJHGJHG", "1234", "!\*(&%"]: - self.assertRaises(ValueError, - self.eng.set_watch_state, - self.ctx, watch_name="OverrideAlarm2", - state=state) - - self.m.VerifyAll() - - def test_set_watch_state_noexist(self): - state = watchrule.WatchRule.ALARM # State valid - - self.m.StubOutWithMock(watchrule.WatchRule, 'load') - watchrule.WatchRule.load( - self.ctx, "nonexistent" - ).AndRaise(exception.WatchRuleNotFound(watch_name='test')) - self.m.ReplayAll() - - ex = self.assertRaises(dispatcher.ExpectedException, - self.eng.set_watch_state, - self.ctx, watch_name="nonexistent", - state=state) - self.assertEqual(exception.WatchRuleNotFound, ex.exc_info[0]) - self.m.VerifyAll() - def test_stack_list_all_empty(self): sl = self.eng.list_stacks(self.ctx)