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 9a28f6ec5..98a87806a 100644 --- a/watcher_tempest_plugin/services/infra_optim/v1/json/client.py +++ b/watcher_tempest_plugin/services/infra_optim/v1/json/client.py @@ -54,25 +54,6 @@ class InfraOptimClientJSON(base.BaseInfraOptimClient): """ return self._show_request('audit_templates', audit_template_uuid) - @base.handle_errors - def filter_audit_template_by_host_aggregate(self, host_aggregate): - """Gets an audit template associated with given host agregate ID. - - :param host_aggregate: Unique identifier of the host aggregate - :return: Serialized audit template as a dictionary. - """ - return self._list_request('/audit_templates', - host_aggregate=host_aggregate) - - @base.handle_errors - def filter_audit_template_by_goal(self, goal): - """Gets an audit template associated with given goal. - - :param goal: goal identifier - :return: Serialized audit template as a dictionary. - """ - return self._list_request('/audit_templates', goal=goal) - @base.handle_errors def create_audit_template(self, **kwargs): """Creates an audit template with the specified parameters. @@ -139,12 +120,6 @@ class InfraOptimClientJSON(base.BaseInfraOptimClient): """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. @@ -254,3 +229,24 @@ class InfraOptimClientJSON(base.BaseInfraOptimClient): :return: Serialized goal as a dictionary """ return self._show_request('/goals', goal) + + # ### ACTIONS ### # + + @base.handle_errors + def list_actions(self, **kwargs): + """List all existing actions""" + return self._list_request('/actions', **kwargs) + + @base.handle_errors + def list_actions_detail(self, **kwargs): + """Lists details of all existing actions""" + return self._list_request('/actions/detail', **kwargs) + + @base.handle_errors + def show_action(self, action_uuid): + """Gets a specific action + + :param action_uuid: Unique identifier of the action + :return: Serialized action as a dictionary + """ + return self._show_request('/actions', action_uuid) diff --git a/watcher_tempest_plugin/tests/api/admin/base.py b/watcher_tempest_plugin/tests/api/admin/base.py index 878f122b3..99b080c13 100644 --- a/watcher_tempest_plugin/tests/api/admin/base.py +++ b/watcher_tempest_plugin/tests/api/admin/base.py @@ -22,11 +22,6 @@ from tempest_lib import exceptions as lib_exc 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', 'audit', 'action_plan'] -# RESOURCE_TYPES = ['action', 'action_plan', 'audit', 'audit_template'] - def creates(resource): """Decorator that adds resources to the appropriate cleanup list.""" @@ -47,6 +42,8 @@ def creates(resource): class BaseInfraOptimTest(test.BaseTestCase): """Base class for Infrastructure Optimization API tests.""" + RESOURCE_TYPES = ['audit_template', 'audit'] + @classmethod def setup_credentials(cls): super(BaseInfraOptimTest, cls).setup_credentials() @@ -62,19 +59,18 @@ class BaseInfraOptimTest(test.BaseTestCase): super(BaseInfraOptimTest, cls).resource_setup() cls.created_objects = {} - for resource in RESOURCE_TYPES: + for resource in cls.RESOURCE_TYPES: cls.created_objects[resource] = set() @classmethod def resource_cleanup(cls): """Ensure that all created objects get destroyed.""" - try: - for resource in RESOURCE_TYPES: - uuids = cls.created_objects[resource] + for resource in cls.RESOURCE_TYPES: + obj_uuids = cls.created_objects[resource] delete_method = getattr(cls.client, 'delete_%s' % resource) - for u in uuids: - delete_method(u, ignore_errors=lib_exc.NotFound) + for obj_uuid in obj_uuids: + delete_method(obj_uuid, ignore_errors=lib_exc.NotFound) finally: super(BaseInfraOptimTest, cls).resource_cleanup() @@ -178,21 +174,6 @@ class BaseInfraOptimTest(test.BaseTestCase): # ### ACTION PLANS ### # - @classmethod - @creates('action_plan') - def start_action_plan(cls, audit_uuid, type='ONESHOT', - state='PENDING', deadline=None): - """Wrapper utility for creating a test action plan - - :param audit_uuid: Audit Template UUID this action plan will use - :param type: Audit type (either ONESHOT or CONTINUOUS) - :return: A tuple with The HTTP response and its body - """ - resp, body = cls.client.create_action_plan( - audit_uuid=audit_uuid, type=type, - state=state, deadline=deadline) - return resp, body - @classmethod def delete_action_plan(cls, action_plan_uuid): """Deletes an action plan having the specified UUID diff --git a/watcher_tempest_plugin/tests/api/admin/test_action.py b/watcher_tempest_plugin/tests/api/admin/test_action.py new file mode 100644 index 000000000..f5b485b96 --- /dev/null +++ b/watcher_tempest_plugin/tests/api/admin/test_action.py @@ -0,0 +1,102 @@ +# -*- 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 + +import collections +import functools + +from tempest import test + +from watcher_tempest_plugin.tests.api.admin import base + + +class TestShowListAction(base.BaseInfraOptimTest): + """Tests for actions""" + + @classmethod + def resource_setup(cls): + super(TestShowListAction, cls).resource_setup() + _, cls.audit_template = cls.create_audit_template() + _, cls.audit = cls.create_audit(cls.audit_template['uuid']) + + assert test.call_until_true( + func=functools.partial(cls.has_audit_succeeded, cls.audit['uuid']), + duration=30, + sleep_for=.5 + ) + _, action_plans = cls.client.list_action_plan_by_audit( + cls.audit['uuid']) + cls.action_plan = action_plans['action_plans'][0] + + @test.attr(type='smoke') + def test_show_one_action(self): + _, action = self.client.show_action( + self.action_plan["first_action_uuid"]) + + self.assertEqual(action['uuid'], self.action_plan["first_action_uuid"]) + self.assertEqual(action['action_type'], "nop") + self.assertEqual(action['state'], "PENDING") + + @test.attr(type='smoke') + def test_show_action_with_links(self): + _, action = self.client.show_action( + self.action_plan["first_action_uuid"]) + self.assertIn('links', action.keys()) + self.assertEqual(2, len(action['links'])) + self.assertIn(action['uuid'], action['links'][0]['href']) + + @test.attr(type="smoke") + def test_list_actions(self): + _, body = self.client.list_actions() + + # Verify self links. + for action in body['actions']: + self.validate_self_link('actions', action['uuid'], + action['links'][0]['href']) + + @test.attr(type="smoke") + def test_list_actions_by_action_plan(self): + _, body = self.client.list_actions( + action_plan_uuid=self.action_plan["uuid"]) + + for item in body['actions']: + self.assertEqual(self.action_plan["uuid"], + item['action_plan_uuid']) + + action_counter = collections.Counter( + act['action_type'] for act in body['actions']) + + # A dummy strategy generates 2 "nop" actions and 1 "sleep" action + self.assertEqual(len(body['actions']), 3) + self.assertEqual(action_counter.get("nop"), 2) + self.assertEqual(action_counter.get("sleep"), 1) + + @test.attr(type="smoke") + def test_list_actions_by_audit(self): + _, body = self.client.list_actions(audit_uuid=self.audit["uuid"]) + + for item in body['actions']: + self.assertEqual(self.action_plan["uuid"], + item['action_plan_uuid']) + + action_counter = collections.Counter( + act['action_type'] for act in body['actions']) + + # A dummy strategy generates 2 "nop" actions and 1 "sleep" action + self.assertEqual(len(body['actions']), 3) + self.assertEqual(action_counter.get("nop"), 2) + self.assertEqual(action_counter.get("sleep"), 1) diff --git a/watcher_tempest_plugin/tests/api/admin/test_action_plan.py b/watcher_tempest_plugin/tests/api/admin/test_action_plan.py index 10d969435..d00faf9e3 100644 --- a/watcher_tempest_plugin/tests/api/admin/test_action_plan.py +++ b/watcher_tempest_plugin/tests/api/admin/test_action_plan.py @@ -34,7 +34,7 @@ class TestCreateDeleteExecuteActionPlan(base.BaseInfraOptimTest): self.assertTrue(test.call_until_true( func=functools.partial(self.has_audit_succeeded, audit['uuid']), - duration=10, + duration=30, sleep_for=.5 )) _, action_plans = self.client.list_action_plan_by_audit(audit['uuid']) @@ -52,7 +52,7 @@ class TestCreateDeleteExecuteActionPlan(base.BaseInfraOptimTest): self.assertTrue(test.call_until_true( func=functools.partial(self.has_audit_succeeded, audit['uuid']), - duration=10, + duration=30, sleep_for=.5 )) _, action_plans = self.client.list_action_plan_by_audit(audit['uuid']) @@ -72,7 +72,7 @@ class TestCreateDeleteExecuteActionPlan(base.BaseInfraOptimTest): self.assertTrue(test.call_until_true( func=functools.partial(self.has_audit_succeeded, audit['uuid']), - duration=10, + duration=30, sleep_for=.5 )) _, action_plans = self.client.list_action_plan_by_audit(audit['uuid']) @@ -89,7 +89,7 @@ class TestCreateDeleteExecuteActionPlan(base.BaseInfraOptimTest): self.assertTrue(test.call_until_true( func=functools.partial( self.has_action_plan_finished, action_plan['uuid']), - duration=10, + duration=30, sleep_for=.5 )) _, finished_ap = self.client.show_action_plan(action_plan['uuid']) @@ -109,7 +109,7 @@ class TestShowListActionPlan(base.BaseInfraOptimTest): assert test.call_until_true( func=functools.partial(cls.has_audit_succeeded, cls.audit['uuid']), - duration=10, + duration=30, sleep_for=.5 ) _, action_plans = cls.client.list_action_plan_by_audit( diff --git a/watcher_tempest_plugin/tests/api/admin/test_audit.py b/watcher_tempest_plugin/tests/api/admin/test_audit.py index dadb3fade..b4d2c4ddc 100644 --- a/watcher_tempest_plugin/tests/api/admin/test_audit.py +++ b/watcher_tempest_plugin/tests/api/admin/test_audit.py @@ -179,9 +179,8 @@ class TestShowListAudit(base.BaseInfraOptimTest): 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']) + _, body = self.client.list_audits( + audit_template=self.audit_template['uuid']) self.assertIn(self.audit['uuid'], [n['uuid'] for n in body['audits']]) diff --git a/watcher_tempest_plugin/tests/api/admin/test_audit_template.py b/watcher_tempest_plugin/tests/api/admin/test_audit_template.py index 8cd344432..a22d31bfc 100644 --- a/watcher_tempest_plugin/tests/api/admin/test_audit_template.py +++ b/watcher_tempest_plugin/tests/api/admin/test_audit_template.py @@ -88,8 +88,8 @@ class TestAuditTemplate(base.BaseInfraOptimTest): @decorators.skip_because(bug="1510189") @test.attr(type='smoke') def test_filter_audit_template_by_goal(self): - _, audit_template = self.client.\ - filter_audit_template_by_goal(self.audit_template['goal']) + _, audit_template = self.client.list_audit_templates( + goal=self.audit_template['goal']) self.assert_expected(self.audit_template, audit_template['audit_templates'][0]) @@ -97,9 +97,8 @@ class TestAuditTemplate(base.BaseInfraOptimTest): @decorators.skip_because(bug="1510189") @test.attr(type='smoke') def test_filter_audit_template_by_host_aggregate(self): - _, audit_template = self.client.\ - filter_audit_template_by_host_aggregate( - self.audit_template['host_aggregate']) + _, audit_template = self.client.list_audit_templates( + host_aggregate=self.audit_template['host_aggregate']) self.assert_expected(self.audit_template, audit_template['audit_templates'][0]) diff --git a/watcher_tempest_plugin/tests/scenario/test_execute_dummy_optim.py b/watcher_tempest_plugin/tests/scenario/test_execute_dummy_optim.py index 683bf0a2f..3162aa119 100644 --- a/watcher_tempest_plugin/tests/scenario/test_execute_dummy_optim.py +++ b/watcher_tempest_plugin/tests/scenario/test_execute_dummy_optim.py @@ -17,6 +17,7 @@ from __future__ import unicode_literals +import collections import functools from tempest import test @@ -62,6 +63,16 @@ class TestExecuteDummyStrategy(base.BaseInfraOptimScenarioTest): sleep_for=.5 )) _, finished_ap = self.client.show_action_plan(action_plan['uuid']) + _, action_list = self.client.list_actions( + action_plan_uuid=finished_ap["uuid"]) + + action_counter = collections.Counter( + act['action_type'] for act in action_list['actions']) self.assertIn(updated_ap['state'], ('TRIGGERED', 'ONGOING')) self.assertEqual(finished_ap['state'], 'SUCCEEDED') + + # A dummy strategy generates 2 "nop" actions and 1 "sleep" action + self.assertEqual(len(action_list['actions']), 3) + self.assertEqual(action_counter.get("nop"), 2) + self.assertEqual(action_counter.get("sleep"), 1)