diff --git a/aodh/tests/functional/api/test_versions.py b/aodh/tests/functional/api/test_versions.py deleted file mode 100644 index 23f6c4532..000000000 --- a/aodh/tests/functional/api/test_versions.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# -# 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. - -from aodh.tests.functional import api - -V2_MEDIA_TYPES = [ - { - 'base': 'application/json', - 'type': 'application/vnd.openstack.telemetry-v2+json' - }, { - 'base': 'application/xml', - 'type': 'application/vnd.openstack.telemetry-v2+xml' - } -] - -V2_HTML_DESCRIPTION = { - 'href': 'https://docs.openstack.org/', - 'rel': 'describedby', - 'type': 'text/html', -} - -V2_EXPECTED_RESPONSE = { - 'id': 'v2', - 'links': [ - { - 'rel': 'self', - 'href': 'http://localhost/v2', - }, - V2_HTML_DESCRIPTION - ], - 'media-types': V2_MEDIA_TYPES, - 'status': 'stable', - 'updated': '2013-02-13T00:00:00Z', -} - -V2_VERSION_RESPONSE = { - "version": V2_EXPECTED_RESPONSE -} - -VERSIONS_RESPONSE = { - "versions": { - "values": [ - V2_EXPECTED_RESPONSE - ] - } -} - - -class TestVersions(api.FunctionalTest): - - def test_versions(self): - data = self.get_json('/') - self.assertEqual(VERSIONS_RESPONSE, data) diff --git a/aodh/tests/functional/api/v2/test_alarm_scenarios.py b/aodh/tests/functional/api/v2/test_alarm_scenarios.py index f1e671e2a..4a997540b 100644 --- a/aodh/tests/functional/api/v2/test_alarm_scenarios.py +++ b/aodh/tests/functional/api/v2/test_alarm_scenarios.py @@ -17,7 +17,6 @@ import copy import datetime import json as jsonlib -import operator import os from unittest import mock @@ -173,13 +172,6 @@ class TestAlarmsBase(v2.FunctionalTest): status=204) -class TestListEmptyAlarms(TestAlarmsBase): - - def test_empty(self): - data = self.get_json('/alarms', headers=self.auth_headers) - self.assertEqual([], data) - - class TestAlarms(TestAlarmsBase): def setUp(self): @@ -187,82 +179,6 @@ class TestAlarms(TestAlarmsBase): for alarm in default_alarms(self.auth_headers): self.alarm_conn.create_alarm(alarm) - def test_list_alarms(self): - data = self.get_json('/alarms', headers=self.auth_headers) - self.assertEqual(3, len(data)) - self.assertEqual(set(['name1', 'name2', 'name3']), - set(r['name'] for r in data)) - self.assertEqual([['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - ['95f3c171-5605-4021-87ed-eede77101268', - 'bf588a78-56c7-4ba4-be46-d71e5002e030']], - [r[RULE_KEY]['metrics'] - for r in sorted(data, - key=operator.itemgetter('name'))]) - - def test_alarms_query_with_timestamp(self): - date_time = datetime.datetime(2012, 7, 2, 10, 41) - isotime = date_time.isoformat() - resp = self.get_json('/alarms', - headers=self.auth_headers, - q=[{'field': 'timestamp', - 'op': 'gt', - 'value': isotime}], - expect_errors=True) - self.assertEqual(resp.status_code, 400) - - def test_alarms_query_with_state(self): - alarm = models.Alarm(name='disabled', - type='gnocchi_aggregation_by_metrics_threshold', - enabled=False, - alarm_id='c', - description='c', - state='ok', - state_reason='Not evaluated', - state_timestamp=constants.MIN_DATETIME, - timestamp=constants.MIN_DATETIME, - ok_actions=[], - insufficient_data_actions=[], - alarm_actions=[], - repeat_actions=False, - user_id=self.auth_headers['X-User-Id'], - project_id=self.auth_headers['X-Project-Id'], - time_constraints=[], - rule=dict( - comparison_operator='gt', - threshold=3.0, - aggregation_method='mean', - evaluation_periods=60, - granularity=1, - metrics=[ - '41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e', - ]), - severity='critical') - self.alarm_conn.update_alarm(alarm) - resp = self.get_json('/alarms', - headers=self.auth_headers, - q=[{'field': 'state', - 'op': 'eq', - 'value': 'ok'}], - ) - self.assertEqual(1, len(resp)) - self.assertEqual('ok', resp[0]['state']) - - def test_list_alarms_by_type(self): - alarms = self.get_json('/alarms', - headers=self.auth_headers, - q=[{'field': 'type', - 'op': 'eq', - 'value': - 'gnocchi_aggregation_by_metrics_threshold' - }]) - self.assertEqual(3, len(alarms)) - self.assertEqual(set(['gnocchi_aggregation_by_metrics_threshold']), - set(alarm['type'] for alarm in alarms)) - def test_list_alarms_all_projects_by_admin(self): auth_headers = copy.copy(self.auth_headers) auth_headers['X-Roles'] = 'admin' @@ -275,116 +191,6 @@ class TestAlarms(TestAlarmsBase): self.assertEqual(3, len(alarms)) - def test_list_alarms_all_projects_forbidden(self): - response = self.get_json( - '/alarms', - headers=self.auth_headers, - q=[{'field': 'all_projects', 'op': 'eq', 'value': 'true'}], - expect_errors=True, - status=401 - ) - - faultstring = 'RBAC Authorization Failed' - self.assertIn(faultstring, - response.json['error_message']['faultstring']) - - def test_list_alarms_other_project(self): - auth_headers = {'X-User-Id': uuidutils.generate_uuid(), - 'X-Project-Id': uuidutils.generate_uuid()} - data = self.get_json('/alarms', headers=auth_headers) - - self.assertEqual(0, len(data)) - - def test_get_not_existing_alarm(self): - resp = self.get_json('/alarms/alarm-id-3', - headers=self.auth_headers, - expect_errors=True) - self.assertEqual(404, resp.status_code) - self.assertIn('Alarm alarm-id-3 not found', - resp.json['error_message']['faultstring']) - - def test_get_alarm(self): - alarms = self.get_json('/alarms', - headers=self.auth_headers, - q=[{'field': 'name', - 'value': 'name1', - }]) - self.assertEqual('name1', alarms[0]['name']) - self.assertEqual(['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - alarms[0][RULE_KEY]['metrics']) - - one = self.get_json('/alarms/%s' % alarms[0]['alarm_id'], - headers=self.auth_headers) - self.assertEqual('name1', one['name']) - self.assertEqual(['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - one[RULE_KEY]['metrics']) - self.assertEqual(alarms[0]['alarm_id'], one['alarm_id']) - self.assertEqual(alarms[0]['repeat_actions'], one['repeat_actions']) - self.assertEqual(alarms[0]['time_constraints'], - one['time_constraints']) - - def test_get_alarm_disabled(self): - alarm = models.Alarm(name='disabled', - type='gnocchi_aggregation_by_metrics_threshold', - enabled=False, - alarm_id='c', - description='c', - state='insufficient data', - state_reason='Not evaluated', - state_timestamp=constants.MIN_DATETIME, - timestamp=constants.MIN_DATETIME, - ok_actions=[], - insufficient_data_actions=[], - alarm_actions=[], - repeat_actions=False, - user_id=self.auth_headers['X-User-Id'], - project_id=self.auth_headers['X-Project-Id'], - time_constraints=[], - rule=dict( - comparison_operator='gt', - threshold=3.0, - aggregation_method='mean', - evaluation_periods=60, - granularity=1, - metrics=[ - '41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e', - ] - ), - severity='critical') - self.alarm_conn.update_alarm(alarm) - - alarms = self.get_json('/alarms', - headers=self.auth_headers, - q=[{'field': 'enabled', - 'value': 'False'}]) - self.assertEqual(1, len(alarms)) - self.assertEqual('disabled', alarms[0]['name']) - - one = self.get_json('/alarms/%s' % alarms[0]['alarm_id'], - headers=self.auth_headers) - self.assertEqual('disabled', one['name']) - - def test_get_alarm_project_filter_wrong_op_normal_user(self): - project = self.auth_headers['X-Project-Id'] - - def _test(field, op): - response = self.get_json('/alarms', - q=[{'field': field, - 'op': op, - 'value': project}], - expect_errors=True, - status=400, - headers=self.auth_headers) - - faultstring = 'Invalid input for field/attribute op' - self.assertIn(faultstring, - response.json['error_message']['faultstring']) - - _test('project_id', 'ne') - def test_get_alarm_project_filter_normal_user(self): project = self.auth_headers['X-Project-Id'] @@ -428,433 +234,6 @@ class TestAlarms(TestAlarmsBase): self.assertEqual(faultstring, response.json['error_message']['faultstring']) - def test_post_alarm_wsme_workaround(self): - jsons = { - 'type': { - 'name': 'missing type', - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'aggregation_method': 'mean', - 'threshold': 2.0, - } - }, - 'name': { - 'type': 'gnocchi_aggregation_by_metrics_threshold', - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'aggregation_method': 'mean', - 'threshold': 2.0, - } - }, - 'threshold_rule/metrics': { - 'name': 'missing metrics', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - RULE_KEY: { - 'aggregation_method': 'mean', - 'threshold': 2.0, - } - }, - 'threshold_rule/threshold': { - 'name': 'missing threshold', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'aggregation_method': 'mean', - } - }, - } - for field, json in jsons.items(): - resp = self.post_json('/alarms', params=json, expect_errors=True, - status=400, headers=self.auth_headers) - self.assertEqual("Invalid input for field/attribute %s." - " Value: \'None\'. Mandatory field missing." - % field.split('/', 1)[-1], - resp.json['error_message']['faultstring']) - alarms = list(self.alarm_conn.get_alarms()) - self.assertEqual(3, len(alarms)) - - def test_post_invalid_alarm_time_constraint_start(self): - json = { - 'name': 'added_alarm_invalid_constraint_duration', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - 'time_constraints': [ - { - 'name': 'testcons', - 'start': '11:00am', - 'duration': 10 - } - ], - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - "aggregation_method": "mean", - 'threshold': 300.0 - } - } - self.post_json('/alarms', params=json, expect_errors=True, status=400, - headers=self.auth_headers) - alarms = list(self.alarm_conn.get_alarms()) - self.assertEqual(3, len(alarms)) - - def test_post_duplicate_time_constraint_name(self): - json = { - 'name': 'added_alarm_duplicate_constraint_name', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - 'time_constraints': [ - { - 'name': 'testcons', - 'start': '* 11 * * *', - 'duration': 10 - }, - { - 'name': 'testcons', - 'start': '* * * * *', - 'duration': 20 - } - ], - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - "aggregation_method": "mean", - 'threshold': 300.0 - } - } - resp = self.post_json('/alarms', params=json, expect_errors=True, - status=400, headers=self.auth_headers) - self.assertEqual( - "Time constraint names must be unique for a given alarm.", - resp.json['error_message']['faultstring']) - alarms = list(self.alarm_conn.get_alarms()) - self.assertEqual(3, len(alarms)) - - def test_post_alarm_null_time_constraint(self): - json = { - 'name': 'added_alarm_invalid_constraint_duration', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - 'time_constraints': None, - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'aggregation_method': 'mean', - 'threshold': 300.0 - } - } - self.post_json('/alarms', params=json, status=201, - headers=self.auth_headers) - - def test_post_invalid_alarm_time_constraint_duration(self): - json = { - 'name': 'added_alarm_invalid_constraint_duration', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - 'time_constraints': [ - { - 'name': 'testcons', - 'start': '* 11 * * *', - 'duration': -1, - } - ], - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'threshold': 300.0 - } - } - self.post_json('/alarms', params=json, expect_errors=True, status=400, - headers=self.auth_headers) - alarms = list(self.alarm_conn.get_alarms()) - self.assertEqual(3, len(alarms)) - - def test_post_invalid_alarm_time_constraint_timezone(self): - json = { - 'name': 'added_alarm_invalid_constraint_timezone', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - 'time_constraints': [ - { - 'name': 'testcons', - 'start': '* 11 * * *', - 'duration': 10, - 'timezone': 'aaaa' - } - ], - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'threshold': 300.0 - } - } - self.post_json('/alarms', params=json, expect_errors=True, status=400, - headers=self.auth_headers) - alarms = list(self.alarm_conn.get_alarms()) - self.assertEqual(3, len(alarms)) - - def test_post_invalid_alarm_granularity(self): - json = { - 'name': 'added_alarm_invalid_granularity', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'comparison_operator': 'gt', - 'threshold': 2.0, - 'aggregation_method': 'mean', - 'granularity': -1, - } - - } - self.post_json('/alarms', params=json, expect_errors=True, status=400, - headers=self.auth_headers) - alarms = list(self.alarm_conn.get_alarms()) - self.assertEqual(3, len(alarms)) - - def test_post_null_rule(self): - json = { - 'name': 'added_alarm_invalid_threshold_rule', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - RULE_KEY: None, - } - resp = self.post_json('/alarms', params=json, expect_errors=True, - status=400, headers=self.auth_headers) - self.assertEqual( - "gnocchi_aggregation_by_metrics_threshold_rule " - "must be set for gnocchi_aggregation_by_metrics_threshold " - "type alarm", - resp.json['error_message']['faultstring']) - - def test_post_invalid_alarm_input_state(self): - json = { - 'name': 'alarm1', - 'state': 'bad_state', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'comparison_operator': 'gt', - 'threshold': 50.0 - } - } - resp = self.post_json('/alarms', params=json, expect_errors=True, - status=400, headers=self.auth_headers) - expected_err_msg = ("Invalid input for field/attribute state." - " Value: 'bad_state'.") - self.assertIn(expected_err_msg, - resp.json['error_message']['faultstring']) - alarms = list(self.alarm_conn.get_alarms()) - self.assertEqual(3, len(alarms)) - - def test_post_invalid_alarm_input_severity(self): - json = { - 'name': 'alarm1', - 'state': 'ok', - 'severity': 'bad_value', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'comparison_operator': 'gt', - 'threshold': 50.0 - } - } - resp = self.post_json('/alarms', params=json, expect_errors=True, - status=400, headers=self.auth_headers) - expected_err_msg = ("Invalid input for field/attribute severity." - " Value: 'bad_value'.") - self.assertIn(expected_err_msg, - resp.json['error_message']['faultstring']) - alarms = list(self.alarm_conn.get_alarms()) - self.assertEqual(3, len(alarms)) - - def test_post_invalid_alarm_input_type(self): - json = { - 'name': 'alarm3', - 'state': 'ok', - 'type': 'bad_type', - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'comparison_operator': 'gt', - 'threshold': 50.0 - } - } - resp = self.post_json('/alarms', params=json, expect_errors=True, - status=400, headers=self.auth_headers) - expected_err_msg = ("Invalid input for field/attribute" - " type." - " Value: 'bad_type'.") - self.assertIn(expected_err_msg, - resp.json['error_message']['faultstring']) - alarms = list(self.alarm_conn.get_alarms()) - self.assertEqual(3, len(alarms)) - - def test_post_invalid_alarm_input_enabled_str(self): - json = { - 'name': 'alarm5', - 'enabled': 'bad_enabled', - 'state': 'ok', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'comparison_operator': 'gt', - 'threshold': 50.0 - } - } - resp = self.post_json('/alarms', params=json, expect_errors=True, - status=400, headers=self.auth_headers) - expected_err_msg = "Value not an unambiguous boolean: bad_enabled" - self.assertIn(expected_err_msg, - resp.json['error_message']['faultstring']) - alarms = list(self.alarm_conn.get_alarms()) - self.assertEqual(3, len(alarms)) - - def test_post_invalid_alarm_input_enabled_int(self): - json = { - 'name': 'alarm6', - 'enabled': 0, - 'state': 'ok', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'comparison_operator': 'gt', - 'aggregation_method': 'mean', - 'threshold': 50.0 - } - } - resp = self.post_json('/alarms', params=json, - headers=self.auth_headers) - self.assertFalse(resp.json['enabled']) - alarms = list(self.alarm_conn.get_alarms()) - self.assertEqual(4, len(alarms)) - - def _do_post_alarm_invalid_action(self, ok_actions=None, - alarm_actions=None, - insufficient_data_actions=None, - error_message=None): - - ok_actions = ok_actions or [] - alarm_actions = alarm_actions or [] - insufficient_data_actions = insufficient_data_actions or [] - json = { - 'enabled': False, - 'name': 'added_alarm', - 'state': 'ok', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - 'ok_actions': ok_actions, - 'alarm_actions': alarm_actions, - 'insufficient_data_actions': insufficient_data_actions, - 'repeat_actions': True, - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'comparison_operator': 'le', - 'aggregation_method': 'count', - 'threshold': 50, - 'evaluation_periods': '3', - 'granularity': '180', - } - } - resp = self.post_json('/alarms', params=json, status=400, - headers=self.auth_headers) - alarms = list(self.alarm_conn.get_alarms()) - self.assertEqual(3, len(alarms)) - self.assertEqual(error_message, - resp.json['error_message']['faultstring']) - - def test_post_invalid_alarm_ok_actions(self): - self._do_post_alarm_invalid_action( - ok_actions=['spam://something/ok'], - error_message='Unsupported action spam://something/ok') - - def test_post_invalid_alarm_alarm_actions(self): - self._do_post_alarm_invalid_action( - alarm_actions=['spam://something/alarm'], - error_message='Unsupported action spam://something/alarm') - - def test_post_invalid_alarm_insufficient_data_actions(self): - self._do_post_alarm_invalid_action( - insufficient_data_actions=['spam://something/insufficient'], - error_message='Unsupported action spam://something/insufficient') - - @staticmethod - def _fake_urlsplit(*args, **kwargs): - raise Exception("Evil urlsplit!") - - def test_post_invalid_alarm_actions_format(self): - with mock.patch('oslo_utils.netutils.urlsplit', - self._fake_urlsplit): - self._do_post_alarm_invalid_action( - alarm_actions=['http://[::1'], - error_message='Unable to parse action http://[::1') - - def test_post_alarm_defaults(self): - to_check = { - 'enabled': True, - 'name': 'added_alarm_defaults', - 'ok_actions': [], - 'alarm_actions': [], - 'insufficient_data_actions': [], - 'repeat_actions': False, - } - - json = { - 'name': 'added_alarm_defaults', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'aggregation_method': 'mean', - 'threshold': 300.0 - } - } - self.post_json('/alarms', params=json, status=201, - headers=self.auth_headers) - alarms = list(self.alarm_conn.get_alarms()) - self.assertEqual(4, len(alarms)) - for alarm in alarms: - if alarm.name == 'added_alarm_defaults': - for key in to_check: - self.assertEqual(to_check[key], - getattr(alarm, key)) - break - else: - self.fail("Alarm not found") - - def test_post_alarm_with_same_name(self): - json = { - 'enabled': False, - 'name': 'dup_alarm_name', - 'state': 'ok', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - 'ok_actions': ['http://something/ok'], - 'alarm_actions': ['http://something/alarm'], - 'insufficient_data_actions': ['http://something/no'], - 'repeat_actions': True, - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'comparison_operator': 'le', - 'aggregation_method': 'count', - 'threshold': 50, - 'evaluation_periods': '3', - 'granularity': '180', - } - } - - resp1 = self.post_json('/alarms', params=json, status=201, - headers=self.auth_headers) - resp2 = self.post_json('/alarms', params=json, status=201, - headers=self.auth_headers) - self.assertEqual(resp1.json['name'], resp2.json['name']) - self.assertNotEqual(resp1.json['alarm_id'], resp2.json['alarm_id']) - alarms = self.get_json('/alarms', - headers=self.auth_headers, - q=[{'field': 'name', - 'value': 'dup_alarm_name'}]) - self.assertEqual(2, len(alarms)) - def test_post_alarm_noauth(self): json = { 'enabled': False, @@ -1006,50 +385,6 @@ class TestAlarms(TestAlarmsBase): "be set for gnocchi_resources_threshold type alarm", resp.json['error_message']['faultstring']) - def test_post_alarm_with_duplicate_actions(self): - body = { - 'name': 'dup-alarm-actions', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'comparison_operator': 'le', - 'aggregation_method': 'count', - 'threshold': 50, - 'evaluation_periods': '3', - 'granularity': '180', - }, - 'alarm_actions': ['http://no.where', 'http://no.where'] - } - resp = self.post_json('/alarms', params=body, - headers=self.auth_headers) - self.assertEqual(201, resp.status_code) - alarms = list(self.alarm_conn.get_alarms(name='dup-alarm-actions')) - self.assertEqual(1, len(alarms)) - self.assertEqual(['http://no.where'], alarms[0].alarm_actions) - - def test_post_alarm_with_too_many_actions(self): - self.CONF.set_override('alarm_max_actions', 1, group='api') - body = { - 'name': 'alarm-with-many-actions', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'comparison_operator': 'le', - 'aggregation_method': 'count', - 'threshold': 50, - 'evaluation_periods': '3', - 'granularity': '180', - }, - 'alarm_actions': ['http://no.where', 'http://no.where2'] - } - resp = self.post_json('/alarms', params=body, expect_errors=True, - headers=self.auth_headers) - self.assertEqual(400, resp.status_code) - self.assertEqual("alarm_actions count exceeds maximum value 1", - resp.json['error_message']['faultstring']) - def test_post_alarm_normal_user_set_log_actions(self): body = { 'name': 'log_alarm_actions', @@ -1118,85 +453,6 @@ class TestAlarms(TestAlarmsBase): self.assertEqual(['test://', 'log://'], alarms[0].alarm_actions) - def test_exercise_state_reason(self): - body = { - 'name': 'nostate', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'comparison_operator': 'le', - 'aggregation_method': 'count', - 'threshold': 50, - 'evaluation_periods': '3', - 'granularity': '180', - }, - } - headers = self.auth_headers - headers['X-Roles'] = 'admin' - - self.post_json('/alarms', params=body, status=201, - headers=headers) - alarms = list(self.alarm_conn.get_alarms(name='nostate')) - self.assertEqual(1, len(alarms)) - alarm_id = alarms[0].alarm_id - - alarm = self._get_alarm(alarm_id) - self.assertEqual("insufficient data", alarm['state']) - self.assertEqual("Not evaluated yet", alarm['state_reason']) - - # Ensure state reason is updated - alarm = self._get_alarm('a') - alarm['state'] = 'ok' - self.put_json('/alarms/%s' % alarm_id, - params=alarm, - headers=self.auth_headers) - alarm = self._get_alarm(alarm_id) - self.assertEqual("ok", alarm['state']) - self.assertEqual("Manually set via API", alarm['state_reason']) - - # Ensure state reason read only - alarm = self._get_alarm('a') - alarm['state'] = 'alarm' - alarm['state_reason'] = 'oh no!' - self.put_json('/alarms/%s' % alarm_id, - params=alarm, - headers=self.auth_headers) - - alarm = self._get_alarm(alarm_id) - self.assertEqual("alarm", alarm['state']) - self.assertEqual("Manually set via API", alarm['state_reason']) - - def test_post_alarm_without_actions(self): - body = { - 'name': 'alarm_actions_none', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'comparison_operator': 'le', - 'aggregation_method': 'count', - 'threshold': 50, - 'evaluation_periods': '3', - 'granularity': '180', - }, - 'alarm_actions': None - } - headers = self.auth_headers - headers['X-Roles'] = 'admin' - self.post_json('/alarms', params=body, status=201, - headers=headers) - alarms = list(self.alarm_conn.get_alarms(name='alarm_actions_none')) - self.assertEqual(1, len(alarms)) - - # FIXME(sileht): This should really returns [] not None - # but SQL just stores the json dict as is... - # migration script for sql will be a mess because we have - # to parse all JSON :( - # I guess we assume that wsme convert the None input to [] - # because of the array type, but it won't... - self.assertIsNone(alarms[0].alarm_actions) - def test_post_alarm_trust(self): json = { 'name': 'added_alarm_defaults', @@ -1252,42 +508,6 @@ class TestAlarms(TestAlarmsBase): extra_environ={'keystone.token_auth': auth}) trust_client.trusts.delete.assert_called_once_with('5678') - def test_put_alarm(self): - json = { - 'enabled': False, - 'name': 'name_put', - 'state': 'ok', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - 'severity': 'critical', - 'ok_actions': ['http://something/ok'], - 'alarm_actions': ['http://something/alarm'], - 'insufficient_data_actions': ['http://something/no'], - 'repeat_actions': True, - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'comparison_operator': 'le', - 'aggregation_method': 'count', - 'threshold': 50, - 'evaluation_periods': 3, - 'granularity': 180, - } - } - data = self.get_json('/alarms', - headers=self.auth_headers, - q=[{'field': 'name', - 'value': 'name1', - }]) - self.assertEqual(1, len(data)) - alarm_id = data[0]['alarm_id'] - - self.put_json('/alarms/%s' % alarm_id, - params=json, - headers=self.auth_headers) - alarm = list(self.alarm_conn.get_alarms(alarm_id=alarm_id, - enabled=False))[0] - self._verify_alarm(json, alarm) - def test_put_alarm_as_admin(self): json = { 'user_id': 'myuserid', @@ -1332,114 +552,6 @@ class TestAlarms(TestAlarmsBase): self.assertEqual('myprojectid', alarm.project_id) self._verify_alarm(json, alarm) - def test_put_alarm_wrong_field(self): - json = { - 'this_can_not_be_correct': 'ha', - 'enabled': False, - 'name': 'name1', - 'state': 'ok', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - 'severity': 'critical', - 'ok_actions': ['http://something/ok'], - 'alarm_actions': ['http://something/alarm'], - 'insufficient_data_actions': ['http://something/no'], - 'repeat_actions': True, - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'comparison_operator': 'le', - 'aggregation_method': 'count', - 'threshold': 50, - 'evaluation_periods': 3, - 'granularity': 180, - } - } - data = self.get_json('/alarms', - headers=self.auth_headers, - q=[{'field': 'name', - 'value': 'name1', - }]) - self.assertEqual(1, len(data)) - alarm_id = data[0]['alarm_id'] - - resp = self.put_json('/alarms/%s' % alarm_id, - expect_errors=True, - params=json, - headers=self.auth_headers) - self.assertEqual(400, resp.status_code) - - def test_put_alarm_with_existing_name(self): - """Test that update a threshold alarm with an existing name.""" - json = { - 'enabled': False, - 'name': 'name1', - 'state': 'ok', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - 'severity': 'critical', - 'ok_actions': ['http://something/ok'], - 'alarm_actions': ['http://something/alarm'], - 'insufficient_data_actions': ['http://something/no'], - 'repeat_actions': True, - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'comparison_operator': 'le', - 'aggregation_method': 'count', - 'threshold': 50, - 'evaluation_periods': 3, - 'granularity': 180, - } - } - data = self.get_json('/alarms', - headers=self.auth_headers, - q=[{'field': 'name', - 'value': 'name2', - }]) - self.assertEqual(1, len(data)) - alarm_id = data[0]['alarm_id'] - - resp = self.put_json('/alarms/%s' % alarm_id, - params=json, - headers=self.auth_headers) - self.assertEqual(200, resp.status_code) - - def test_put_invalid_alarm_actions(self): - json = { - 'enabled': False, - 'name': 'name1', - 'state': 'ok', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - 'severity': 'critical', - 'ok_actions': ['spam://something/ok'], - 'alarm_actions': ['http://something/alarm'], - 'insufficient_data_actions': ['http://something/no'], - 'repeat_actions': True, - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'comparison_operator': 'le', - 'aggregation_method': 'count', - 'threshold': 50, - 'evaluation_periods': 3, - 'granularity': 180, - } - } - data = self.get_json('/alarms', - headers=self.auth_headers, - q=[{'field': 'name', - 'value': 'name2', - }]) - self.assertEqual(1, len(data)) - alarm_id = data[0]['alarm_id'] - - resp = self.put_json('/alarms/%s' % alarm_id, - expect_errors=True, status=400, - params=json, - headers=self.auth_headers) - self.assertEqual( - 'Unsupported action spam://something/ok', - resp.json['error_message']['faultstring']) - def test_put_alarm_trust(self): data = self._get_alarm('a') data.update({'ok_actions': ['trust+http://something/ok']}) @@ -1480,48 +592,6 @@ class TestAlarms(TestAlarmsBase): self.assertEqual( ['http://no-trust-something/ok'], data['ok_actions']) - def test_delete_alarm(self): - data = self.get_json('/alarms', headers=self.auth_headers) - self.assertEqual(3, len(data)) - - resp = self.delete('/alarms/%s' % data[0]['alarm_id'], - headers=self.auth_headers, - status=204) - self.assertEqual(b'', resp.body) - alarms = list(self.alarm_conn.get_alarms()) - self.assertEqual(2, len(alarms)) - - def test_get_state_alarm(self): - data = self.get_json('/alarms', headers=self.auth_headers) - self.assertEqual(3, len(data)) - - resp = self.get_json('/alarms/%s/state' % data[0]['alarm_id'], - headers=self.auth_headers) - self.assertEqual(resp, data[0]['state']) - - def test_set_state_alarm(self): - data = self.get_json('/alarms', headers=self.auth_headers) - self.assertEqual(3, len(data)) - - resp = self.put_json('/alarms/%s/state' % data[0]['alarm_id'], - headers=self.auth_headers, - params='alarm') - alarms = list(self.alarm_conn.get_alarms(alarm_id=data[0]['alarm_id'])) - self.assertEqual(1, len(alarms)) - self.assertEqual('alarm', alarms[0].state) - self.assertEqual('Manually set via API', - alarms[0].state_reason) - self.assertEqual('alarm', resp.json) - - def test_set_invalid_state_alarm(self): - data = self.get_json('/alarms', headers=self.auth_headers) - self.assertEqual(3, len(data)) - - self.put_json('/alarms/%s/state' % data[0]['alarm_id'], - headers=self.auth_headers, - params='not valid', - status=400) - def test_alarms_sends_notification(self): # Hit the AlarmsController ... json = { @@ -1660,20 +730,6 @@ class TestAlarmsHistory(TestAlarmsBase): history = self._get_alarm_history('a') self.assertEqual(1, len(history)) - def test_record_alarm_history_severity(self): - alarm = self._get_alarm('a') - history = self._get_alarm_history('a') - self.assertEqual([], history) - self.assertEqual('critical', alarm['severity']) - - self._update_alarm('a', dict(severity='low')) - new_alarm = self._get_alarm('a') - history = self._get_alarm_history('a') - self.assertEqual(1, len(history)) - self.assertEqual(jsonlib.dumps({'severity': 'low'}), - history[0]['detail']) - self.assertEqual('low', new_alarm['severity']) - def test_record_alarm_history_statistic(self): alarm = self._get_alarm('a') history = self._get_alarm_history('a') @@ -1691,92 +747,6 @@ class TestAlarmsHistory(TestAlarmsBase): ['rule']["aggregation_method"]) self.assertEqual('min', new_alarm[RULE_KEY]['aggregation_method']) - def test_redundant_update_alarm_property_no_history_change(self): - alarm = self._get_alarm('a') - history = self._get_alarm_history('a') - self.assertEqual([], history) - self.assertEqual('critical', alarm['severity']) - - self._update_alarm('a', dict(severity='low')) - new_alarm = self._get_alarm('a') - history = self._get_alarm_history('a') - self.assertEqual(1, len(history)) - self.assertEqual(jsonlib.dumps({'severity': 'low'}), - history[0]['detail']) - self.assertEqual('low', new_alarm['severity']) - - self._update_alarm('a', dict(severity='low')) - updated_history = self._get_alarm_history('a') - self.assertEqual(1, len(updated_history)) - self.assertEqual(jsonlib.dumps({'severity': 'low'}), - updated_history[0]['detail']) - self.assertEqual(history, updated_history) - - def test_get_recorded_alarm_history_on_create(self): - new_alarm = { - 'name': 'new_alarm', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'comparison_operator': 'le', - 'aggregation_method': 'max', - 'threshold': 42.0, - 'granularity': 60, - 'evaluation_periods': 1, - } - } - self.post_json('/alarms', params=new_alarm, status=201, - headers=self.auth_headers) - - alarms = self.get_json('/alarms', - headers=self.auth_headers, - q=[{'field': 'name', - 'value': 'new_alarm', - }]) - self.assertEqual(1, len(alarms)) - alarm = alarms[0] - - history = self._get_alarm_history(alarm['alarm_id']) - self.assertEqual(1, len(history)) - self._assert_is_subset(dict(alarm_id=alarm['alarm_id'], - on_behalf_of=alarm['project_id'], - project_id=alarm['project_id'], - type='creation', - user_id=alarm['user_id']), - history[0]) - new_alarm['rule'] = new_alarm[RULE_KEY] - del new_alarm[RULE_KEY] - self._assert_in_json(new_alarm, history[0]['detail']) - - def _do_test_get_recorded_alarm_history_on_update(self, - data, - type, - detail, - auth=None): - alarm = self._get_alarm('a') - history = self._get_alarm_history('a') - self.assertEqual([], history) - self._update_alarm('a', data, auth) - history = self._get_alarm_history('a') - self.assertEqual(1, len(history)) - project_id = auth['X-Project-Id'] if auth else alarm['project_id'] - user_id = auth['X-User-Id'] if auth else alarm['user_id'] - self._assert_is_subset(dict(alarm_id=alarm['alarm_id'], - detail=detail, - on_behalf_of=alarm['project_id'], - project_id=project_id, - type=type, - user_id=user_id), - history[0]) - - def test_get_recorded_alarm_history_rule_change(self): - data = dict(name='renamed') - detail = '{"name": "renamed"}' - self._do_test_get_recorded_alarm_history_on_update(data, - 'rule change', - detail) - def test_get_recorded_alarm_history_state_transition_on_behalf_of(self): # credentials for new non-admin user, on who's behalf the alarm # is created @@ -1846,18 +816,6 @@ class TestAlarmsHistory(TestAlarmsBase): query=query, expect_errors=True, status=400) - def test_get_recorded_alarm_history_segregation(self): - data = dict(name='renamed') - detail = '{"name": "renamed"}' - self._do_test_get_recorded_alarm_history_on_update(data, - 'rule change', - detail) - auth = {'X-Roles': 'member', - 'X-User-Id': uuidutils.generate_uuid(), - 'X-Project-Id': uuidutils.generate_uuid()} - self._get_alarm_history('a', auth_headers=auth, - expect_errors=True, status=404) - def test_delete_alarm_history_after_deletion(self): self._update_alarm('a', dict(name='renamed')) history = self._get_alarm_history('a') @@ -1950,9 +908,6 @@ class TestAlarmsHistory(TestAlarmsBase): self.assertEqual(jsonlib.dumps({'severity': 'low'}), history[0]['detail']) - def test_get_nonexistent_alarm_history(self): - self._get_alarm_history('foobar', expect_errors=True, status=404) - class TestAlarmsQuotas(TestAlarmsBase): def setUp(self): @@ -2155,50 +1110,6 @@ class TestAlarmsQuotas(TestAlarmsBase): class TestAlarmsRuleThreshold(TestAlarmsBase): - def test_post_invalid_alarm_statistic(self): - json = { - 'name': 'added_alarm', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'comparison_operator': 'gt', - 'threshold': 2.0, - 'aggregation_method': 'magic', - } - } - resp = self.post_json('/alarms', params=json, expect_errors=True, - status=400, headers=self.auth_headers) - expected_err_msg = ("aggregation_method should be in ['count', " - "'mean', 'max', 'min', 'first', 'last', 'std'] " - "not magic") - self.assertIn(expected_err_msg, - resp.json['error_message']['faultstring']) - alarms = list(self.alarm_conn.get_alarms()) - self.assertEqual(0, len(alarms)) - - def test_post_invalid_alarm_input_comparison_operator(self): - json = { - 'name': 'alarm2', - 'state': 'ok', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - RULE_KEY: { - 'metrics': ['41869681-5776-46d6-91ed-cccc43b6e4e3', - 'a1fb80f4-c242-4f57-87c6-68f47521059e'], - 'comparison_operator': 'bad_co', - 'threshold': 50.0 - } - } - resp = self.post_json('/alarms', params=json, expect_errors=True, - status=400, headers=self.auth_headers) - expected_err_msg = ("Invalid input for field/attribute" - " comparison_operator." - " Value: 'bad_co'.") - self.assertIn(expected_err_msg, - resp.json['error_message']['faultstring']) - alarms = list(self.alarm_conn.get_alarms()) - self.assertEqual(0, len(alarms)) - def test_post_threshold_rule_defaults(self): to_check = { 'name': 'added_alarm_defaults', @@ -2383,74 +1294,6 @@ class TestAlarmsRuleGnocchi(TestAlarmsBase): self.post_json('/alarms', params=json, headers=self.auth_headers) self.assertFalse(clientlib.called) - def test_post_gnocchi_resources_alarm(self): - json = { - 'enabled': False, - 'name': 'name_post', - 'state': 'ok', - 'type': 'gnocchi_resources_threshold', - 'severity': 'critical', - 'ok_actions': ['http://something/ok'], - 'alarm_actions': ['http://something/alarm'], - 'insufficient_data_actions': ['http://something/no'], - 'repeat_actions': True, - 'gnocchi_resources_threshold_rule': { - 'metric': 'ameter', - 'comparison_operator': 'le', - 'aggregation_method': 'count', - 'threshold': 50, - 'evaluation_periods': 3, - 'granularity': 180, - 'resource_type': 'instance', - 'resource_id': '209ef69c-c10c-4efb-90ff-46f4b2d90d2e', - } - } - - with mock.patch('aodh.api.controllers.v2.alarm_rules.' - 'gnocchi.client') as clientlib: - c = clientlib.Client.return_value - c.capabilities.list.return_value = { - 'aggregation_methods': ['count']} - self.post_json('/alarms', params=json, headers=self.auth_headers) - - alarms = list(self.alarm_conn.get_alarms(enabled=False)) - self.assertEqual(1, len(alarms)) - self._verify_alarm(json, alarms[0]) - - def test_post_gnocchi_metrics_alarm(self): - json = { - 'enabled': False, - 'name': 'name_post', - 'state': 'ok', - 'type': 'gnocchi_aggregation_by_metrics_threshold', - 'severity': 'critical', - 'ok_actions': ['http://something/ok'], - 'alarm_actions': ['http://something/alarm'], - 'insufficient_data_actions': ['http://something/no'], - 'repeat_actions': True, - RULE_KEY: { - 'metrics': ['b3d9d8ab-05e8-439f-89ad-5e978dd2a5eb', - '009d4faf-c275-46f0-8f2d-670b15bac2b0'], - 'comparison_operator': 'le', - 'aggregation_method': 'count', - 'threshold': 50, - 'evaluation_periods': 3, - 'granularity': 180, - } - } - - with mock.patch('aodh.api.controllers.v2.alarm_rules.' - 'gnocchi.client') as clientlib: - c = clientlib.Client.return_value - c.capabilities.list.return_value = { - 'aggregation_methods': ['count']} - - self.post_json('/alarms', params=json, headers=self.auth_headers) - - alarms = list(self.alarm_conn.get_alarms(enabled=False)) - self.assertEqual(1, len(alarms)) - self._verify_alarm(json, alarms[0]) - @mock.patch('aodh.keystone_client.get_client') def test_post_gnocchi_aggregation_alarm_project_constraint(self, get_client): @@ -2522,97 +1365,6 @@ class TestAlarmsRuleGnocchi(TestAlarmsBase): self._verify_alarm(json, alarms[0]) -class TestAlarmsRuleLoadBalancer(TestAlarmsBase): - def test_post(self): - json = { - 'name': 'added_alarm_defaults', - 'type': 'loadbalancer_member_health', - 'loadbalancer_member_health_rule': { - "pool_id": "2177ccd8-b09c-417a-89a0-e8d2419be612", - "stack_id": "1b974012-ebcb-4888-8ae2-47714d4d2c4d", - "autoscaling_group_id": "681c9266-61d2-4c9a-ad18-526807f6adc0" - } - } - self.post_json('/alarms', params=json, status=201, - headers=self.auth_headers) - - alarms = list(self.alarm_conn.get_alarms()) - - self.assertEqual(1, len(alarms)) - self._verify_alarm(json, alarms[0]) - - -class TestAlarmsEvent(TestAlarmsBase): - - def test_list_alarms(self): - alarm = models.Alarm(name='event.alarm.1', - type='event', - enabled=True, - alarm_id='h', - description='h', - state='insufficient data', - state_reason='insufficient data', - severity='moderate', - state_timestamp=constants.MIN_DATETIME, - timestamp=constants.MIN_DATETIME, - ok_actions=[], - insufficient_data_actions=[], - alarm_actions=[], - repeat_actions=False, - user_id=self.auth_headers['X-User-Id'], - project_id=self.auth_headers['X-Project-Id'], - time_constraints=[], - rule=dict(event_type='event.test', - query=[]), - ) - self.alarm_conn.create_alarm(alarm) - - data = self.get_json('/alarms', headers=self.auth_headers) - self.assertEqual(1, len(data)) - self.assertEqual(set(['event.alarm.1']), - set(r['name'] for r in data)) - self.assertEqual(set(['event.test']), - set(r['event_rule']['event_type'] - for r in data if 'event_rule' in r)) - - def test_post_event_alarm_defaults(self): - to_check = { - 'enabled': True, - 'name': 'added_alarm_defaults', - 'state': 'insufficient data', - 'description': 'Alarm when * event occurred.', - 'type': 'event', - 'ok_actions': [], - 'alarm_actions': [], - 'insufficient_data_actions': [], - 'repeat_actions': False, - 'rule': { - 'event_type': '*', - 'query': [], - } - } - - json = { - 'name': 'added_alarm_defaults', - 'type': 'event', - 'event_rule': { - 'event_type': '*', - 'query': [] - } - } - self.post_json('/alarms', params=json, status=201, - headers=self.auth_headers) - alarms = list(self.alarm_conn.get_alarms()) - self.assertEqual(1, len(alarms)) - for alarm in alarms: - if alarm.name == 'added_alarm_defaults': - for key in to_check: - self.assertEqual(to_check[key], getattr(alarm, key)) - break - else: - self.fail("Alarm not found") - - class TestAlarmsCompositeRule(TestAlarmsBase): def setUp(self): @@ -2654,34 +1406,6 @@ class TestAlarmsCompositeRule(TestAlarmsBase): "and": [self.sub_rule2, self.sub_rule3] }]} - def test_list_alarms(self): - alarm = models.Alarm(name='composite_alarm', - type='composite', - enabled=True, - alarm_id='composite', - description='composite', - state='insufficient data', - state_reason='insufficient data', - severity='moderate', - state_timestamp=constants.MIN_DATETIME, - timestamp=constants.MIN_DATETIME, - ok_actions=[], - insufficient_data_actions=[], - alarm_actions=[], - repeat_actions=False, - user_id=self.auth_headers['X-User-Id'], - project_id=self.auth_headers['X-Project-Id'], - time_constraints=[], - rule=self.rule, - ) - self.alarm_conn.create_alarm(alarm) - - data = self.get_json('/alarms', headers=self.auth_headers) - self.assertEqual(1, len(data)) - self.assertEqual(set(['composite_alarm']), - set(r['name'] for r in data)) - self.assertEqual(self.rule, data[0]['composite_rule']) - def test_post_with_composite_rule(self): json = { "type": "composite", @@ -2759,16 +1483,6 @@ class TestPaginationQuery(TestAlarmsBase): for alarm in default_alarms(self.auth_headers): self.alarm_conn.create_alarm(alarm) - def test_pagination_query_single_sort(self): - data = self.get_json('/alarms?sort=name:desc', - headers=self.auth_headers) - names = [a['name'] for a in data] - self.assertEqual(['name3', 'name2', 'name1'], names) - data = self.get_json('/alarms?sort=name:asc', - headers=self.auth_headers) - names = [a['name'] for a in data] - self.assertEqual(['name1', 'name2', 'name3'], names) - def test_sort_by_severity_with_its_value(self): if self.engine != "mysql": self.skipTest("This is only implemented for MySQL") @@ -2783,66 +1497,6 @@ class TestPaginationQuery(TestAlarmsBase): self.assertEqual(['critical', 'critical', 'moderate'], severities) - def test_pagination_query_limit(self): - data = self.get_json('/alarms?limit=2', headers=self.auth_headers) - self.assertEqual(2, len(data)) - - def test_pagination_query_limit_sort(self): - data = self.get_json('/alarms?sort=name:asc&limit=2', - headers=self.auth_headers) - self.assertEqual(2, len(data)) - - def test_pagination_query_marker(self): - data = self.get_json('/alarms?sort=name:desc', - headers=self.auth_headers) - self.assertEqual(3, len(data)) - alarm_ids = [a['alarm_id'] for a in data] - names = [a['name'] for a in data] - self.assertEqual(['name3', 'name2', 'name1'], names) - marker_url = ('/alarms?sort=name:desc&marker=%s' % alarm_ids[1]) - data = self.get_json(marker_url, headers=self.auth_headers) - self.assertEqual(1, len(data)) - new_alarm_ids = [a['alarm_id'] for a in data] - self.assertEqual(alarm_ids[2:], new_alarm_ids) - new_names = [a['name'] for a in data] - self.assertEqual(['name1'], new_names) - - def test_pagination_query_multiple_sorts(self): - new_alarms = default_alarms(self.auth_headers) - for a_id in zip(new_alarms, ['e', 'f', 'g', 'h']): - a_id[0].alarm_id = a_id[1] - self.alarm_conn.create_alarm(a_id[0]) - data = self.get_json('/alarms', headers=self.auth_headers) - self.assertEqual(6, len(data)) - sort_url = '/alarms?sort=name:desc&sort=alarm_id:asc' - data = self.get_json(sort_url, headers=self.auth_headers) - name_ids = [(a['name'], a['alarm_id']) for a in data] - expected = [('name3', 'c'), - ('name3', 'g'), ('name2', 'b'), ('name2', 'f'), - ('name1', 'a'), ('name1', 'e')] - self.assertEqual(expected, name_ids) - - def test_pagination_query_invalid_sort_key(self): - resp = self.get_json('/alarms?sort=invalid_key:desc', - headers=self.auth_headers, - expect_errors=True) - self.assertEqual(resp.status_code, 400) - self.assertEqual("Invalid input for field/attribute sort. Value: " - "'invalid_key:desc'. the sort parameter should be" - " a pair of sort key and sort dir combined with " - "':', or only sort key specified and sort dir will " - "be default 'asc', the supported sort keys are: " - "('alarm_id', 'enabled', 'name', 'type', 'severity'," - " 'timestamp', 'user_id', 'project_id', 'state', " - "'repeat_actions', 'state_timestamp')", - resp.json['error_message']['faultstring']) - - def test_pagination_query_only_sort_key_specified(self): - data = self.get_json('/alarms?sort=name', - headers=self.auth_headers) - names = [a['name'] for a in data] - self.assertEqual(['name1', 'name2', 'name3'], names) - def test_pagination_query_history_data(self): for i in range(10): self._update_alarm('a', dict(name='%s' % i)) diff --git a/aodh/tests/functional/api/v2/test_app.py b/aodh/tests/functional/api/v2/test_app.py index 109553528..e68c6ac18 100644 --- a/aodh/tests/functional/api/v2/test_app.py +++ b/aodh/tests/functional/api/v2/test_app.py @@ -35,47 +35,6 @@ class TestApiMiddleware(v2.FunctionalTest): else: return self.en_US_translated_error - def test_json_parsable_error_middleware_404(self): - response = self.get_json('/invalid_path', - expect_errors=True, - headers={"Accept": - "application/json"} - ) - self.assertEqual(404, response.status_int) - self.assertEqual("application/json", response.content_type) - self.assertTrue(response.json['error_message']) - response = self.get_json('/invalid_path', - expect_errors=True, - headers={"Accept": - "application/json,application/xml"} - ) - self.assertEqual(404, response.status_int) - self.assertEqual("application/json", response.content_type) - self.assertTrue(response.json['error_message']) - response = self.get_json('/invalid_path', - expect_errors=True, - headers={"Accept": - "application/xml;q=0.8, \ - application/json"} - ) - self.assertEqual(404, response.status_int) - self.assertEqual("application/json", response.content_type) - self.assertTrue(response.json['error_message']) - response = self.get_json('/invalid_path', - expect_errors=True - ) - self.assertEqual(404, response.status_int) - self.assertEqual("application/json", response.content_type) - self.assertTrue(response.json['error_message']) - response = self.get_json('/invalid_path', - expect_errors=True, - headers={"Accept": - "text/html,*/*"} - ) - self.assertEqual(404, response.status_int) - self.assertEqual("application/json", response.content_type) - self.assertTrue(response.json['error_message']) - def test_json_parsable_error_middleware_translation_400(self): # Ensure translated messages get placed properly into json faults with mock.patch.object(i18n, 'translate', @@ -89,25 +48,6 @@ class TestApiMiddleware(v2.FunctionalTest): self.assertEqual(self.no_lang_translated_error, response.json['error_message']['faultstring']) - def test_xml_parsable_error_middleware_404(self): - response = self.get_json('/invalid_path', - expect_errors=True, - headers={"Accept": - "application/xml,*/*"} - ) - self.assertEqual(404, response.status_int) - self.assertEqual("application/xml", response.content_type) - self.assertEqual('error_message', response.xml.tag) - response = self.get_json('/invalid_path', - expect_errors=True, - headers={"Accept": - "application/json;q=0.8 \ - ,application/xml"} - ) - self.assertEqual(404, response.status_int) - self.assertEqual("application/xml", response.content_type) - self.assertEqual('error_message', response.xml.tag) - def test_xml_parsable_error_middleware_translation_400(self): # Ensure translated messages get placed properly into xml faults with mock.patch.object(i18n, 'translate', diff --git a/aodh/tests/functional/api/v2/test_capabilities.py b/aodh/tests/functional/api/v2/test_capabilities.py deleted file mode 100644 index 334e1109c..000000000 --- a/aodh/tests/functional/api/v2/test_capabilities.py +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright Ericsson AB 2014. All rights reserved -# -# 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. -from aodh.tests.functional.api import v2 as tests_api - - -class TestCapabilitiesController(tests_api.FunctionalTest): - - def setUp(self): - super(TestCapabilitiesController, self).setUp() - self.url = '/capabilities' - - def test_capabilities(self): - data = self.get_json(self.url) - # check that capabilities data contains both 'api' and 'storage' fields - self.assertIsNotNone(data) - self.assertNotEqual({}, data) - self.assertIn('api', data) - self.assertIn('alarm_storage', data) diff --git a/aodh/tests/functional/gabbi/__init__.py b/aodh/tests/functional/gabbi/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/aodh/tests/functional/gabbi/fixtures.py b/aodh/tests/functional/gabbi/fixtures.py deleted file mode 100644 index 938cc3a8c..000000000 --- a/aodh/tests/functional/gabbi/fixtures.py +++ /dev/null @@ -1,131 +0,0 @@ -# -# Copyright 2015 Red Hat. All Rights Reserved. -# -# 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. - -"""Fixtures used during Gabbi-based test runs.""" - -import os -import unittest -from unittest import mock - -from gabbi import fixture -from oslo_config import cfg -from oslo_config import fixture as fixture_config -from oslo_policy import opts -from oslo_utils import uuidutils -import sqlalchemy_utils -from urllib import parse as urlparse - -from aodh.api import app -from aodh.api import rbac -from aodh import service -from aodh import storage - - -# NOTE(chdent): Hack to restore semblance of global configuration to -# pass to the WSGI app used per test suite. LOAD_APP_KWARGS are the olso -# configuration, and the pecan application configuration of -# which the critical part is a reference to the current indexer. -LOAD_APP_KWARGS = None - - -def setup_app(): - global LOAD_APP_KWARGS - return app.load_app(**LOAD_APP_KWARGS) - - -class ConfigFixture(fixture.GabbiFixture): - """Establish the relevant configuration for a test run.""" - - def start_fixture(self): - """Set up config.""" - - global LOAD_APP_KWARGS - - self.conf = None - self.conn = None - - # Determine the database connection. - db_url = os.environ.get( - 'AODH_TEST_STORAGE_URL', "").replace( - "mysql://", "mysql+pymysql://") - if not db_url: - raise unittest.TestCase.failureException( - 'No database connection configured') - - conf = service.prepare_service([], config_files=[]) - # NOTE(jd): prepare_service() is called twice: first by load_app() for - # Pecan, then Pecan calls pastedeploy, which starts the app, which has - # no way to pass the conf object so that Paste apps calls again - # prepare_service. In real life, that's not a problem, but here we want - # to be sure that the second time the same conf object is returned - # since we tweaked it. To that, once we called prepare_service() we - # mock it so it returns the same conf object. - self.prepare_service = service.prepare_service - service.prepare_service = mock.Mock() - service.prepare_service.return_value = conf - conf = fixture_config.Config(conf).conf - self.conf = conf - opts.set_defaults(self.conf) - - rbac.enforce = mock.Mock() - conf.set_override('auth_mode', None, group='api') - - parsed_url = urlparse.urlparse(db_url) - if parsed_url.scheme != 'sqlite': - parsed_url = list(parsed_url) - parsed_url[2] += '-%s' % uuidutils.generate_uuid(dashed=False) - db_url = urlparse.urlunparse(parsed_url) - - conf.set_override('connection', db_url, group='database') - - if (parsed_url[0].startswith("mysql") - or parsed_url[0].startswith("postgresql")): - sqlalchemy_utils.create_database(conf.database.connection) - - self.conn = storage.get_connection_from_config(self.conf) - self.conn.upgrade() - - LOAD_APP_KWARGS = { - 'conf': conf, - } - - def stop_fixture(self): - """Reset the config and remove data.""" - if self.conn: - self.conn.clear() - if self.conf: - self.conf.reset() - service.prepare_service = self.prepare_service - - -class CORSConfigFixture(fixture.GabbiFixture): - """Inject mock configuration for the CORS middleware.""" - - def start_fixture(self): - # Here we monkeypatch GroupAttr.__getattr__, necessary because the - # paste.ini method of initializing this middleware creates its own - # ConfigOpts instance, bypassing the regular config fixture. - - def _mock_getattr(instance, key): - if key != 'allowed_origin': - return self._original_call_method(instance, key) - return "http://valid.example.com" - - self._original_call_method = cfg.ConfigOpts.GroupAttr.__getattr__ - cfg.ConfigOpts.GroupAttr.__getattr__ = _mock_getattr - - def stop_fixture(self): - """Remove the monkeypatch.""" - cfg.ConfigOpts.GroupAttr.__getattr__ = self._original_call_method diff --git a/aodh/tests/functional/gabbi/gabbits/alarms.yaml b/aodh/tests/functional/gabbi/gabbits/alarms.yaml deleted file mode 100644 index b011fbe7e..000000000 --- a/aodh/tests/functional/gabbi/gabbits/alarms.yaml +++ /dev/null @@ -1,194 +0,0 @@ -# Requests to cover the basic endpoints for alarms. - -fixtures: - - ConfigFixture - -tests: -- name: list alarms none - desc: Lists alarms, none yet exist - GET: /v2/alarms - response_strings: - - "[]" - -- name: try to PUT an alarm - desc: what does PUT do - PUT: /v2/alarms - request_headers: - content-type: application/json - data: - name: added_alarm_defaults2 - type: gnocchi_resources_threshold - gnocchi_resources_threshold_rule: - metric: ameter - resource_id: random_id - resource_type: instance - aggregation_method: max - threshold: 300.0 - status: 405 - response_headers: - allow: GET, POST - -- name: try to POST an event type alarm - desc: what does POST response be - POST: /v2/alarms - request_headers: - content-type: application/json - data: - name: instance_off - type: event - event_rule: - query: [{'field': "{=:", 'op': "eq", 'type': "string", 'value': "sample_string"}] - status: 400 - response_strings: - - "Query value or traits invalid:" - -- name: try to POST an event type alarm2 - desc: what does POST response be - POST: /v2/alarms - request_headers: - content-type: application/json - data: - name: instance_off - type: event - event_rule: - query: [{'field': "traits.instance_id", 'op': "eq", 'type': "", 'value': "default_string_datatype_isconsidered"}] - status: 201 - -- name: try to POST an event type alarm3 - desc: what does POST response be - POST: /v2/alarms - request_headers: - content-type: application/json - data: - name: instance_off - type: event - event_rule: - query: [{'field': "traits.instance_id", 'op': "lt", 'type': "integer", 'value': "1234567"}] - status: 201 - -- name: try to POST an event type alarm4 - desc: what does POST response be - POST: /v2/alarms - request_headers: - content-type: application/json - data: - name: instance_off - type: event - event_rule: - query: [{'field': "traits.instance_id", 'op': "lt", 'type': "integer", 'value': "hello"}] - status: 400 - response_strings: - - "Unable to convert the value hello to the expected data type integer" - -- name: try to POST an event type alarm5 - desc: what does POST response be - POST: /v2/alarms - request_headers: - content-type: application/json - data: - name: instance_off - type: event - event_rule: - query: [{'field': "traits.instance_id", 'op': "ltt", 'type': "integer", 'value': "1234567"}] - status: 400 - response_strings: - - "Query value or traits invalid:" - -- name: createAlarm - desc: Creates an alarm. - POST: /v2/alarms - request_headers: - content-type: application/json - data: - ok_actions: null - name: added_alarm_defaults - type: gnocchi_resources_threshold - gnocchi_resources_threshold_rule: - metric: ameter - resource_id: random_id - resource_type: instance - aggregation_method: max - threshold: 300.0 - status: 201 - response_headers: - location: /$SCHEME://$NETLOC/v2/alarms/ - content-type: application/json - response_json_paths: - $.severity: low - $.gnocchi_resources_threshold_rule.threshold: 300.0 - $.gnocchi_resources_threshold_rule.comparison_operator: eq - -- name: showAlarm - desc: Shows information for a specified alarm. - GET: /v2/alarms/$RESPONSE['$.alarm_id'] - response_json_paths: - $.severity: low - $.alarm_id: $RESPONSE['$.alarm_id'] - $.gnocchi_resources_threshold_rule.threshold: 300.0 - $.gnocchi_resources_threshold_rule.comparison_operator: eq - response_headers: - content-type: application/json - -- name: updateAlarm - desc: Updates a specified alarm. - PUT: /v2/alarms/$RESPONSE['$.alarm_id'] - request_headers: - content-type: application/json - data: - name: added_alarm_defaults - severity: moderate - type: gnocchi_resources_threshold - gnocchi_resources_threshold_rule: - metric: ameter - resource_id: random_id - resource_type: instance - aggregation_method: max - threshold: 200.0 -# TODO(chdent): why do we have a response, why not status: 204? -# status: 204 - response_json_paths: - $.gnocchi_resources_threshold_rule.threshold: 200.0 - $.severity: moderate - $.state: insufficient data - -- name: showAlarmHistory - desc: Assembles the history for a specified alarm. - GET: /v2/alarms/$RESPONSE['$.alarm_id']/history?q.field=type&q.op=eq&q.value=rule%20change - response_json_paths: - $[0].type: rule change - -- name: updateAlarmState - desc: Sets the state of a specified alarm. - PUT: /v2/alarms/$RESPONSE['$[0].alarm_id']/state - request_headers: - content-type: application/json - data: '"alarm"' -# TODO(chdent): really? Of what possible use is this? - response_json_paths: - $: alarm - -# Get a list of alarms so we can extract an id for the next test -- name: list alarms - desc: Lists alarms, only one - GET: /v2/alarms - response_json_paths: - $[0].name: added_alarm_defaults - -- name: showAlarmState - desc: Gets the state of a specified alarm. - GET: /v2/alarms/$RESPONSE['$[0].alarm_id']/state - response_headers: - content-type: application/json - response_json_paths: - $: alarm - -- name: deleteAlarm - desc: Deletes a specified alarm. - DELETE: /v2/alarms/$HISTORY['list alarms'].$RESPONSE['$[0].alarm_id'] - status: 204 - -- name: list alarms none end - desc: Lists alarms, none now exist - GET: /v2/alarms - response_strings: - - "[]" diff --git a/aodh/tests/functional/gabbi/gabbits/basic.yaml b/aodh/tests/functional/gabbi/gabbits/basic.yaml deleted file mode 100644 index d56a0de67..000000000 --- a/aodh/tests/functional/gabbi/gabbits/basic.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# -# Some simple tests just to confirm that the system works. -# -fixtures: - - ConfigFixture - -tests: - -# Root gives us some information on where to go from here. -- name: quick root check - GET: / - response_headers: - content-type: application/json - response_strings: - - '"base": "application/json"' - response_json_paths: - versions.values.[0].status: stable - versions.values.[0].media-types.[0].base: application/json - -# NOTE(chdent): Ideally since / has a links ref to /v2, /v2 ought not 404! -- name: v2 visit - desc: this demonstrates a bug in the info in / - GET: $RESPONSE['versions.values.[0].links.[0].href'] - status: 404 diff --git a/aodh/tests/functional/gabbi/gabbits/capabilities.yaml b/aodh/tests/functional/gabbi/gabbits/capabilities.yaml deleted file mode 100644 index 66a7d7a74..000000000 --- a/aodh/tests/functional/gabbi/gabbits/capabilities.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# -# Explore the capabilities API -# -fixtures: - - ConfigFixture - -tests: - -- name: get capabilities - GET: /v2/capabilities - response_json_paths: - $.alarm_storage.['storage:production_ready']: true diff --git a/aodh/tests/functional/gabbi/gabbits/healthcheck.yaml b/aodh/tests/functional/gabbi/gabbits/healthcheck.yaml deleted file mode 100644 index a2cf6fd1c..000000000 --- a/aodh/tests/functional/gabbi/gabbits/healthcheck.yaml +++ /dev/null @@ -1,7 +0,0 @@ -fixtures: - - ConfigFixture - -tests: - - name: healthcheck - GET: /healthcheck - status: 200 diff --git a/aodh/tests/functional/gabbi/gabbits/middleware.yaml b/aodh/tests/functional/gabbi/gabbits/middleware.yaml deleted file mode 100644 index 3d2204833..000000000 --- a/aodh/tests/functional/gabbi/gabbits/middleware.yaml +++ /dev/null @@ -1,44 +0,0 @@ -# -# Test the middlewares. Just CORS for now. -# - -fixtures: - - ConfigFixture - - CORSConfigFixture - -tests: - - - name: valid cors options - OPTIONS: / - status: 200 - request_headers: - origin: http://valid.example.com - access-control-request-method: GET - response_headers: - access-control-allow-origin: http://valid.example.com - - - name: invalid cors options - OPTIONS: / - status: 200 - request_headers: - origin: http://invalid.example.com - access-control-request-method: GET - response_forbidden_headers: - - access-control-allow-origin - - - name: valid cors get - GET: / - status: 200 - request_headers: - origin: http://valid.example.com - access-control-request-method: GET - response_headers: - access-control-allow-origin: http://valid.example.com - - - name: invalid cors get - GET: / - status: 200 - request_headers: - origin: http://invalid.example.com - response_forbidden_headers: - - access-control-allow-origin diff --git a/aodh/tests/functional/gabbi/test_gabbi.py b/aodh/tests/functional/gabbi/test_gabbi.py deleted file mode 100644 index 67d961887..000000000 --- a/aodh/tests/functional/gabbi/test_gabbi.py +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright 2015 Red Hat. All Rights Reserved. -# -# 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. - -"""A test module to exercise the aodh API with gabbi - -For the sake of exploratory development. -""" - -import os - -from gabbi import driver - -from aodh.tests.functional.gabbi import fixtures as fixture_module - - -TESTS_DIR = 'gabbits' - - -def load_tests(loader, tests, pattern): - """Provide a TestSuite to the discovery process.""" - test_dir = os.path.join(os.path.dirname(__file__), TESTS_DIR) - return driver.build_tests(test_dir, loader, host=None, - intercept=fixture_module.setup_app, - fixture_module=fixture_module) diff --git a/aodh/tests/functional/api/v2/test_query.py b/aodh/tests/unit/test_query.py similarity index 100% rename from aodh/tests/functional/api/v2/test_query.py rename to aodh/tests/unit/test_query.py diff --git a/aodh/tests/functional/api/v2/test_wsme_custom_type.py b/aodh/tests/unit/test_wsme_custom_type.py similarity index 100% rename from aodh/tests/functional/api/v2/test_wsme_custom_type.py rename to aodh/tests/unit/test_wsme_custom_type.py diff --git a/run-tests.sh b/run-tests.sh deleted file mode 100755 index e657a7af0..000000000 --- a/run-tests.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash -x -set -e - -AODH_TEST_DRIVERS=${AODH_TEST_DRIVERS:-postgresql} -export GABBI_LIVE_FAIL_IF_NO_TEST=1 -export AODH_SERVICE_TOKEN=foobar # Needed for gabbi -export AODH_SERVICE_ROLES=admin - -# mysqld may be installed to /usr/sbin, which isn't in -# PATH on some distributions -export PATH=$PATH:/usr/sbin - -# unit tests - -export OS_TEST_PATH=aodh/tests/unit -stestr run $* - -# functional tests - -export OS_TEST_PATH=aodh/tests/functional -for indexer in ${AODH_TEST_DRIVERS} -do - pifpaf -g AODH_TEST_STORAGE_URL run $indexer -- stestr run $* -done - -# live functional tests - -cleanup(){ - type -t database_stop >/dev/null && database_stop || true -} -trap cleanup EXIT - -export OS_TEST_PATH=aodh/tests/functional_live -for indexer in ${AODH_TEST_DRIVERS} -do - eval $(pifpaf -e DATABASE run $indexer) - pifpaf -e AODH run aodh --database-url $DATABASE_URL -- stestr run $* - cleanup -done diff --git a/tox.ini b/tox.ini index 99e2c09d6..025ce5b95 100644 --- a/tox.ini +++ b/tox.ini @@ -17,8 +17,6 @@ setenv = mysql: AODH_TEST_DEPS=mysql postgresql: AODH_TEST_DEPS=postgresql deps = - gnocchi[postgresql, file] - pifpaf[gnocchi]>=1.0.1 -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} .[{env:AODH_TEST_DEPS}] -r{toxinidir}/test-requirements.txt @@ -30,11 +28,11 @@ passenv = OS_LOG_CAPTURE AODH_TEST_DRIVERS commands = - {toxinidir}/run-tests.sh {posargs} + stestr --test-path=./aodh/tests run aodh-config-generator allowlist_externals = bash - {toxinidir}/run-tests.sh + stestr [testenv:cover] setenv = @@ -48,7 +46,7 @@ commands = coverage html -d cover coverage xml -o cover/coverage.xml coverage report - pifpaf -g AODH_TEST_STORAGE_URL run mysql -- stestr --test-path=./aodh/tests run + stestr --test-path=./aodh/tests run coverage report [testenv:pep8]