From 8c6bf734af8b1cbd07386f16a9dd64ac5558e6ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20Fran=C3=A7oise?= Date: Fri, 22 Apr 2016 15:42:36 +0200 Subject: [PATCH] Add goal_name & strategy_name in /audit_templates In this changeset, I added both the 'goal_name' and the 'strategy_name' field. Change-Id: Ic164df84d4e23ec75b2b2f4b358cf827d0ad7fa5 Related-Bug: #1573582 --- watcher/api/controllers/v1/audit_template.py | 176 +++++++++++----- watcher/db/sqlalchemy/api.py | 2 + watcher/tests/api/v1/test_audit_templates.py | 194 ++++++++++-------- .../services/infra_optim/v1/json/client.py | 14 +- .../tests/api/admin/base.py | 21 +- .../tests/api/admin/test_audit_template.py | 74 ++++--- watcher_tempest_plugin/tests/scenario/base.py | 21 +- 7 files changed, 303 insertions(+), 199 deletions(-) diff --git a/watcher/api/controllers/v1/audit_template.py b/watcher/api/controllers/v1/audit_template.py index c6f104e3f..a1a2f27c0 100644 --- a/watcher/api/controllers/v1/audit_template.py +++ b/watcher/api/controllers/v1/audit_template.py @@ -87,48 +87,51 @@ class AuditTemplatePostType(wtypes.Base): extra = wtypes.wsattr({wtypes.text: types.jsontype}, mandatory=False) """The metadata of the audit template""" - goal_uuid = wtypes.wsattr(types.uuid, mandatory=True) - """Goal UUID of the audit template""" + goal = wtypes.wsattr(wtypes.text, mandatory=True) + """Goal UUID or name of the audit template""" - strategy_uuid = wsme.wsattr(types.uuid, mandatory=False) - """Strategy UUID of the audit template""" + strategy = wtypes.wsattr(wtypes.text, mandatory=False) + """Strategy UUID or name of the audit template""" version = wtypes.text """Internal version of the audit template""" def as_audit_template(self): - related_strategy_uuid = self.strategy_uuid or None return AuditTemplate( name=self.name, description=self.description, deadline=self.deadline, host_aggregate=self.host_aggregate, extra=self.extra, - goal_id=self.goal_uuid, # Dirty trick ... - goal_uuid=self.goal_uuid, - strategy_id=related_strategy_uuid, # Dirty trick ... - strategy_uuid=related_strategy_uuid, + goal_id=self.goal, # Dirty trick ... + goal=self.goal, + strategy_id=self.strategy, # Dirty trick ... + strategy_uuid=self.strategy, version=self.version, ) @staticmethod def validate(audit_template): available_goals = objects.Goal.list(AuditTemplatePostType._ctx) - available_goals_map = {g.uuid: g for g in available_goals} - if audit_template.goal_uuid not in available_goals_map: - raise exception.InvalidGoal(goal=audit_template.goal_uuid) + available_goal_uuids_map = {g.uuid: g for g in available_goals} + available_goal_names_map = {g.name: g for g in available_goals} + if audit_template.goal in available_goal_uuids_map: + goal = available_goal_uuids_map[audit_template.goal] + elif audit_template.goal in available_goal_names_map: + goal = available_goal_names_map[audit_template.goal] + else: + raise exception.InvalidGoal(goal=audit_template.goal) - if audit_template.strategy_uuid: + if audit_template.strategy: available_strategies = objects.Strategy.list( AuditTemplatePostType._ctx) available_strategies_map = { s.uuid: s for s in available_strategies} - if audit_template.strategy_uuid not in available_strategies_map: + if audit_template.strategy not in available_strategies_map: raise exception.InvalidStrategy( - strategy=audit_template.strategy_uuid) + strategy=audit_template.strategy) - goal = available_goals_map[audit_template.goal_uuid] - strategy = available_strategies_map[audit_template.strategy_uuid] + strategy = available_strategies_map[audit_template.strategy] # Check that the strategy we indicate is actually related to the # specified goal if strategy.goal_id != goal.id: @@ -140,6 +143,12 @@ class AuditTemplatePostType(wtypes.Base): "'%(goal)s' goal. Possible choices: %(choices)s") % dict(strategy=strategy.name, goal=goal.name, choices=", ".join(choices))) + audit_template.strategy = strategy.uuid + + # We force the UUID so that we do not need to query the DB with the + # name afterwards + audit_template.goal = goal.uuid + return audit_template @@ -153,43 +162,50 @@ class AuditTemplatePatchType(types.JsonPatchType): @staticmethod def validate(patch): - if patch.path == "/goal_uuid" and patch.op != "remove": + if patch.path == "/goal" and patch.op != "remove": AuditTemplatePatchType._validate_goal(patch) - elif patch.path == "/goal_uuid" and patch.op == "remove": + elif patch.path == "/goal" and patch.op == "remove": raise exception.OperationNotPermitted( - _("Cannot remove 'goal_uuid' attribute " + _("Cannot remove 'goal' attribute " "from an audit template")) - if patch.path == "/strategy_uuid": + if patch.path == "/strategy": AuditTemplatePatchType._validate_strategy(patch) return types.JsonPatchType.validate(patch) @staticmethod def _validate_goal(patch): patch.path = "/goal_id" - goal_uuid = patch.value + goal = patch.value - if goal_uuid: + if goal: available_goals = objects.Goal.list( AuditTemplatePatchType._ctx) - available_goals_map = {g.uuid: g for g in available_goals} - if goal_uuid not in available_goals_map: - raise exception.InvalidGoal(goal=goal_uuid) - - patch.value = available_goals_map[goal_uuid].id + available_goal_uuids_map = {g.uuid: g for g in available_goals} + available_goal_names_map = {g.name: g for g in available_goals} + if goal in available_goal_uuids_map: + patch.value = available_goal_uuids_map[goal].id + elif goal in available_goal_names_map: + patch.value = available_goal_names_map[goal].id + else: + raise exception.InvalidGoal(goal=goal) @staticmethod def _validate_strategy(patch): patch.path = "/strategy_id" - strategy_uuid = patch.value - if strategy_uuid: + strategy = patch.value + if strategy: available_strategies = objects.Strategy.list( AuditTemplatePatchType._ctx) - available_strategies_map = { + available_strategy_uuids_map = { s.uuid: s for s in available_strategies} - if strategy_uuid not in available_strategies_map: - raise exception.InvalidStrategy(strategy=strategy_uuid) - - patch.value = available_strategies_map[strategy_uuid].id + available_strategy_names_map = { + s.name: s for s in available_strategies} + if strategy in available_strategy_uuids_map: + patch.value = available_strategy_uuids_map[strategy].id + elif strategy in available_strategy_names_map: + patch.value = available_strategy_names_map[strategy].id + else: + raise exception.InvalidStrategy(strategy=strategy) class AuditTemplate(base.APIBase): @@ -201,7 +217,10 @@ class AuditTemplate(base.APIBase): """ _goal_uuid = None + _goal_name = None + _strategy_uuid = None + _strategy_name = None def _get_goal(self, value): if value == wtypes.Unset: @@ -259,6 +278,26 @@ class AuditTemplate(base.APIBase): if strategy: self._strategy_uuid = strategy.uuid + def _get_goal_name(self): + return self._goal_name + + def _set_goal_name(self, value): + if value and self._goal_name != value: + self._goal_name = None + goal = self._get_goal(value) + if goal: + self._goal_name = goal.name + + def _get_strategy_name(self): + return self._strategy_name + + def _set_strategy_name(self, value): + if value and self._strategy_name != value: + self._strategy_name = None + strategy = self._get_strategy(value) + if strategy: + self._strategy_name = strategy.name + uuid = wtypes.wsattr(types.uuid, readonly=True) """Unique UUID for this audit template""" @@ -279,11 +318,19 @@ class AuditTemplate(base.APIBase): goal_uuid = wsme.wsproperty( wtypes.text, _get_goal_uuid, _set_goal_uuid, mandatory=True) - """Goal UUID of the audit template""" + """Goal UUID the audit template refers to""" + + goal_name = wsme.wsproperty( + wtypes.text, _get_goal_name, _set_goal_name, mandatory=False) + """The name of the goal this audit template refers to""" strategy_uuid = wsme.wsproperty( wtypes.text, _get_strategy_uuid, _set_strategy_uuid, mandatory=False) - """Strategy UUID the audit template""" + """Strategy UUID the audit template refers to""" + + strategy_name = wsme.wsproperty( + wtypes.text, _get_strategy_name, _set_strategy_name, mandatory=False) + """The name of the strategy this audit template refers to""" version = wtypes.text """Internal version of the audit template""" @@ -312,17 +359,22 @@ class AuditTemplate(base.APIBase): # goal_uuid & strategy_uuid are not part of # objects.AuditTemplate.fields because they're API-only attributes. self.fields.append('goal_uuid') + self.fields.append('goal_name') self.fields.append('strategy_uuid') + self.fields.append('strategy_name') setattr(self, 'goal_uuid', kwargs.get('goal_id', wtypes.Unset)) + setattr(self, 'goal_name', kwargs.get('goal_id', wtypes.Unset)) setattr(self, 'strategy_uuid', kwargs.get('strategy_id', wtypes.Unset)) + setattr(self, 'strategy_name', + kwargs.get('strategy_id', wtypes.Unset)) @staticmethod def _convert_with_links(audit_template, url, expand=True): if not expand: audit_template.unset_fields_except( - ['uuid', 'name', 'host_aggregate', - 'goal_uuid', 'strategy_uuid']) + ['uuid', 'name', 'host_aggregate', 'goal_uuid', 'goal_name', + 'strategy_uuid', 'strategy_name']) # The numeric ID should not be exposed to # the user, it's internal only. @@ -404,7 +456,7 @@ class AuditTemplatesController(rest.RestController): resource_url=None): api_utils.validate_search_filters( filters, list(objects.audit_template.AuditTemplate.fields.keys()) + - ["goal_uuid", "strategy_uuid"]) + ["goal_uuid", "goal_name", "strategy_uuid", "strategy_name"]) limit = api_utils.validate_limit(limit) api_utils.validate_sort_dir(sort_dir) @@ -428,33 +480,43 @@ class AuditTemplatesController(rest.RestController): sort_key=sort_key, sort_dir=sort_dir) - @wsme_pecan.wsexpose(AuditTemplateCollection, types.uuid, types.uuid, + @wsme_pecan.wsexpose(AuditTemplateCollection, wtypes.text, wtypes.text, types.uuid, int, wtypes.text, wtypes.text) - def get_all(self, goal_uuid=None, strategy_uuid=None, marker=None, + def get_all(self, goal=None, strategy=None, marker=None, limit=None, sort_key='id', sort_dir='asc'): """Retrieve a list of audit templates. - :param goal_uuid: goal UUID to filter by - :param strategy_uuid: strategy UUID to filter by + :param goal: goal UUID or name to filter by + :param strategy: strategy UUID or name to filter by :param marker: pagination marker for large data sets. :param limit: maximum number of resources to return in a single result. :param sort_key: column to sort results by. Default: id. :param sort_dir: direction to sort. "asc" or "desc". Default: asc. """ - filters = api_utils.as_filters_dict(goal_uuid=goal_uuid, - strategy_uuid=strategy_uuid) + filters = {} + if goal: + if common_utils.is_uuid_like(goal): + filters['goal_uuid'] = goal + else: + filters['goal_name'] = goal + + if strategy: + if common_utils.is_uuid_like(strategy): + filters['strategy_uuid'] = strategy + else: + filters['strategy_name'] = strategy return self._get_audit_templates_collection( filters, marker, limit, sort_key, sort_dir) - @wsme_pecan.wsexpose(AuditTemplateCollection, types.uuid, types.uuid, + @wsme_pecan.wsexpose(AuditTemplateCollection, wtypes.text, wtypes.text, types.uuid, int, wtypes.text, wtypes.text) - def detail(self, goal_uuid=None, strategy_uuid=None, marker=None, + def detail(self, goal=None, strategy=None, marker=None, limit=None, sort_key='id', sort_dir='asc'): """Retrieve a list of audit templates with detail. - :param goal_uuid: goal UUID to filter by - :param strategy_uuid: strategy UUID to filter by + :param goal: goal UUID or name to filter by + :param strategy: strategy UUID or name to filter by :param marker: pagination marker for large data sets. :param limit: maximum number of resources to return in a single result. :param sort_key: column to sort results by. Default: id. @@ -465,8 +527,18 @@ class AuditTemplatesController(rest.RestController): if parent != "audit_templates": raise exception.HTTPNotFound - filters = api_utils.as_filters_dict(goal_uuid=goal_uuid, - strategy_uuid=strategy_uuid) + filters = {} + if goal: + if common_utils.is_uuid_like(goal): + filters['goal_uuid'] = goal + else: + filters['goal_name'] = goal + + if strategy: + if common_utils.is_uuid_like(strategy): + filters['strategy_uuid'] = strategy + else: + filters['strategy_name'] = strategy expand = True resource_url = '/'.join(['audit_templates', 'detail']) diff --git a/watcher/db/sqlalchemy/api.py b/watcher/db/sqlalchemy/api.py index fc283a9b8..7524aa786 100644 --- a/watcher/db/sqlalchemy/api.py +++ b/watcher/db/sqlalchemy/api.py @@ -295,7 +295,9 @@ class Connection(api.BaseConnection): 'goal_id', 'strategy_id'] join_fieldmap = { 'goal_uuid': ("uuid", models.Goal), + 'goal_name': ("name", models.Goal), 'strategy_uuid': ("uuid", models.Strategy), + 'strategy_name': ("name", models.Strategy), } return self._add_filters( diff --git a/watcher/tests/api/v1/test_audit_templates.py b/watcher/tests/api/v1/test_audit_templates.py index a87651df4..2e2e5df41 100644 --- a/watcher/tests/api/v1/test_audit_templates.py +++ b/watcher/tests/api/v1/test_audit_templates.py @@ -11,6 +11,7 @@ # limitations under the License. import datetime +import itertools import mock from oslo_config import cfg @@ -36,8 +37,8 @@ def post_get_test_audit_template(**kw): del audit_template['uuid'] del audit_template['goal_id'] del audit_template['strategy_id'] - audit_template['goal_uuid'] = kw.get('goal_uuid', goal['uuid']) - audit_template['strategy_uuid'] = kw.get('strategy_uuid', strategy['uuid']) + audit_template['goal'] = kw.get('goal', goal['uuid']) + audit_template['strategy'] = kw.get('strategy', strategy['uuid']) return audit_template @@ -51,28 +52,42 @@ class TestAuditTemplateObject(base.TestCase): self.assertEqual(wtypes.Unset, audit_template.name) -class TestListAuditTemplate(api_base.FunctionalTest): +class FunctionalTestWithSetup(api_base.FunctionalTest): def setUp(self): - super(self.__class__, self).setUp() + super(FunctionalTestWithSetup, self).setUp() self.fake_goal1 = obj_utils.get_test_goal( self.context, id=1, uuid=utils.generate_uuid(), name="DUMMY_1") self.fake_goal2 = obj_utils.get_test_goal( self.context, id=2, uuid=utils.generate_uuid(), name="DUMMY_2") self.fake_goal1.create() self.fake_goal2.create() + self.fake_strategy1 = obj_utils.get_test_strategy( + self.context, id=1, uuid=utils.generate_uuid(), name="STRATEGY_1", + goal_id=self.fake_goal1.id) + self.fake_strategy2 = obj_utils.get_test_strategy( + self.context, id=2, uuid=utils.generate_uuid(), name="STRATEGY_2", + goal_id=self.fake_goal2.id) + self.fake_strategy1.create() + self.fake_strategy2.create() + + +class TestListAuditTemplate(FunctionalTestWithSetup): def test_empty(self): response = self.get_json('/audit_templates') self.assertEqual([], response['audit_templates']) def _assert_audit_template_fields(self, audit_template): - audit_template_fields = ['name', 'goal_uuid', 'host_aggregate'] + audit_template_fields = ['name', 'goal_uuid', 'goal_name', + 'strategy_uuid', 'strategy_name', + 'host_aggregate'] for field in audit_template_fields: self.assertIn(field, audit_template) def test_one(self): - audit_template = obj_utils.create_test_audit_template(self.context) + audit_template = obj_utils.create_test_audit_template( + self.context, strategy_id=self.fake_strategy1.id) response = self.get_json('/audit_templates') self.assertEqual(audit_template.uuid, response['audit_templates'][0]["uuid"]) @@ -146,53 +161,57 @@ class TestListAuditTemplate(api_base.FunctionalTest): def test_many(self): audit_template_list = [] - for id_ in range(5): + for id_ in range(1, 6): audit_template = obj_utils.create_test_audit_template( self.context, id=id_, uuid=utils.generate_uuid(), name='My Audit Template {0}'.format(id_)) - audit_template_list.append(audit_template.uuid) + audit_template_list.append(audit_template) + response = self.get_json('/audit_templates') self.assertEqual(len(audit_template_list), len(response['audit_templates'])) uuids = [s['uuid'] for s in response['audit_templates']] - self.assertEqual(sorted(audit_template_list), sorted(uuids)) + self.assertEqual( + sorted([at.uuid for at in audit_template_list]), + sorted(uuids)) def test_many_without_soft_deleted(self): audit_template_list = [] - for id_ in [1, 2, 3]: + for id_ in range(1, 6): audit_template = obj_utils.create_test_audit_template( self.context, id=id_, uuid=utils.generate_uuid(), name='My Audit Template {0}'.format(id_)) - audit_template_list.append(audit_template.uuid) - for id_ in [4, 5]: - audit_template = obj_utils.create_test_audit_template( - self.context, id=id_, uuid=utils.generate_uuid(), - name='My Audit Template {0}'.format(id_)) - audit_template.soft_delete() + audit_template_list.append(audit_template) + + # We soft delete the ones with ID 4 and 5 + [at.soft_delete() for at in audit_template_list[3:]] + response = self.get_json('/audit_templates') self.assertEqual(3, len(response['audit_templates'])) uuids = [s['uuid'] for s in response['audit_templates']] - self.assertEqual(sorted(audit_template_list), sorted(uuids)) + self.assertEqual( + sorted([at.uuid for at in audit_template_list[:3]]), + sorted(uuids)) def test_many_with_soft_deleted(self): audit_template_list = [] - for id_ in [1, 2, 3]: + for id_ in range(1, 6): audit_template = obj_utils.create_test_audit_template( self.context, id=id_, uuid=utils.generate_uuid(), name='My Audit Template {0}'.format(id_)) - audit_template_list.append(audit_template.uuid) - for id_ in [4, 5]: - audit_template = obj_utils.create_test_audit_template( - self.context, id=id_, uuid=utils.generate_uuid(), - name='My Audit Template {0}'.format(id_)) - audit_template.soft_delete() - audit_template_list.append(audit_template.uuid) + audit_template_list.append(audit_template) + + # We soft delete the ones with ID 4 and 5 + [at.soft_delete() for at in audit_template_list[3:]] + response = self.get_json('/audit_templates', headers={'X-Show-Deleted': 'True'}) self.assertEqual(5, len(response['audit_templates'])) uuids = [s['uuid'] for s in response['audit_templates']] - self.assertEqual(sorted(audit_template_list), sorted(uuids)) + self.assertEqual( + sorted([at.uuid for at in audit_template_list]), + sorted(uuids)) def test_links(self): uuid = utils.generate_uuid() @@ -230,43 +249,64 @@ class TestListAuditTemplate(api_base.FunctionalTest): self.assertIn(next_marker, response['next']) def test_filter_by_goal_uuid(self): - for id_ in range(1, 3): + for id_, goal_id in enumerate(itertools.chain.from_iterable([ + itertools.repeat(self.fake_goal1.id, 3), + itertools.repeat(self.fake_goal2.id, 2)]), 1): obj_utils.create_test_audit_template( self.context, id=id_, uuid=utils.generate_uuid(), name='My Audit Template {0}'.format(id_), - goal_id=self.fake_goal1.id) - - for id_ in range(3, 6): - obj_utils.create_test_audit_template( - self.context, id=id_, uuid=utils.generate_uuid(), - name='My Audit Template {0}'.format(id_), - goal_id=self.fake_goal2.id) + goal_id=goal_id) response = self.get_json( - '/audit_templates?goal_uuid=%s' % self.fake_goal2.uuid) - self.assertEqual(3, len(response['audit_templates'])) + '/audit_templates?goal=%s' % self.fake_goal2.uuid) + self.assertEqual(2, len(response['audit_templates'])) + + def test_filter_by_goal_name(self): + for id_, goal_id in enumerate(itertools.chain.from_iterable([ + itertools.repeat(self.fake_goal1.id, 3), + itertools.repeat(self.fake_goal2.id, 2)]), 1): + obj_utils.create_test_audit_template( + self.context, id=id_, uuid=utils.generate_uuid(), + name='My Audit Template {0}'.format(id_), + goal_id=goal_id) + + response = self.get_json( + '/audit_templates?goal=%s' % self.fake_goal2.name) + self.assertEqual(2, len(response['audit_templates'])) + + def test_filter_by_strategy_uuid(self): + for id_, strategy_id in enumerate(itertools.chain.from_iterable([ + itertools.repeat(self.fake_strategy1.id, 3), + itertools.repeat(self.fake_strategy2.id, 2)]), 1): + obj_utils.create_test_audit_template( + self.context, id=id_, uuid=utils.generate_uuid(), + name='My Audit Template {0}'.format(id_), + strategy_id=strategy_id) + + response = self.get_json( + '/audit_templates?strategy=%s' % self.fake_strategy2.uuid) + self.assertEqual(2, len(response['audit_templates'])) + + def test_filter_by_strategy_name(self): + for id_, strategy_id in enumerate(itertools.chain.from_iterable([ + itertools.repeat(self.fake_strategy1.id, 3), + itertools.repeat(self.fake_strategy2.id, 2)]), 1): + obj_utils.create_test_audit_template( + self.context, id=id_, uuid=utils.generate_uuid(), + name='My Audit Template {0}'.format(id_), + strategy_id=strategy_id) + + response = self.get_json( + '/audit_templates?strategy=%s' % self.fake_strategy2.name) + self.assertEqual(2, len(response['audit_templates'])) -class TestPatch(api_base.FunctionalTest): +class TestPatch(FunctionalTestWithSetup): def setUp(self): super(TestPatch, self).setUp() self.audit_template = obj_utils.create_test_audit_template( self.context, strategy_id=None) - self.fake_goal1 = obj_utils.get_test_goal( - self.context, id=1, uuid=utils.generate_uuid(), name="DUMMY_1") - self.fake_goal2 = obj_utils.get_test_goal( - self.context, id=2, uuid=utils.generate_uuid(), name="DUMMY_2") - self.fake_goal1.create() - self.fake_goal2.create() - self.fake_strategy1 = obj_utils.get_test_strategy( - self.context, id=1, uuid=utils.generate_uuid(), name="STRATEGY_1", - goal_id=self.fake_goal1.id) - self.fake_strategy2 = obj_utils.get_test_strategy( - self.context, id=2, uuid=utils.generate_uuid(), name="STRATEGY_2", - goal_id=self.fake_goal2.id) - self.fake_strategy1.create() - self.fake_strategy2.create() @mock.patch.object(timeutils, 'utcnow') def test_replace_goal_uuid(self, mock_utcnow): @@ -280,7 +320,7 @@ class TestPatch(api_base.FunctionalTest): response = self.patch_json( '/audit_templates/%s' % self.audit_template.uuid, - [{'path': '/goal_uuid', 'value': new_goal_uuid, + [{'path': '/goal', 'value': new_goal_uuid, 'op': 'replace'}]) self.assertEqual('application/json', response.content_type) self.assertEqual(200, response.status_code) @@ -304,7 +344,7 @@ class TestPatch(api_base.FunctionalTest): response = self.patch_json( '/audit_templates/%s' % self.audit_template.name, - [{'path': '/goal_uuid', 'value': new_goal_uuid, + [{'path': '/goal', 'value': new_goal_uuid, 'op': 'replace'}]) self.assertEqual('application/json', response.content_type) self.assertEqual(200, response.status_code) @@ -319,7 +359,7 @@ class TestPatch(api_base.FunctionalTest): def test_replace_non_existent_audit_template(self): response = self.patch_json( '/audit_templates/%s' % utils.generate_uuid(), - [{'path': '/goal_uuid', 'value': self.fake_goal1.uuid, + [{'path': '/goal', 'value': self.fake_goal1.uuid, 'op': 'replace'}], expect_errors=True) self.assertEqual(404, response.status_int) @@ -334,7 +374,7 @@ class TestPatch(api_base.FunctionalTest): ) as cn_mock: response = self.patch_json( '/audit_templates/%s' % self.audit_template.uuid, - [{'path': '/goal_uuid', 'value': utils.generate_uuid(), + [{'path': '/goal', 'value': utils.generate_uuid(), 'op': 'replace'}], expect_errors=True) self.assertEqual(400, response.status_int) @@ -343,7 +383,7 @@ class TestPatch(api_base.FunctionalTest): def test_add_goal_uuid(self): response = self.patch_json( '/audit_templates/%s' % self.audit_template.uuid, - [{'path': '/goal_uuid', + [{'path': '/goal', 'value': self.fake_goal2.uuid, 'op': 'add'}]) self.assertEqual('application/json', response.content_type) @@ -356,7 +396,7 @@ class TestPatch(api_base.FunctionalTest): def test_add_strategy_uuid(self): response = self.patch_json( '/audit_templates/%s' % self.audit_template.uuid, - [{'path': '/strategy_uuid', + [{'path': '/strategy', 'value': self.fake_strategy1.uuid, 'op': 'add'}]) self.assertEqual('application/json', response.content_type) @@ -369,7 +409,7 @@ class TestPatch(api_base.FunctionalTest): def test_replace_strategy_uuid(self): response = self.patch_json( '/audit_templates/%s' % self.audit_template.uuid, - [{'path': '/strategy_uuid', + [{'path': '/strategy', 'value': self.fake_strategy2['uuid'], 'op': 'replace'}]) self.assertEqual('application/json', response.content_type) @@ -383,7 +423,7 @@ class TestPatch(api_base.FunctionalTest): def test_replace_invalid_strategy(self): response = self.patch_json( '/audit_templates/%s' % self.audit_template.uuid, - [{'path': '/strategy_uuid', + [{'path': '/strategy', 'value': utils.generate_uuid(), # Does not exist 'op': 'replace'}], expect_errors=True) self.assertEqual('application/json', response.content_type) @@ -411,7 +451,7 @@ class TestPatch(api_base.FunctionalTest): response = self.patch_json( '/audit_templates/%s' % self.audit_template.uuid, - [{'path': '/strategy_uuid', 'op': 'remove'}]) + [{'path': '/strategy', 'op': 'remove'}]) self.assertEqual('application/json', response.content_type) self.assertEqual(200, response.status_code) @@ -422,7 +462,7 @@ class TestPatch(api_base.FunctionalTest): response = self.patch_json( '/audit_templates/%s' % self.audit_template.uuid, - [{'path': '/goal_uuid', 'op': 'remove'}], + [{'path': '/goal', 'op': 'remove'}], expect_errors=True) self.assertEqual(403, response.status_code) self.assertEqual('application/json', response.content_type) @@ -447,31 +487,13 @@ class TestPatch(api_base.FunctionalTest): self.assertTrue(response.json['error_message']) -class TestPost(api_base.FunctionalTest): - - def setUp(self): - super(TestPost, self).setUp() - - self.fake_goal1 = obj_utils.get_test_goal( - self.context, id=1, uuid=utils.generate_uuid(), name="DUMMY_1") - self.fake_goal2 = obj_utils.get_test_goal( - self.context, id=2, uuid=utils.generate_uuid(), name="DUMMY_2") - self.fake_goal1.create() - self.fake_goal2.create() - self.fake_strategy1 = obj_utils.get_test_strategy( - self.context, id=1, uuid=utils.generate_uuid(), name="STRATEGY_1", - goal_id=self.fake_goal1.id) - self.fake_strategy2 = obj_utils.get_test_strategy( - self.context, id=2, uuid=utils.generate_uuid(), name="STRATEGY_2", - goal_id=self.fake_goal2.id) - self.fake_strategy1.create() - self.fake_strategy2.create() +class TestPost(FunctionalTestWithSetup): @mock.patch.object(timeutils, 'utcnow') def test_create_audit_template(self, mock_utcnow): audit_template_dict = post_get_test_audit_template( - goal_uuid=self.fake_goal1.uuid, - strategy_uuid=self.fake_strategy1.uuid) + goal=self.fake_goal1.uuid, + strategy=self.fake_strategy1.uuid) test_time = datetime.datetime(2000, 1, 1, 0, 0) mock_utcnow.return_value = test_time @@ -496,21 +518,21 @@ class TestPost(api_base.FunctionalTest): def test_create_audit_template_does_autogenerate_id(self): audit_template_dict = post_get_test_audit_template( - goal_uuid=self.fake_goal1.uuid, strategy_uuid=None) + goal=self.fake_goal1.uuid, strategy=None) with mock.patch.object( self.dbapi, 'create_audit_template', wraps=self.dbapi.create_audit_template ) as cn_mock: response = self.post_json('/audit_templates', audit_template_dict) - self.assertEqual(audit_template_dict['goal_uuid'], + self.assertEqual(audit_template_dict['goal'], response.json['goal_uuid']) # Check that 'id' is not in first arg of positional args self.assertNotIn('id', cn_mock.call_args[0][0]) def test_create_audit_template_generate_uuid(self): audit_template_dict = post_get_test_audit_template( - goal_uuid=self.fake_goal1.uuid, strategy_uuid=None) + goal=self.fake_goal1.uuid, strategy=None) response = self.post_json('/audit_templates', audit_template_dict) self.assertEqual('application/json', response.content_type) @@ -552,7 +574,7 @@ class TestPost(api_base.FunctionalTest): ) as cn_mock: audit_template_dict = post_get_test_audit_template( goal_uuid=self.fake_goal1['uuid'], - strategy_uuid=self.fake_strategy2['uuid']) + strategy=self.fake_strategy2['uuid']) response = self.post_json('/audit_templates', audit_template_dict, expect_errors=True) self.assertEqual(400, response.status_int) 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 725910d98..b72c158db 100644 --- a/watcher_tempest_plugin/services/infra_optim/v1/json/client.py +++ b/watcher_tempest_plugin/services/infra_optim/v1/json/client.py @@ -58,17 +58,13 @@ class InfraOptimClientJSON(base.BaseInfraOptimClient): def create_audit_template(self, **kwargs): """Creates an audit template with the specified parameters. - :param name: The name of the audit template. Default: My Audit Template + :param name: The name of the audit template. :param description: The description of the audit template. - Default: AT Description :param goal_uuid: The related Goal UUID associated. - Default: None :param strategy_uuid: The related Strategy UUID associated. - Default: None :param host_aggregate: ID of the host aggregate targeted by - this audit template. Default: 1 - :param extra: IMetadata associated to this audit template. - Default: {} + this audit template. + :param extra: Metadata associated to this audit template. :return: A tuple with the server response and the created audit template. """ @@ -80,8 +76,8 @@ class InfraOptimClientJSON(base.BaseInfraOptimClient): audit_template = { 'name': parameters.get('name', unique_name), 'description': parameters.get('description'), - 'goal_uuid': parameters.get('goal_uuid'), - 'strategy_uuid': parameters.get('strategy_uuid'), + 'goal': parameters.get('goal'), + 'strategy': parameters.get('strategy'), 'host_aggregate': parameters.get('host_aggregate', 1), 'extra': parameters.get('extra', {}), } diff --git a/watcher_tempest_plugin/tests/api/admin/base.py b/watcher_tempest_plugin/tests/api/admin/base.py index f7602b729..87cdfe2d9 100644 --- a/watcher_tempest_plugin/tests/api/admin/base.py +++ b/watcher_tempest_plugin/tests/api/admin/base.py @@ -114,30 +114,25 @@ class BaseInfraOptimTest(test.BaseTestCase): # ### AUDIT TEMPLATES ### # @classmethod - def create_audit_template(cls, goal_uuid, name=None, description=None, - strategy_uuid=None, host_aggregate=None, + def create_audit_template(cls, goal, name=None, description=None, + strategy=None, host_aggregate=None, extra=None): """Wrapper utility for creating a test audit template - :param goal_uuid: The goal UUID related to the audit template. - Default: DUMMY + :param goal: Goal UUID or name related to the audit template. :param name: The name of the audit template. Default: My Audit Template :param description: The description of the audit template. - Default: AT Description - :param strategy_uuid: The strategy UUID related to the audit template. - Default: dummy + :param strategy: Strategy UUID or name related to the audit template. :param host_aggregate: ID of the host aggregate targeted by - this audit template. Default: 1 - :param extra: IMetadata associated to this audit template. - Default: {} + this audit template. + :param extra: Metadata associated to this audit template. :return: A tuple with The HTTP response and its body """ description = description or data_utils.rand_name( 'test-audit_template') resp, body = cls.client.create_audit_template( - name=name, description=description, goal_uuid=goal_uuid, - strategy_uuid=strategy_uuid, host_aggregate=host_aggregate, - extra=extra) + name=name, description=description, goal=goal, strategy=strategy, + host_aggregate=host_aggregate, extra=extra) cls.created_audit_templates.add(body['uuid']) 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 9c86b24c4..81b68bd46 100644 --- a/watcher_tempest_plugin/tests/api/admin/test_audit_template.py +++ b/watcher_tempest_plugin/tests/api/admin/test_audit_template.py @@ -29,35 +29,57 @@ class TestCreateDeleteAuditTemplate(base.BaseInfraOptimTest): @test.attr(type='smoke') def test_create_audit_template(self): - _, goal = self.client.show_goal("DUMMY") + goal_name = "DUMMY" + _, goal = self.client.show_goal(goal_name) - params = {'name': 'my at name %s' % uuid.uuid4(), - 'description': 'my at description', - 'host_aggregate': 12, - 'goal_uuid': goal['uuid'], - 'extra': {'str': 'value', 'int': 123, 'float': 0.123, - 'bool': True, 'list': [1, 2, 3], - 'dict': {'foo': 'bar'}}} + params = { + 'name': 'my at name %s' % uuid.uuid4(), + 'description': 'my at description', + 'host_aggregate': 12, + 'goal': goal['uuid'], + 'extra': {'str': 'value', 'int': 123, 'float': 0.123, + 'bool': True, 'list': [1, 2, 3], + 'dict': {'foo': 'bar'}}} + expected_data = { + 'name': params['name'], + 'description': params['description'], + 'host_aggregate': params['host_aggregate'], + 'goal_uuid': params['goal'], + 'goal_name': goal_name, + 'strategy_uuid': None, + 'strategy_name': None, + 'extra': params['extra']} _, body = self.create_audit_template(**params) - self.assert_expected(params, body) + self.assert_expected(expected_data, body) _, audit_template = self.client.show_audit_template(body['uuid']) self.assert_expected(audit_template, body) @test.attr(type='smoke') def test_create_audit_template_unicode_description(self): - _, goal = self.client.show_goal("DUMMY") - + goal_name = "DUMMY" + _, goal = self.client.show_goal(goal_name) # Use a unicode string for testing: - params = {'name': 'my at name %s' % uuid.uuid4(), - 'description': 'my àt déscrïptïôn', - 'host_aggregate': 12, - 'goal_uuid': goal['uuid'], - 'extra': {'foo': 'bar'}} + params = { + 'name': 'my at name %s' % uuid.uuid4(), + 'description': 'my àt déscrïptïôn', + 'host_aggregate': 12, + 'goal': goal['uuid'], + 'extra': {'foo': 'bar'}} + + expected_data = { + 'name': params['name'], + 'description': params['description'], + 'host_aggregate': params['host_aggregate'], + 'goal_uuid': params['goal'], + 'goal_name': goal_name, + 'strategy_uuid': None, + 'strategy_name': None, + 'extra': params['extra']} _, body = self.create_audit_template(**params) - self.assert_expected(params, body) + self.assert_expected(expected_data, body) _, audit_template = self.client.show_audit_template(body['uuid']) self.assert_expected(audit_template, body) @@ -65,7 +87,7 @@ class TestCreateDeleteAuditTemplate(base.BaseInfraOptimTest): @test.attr(type='smoke') def test_delete_audit_template(self): _, goal = self.client.show_goal("DUMMY") - _, body = self.create_audit_template(goal_uuid=goal['uuid']) + _, body = self.create_audit_template(goal=goal['uuid']) audit_uuid = body['uuid'] self.delete_audit_template(audit_uuid) @@ -83,7 +105,7 @@ class TestAuditTemplate(base.BaseInfraOptimTest): _, cls.goal = cls.client.show_goal("DUMMY") _, cls.strategy = cls.client.show_strategy("dummy") _, cls.audit_template = cls.create_audit_template( - goal_uuid=cls.goal['uuid'], strategy_uuid=cls.strategy['uuid']) + goal=cls.goal['uuid'], strategy=cls.strategy['uuid']) @test.attr(type='smoke') def test_show_audit_template(self): @@ -95,7 +117,7 @@ class TestAuditTemplate(base.BaseInfraOptimTest): @test.attr(type='smoke') def test_filter_audit_template_by_goal_uuid(self): _, audit_templates = self.client.list_audit_templates( - goal_uuid=self.audit_template['goal_uuid']) + goal=self.audit_template['goal_uuid']) audit_template_uuids = [ at["uuid"] for at in audit_templates['audit_templates']] @@ -104,7 +126,7 @@ class TestAuditTemplate(base.BaseInfraOptimTest): @test.attr(type='smoke') def test_filter_audit_template_by_strategy_uuid(self): _, audit_templates = self.client.list_audit_templates( - strategy_uuid=self.audit_template['strategy_uuid']) + strategy=self.audit_template['strategy_uuid']) audit_template_uuids = [ at["uuid"] for at in audit_templates['audit_templates']] @@ -149,7 +171,7 @@ class TestAuditTemplate(base.BaseInfraOptimTest): params = {'name': 'my at name %s' % uuid.uuid4(), 'description': 'my at description', 'host_aggregate': 12, - 'goal_uuid': self.goal['uuid'], + 'goal': self.goal['uuid'], 'extra': {'key1': 'value1', 'key2': 'value2'}} _, body = self.create_audit_template(**params) @@ -168,10 +190,10 @@ class TestAuditTemplate(base.BaseInfraOptimTest): {'path': '/host_aggregate', 'op': 'replace', 'value': new_host_aggregate}, - {'path': '/goal_uuid', + {'path': '/goal', 'op': 'replace', 'value': new_goal['uuid']}, - {'path': '/strategy_uuid', + {'path': '/strategy', 'op': 'replace', 'value': new_strategy['uuid']}, {'path': '/extra/key1', @@ -199,7 +221,7 @@ class TestAuditTemplate(base.BaseInfraOptimTest): params = {'name': name, 'description': description, 'host_aggregate': 12, - 'goal_uuid': self.goal['uuid'], + 'goal': self.goal['uuid'], 'extra': extra} _, audit_template = self.create_audit_template(**params) @@ -237,7 +259,7 @@ class TestAuditTemplate(base.BaseInfraOptimTest): params = {'name': 'my at name %s' % uuid.uuid4(), 'description': 'my at description', 'host_aggregate': 12, - 'goal_uuid': self.goal['uuid']} + 'goal': self.goal['uuid']} _, body = self.create_audit_template(**params) diff --git a/watcher_tempest_plugin/tests/scenario/base.py b/watcher_tempest_plugin/tests/scenario/base.py index a1bd3a7bf..26df64de0 100644 --- a/watcher_tempest_plugin/tests/scenario/base.py +++ b/watcher_tempest_plugin/tests/scenario/base.py @@ -73,30 +73,25 @@ class BaseInfraOptimScenarioTest(manager.ScenarioTest): # ### AUDIT TEMPLATES ### # - def create_audit_template(self, goal_uuid, name=None, description=None, - strategy_uuid=None, host_aggregate=None, + def create_audit_template(self, goal, name=None, description=None, + strategy=None, host_aggregate=None, extra=None): """Wrapper utility for creating a test audit template - :param goal_uuid: The goal UUID related to the audit template. - Default: DUMMY + :param goal: Goal UUID or name related to the audit template. :param name: The name of the audit template. Default: My Audit Template :param description: The description of the audit template. - Default: AT Description - :param strategy_uuid: The strategy UUID related to the audit template. - Default: dummy + :param strategy: Strategy UUID or name related to the audit template. :param host_aggregate: ID of the host aggregate targeted by - this audit template. Default: 1 - :param extra: IMetadata associated to this audit template. - Default: {} + this audit template. + :param extra: Metadata associated to this audit template. :return: A tuple with The HTTP response and its body """ description = description or data_utils.rand_name( 'test-audit_template') resp, body = self.client.create_audit_template( - name=name, description=description, goal_uuid=goal_uuid, - strategy_uuid=strategy_uuid, host_aggregate=host_aggregate, - extra=extra) + name=name, description=description, goal=goal, strategy=strategy, + host_aggregate=host_aggregate, extra=extra) self.addCleanup( self.delete_audit_template,