diff --git a/congress_tempest_plugin/tests/scenario/congress_datasources/test_vitrage.py b/congress_tempest_plugin/tests/scenario/congress_datasources/test_vitrage.py index 8107fa0..4509693 100644 --- a/congress_tempest_plugin/tests/scenario/congress_datasources/test_vitrage.py +++ b/congress_tempest_plugin/tests/scenario/congress_datasources/test_vitrage.py @@ -14,6 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +from oslo_log import log as logging from tempest import config from tempest.lib.common.utils import test_utils from tempest.lib import decorators @@ -24,6 +25,48 @@ from congress_tempest_plugin.tests.scenario import manager_congress CONF = config.CONF +LOG = logging.getLogger(__name__) + +DS_NAME = 'vitrage' +DRIVER_NAME = 'vitrage' +TEST_PAYLOAD_ACTIVATE = { + "notification": "vitrage.alarm.activate", + "payload": { + "vitrage_id": "2def31e9-6d9f-4c16-b007-893caa806cd4", + "resource": { + "vitrage_id": "437f1f4c-ccce-40a4-ac62-1c2f1fd9f6ac", + "name": "app-1-server-1-jz6qvznkmnif", + "update_timestamp": "2018-01-22 10:00:34.327142+00:00", + "vitrage_category": "RESOURCE", + "vitrage_operational_state": "OK", + "vitrage_type": "nova.instance", + "project_id": "8f007e5ba0944e84baa6f2a4f2b5d03a", + "id": "9b7d93b9-94ec-41e1-9cec-f28d4f8d702c"}, + "update_timestamp": "2018-01-22T10:00:34Z", + "vitrage_category": "ALARM", + "state": "Active", + "vitrage_type": "vitrage", + "vitrage_operational_severity": "WARNING", + "name": "Instance memory performance degraded"}} +TEST_PAYLOAD_DEACTIVATE = { + "notification": "vitrage.alarm.deactivate", + "payload": { + "vitrage_id": "2def31e9-6d9f-4c16-b007-893caa806cd4", + "resource": { + "vitrage_id": "437f1f4c-ccce-40a4-ac62-1c2f1fd9f6ac", + "name": "app-1-server-1-jz6qvznkmnif", + "update_timestamp": "2018-01-22 11:00:34.327142+00:00", + "vitrage_category": "RESOURCE", + "vitrage_operational_state": "OK", + "vitrage_type": "nova.instance", + "project_id": "8f007e5ba0944e84baa6f2a4f2b5d03a", + "id": "9b7d93b9-94ec-41e1-9cec-f28d4f8d702c"}, + "update_timestamp": "2018-01-22T11:00:34Z", + "vitrage_category": "ALARM", + "state": "Inactive", + "vitrage_type": "vitrage", + "vitrage_operational_severity": "OK", + "name": "Instance memory performance degraded"}} class TestVitrageDriver(manager_congress.ScenarioPolicyBase): @@ -38,8 +81,8 @@ class TestVitrageDriver(manager_congress.ScenarioPolicyBase): def setUp(self): super(TestVitrageDriver, self).setUp() vitrage_setting = { - 'name': 'vitrage', - 'driver': 'vitrage', + 'name': DS_NAME, + 'driver': DRIVER_NAME, 'config': None, } self.client = self.os_admin.congress_client @@ -47,35 +90,6 @@ class TestVitrageDriver(manager_congress.ScenarioPolicyBase): response = self.client.create_datasource(vitrage_setting) self.datasource_id = response['id'] - def tearDown(self): - super(TestVitrageDriver, self).tearDown() - self.client.delete_datasource(self.datasource_id) - - def _list_datasource_rows(self, datasource, table): - return self.client.list_datasource_rows(datasource, table) - - @decorators.attr(type='smoke') - def test_vitrage_alarms_table(self): - test_payload = { - "notification": "vitrage.alarm.activate", - "payload": { - "vitrage_id": "2def31e9-6d9f-4c16-b007-893caa806cd4", - "resource": { - "vitrage_id": "437f1f4c-ccce-40a4-ac62-1c2f1fd9f6ac", - "name": "app-1-server-1-jz6qvznkmnif", - "update_timestamp": "2018-01-22 10:00:34.327142+00:00", - "vitrage_category": "RESOURCE", - "vitrage_operational_state": "OK", - "vitrage_type": "nova.instance", - "project_id": "8f007e5ba0944e84baa6f2a4f2b5d03a", - "id": "9b7d93b9-94ec-41e1-9cec-f28d4f8d702c"}, - "update_timestamp": "2018-01-22T10:00:34Z", - "vitrage_category": "ALARM", - "state": "Active", - "vitrage_type": "vitrage", - "vitrage_operational_severity": "WARNING", - "name": "Instance memory performance degraded"}} - # Check if service is up @helper.retry_on_exception def _check_service(): @@ -87,7 +101,17 @@ class TestVitrageDriver(manager_congress.ScenarioPolicyBase): raise exceptions.TimeoutException( "Vitrage data source service is not up") - self.client.send_datasource_webhook(self.datasource_id, test_payload) + def tearDown(self): + super(TestVitrageDriver, self).tearDown() + self.client.delete_datasource(self.datasource_id) + + def _list_datasource_rows(self, datasource, table): + return self.client.list_datasource_rows(datasource, table) + + @decorators.attr(type='smoke') + def test_vitrage_alarms_table(self): + self.client.send_datasource_webhook( + self.datasource_id, TEST_PAYLOAD_ACTIVATE) results = self._list_datasource_rows(self.datasource_id, 'alarms') if len(results['results']) != 1: error_msg = ('Unexpected additional rows are ' @@ -113,27 +137,8 @@ class TestVitrageDriver(manager_congress.ScenarioPolicyBase): % (results['results'][0]['data'], expected_row)) raise exceptions.InvalidStructure(msg) - test_payload = { - "notification": "vitrage.alarm.deactivate", - "payload": { - "vitrage_id": "2def31e9-6d9f-4c16-b007-893caa806cd4", - "resource": { - "vitrage_id": "437f1f4c-ccce-40a4-ac62-1c2f1fd9f6ac", - "name": "app-1-server-1-jz6qvznkmnif", - "update_timestamp": "2018-01-22 11:00:34.327142+00:00", - "vitrage_category": "RESOURCE", - "vitrage_operational_state": "OK", - "vitrage_type": "nova.instance", - "project_id": "8f007e5ba0944e84baa6f2a4f2b5d03a", - "id": "9b7d93b9-94ec-41e1-9cec-f28d4f8d702c"}, - "update_timestamp": "2018-01-22T11:00:34Z", - "vitrage_category": "ALARM", - "state": "Inactive", - "vitrage_type": "vitrage", - "vitrage_operational_severity": "OK", - "name": "Instance memory performance degraded"}} - - self.client.send_datasource_webhook(self.datasource_id, test_payload) + self.client.send_datasource_webhook( + self.datasource_id, TEST_PAYLOAD_DEACTIVATE) results = self._list_datasource_rows(self.datasource_id, 'alarms') if len(results['results']) != 1: error_msg = ('Unexpected additional rows are ' @@ -158,3 +163,58 @@ class TestVitrageDriver(manager_congress.ScenarioPolicyBase): msg = ('inserted row %s is not expected row %s' % (results['results'][0]['data'], expected_row)) raise exceptions.InvalidStructure(msg) + + @decorators.attr(type='smoke') + def test_vitrage_alarms_table_subscribe_then_publish(self): + policy_name = self._create_random_policy('vitrage') + policy_rule = 'test(name) :- {}:alarms(name=name)'.format(DS_NAME) + self._create_policy_rule_retry(policy_name, policy_rule) + + self.client.send_datasource_webhook( + self.datasource_id, TEST_PAYLOAD_ACTIVATE) + + @helper.retry_on_exception + def _check_policy_eval(): + rows = self.client.list_policy_rows(policy_name, 'test')['results'] + if len(rows) < 1: + LOG.debug('Too few rows: %s', rows) + return False + elif len(rows) > 1: + LOG.debug('Too many rows: %s', rows) + return False + elif rows[0]['data'] != ['Instance memory performance degraded']: + LOG.debug('Incorrect row data: %s', rows[0]['data']) + return False + return True + + if not test_utils.call_until_true(func=_check_policy_eval, + duration=10, sleep_for=1): + raise exceptions.TimeoutException("Data did not converge in time " + "or failure in server") + + @decorators.attr(type='smoke') + def test_vitrage_alarms_table_publish_then_subscribe(self): + self.client.send_datasource_webhook( + self.datasource_id, TEST_PAYLOAD_ACTIVATE) + policy_name = self._create_random_policy('vitrage') + policy_rule = 'test(name) :- {}:alarms(name=name)'.format(DS_NAME) + self._create_policy_rule_retry(policy_name, policy_rule) + + @helper.retry_on_exception + def _check_policy_eval(): + rows = self.client.list_policy_rows(policy_name, 'test')['results'] + if len(rows) < 1: + LOG.debug('Too few rows: %s', rows) + return False + elif len(rows) > 1: + LOG.debug('Too many rows: %s', rows) + return False + elif rows[0]['data'] != ['Instance memory performance degraded']: + LOG.debug('Incorrect row data: %s', rows[0]['data']) + return False + return True + + if not test_utils.call_until_true(func=_check_policy_eval, + duration=10, sleep_for=1): + raise exceptions.TimeoutException("Data did not converge in time " + "or failure in server") diff --git a/congress_tempest_plugin/tests/scenario/helper.py b/congress_tempest_plugin/tests/scenario/helper.py index 538074b..f648a09 100644 --- a/congress_tempest_plugin/tests/scenario/helper.py +++ b/congress_tempest_plugin/tests/scenario/helper.py @@ -18,15 +18,30 @@ import os import tenacity -@tenacity.retry(stop=tenacity.stop_after_attempt(20), - wait=tenacity.wait_fixed(1)) +def retry_check_function_return_value_condition( + f, check_condition, error_msg=None, retry_interval=1, + retry_attempts=20): + """Check if function f returns value s.t check_condition(value) is True.""" + + @tenacity.retry(stop=tenacity.stop_after_attempt(retry_attempts), + wait=tenacity.wait_fixed(retry_interval)) + def retried_function(): + r = f() + if not check_condition(r): + raise Exception(error_msg or + 'Actual return value ({}) does not satisfy ' + 'provided condition'.format(r)) + return r + + return retried_function() + + def retry_check_function_return_value(f, expected_value, error_msg=None): """Check if function f returns expected value.""" if not error_msg: error_msg = 'Expected value "%s" not found' % expected_value - r = f() - if r != expected_value: - raise Exception(error_msg) + retry_check_function_return_value_condition( + f, lambda v: v == expected_value, error_msg) def retry_on_exception(f): diff --git a/congress_tempest_plugin/tests/scenario/manager_congress.py b/congress_tempest_plugin/tests/scenario/manager_congress.py index 22a1dc4..41f9d5e 100755 --- a/congress_tempest_plugin/tests/scenario/manager_congress.py +++ b/congress_tempest_plugin/tests/scenario/manager_congress.py @@ -32,6 +32,7 @@ from congress_tempest_plugin.services.congress_network import qos_client from congress_tempest_plugin.services.congress_network import qos_rule_client from congress_tempest_plugin.services.policy import policy_client # use local copy of tempest scenario manager during upstream refactoring +from congress_tempest_plugin.tests.scenario import helper from congress_tempest_plugin.tests.scenario import manager CONF = config.CONF @@ -261,9 +262,9 @@ class ScenarioPolicyBase(manager.NetworkScenarioTest): src=floating_ip)) raise - def _create_random_policy(self): - policy_name = "nova_%s" % ''.join(random.choice(string.ascii_lowercase) - for x in range(10)) + def _create_random_policy(self, prefix='nova'): + policy_name = prefix + "_%s" % ''.join( + random.choice(string.ascii_lowercase) for x in range(10)) body = {"name": policy_name} resp = self.os_admin.congress_client.create_policy(body) self.addCleanup(self.os_admin.congress_client.delete_policy, @@ -287,6 +288,13 @@ class ScenarioPolicyBase(manager.NetworkScenarioTest): raise Exception('Failed to create policy rule (%s, %s)' % (policy_name, rule)) + def _create_policy_rule_retry( + self, policy_name, rule, rule_name=None, comment=None): + return helper.retry_check_function_return_value_condition( + lambda: self._create_policy_rule( + policy_name, rule, rule_name, comment), + lambda v: True, retry_attempts=20, retry_interval=2) + class DatasourceDriverTestBase(ScenarioPolicyBase):