From 52dc30305521321333fc9f07206fdf84eb94cefd Mon Sep 17 00:00:00 2001 From: Steven Hardy Date: Thu, 4 Jul 2013 10:26:31 +0100 Subject: [PATCH] cleanup watchrule delete logic/tests Rework watchrule delete interface so we delete by ID, rather than by name (where we only delete the first rule in the event of multiple watcherule rows with the same name, which is allowed although not likely in normal heat operation - it can cause weird behavior in the tests) Encapsulating the delete in a WatchRule.destroy() is cleaner and more consistent with the rest of the codebase, and reworking the tests to ensure proper cleanup reduces the chances of odd errors and cascading failures between tests on failure. fixes bug #1197718 Change-Id: I94e9eb610519bb7321a2be7718312fd50f308a8b --- heat/db/api.py | 4 +- heat/db/sqlalchemy/api.py | 8 +- heat/engine/resources/cloud_watch.py | 6 +- heat/engine/watchrule.py | 7 + heat/tests/test_engine_service.py | 148 ++++++++-------- heat/tests/test_watch.py | 254 +++++++++++++++------------ heat/tests/utils.py | 39 ++++ 7 files changed, 276 insertions(+), 190 deletions(-) diff --git a/heat/db/api.py b/heat/db/api.py index 3835c14631..23cc8b9bdf 100644 --- a/heat/db/api.py +++ b/heat/db/api.py @@ -172,8 +172,8 @@ def watch_rule_update(context, watch_id, values): return IMPL.watch_rule_update(context, watch_id, values) -def watch_rule_delete(context, watch_rule_name): - return IMPL.watch_rule_delete(context, watch_rule_name) +def watch_rule_delete(context, watch_id): + return IMPL.watch_rule_delete(context, watch_id) def watch_data_create(context, values): diff --git a/heat/db/sqlalchemy/api.py b/heat/db/sqlalchemy/api.py index 9e825784c3..02941bf77d 100644 --- a/heat/db/sqlalchemy/api.py +++ b/heat/db/sqlalchemy/api.py @@ -302,13 +302,11 @@ def watch_rule_update(context, watch_id, values): wr.save(_session(context)) -def watch_rule_delete(context, watch_name): - wr = model_query(context, models.WatchRule).\ - filter_by(name=watch_name).first() - +def watch_rule_delete(context, watch_id): + wr = watch_rule_get(context, watch_id) if not wr: raise exception.NotFound('Attempt to delete watch_rule: %s %s' % - (watch_name, 'that does not exist')) + (watch_id, 'that does not exist')) session = Session.object_session(wr) diff --git a/heat/engine/resources/cloud_watch.py b/heat/engine/resources/cloud_watch.py index 46cbdd3edd..0d2d9ecb4d 100644 --- a/heat/engine/resources/cloud_watch.py +++ b/heat/engine/resources/cloud_watch.py @@ -17,7 +17,6 @@ from heat.common import exception from heat.engine import watchrule from heat.engine import resource from heat.engine.properties import Properties -from heat.db import api as db_api from heat.openstack.common import log as logging @@ -107,8 +106,9 @@ class CloudWatchAlarm(resource.Resource): def handle_delete(self): try: - db_api.watch_rule_delete(self.context, - self.physical_resource_name()) + wr = watchrule.WatchRule.load( + self.context, watch_name=self.physical_resource_name()) + wr.destroy() except exception.NotFound: pass diff --git a/heat/engine/watchrule.py b/heat/engine/watchrule.py index 0a70ac9333..d646b29b2b 100644 --- a/heat/engine/watchrule.py +++ b/heat/engine/watchrule.py @@ -99,6 +99,13 @@ class WatchRule(object): else: db_api.watch_rule_update(self.context, self.id, wr_values) + def destroy(self): + ''' + Delete the watchrule from the database. + ''' + if self.id: + db_api.watch_rule_delete(self.context, self.id) + def do_data_cmp(self, data, threshold): op = self.rule['ComparisonOperator'] if op == 'GreaterThanThreshold': diff --git a/heat/tests/test_engine_service.py b/heat/tests/test_engine_service.py index b524aed25a..8a71eaeed0 100644 --- a/heat/tests/test_engine_service.py +++ b/heat/tests/test_engine_service.py @@ -1026,25 +1026,34 @@ class stackServiceTest(HeatTestCase): self.m.VerifyAll() @stack_context('service_show_watch_test_stack', False) + @utils.wr_delete_after def test_show_watch(self): # Insert two dummy watch rules into the DB - values = {'stack_id': self.stack.id, - 'state': 'NORMAL', - 'name': u'HttpFailureAlarm', - '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'}} - db_ret = db_api.watch_rule_create(self.ctx, values) - self.assertNotEqual(db_ret, None) - values['name'] = "AnotherWatch" - db_ret = db_api.watch_rule_create(self.ctx, values) - self.assertNotEqual(db_ret, None) + 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='HttpFailureAlarm', + 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='AnotherWatch', + rule=rule, + watch_data=[], + stack_id=self.stack.id, + state='NORMAL')) + self.wr[1].store() # watch_name=None should return both watches result = self.eng.show_watch(self.ctx, watch_name=None) @@ -1062,27 +1071,26 @@ class stackServiceTest(HeatTestCase): for key in engine_api.WATCH_KEYS: self.assertTrue(key in result[0]) - # Cleanup, delete the dummy rules - db_api.watch_rule_delete(self.ctx, "HttpFailureAlarm") - db_api.watch_rule_delete(self.ctx, "AnotherWatch") - @stack_context('service_show_watch_metric_test_stack', False) + @utils.wr_delete_after def test_show_watch_metric(self): # Insert dummy watch rule into the DB - values = {'stack_id': self.stack.id, - 'state': 'NORMAL', - 'name': u'HttpFailureAlarm', - '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'}} - db_ret = db_api.watch_rule_create(self.ctx, values) - self.assertNotEqual(db_ret, None) + 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='HttpFailureAlarm', + rule=rule, + watch_data=[], + stack_id=self.stack.id, + state='NORMAL') + self.wr.store() # And add a metric datapoint watch = db_api.watch_rule_get_by_name(self.ctx, "HttpFailureAlarm") @@ -1106,30 +1114,30 @@ class stackServiceTest(HeatTestCase): metric_name=None) self.assertEqual(2, len(result)) - # Cleanup, delete the dummy rule - db_api.watch_rule_delete(self.ctx, "HttpFailureAlarm") - # Check the response has all keys defined in the engine API for key in engine_api.WATCH_DATA_KEYS: self.assertTrue(key in result[0]) @stack_context('service_show_watch_state_test_stack') + @utils.wr_delete_after def test_set_watch_state(self): # Insert dummy watch rule into the DB - values = {'stack_id': self.stack.id, - 'state': 'NORMAL', - 'name': u'OverrideAlarm', - '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'}} - db_ret = db_api.watch_rule_create(self.ctx, values) - self.assertNotEqual(db_ret, None) + 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: alarm = "dummyfoo" @@ -1168,26 +1176,27 @@ class stackServiceTest(HeatTestCase): [DummyAction.alarm]) self.m.VerifyAll() - # Cleanup, delete the dummy rule - db_api.watch_rule_delete(self.ctx, "OverrideAlarm") @stack_context('service_show_watch_state_badstate_test_stack') + @utils.wr_delete_after def test_set_watch_state_badstate(self): # Insert dummy watch rule into the DB - values = {'stack_id': self.stack.id, - 'state': 'NORMAL', - 'name': u'OverrideAlarm2', - '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'}} - db_ret = db_api.watch_rule_create(self.ctx, values) - self.assertNotEqual(db_ret, None) + 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", "!\*(&%"]: @@ -1203,9 +1212,6 @@ class stackServiceTest(HeatTestCase): self.m.VerifyAll() - # Cleanup, delete the dummy rule - db_api.watch_rule_delete(self.ctx, "OverrideAlarm2") - def test_set_watch_state_noexist(self): state = watchrule.WatchRule.ALARM # State valid diff --git a/heat/tests/test_watch.py b/heat/tests/test_watch.py index 1c342dd704..2ac4cc328b 100644 --- a/heat/tests/test_watch.py +++ b/heat/tests/test_watch.py @@ -18,6 +18,7 @@ import mox from heat.common import context import heat.db.api as db_api +from heat.common import exception from heat.openstack.common import timeutils from heat.engine import watchrule from heat.engine import parser @@ -97,23 +98,23 @@ class WatchRuleTest(HeatTestCase): data.append(WatchData(53, now - datetime.timedelta(seconds=150))) # all > 50 -> NORMAL - watcher = watchrule.WatchRule(context=self.ctx, + self.wr = watchrule.WatchRule(context=self.ctx, watch_name="testwatch", rule=rule, watch_data=data, stack_id=self.stack_id, last_evaluated=last) - new_state = watcher.get_alarm_state() + new_state = self.wr.get_alarm_state() self.assertEqual(new_state, 'NORMAL') data.append(WatchData(25, now - datetime.timedelta(seconds=250))) - watcher = watchrule.WatchRule(context=self.ctx, + self.wr = watchrule.WatchRule(context=self.ctx, watch_name="testwatch", rule=rule, watch_data=data, stack_id=self.stack_id, last_evaluated=last) - new_state = watcher.get_alarm_state() + new_state = self.wr.get_alarm_state() self.assertEqual(new_state, 'ALARM') def test_maximum(self): @@ -130,25 +131,25 @@ class WatchRuleTest(HeatTestCase): data.append(WatchData(23, now - datetime.timedelta(seconds=150))) # all < 30 -> NORMAL - watcher = watchrule.WatchRule(context=self.ctx, + self.wr = watchrule.WatchRule(context=self.ctx, watch_name="testwatch", rule=rule, watch_data=data, stack_id=self.stack_id, last_evaluated=last) - watcher.now = now - new_state = watcher.get_alarm_state() + self.wr.now = now + new_state = self.wr.get_alarm_state() self.assertEqual(new_state, 'NORMAL') data.append(WatchData(35, now - datetime.timedelta(seconds=150))) - watcher = watchrule.WatchRule(context=self.ctx, + self.wr = watchrule.WatchRule(context=self.ctx, watch_name="testwatch", rule=rule, watch_data=data, stack_id=self.stack_id, last_evaluated=last) - watcher.now = now - new_state = watcher.get_alarm_state() + self.wr.now = now + new_state = self.wr.get_alarm_state() self.assertEqual(new_state, 'ALARM') def test_samplecount(self): @@ -166,39 +167,39 @@ class WatchRuleTest(HeatTestCase): data.append(WatchData(1, now - datetime.timedelta(seconds=150))) # only 2 samples -> NORMAL - watcher = watchrule.WatchRule(context=self.ctx, + self.wr = watchrule.WatchRule(context=self.ctx, watch_name="testwatch", rule=rule, watch_data=data, stack_id=self.stack_id, last_evaluated=last) - watcher.now = now - new_state = watcher.get_alarm_state() + self.wr.now = now + new_state = self.wr.get_alarm_state() self.assertEqual(new_state, 'NORMAL') # only 3 samples -> ALARM data.append(WatchData(1, now - datetime.timedelta(seconds=200))) - watcher = watchrule.WatchRule(context=self.ctx, + self.wr = watchrule.WatchRule(context=self.ctx, watch_name="testwatch", rule=rule, watch_data=data, stack_id=self.stack_id, last_evaluated=last) - watcher.now = now - new_state = watcher.get_alarm_state() + self.wr.now = now + new_state = self.wr.get_alarm_state() self.assertEqual(new_state, 'ALARM') # only 3 samples (one old) -> NORMAL data.pop(0) data.append(WatchData(1, now - datetime.timedelta(seconds=400))) - watcher = watchrule.WatchRule(context=self.ctx, + self.wr = watchrule.WatchRule(context=self.ctx, watch_name="testwatch", rule=rule, watch_data=data, stack_id=self.stack_id, last_evaluated=last) - watcher.now = now - new_state = watcher.get_alarm_state() + self.wr.now = now + new_state = self.wr.get_alarm_state() self.assertEqual(new_state, 'NORMAL') def test_sum(self): @@ -215,26 +216,26 @@ class WatchRuleTest(HeatTestCase): data.append(WatchData(23, now - datetime.timedelta(seconds=150))) # all < 40 -> NORMAL - watcher = watchrule.WatchRule(context=self.ctx, + self.wr = watchrule.WatchRule(context=self.ctx, watch_name="testwatch", rule=rule, watch_data=data, stack_id=self.stack_id, last_evaluated=last) - watcher.now = now - new_state = watcher.get_alarm_state() + self.wr.now = now + new_state = self.wr.get_alarm_state() self.assertEqual(new_state, 'NORMAL') # sum > 100 -> ALARM data.append(WatchData(85, now - datetime.timedelta(seconds=150))) - watcher = watchrule.WatchRule(context=self.ctx, + self.wr = watchrule.WatchRule(context=self.ctx, watch_name="testwatch", rule=rule, watch_data=data, stack_id=self.stack_id, last_evaluated=last) - watcher.now = now - new_state = watcher.get_alarm_state() + self.wr.now = now + new_state = self.wr.get_alarm_state() self.assertEqual(new_state, 'ALARM') def test_ave(self): @@ -250,46 +251,55 @@ class WatchRuleTest(HeatTestCase): data = [WatchData(117, now - datetime.timedelta(seconds=100))] data.append(WatchData(23, now - datetime.timedelta(seconds=150))) - watcher = watchrule.WatchRule(context=self.ctx, + self.wr = watchrule.WatchRule(context=self.ctx, watch_name="testwatch", rule=rule, watch_data=data, stack_id=self.stack_id, last_evaluated=last) - watcher.now = now - new_state = watcher.get_alarm_state() + self.wr.now = now + new_state = self.wr.get_alarm_state() self.assertEqual(new_state, 'NORMAL') data.append(WatchData(195, now - datetime.timedelta(seconds=250))) - watcher = watchrule.WatchRule(context=self.ctx, + self.wr = watchrule.WatchRule(context=self.ctx, watch_name="testwatch", rule=rule, watch_data=data, stack_id=self.stack_id, last_evaluated=last) - watcher.now = now - new_state = watcher.get_alarm_state() + self.wr.now = now + new_state = self.wr.get_alarm_state() self.assertEqual(new_state, 'ALARM') + @utils.wr_delete_after def test_load(self): # Insert two dummy watch rules into the DB - values = {'stack_id': self.stack_id, - 'state': 'NORMAL', - 'name': u'HttpFailureAlarm', - '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'}} - db_ret = db_api.watch_rule_create(self.ctx, values) - self.assertNotEqual(db_ret, None) - values['name'] = 'AnotherWatch' - db_ret = db_api.watch_rule_create(self.ctx, values) - self.assertNotEqual(db_ret, None) + 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='HttpFailureAlarm', + 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='AnotherWatch', + rule=rule, + watch_data=[], + stack_id=self.stack_id, + state='NORMAL')) + self.wr[1].store() # Then use WatchRule.load() to retrieve each by name # and check that the object properties match the data above @@ -297,15 +307,12 @@ class WatchRuleTest(HeatTestCase): wr = watchrule.WatchRule.load(self.ctx, wn) self.assertEqual(type(wr), watchrule.WatchRule) self.assertEqual(wr.name, wn) - self.assertEqual(wr.state, values['state']) - self.assertEqual(wr.rule, values['rule']) + self.assertEqual(wr.state, 'NORMAL') + self.assertEqual(wr.rule, rule) self.assertEqual(wr.timeperiod, datetime.timedelta( - seconds=int(values['rule']['Period']))) - - # Cleanup - db_api.watch_rule_delete(self.ctx, 'HttpFailureAlarm') - db_api.watch_rule_delete(self.ctx, 'AnotherWatch') + seconds=int(rule['Period']))) + @utils.wr_delete_after def test_store(self): rule = {u'EvaluationPeriods': u'1', u'AlarmActions': [u'WebServerRestartPolicy'], @@ -316,9 +323,9 @@ class WatchRuleTest(HeatTestCase): u'Statistic': u'SampleCount', u'Threshold': u'2', u'MetricName': u'ServiceFailure'} - wr = watchrule.WatchRule(context=self.ctx, watch_name='storetest', - stack_id=self.stack_id, rule=rule) - wr.store() + self.wr = watchrule.WatchRule(context=self.ctx, watch_name='storetest', + stack_id=self.stack_id, rule=rule) + self.wr.store() dbwr = db_api.watch_rule_get_by_name(self.ctx, 'storetest') self.assertNotEqual(dbwr, None) @@ -326,9 +333,7 @@ class WatchRuleTest(HeatTestCase): self.assertEqual(dbwr.state, watchrule.WatchRule.NODATA) self.assertEqual(dbwr.rule, rule) - # Cleanup - db_api.watch_rule_delete(self.ctx, 'storetest') - + @utils.wr_delete_after def test_evaluate(self): rule = {'EvaluationPeriods': '1', 'MetricName': 'test_metric', @@ -345,47 +350,48 @@ class WatchRuleTest(HeatTestCase): # It's not time to evaluate, so should stay NODATA last = now - datetime.timedelta(seconds=299) data = WatchData(25, now - datetime.timedelta(seconds=150)) - watcher = watchrule.WatchRule(context=self.ctx, + self.wr = watchrule.WatchRule(context=self.ctx, watch_name="testwatch", rule=rule, watch_data=[data], stack_id=self.stack_id, last_evaluated=last) - actions = watcher.evaluate() - self.assertEqual(watcher.state, 'NODATA') + actions = self.wr.evaluate() + self.assertEqual(self.wr.state, 'NODATA') self.assertEqual(actions, []) # now - last == Period, so should set NORMAL last = now - datetime.timedelta(seconds=300) data = WatchData(25, now - datetime.timedelta(seconds=150)) - watcher = watchrule.WatchRule(context=self.ctx, + self.wr = watchrule.WatchRule(context=self.ctx, watch_name="testwatch", rule=rule, watch_data=[data], stack_id=self.stack_id, last_evaluated=last) - actions = watcher.evaluate() - self.assertEqual(watcher.state, 'NORMAL') - self.assertEqual(watcher.last_evaluated, now) + actions = self.wr.evaluate() + self.assertEqual(self.wr.state, 'NORMAL') + self.assertEqual(self.wr.last_evaluated, now) self.assertEqual(actions, []) # Now data breaches Threshold, so should set ALARM last = now - datetime.timedelta(seconds=300) data = WatchData(35, now - datetime.timedelta(seconds=150)) - watcher = watchrule.WatchRule(context=self.ctx, + self.wr = watchrule.WatchRule(context=self.ctx, watch_name="testwatch", rule=rule, watch_data=[data], stack_id=self.stack_id, last_evaluated=last) - actions = watcher.evaluate() - self.assertEqual(watcher.state, 'ALARM') - self.assertEqual(watcher.last_evaluated, now) + actions = self.wr.evaluate() + self.assertEqual(self.wr.state, 'ALARM') + self.assertEqual(self.wr.last_evaluated, now) self.assertEqual(actions, []) + @utils.wr_delete_after def test_rule_actions_alarm_normal(self): rule = {'EvaluationPeriods': '1', 'MetricName': 'test_metric', @@ -401,18 +407,19 @@ class WatchRuleTest(HeatTestCase): # Set data so rule evaluates to NORMAL state last = now - datetime.timedelta(seconds=300) data = WatchData(25, now - datetime.timedelta(seconds=150)) - watcher = watchrule.WatchRule(context=self.ctx, + self.wr = watchrule.WatchRule(context=self.ctx, watch_name="testwatch", rule=rule, watch_data=[data], stack_id=self.stack_id, last_evaluated=last) - actions = watcher.evaluate() - self.assertEqual(watcher.state, 'NORMAL') + actions = self.wr.evaluate() + self.assertEqual(self.wr.state, 'NORMAL') self.assertEqual(actions, []) self.m.VerifyAll() + @utils.wr_delete_after def test_rule_actions_alarm_alarm(self): rule = {'EvaluationPeriods': '1', 'MetricName': 'test_metric', @@ -428,25 +435,26 @@ class WatchRuleTest(HeatTestCase): # Set data so rule evaluates to ALARM state last = now - datetime.timedelta(seconds=300) data = WatchData(35, now - datetime.timedelta(seconds=150)) - watcher = watchrule.WatchRule(context=self.ctx, + self.wr = watchrule.WatchRule(context=self.ctx, watch_name="testwatch", rule=rule, watch_data=[data], stack_id=self.stack_id, last_evaluated=last) - actions = watcher.evaluate() - self.assertEqual(watcher.state, 'ALARM') + actions = self.wr.evaluate() + self.assertEqual(self.wr.state, 'ALARM') self.assertEqual(actions, ['DummyAction']) # re-set last_evaluated so the rule will be evaluated again. last = now - datetime.timedelta(seconds=300) - watcher.last_evaluated = last - actions = watcher.evaluate() - self.assertEqual(watcher.state, 'ALARM') + self.wr.last_evaluated = last + actions = self.wr.evaluate() + self.assertEqual(self.wr.state, 'ALARM') self.assertEqual(actions, ['DummyAction']) self.m.VerifyAll() + @utils.wr_delete_after def test_rule_actions_alarm_two_actions(self): rule = {'EvaluationPeriods': '1', 'MetricName': 'test_metric', @@ -462,18 +470,19 @@ class WatchRuleTest(HeatTestCase): # Set data so rule evaluates to ALARM state last = now - datetime.timedelta(seconds=300) data = WatchData(35, now - datetime.timedelta(seconds=150)) - watcher = watchrule.WatchRule(context=self.ctx, + self.wr = watchrule.WatchRule(context=self.ctx, watch_name="testwatch", rule=rule, watch_data=[data], stack_id=self.stack_id, last_evaluated=last) - actions = watcher.evaluate() - self.assertEqual(watcher.state, 'ALARM') + actions = self.wr.evaluate() + self.assertEqual(self.wr.state, 'ALARM') self.assertEqual(actions, ['DummyAction', 'DummyAction']) self.m.VerifyAll() + @utils.wr_delete_after def test_rule_actions_ok_alarm(self): rule = {'EvaluationPeriods': '1', 'MetricName': 'test_metric', @@ -488,15 +497,15 @@ class WatchRuleTest(HeatTestCase): # On creation the rule evaluates to NODATA state last = now - datetime.timedelta(seconds=300) - watcher = watchrule.WatchRule(context=self.ctx, + self.wr = watchrule.WatchRule(context=self.ctx, watch_name="testwatch", rule=rule, watch_data=[], stack_id=self.stack_id, last_evaluated=last) - actions = watcher.evaluate() - self.assertEqual(watcher.state, 'NODATA') + actions = self.wr.evaluate() + self.assertEqual(self.wr.state, 'NODATA') self.assertEqual(actions, []) # Move time forward and add data below threshold so we transition from @@ -507,13 +516,14 @@ class WatchRuleTest(HeatTestCase): self._action_set_stubs(now) data = WatchData(25, now - datetime.timedelta(seconds=150)) - watcher.watch_data = [data] + self.wr.watch_data = [data] - actions = watcher.evaluate() - self.assertEqual(watcher.state, 'NORMAL') + actions = self.wr.evaluate() + self.assertEqual(self.wr.state, 'NORMAL') self.assertEqual(actions, ['DummyAction']) self.m.VerifyAll() + @utils.wr_delete_after def test_rule_actions_nodata(self): rule = {'EvaluationPeriods': '1', 'MetricName': 'test_metric', @@ -529,15 +539,15 @@ class WatchRuleTest(HeatTestCase): # Set data so rule evaluates to ALARM state last = now - datetime.timedelta(seconds=300) data = WatchData(35, now - datetime.timedelta(seconds=150)) - watcher = watchrule.WatchRule(context=self.ctx, + self.wr = watchrule.WatchRule(context=self.ctx, watch_name="testwatch", rule=rule, watch_data=[data], stack_id=self.stack_id, last_evaluated=last) - actions = watcher.evaluate() - self.assertEqual(watcher.state, 'ALARM') + actions = self.wr.evaluate() + self.assertEqual(self.wr.state, 'ALARM') self.assertEqual(actions, []) # Move time forward and don't add data so we transition from @@ -547,11 +557,12 @@ class WatchRuleTest(HeatTestCase): self.m.UnsetStubs() self._action_set_stubs(now) - actions = watcher.evaluate() - self.assertEqual(watcher.state, 'NODATA') + actions = self.wr.evaluate() + self.assertEqual(self.wr.state, 'NODATA') self.assertEqual(actions, ['DummyAction']) self.m.VerifyAll() + @utils.wr_delete_after def test_create_watch_data(self): rule = {u'EvaluationPeriods': u'1', u'AlarmDescription': u'test alarm', @@ -560,16 +571,16 @@ class WatchRuleTest(HeatTestCase): u'Statistic': u'SampleCount', u'Threshold': u'2', u'MetricName': u'CreateDataMetric'} - wr = watchrule.WatchRule(context=self.ctx, - watch_name='create_data_test', - stack_id=self.stack_id, rule=rule) + self.wr = watchrule.WatchRule(context=self.ctx, + watch_name='create_data_test', + stack_id=self.stack_id, rule=rule) - wr.store() + self.wr.store() data = {u'CreateDataMetric': {"Unit": "Counter", "Value": "1", "Dimensions": []}} - wr.create_watch_data(data) + self.wr.create_watch_data(data) dbwr = db_api.watch_rule_get_by_name(self.ctx, 'create_data_test') self.assertEqual(dbwr.watch_data[0].data, data) @@ -581,8 +592,33 @@ class WatchRuleTest(HeatTestCase): # correctly get a list of all datapoints where watch_rule_id == # watch_rule.id, so leave it as a single-datapoint test for now. - # Cleanup - db_api.watch_rule_delete(self.ctx, 'create_data_test') + def test_destroy(self): + rule = {'EvaluationPeriods': '1', + 'MetricName': 'test_metric', + 'AlarmActions': ['DummyAction'], + 'Period': '300', + 'Statistic': 'Maximum', + 'ComparisonOperator': 'GreaterThanOrEqualToThreshold', + 'Threshold': '30'} + + last = timeutils.utcnow() + self.wr = watchrule.WatchRule(context=self.ctx, + watch_name="testwatch_destroy", + rule=rule, + watch_data=[], + stack_id=self.stack_id, + last_evaluated=last) + + self.wr.store() + + check = watchrule.WatchRule.load(context=self.ctx, + watch_name="testwatch_destroy") + self.assertTrue(isinstance(check, watchrule.WatchRule)) + + self.wr.destroy() + self.assertRaises(exception.WatchRuleNotFound, + watchrule.WatchRule.load, context=self.ctx, + watch_name="testwatch_destroy") def test_set_watch_state(self): rule = {'EvaluationPeriods': '1', @@ -598,20 +634,20 @@ class WatchRuleTest(HeatTestCase): # Set data so rule evaluates to ALARM state last = now - datetime.timedelta(seconds=200) - watcher = watchrule.WatchRule(context=self.ctx, + self.wr = watchrule.WatchRule(context=self.ctx, watch_name="testwatch", rule=rule, watch_data=[], stack_id=self.stack_id, last_evaluated=last) - actions = watcher.set_watch_state(watchrule.WatchRule.NODATA) + actions = self.wr.set_watch_state(watchrule.WatchRule.NODATA) self.assertEqual(actions, []) - actions = watcher.set_watch_state(watchrule.WatchRule.NORMAL) + actions = self.wr.set_watch_state(watchrule.WatchRule.NORMAL) self.assertEqual(actions, []) - actions = watcher.set_watch_state(watchrule.WatchRule.ALARM) + actions = self.wr.set_watch_state(watchrule.WatchRule.ALARM) self.assertEqual(actions, ['DummyAction']) self.m.VerifyAll() @@ -627,13 +663,13 @@ class WatchRuleTest(HeatTestCase): now = timeutils.utcnow() last = now - datetime.timedelta(seconds=200) - watcher = watchrule.WatchRule(context=self.ctx, + self.wr = watchrule.WatchRule(context=self.ctx, watch_name="testwatch", rule=rule, watch_data=[], stack_id=self.stack_id, last_evaluated=last) - self.assertRaises(ValueError, watcher.set_watch_state, None) + self.assertRaises(ValueError, self.wr.set_watch_state, None) - self.assertRaises(ValueError, watcher.set_watch_state, "BADSTATE") + self.assertRaises(ValueError, self.wr.set_watch_state, "BADSTATE") diff --git a/heat/tests/utils.py b/heat/tests/utils.py index 66567480c0..2c622beeb1 100644 --- a/heat/tests/utils.py +++ b/heat/tests/utils.py @@ -16,6 +16,7 @@ import sys import functools from heat.common import context +from heat.common import exception from heat.engine import environment from heat.engine import parser @@ -49,6 +50,44 @@ def stack_delete_after(test_fn): return wrapped_test +def wr_delete_after(test_fn): + """ + Decorator which calls test class self.wr.destroy() + to ensure tests clean up their watchrule regardless of test success/failure + Used by tests which create watchrule objects directly to cleanup correctly + self.wr can be either a single watchrule, or a list of several watchrules + """ + @functools.wraps(test_fn) + def wrapped_test(test_case, *args, **kwargs): + + def delete_wrs(): + wr = getattr(test_case, 'wr', None) + try: + for w in wr: + delete_wr(w) + except TypeError: + delete_wr(wr) + + def delete_wr(w): + if w.id is not None: + try: + w.destroy() + except exception.NotFound: + pass + try: + test_fn(test_case, *args, **kwargs) + except: + exc_class, exc_val, exc_tb = sys.exc_info() + try: + delete_wrs() + finally: + raise exc_class, exc_val, exc_tb + else: + delete_wrs() + + return wrapped_test + + def setup_dummy_db(): migration.db_sync() engine = get_engine()