diff --git a/watcher_tempest_plugin/services/infra_optim/v1/json/client.py b/watcher_tempest_plugin/services/infra_optim/v1/json/client.py index ebc6e222c..b7bfc9cc1 100644 --- a/watcher_tempest_plugin/services/infra_optim/v1/json/client.py +++ b/watcher_tempest_plugin/services/infra_optim/v1/json/client.py @@ -40,12 +40,6 @@ class InfraOptimClientJSON(base.BaseInfraOptimClient): """List all existing audit templates.""" return self._list_request('audit_templates', **kwargs) - @base.handle_errors - def list_audit_template_audits(self, audit_template_uuid): - """Lists all audits associated with a audit template.""" - return self._list_request( - '/audit_templates/%s/audits' % audit_template_uuid) - @base.handle_errors def list_audit_templates_detail(self, **kwargs): """Lists details of all existing audit templates.""" @@ -110,18 +104,6 @@ class InfraOptimClientJSON(base.BaseInfraOptimClient): return self._create_request('audit_templates', audit_template) - @base.handle_errors - def create_audit(self, audit_template_uuid, **kwargs): - """Create an audit with the specified parameters. - - :param audit_template_uuid: Audit template ID used by the audit - :return: A tuple with the server response and the created audit. - """ - audit = {'audit_template_uuid': audit_template_uuid} - audit.update(kwargs) - - return self._create_request('audits', audit) - @base.handle_errors def delete_audit_template(self, audit_template_uuid): """Deletes an audit template having the specified UUID. @@ -144,3 +126,63 @@ class InfraOptimClientJSON(base.BaseInfraOptimClient): return self._patch_request('audit_templates', audit_template_uuid, patch) + + # ### AUDITS ### # + + @base.handle_errors + def list_audits(self, **kwargs): + """List all existing audit templates.""" + return self._list_request('audits', **kwargs) + + @base.handle_errors + def list_audits_detail(self, **kwargs): + """Lists details of all existing audit templates.""" + return self._list_request('/audits/detail', **kwargs) + + @base.handle_errors + def list_audit_by_audit_template(self, audit_template_uuid): + """Lists all audits associated with an audit template.""" + return self._list_request( + '/audits', audit_template=audit_template_uuid) + + @base.handle_errors + def show_audit(self, audit_uuid): + """Gets a specific audit template. + + :param audit_uuid: Unique identifier of the audit template + :return: Serialized audit template as a dictionary + """ + return self._show_request('audits', audit_uuid) + + @base.handle_errors + def create_audit(self, audit_template_uuid, **kwargs): + """Create an audit with the specified parameters + + :param audit_template_uuid: Audit template ID used by the audit + :return: A tuple with the server response and the created audit + """ + audit = {'audit_template_uuid': audit_template_uuid} + audit.update(kwargs) + + return self._create_request('audits', audit) + + @base.handle_errors + def delete_audit(self, audit_uuid): + """Deletes an audit having the specified UUID + + :param audit_uuid: The unique identifier of the audit + :return: A tuple with the server response and the response body + """ + + return self._delete_request('audits', audit_uuid) + + @base.handle_errors + def update_audit(self, audit_uuid, patch): + """Update the specified audit. + + :param audit_uuid: The unique identifier of the audit + :param patch: List of dicts representing json patches. + :return: Tuple with the server response and the updated audit + """ + + return self._patch_request('audits', uuid, patch) diff --git a/watcher_tempest_plugin/tests/api/admin/base.py b/watcher_tempest_plugin/tests/api/admin/base.py index c40714766..085220824 100644 --- a/watcher_tempest_plugin/tests/api/admin/base.py +++ b/watcher_tempest_plugin/tests/api/admin/base.py @@ -24,7 +24,7 @@ from watcher_tempest_plugin import infra_optim_clients as clients # Resources must be deleted in a specific order, this list # defines the resource types to clean up, and the correct order. -RESOURCE_TYPES = ['audit_template'] +RESOURCE_TYPES = ['audit_template', 'audit'] # RESOURCE_TYPES = ['action', 'action_plan', 'audit', 'audit_template'] @@ -137,3 +137,36 @@ class BaseInfraOptimTest(test.BaseTestCase): cls.created_objects['audit_template'].remove(uuid) return resp + + # ### AUDITS ### # + + @classmethod + @creates('audit') + def create_audit(cls, audit_template_uuid, type='ONESHOT', + state='PENDING', deadline=None): + """Wrapper utility for creating a test audit + + :param audit_template_uuid: Audit Template UUID this audit will use + :param type: Audit type (either ONESHOT or CONTINUOUS) + :param state: Audit state (str) + :param deadline: Audit deadline (datetime) + :return: A tuple with The HTTP response and its body + """ + resp, body = cls.client.create_audit( + audit_template_uuid=audit_template_uuid, type=type, + state=state, deadline=deadline) + return resp, body + + @classmethod + def delete_audit(cls, audit_uuid): + """Deletes an audit having the specified UUID + + :param audit_uuid: The unique identifier of the audit. + :return: the HTTP response + """ + resp, body = cls.client.delete_audit(audit_uuid) + + if audit_uuid in cls.created_objects['audit']: + cls.created_objects['audit'].remove(audit_uuid) + + return resp diff --git a/watcher_tempest_plugin/tests/api/admin/test_audit.py b/watcher_tempest_plugin/tests/api/admin/test_audit.py new file mode 100644 index 000000000..dadb3fade --- /dev/null +++ b/watcher_tempest_plugin/tests/api/admin/test_audit.py @@ -0,0 +1,187 @@ +# -*- encoding: utf-8 -*- +# Copyright (c) 2016 b<>com +# +# 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 __future__ import unicode_literals + +from tempest import test +from tempest_lib import decorators +from tempest_lib import exceptions as lib_exc + +from watcher_tempest_plugin.tests.api.admin import base + + +class TestCreateUpdateDeleteAudit(base.BaseInfraOptimTest): + """Tests for audit.""" + + def assert_expected(self, expected, actual, + keys=('created_at', 'updated_at', + 'deleted_at', 'state')): + super(TestCreateUpdateDeleteAudit, self).assert_expected( + expected, actual, keys) + + @test.attr(type='smoke') + def test_create_audit_oneshot(self): + _, audit_template = self.create_audit_template() + + audit_params = dict( + audit_template_uuid=audit_template['uuid'], + type='ONESHOT', + ) + + _, body = self.create_audit(**audit_params) + self.assert_expected(audit_params, body) + + _, audit = self.client.show_audit(body['uuid']) + self.assert_expected(audit, body) + + @test.attr(type='smoke') + def test_create_audit_continuous(self): + _, audit_template = self.create_audit_template() + + audit_params = dict( + audit_template_uuid=audit_template['uuid'], + type='CONTINUOUS', + ) + + _, body = self.create_audit(**audit_params) + self.assert_expected(audit_params, body) + + _, audit = self.client.show_audit(body['uuid']) + self.assert_expected(audit, body) + + @test.attr(type='smoke') + def test_create_audit_with_wrong_audit_template(self): + audit_params = dict( + audit_template_uuid='INVALID', + type='ONESHOT', + ) + + self.assertRaises( + lib_exc.BadRequest, self.create_audit, **audit_params) + + @decorators.skip_because(bug="1532843") + @test.attr(type='smoke') + def test_create_audit_with_invalid_state(self): + _, audit_template = self.create_audit_template() + + audit_params = dict( + audit_template_uuid=audit_template['uuid'], + state='INVALID', + ) + + self.assertRaises( + lib_exc.BadRequest, self.create_audit, **audit_params) + + @decorators.skip_because(bug="1533210") + @test.attr(type='smoke') + def test_create_audit_with_no_state(self): + _, audit_template = self.create_audit_template() + + audit_params = dict( + audit_template_uuid=audit_template['uuid'], + state='', + ) + + _, body = self.create_audit(**audit_params) + self.assert_expected(audit_params, body) + + _, audit = self.client.show_audit(body['uuid']) + + initial_audit_state = audit.pop('state') + self.assertEqual(initial_audit_state, 'PENDING') + + self.assert_expected(audit, body) + + @test.attr(type='smoke') + def test_delete_audit(self): + _, audit_template = self.create_audit_template() + _, body = self.create_audit(audit_template['uuid']) + audit_uuid = body['uuid'] + + self.delete_audit(audit_uuid) + + self.assertRaises(lib_exc.NotFound, self.client.show_audit, audit_uuid) + + +class TestShowListAudit(base.BaseInfraOptimTest): + """Tests for audit.""" + + audit_states = ['ONGOING', 'SUCCEEDED', 'SUBMITTED', 'FAILED', + 'CANCELLED', 'DELETED', 'PENDING'] + + @classmethod + def resource_setup(cls): + super(TestShowListAudit, cls).resource_setup() + _, cls.audit_template = cls.create_audit_template() + _, cls.audit = cls.create_audit(cls.audit_template['uuid']) + + def assert_expected(self, expected, actual, + keys=('created_at', 'updated_at', + 'deleted_at', 'state')): + super(TestShowListAudit, self).assert_expected( + expected, actual, keys) + + @test.attr(type='smoke') + def test_show_audit(self): + _, audit = self.client.show_audit( + self.audit['uuid']) + + initial_audit = self.audit.copy() + del initial_audit['state'] + audit_state = audit['state'] + actual_audit = audit.copy() + del actual_audit['state'] + + self.assertIn(audit_state, self.audit_states) + self.assert_expected(initial_audit, actual_audit) + + @test.attr(type='smoke') + def test_show_audit_with_links(self): + _, audit = self.client.show_audit( + self.audit['uuid']) + self.assertIn('links', audit.keys()) + self.assertEqual(2, len(audit['links'])) + self.assertIn(audit['uuid'], + audit['links'][0]['href']) + + @test.attr(type="smoke") + def test_list_audits(self): + _, body = self.client.list_audits() + self.assertIn(self.audit['uuid'], + [i['uuid'] for i in body['audits']]) + # Verify self links. + for audit in body['audits']: + self.validate_self_link('audits', audit['uuid'], + audit['links'][0]['href']) + + @test.attr(type='smoke') + def test_list_with_limit(self): + # We create 3 extra audits to exceed the limit we fix + for _ in range(3): + self.create_audit(self.audit_template['uuid']) + + _, body = self.client.list_audits(limit=3) + + next_marker = body['audits'][-1]['uuid'] + self.assertEqual(len(body['audits']), 3) + self.assertIn(next_marker, body['next']) + + # @decorators.skip_because(bug="1533220") + @test.attr(type='smoke') + def test_list_audits_related_to_given_audit_template(self): + _, body = self.client.list_audit_by_audit_template( + self.audit_template['uuid']) + self.assertIn(self.audit['uuid'], [n['uuid'] for n in body['audits']])