diff --git a/watcher/objects/audit_template.py b/watcher/objects/audit_template.py index 842c556d8..edb753104 100644 --- a/watcher/objects/audit_template.py +++ b/watcher/objects/audit_template.py @@ -49,7 +49,8 @@ provided as a list of key-value pairs. from watcher.common import exception from watcher.common import utils -from watcher.db import api as dbapi +from watcher.db import api as db_api +from watcher import objects from watcher.objects import base from watcher.objects import fields as wfields @@ -57,10 +58,12 @@ from watcher.objects import fields as wfields @base.WatcherObjectRegistry.register class AuditTemplate(base.WatcherPersistentObject, base.WatcherObject, base.WatcherObjectDictCompat): - # Version 1.0: Initial version - VERSION = '1.0' - dbapi = dbapi.get_instance() + # Version 1.0: Initial version + # Version 1.1: Added 'goal' and 'strategy' object field + VERSION = '1.1' + + dbapi = db_api.get_instance() fields = { 'id': wfields.IntegerField(), @@ -70,10 +73,18 @@ class AuditTemplate(base.WatcherPersistentObject, base.WatcherObject, 'scope': wfields.FlexibleListOfDictField(nullable=True), 'goal_id': wfields.IntegerField(), 'strategy_id': wfields.IntegerField(nullable=True), + + 'goal': wfields.ObjectField('Goal', nullable=True), + 'strategy': wfields.ObjectField('Strategy', nullable=True), + } + + object_fields = { + 'goal': (objects.Goal, 'goal_id'), + 'strategy': (objects.Strategy, 'strategy_id'), } @base.remotable_classmethod - def get(cls, context, audit_template_id): + def get(cls, context, audit_template_id, eager=False): """Find an audit template based on its id or uuid :param context: Security context. NOTE: This should only @@ -83,17 +94,18 @@ class AuditTemplate(base.WatcherPersistentObject, base.WatcherObject, A context should be set when instantiating the object, e.g.: AuditTemplate(context) :param audit_template_id: the id *or* uuid of a audit_template. + :param eager: Load object fields if True (Default: False) :returns: a :class:`AuditTemplate` object. """ if utils.is_int_like(audit_template_id): - return cls.get_by_id(context, audit_template_id) + return cls.get_by_id(context, audit_template_id, eager=eager) elif utils.is_uuid_like(audit_template_id): - return cls.get_by_uuid(context, audit_template_id) + return cls.get_by_uuid(context, audit_template_id, eager=eager) else: raise exception.InvalidIdentity(identity=audit_template_id) @base.remotable_classmethod - def get_by_id(cls, context, audit_template_id): + def get_by_id(cls, context, audit_template_id, eager=False): """Find an audit template based on its integer id :param context: Security context. NOTE: This should only @@ -103,17 +115,17 @@ class AuditTemplate(base.WatcherPersistentObject, base.WatcherObject, A context should be set when instantiating the object, e.g.: AuditTemplate(context) :param audit_template_id: the id of a audit_template. + :param eager: Load object fields if True (Default: False) :returns: a :class:`AuditTemplate` object. """ db_audit_template = cls.dbapi.get_audit_template_by_id( - context, - audit_template_id) - audit_template = AuditTemplate._from_db_object(cls(context), - db_audit_template) + context, audit_template_id, eager=eager) + audit_template = cls._from_db_object( + cls(context), db_audit_template, eager=eager) return audit_template @base.remotable_classmethod - def get_by_uuid(cls, context, uuid): + def get_by_uuid(cls, context, uuid, eager=False): """Find an audit template based on uuid :param context: Security context. NOTE: This should only @@ -123,29 +135,33 @@ class AuditTemplate(base.WatcherPersistentObject, base.WatcherObject, A context should be set when instantiating the object, e.g.: AuditTemplate(context) :param uuid: the uuid of a audit_template. + :param eager: Load object fields if True (Default: False) :returns: a :class:`AuditTemplate` object. """ - db_audit_template = cls.dbapi.get_audit_template_by_uuid(context, uuid) - audit_template = AuditTemplate._from_db_object(cls(context), - db_audit_template) + db_audit_template = cls.dbapi.get_audit_template_by_uuid( + context, uuid, eager=eager) + audit_template = cls._from_db_object( + cls(context), db_audit_template, eager=eager) return audit_template @base.remotable_classmethod - def get_by_name(cls, context, name): + def get_by_name(cls, context, name, eager=False): """Find an audit template based on name :param name: the logical name of a audit_template. :param context: Security context + :param eager: Load object fields if True (Default: False) :returns: a :class:`AuditTemplate` object. """ - db_audit_template = cls.dbapi.get_audit_template_by_name(context, name) - audit_template = AuditTemplate._from_db_object(cls(context), - db_audit_template) + db_audit_template = cls.dbapi.get_audit_template_by_name( + context, name, eager=eager) + audit_template = cls._from_db_object( + cls(context), db_audit_template, eager=eager) return audit_template @base.remotable_classmethod def list(cls, context, filters=None, limit=None, marker=None, - sort_key=None, sort_dir=None): + sort_key=None, sort_dir=None, eager=False): """Return a list of :class:`AuditTemplate` objects. :param context: Security context. NOTE: This should only @@ -159,6 +175,7 @@ class AuditTemplate(base.WatcherPersistentObject, base.WatcherObject, :param marker: pagination marker for large data sets. :param sort_key: column to sort results by. :param sort_dir: direction to sort. "asc" or "desc". + :param eager: Load object fields if True (Default: False) :returns: a list of :class:`AuditTemplate` object. """ db_audit_templates = cls.dbapi.get_audit_template_list( @@ -167,17 +184,23 @@ class AuditTemplate(base.WatcherPersistentObject, base.WatcherObject, limit=limit, marker=marker, sort_key=sort_key, - sort_dir=sort_dir) + sort_dir=sort_dir, + eager=eager) - return [cls._from_db_object(cls(context), obj) + return [cls._from_db_object(cls(context), obj, eager=eager) for obj in db_audit_templates] @base.remotable def create(self): - """Create a :class:`AuditTemplate` record in the DB""" + """Create a :class:`AuditTemplate` record in the DB + + :returns: An :class:`AuditTemplate` object. + """ values = self.obj_get_changes() db_audit_template = self.dbapi.create_audit_template(values) - self._from_db_object(self, db_audit_template) + # Note(v-francoise): Always load eagerly upon creation so we can send + # notifications containing information about the related relationships + self._from_db_object(self, db_audit_template, eager=True) def destroy(self): """Delete the :class:`AuditTemplate` from the DB""" @@ -197,14 +220,15 @@ class AuditTemplate(base.WatcherPersistentObject, base.WatcherObject, self.obj_reset_changes() @base.remotable - def refresh(self): + def refresh(self, eager=False): """Loads updates for this :class:`AuditTemplate`. Loads a audit_template with the same uuid from the database and checks for updated attributes. Updates are applied from the loaded audit_template column by column, if there are any updates. + :param eager: Load object fields if True (Default: False) """ - current = self.__class__.get_by_uuid(self._context, uuid=self.uuid) + current = self.get_by_uuid(self._context, uuid=self.uuid, eager=eager) self.obj_refresh(current) @base.remotable diff --git a/watcher/tests/api/v1/test_audit_templates.py b/watcher/tests/api/v1/test_audit_templates.py index d31b36cb9..e17443db4 100644 --- a/watcher/tests/api/v1/test_audit_templates.py +++ b/watcher/tests/api/v1/test_audit_templates.py @@ -305,6 +305,7 @@ class TestPatch(FunctionalTestWithSetup): def setUp(self): super(TestPatch, self).setUp() + obj_utils.create_test_goal(self.context) self.audit_template = obj_utils.create_test_audit_template( self.context, strategy_id=None) @@ -598,6 +599,7 @@ class TestDelete(api_base.FunctionalTest): def setUp(self): super(TestDelete, self).setUp() + obj_utils.create_test_goal(self.context) self.audit_template = obj_utils.create_test_audit_template( self.context) @@ -656,7 +658,7 @@ class TestDelete(api_base.FunctionalTest): self.assertTrue(response.json['error_message']) -class TestAuaditTemplatePolicyEnforcement(api_base.FunctionalTest): +class TestAuditTemplatePolicyEnforcement(api_base.FunctionalTest): def _common_policy_check(self, rule, func, *arg, **kwarg): self.policy.set_rules({ @@ -676,6 +678,7 @@ class TestAuaditTemplatePolicyEnforcement(api_base.FunctionalTest): expect_errors=True) def test_policy_disallow_get_one(self): + obj_utils.create_test_goal(self.context) audit_template = obj_utils.create_test_audit_template(self.context) self._common_policy_check( "audit_template:get", self.get_json, @@ -689,6 +692,7 @@ class TestAuaditTemplatePolicyEnforcement(api_base.FunctionalTest): expect_errors=True) def test_policy_disallow_update(self): + obj_utils.create_test_goal(self.context) audit_template = obj_utils.create_test_audit_template(self.context) self._common_policy_check( "audit_template:update", self.patch_json, @@ -713,6 +717,7 @@ class TestAuaditTemplatePolicyEnforcement(api_base.FunctionalTest): audit_template_dict, expect_errors=True) def test_policy_disallow_delete(self): + obj_utils.create_test_goal(self.context) audit_template = obj_utils.create_test_audit_template(self.context) self._common_policy_check( "audit_template:delete", self.delete, diff --git a/watcher/tests/api/v1/test_audits.py b/watcher/tests/api/v1/test_audits.py index e5cb056f0..70c7b94f5 100644 --- a/watcher/tests/api/v1/test_audits.py +++ b/watcher/tests/api/v1/test_audits.py @@ -78,9 +78,9 @@ class TestListAudit(api_base.FunctionalTest): def setUp(self): super(TestListAudit, self).setUp() - obj_utils.create_test_audit_template(self.context) obj_utils.create_test_goal(self.context) obj_utils.create_test_strategy(self.context) + obj_utils.create_test_audit_template(self.context) def test_empty(self): response = self.get_json('/audits') @@ -249,6 +249,8 @@ class TestPatch(api_base.FunctionalTest): def setUp(self): super(TestPatch, self).setUp() + obj_utils.create_test_goal(self.context) + obj_utils.create_test_strategy(self.context) obj_utils.create_test_audit_template(self.context) self.audit = obj_utils.create_test_audit(self.context, ) p = mock.patch.object(db_api.BaseConnection, 'update_audit') @@ -345,9 +347,9 @@ class TestPost(api_base.FunctionalTest): def setUp(self): super(TestPost, self).setUp() - obj_utils.create_test_audit_template(self.context) obj_utils.create_test_goal(self.context) obj_utils.create_test_strategy(self.context) + obj_utils.create_test_audit_template(self.context) p = mock.patch.object(db_api.BaseConnection, 'create_audit') self.mock_create_audit = p.start() self.mock_create_audit.side_effect = ( @@ -640,6 +642,8 @@ class TestDelete(api_base.FunctionalTest): def setUp(self): super(TestDelete, self).setUp() + obj_utils.create_test_goal(self.context) + obj_utils.create_test_strategy(self.context) obj_utils.create_test_audit_template(self.context) self.audit = obj_utils.create_test_audit(self.context) p = mock.patch.object(db_api.BaseConnection, 'update_audit') @@ -677,7 +681,7 @@ class TestDelete(api_base.FunctionalTest): self.assertTrue(response.json['error_message']) -class TestAuaditPolicyEnforcement(api_base.FunctionalTest): +class TestAuditPolicyEnforcement(api_base.FunctionalTest): def _common_policy_check(self, rule, func, *arg, **kwarg): self.policy.set_rules({ diff --git a/watcher/tests/db/test_audit_template.py b/watcher/tests/db/test_audit_template.py index d639f7267..a885be4f7 100644 --- a/watcher/tests/db/test_audit_template.py +++ b/watcher/tests/db/test_audit_template.py @@ -225,6 +225,11 @@ class TestDbAuditTemplateFilters(base.DbTestCase): class DbAuditTemplateTestCase(base.DbTestCase): + def _create_test_goal(self, **kwargs): + goal = utils.get_test_goal(**kwargs) + self.dbapi.create_goal(goal) + return goal + def _create_test_audit_template(self, **kwargs): audit_template = utils.get_test_audit_template(**kwargs) self.dbapi.create_audit_template(audit_template) @@ -268,18 +273,19 @@ class DbAuditTemplateTestCase(base.DbTestCase): strategy.as_dict(), eager_audit_template.strategy.as_dict()) def test_get_audit_template_list_with_filters(self): + goal = self._create_test_goal(name='DUMMY') audit_template1 = self._create_test_audit_template( id=1, uuid=w_utils.generate_uuid(), name='My Audit Template 1', description='Description of my audit template 1', - goal='DUMMY') + goal_id=goal['id']) audit_template2 = self._create_test_audit_template( id=2, uuid=w_utils.generate_uuid(), name='My Audit Template 2', description='Description of my audit template 2', - goal='DUMMY') + goal_id=goal['id']) res = self.dbapi.get_audit_template_list( self.context, filters={'name': 'My Audit Template 1'}) diff --git a/watcher/tests/db/test_purge.py b/watcher/tests/db/test_purge.py index 6a86b2684..dcd4a4a48 100644 --- a/watcher/tests/db/test_purge.py +++ b/watcher/tests/db/test_purge.py @@ -265,7 +265,7 @@ class TestPurgeCommand(base.DbTestCase): with freezegun.freeze_time(self.fake_today): # orphan audit template audit_template4 = obj_utils.create_test_audit_template( - self.context, goal_id=404, # Does not exist + self.context, goal_id=self.goal2.id, # Does not exist name=self.generate_unique_name(prefix="Audit Template 4 "), strategy_id=None, id=self._generate_id(), uuid=utils.generate_uuid()) @@ -362,7 +362,7 @@ class TestPurgeCommand(base.DbTestCase): with freezegun.freeze_time(self.fake_today): # orphan audit template audit_template4 = obj_utils.create_test_audit_template( - self.context, goal_id=404, # Does not exist + self.context, goal_id=self.goal2.id, # Does not exist name=self.generate_unique_name(prefix="Audit Template 4 "), strategy_id=None, id=self._generate_id(), uuid=utils.generate_uuid()) diff --git a/watcher/tests/db/utils.py b/watcher/tests/db/utils.py index ad91aa9cd..c540f4a4b 100644 --- a/watcher/tests/db/utils.py +++ b/watcher/tests/db/utils.py @@ -21,7 +21,7 @@ from watcher import objects def get_test_audit_template(**kwargs): - return { + audit_template_data = { 'id': kwargs.get('id', 1), 'uuid': kwargs.get('uuid', 'e74c40e0-d825-11e2-a28f-0800200c9a66'), 'goal_id': kwargs.get('goal_id', 1), @@ -34,6 +34,15 @@ def get_test_audit_template(**kwargs): 'deleted_at': kwargs.get('deleted_at'), } + # ObjectField doesn't allow None nor dict, so if we want to simulate a + # non-eager object loading, the field should not be referenced at all. + if kwargs.get('goal'): + audit_template_data['goal'] = kwargs.get('goal') + if kwargs.get('strategy'): + audit_template_data['strategy'] = kwargs.get('strategy') + + return audit_template_data + def create_test_audit_template(**kwargs): """Create test audit template entry in DB and return AuditTemplate DB object. diff --git a/watcher/tests/decision_engine/messaging/test_audit_endpoint.py b/watcher/tests/decision_engine/messaging/test_audit_endpoint.py index 3ee24627a..9585382cb 100644 --- a/watcher/tests/decision_engine/messaging/test_audit_endpoint.py +++ b/watcher/tests/decision_engine/messaging/test_audit_endpoint.py @@ -27,6 +27,7 @@ from watcher.tests.objects import utils as obj_utils class TestAuditEndpoint(base.DbTestCase): def setUp(self): super(TestAuditEndpoint, self).setUp() + self.goal = obj_utils.create_test_goal(self.context) self.audit_template = obj_utils.create_test_audit_template( self.context) self.audit = obj_utils.create_test_audit( diff --git a/watcher/tests/objects/test_audit_template.py b/watcher/tests/objects/test_audit_template.py index 5837508de..8f353db70 100644 --- a/watcher/tests/objects/test_audit_template.py +++ b/watcher/tests/objects/test_audit_template.py @@ -17,6 +17,7 @@ import mock from watcher.common import exception from watcher.common import utils as w_utils +from watcher.db.sqlalchemy import api as db_api from watcher import objects from watcher.tests.db import base from watcher.tests.db import utils @@ -24,135 +25,172 @@ from watcher.tests.db import utils class TestAuditTemplateObject(base.DbTestCase): + goal_id = 1 + + goal_data = utils.get_test_goal( + id=goal_id, uuid=w_utils.generate_uuid(), name="DUMMY") + + scenarios = [ + ('non_eager', dict( + eager=False, + fake_audit_template=utils.get_test_audit_template( + goal_id=goal_id))), + ('eager_with_non_eager_load', dict( + eager=True, + fake_audit_template=utils.get_test_audit_template( + goal_id=goal_id))), + ('eager_with_eager_load', dict( + eager=True, + fake_audit_template=utils.get_test_audit_template( + goal_id=goal_id, goal=goal_data))), + ] + def setUp(self): super(TestAuditTemplateObject, self).setUp() - self.fake_audit_template = utils.get_test_audit_template() - self.fake_goal1 = utils.create_test_goal( - id=1, uuid=w_utils.generate_uuid(), name="DUMMY") - self.fake_goal2 = utils.create_test_goal( - id=2, uuid=w_utils.generate_uuid(), name="BALANCE_LOAD") + self.fake_goal = utils.create_test_goal(**self.goal_data) - def test_get_by_id(self): + def eager_load_audit_template_assert(self, audit_template, goal): + if self.eager: + self.assertIsNotNone(audit_template.goal) + fields_to_check = set( + super(objects.Goal, objects.Goal).fields + ).symmetric_difference(objects.Goal.fields) + db_data = { + k: v for k, v in goal.as_dict().items() + if k in fields_to_check} + object_data = { + k: v for k, v in audit_template.goal.as_dict().items() + if k in fields_to_check} + self.assertEqual(db_data, object_data) + + @mock.patch.object(db_api.Connection, 'get_audit_template_by_id') + def test_get_by_id(self, mock_get_audit_template): + mock_get_audit_template.return_value = self.fake_audit_template audit_template_id = self.fake_audit_template['id'] - with mock.patch.object(self.dbapi, 'get_audit_template_by_id', - autospec=True) as mock_get_audit_template: - mock_get_audit_template.return_value = self.fake_audit_template - audit_template = objects.AuditTemplate.get(self.context, - audit_template_id) - mock_get_audit_template.assert_called_once_with( - self.context, audit_template_id) - self.assertEqual(self.context, audit_template._context) + audit_template = objects.AuditTemplate.get( + self.context, audit_template_id, eager=self.eager) + mock_get_audit_template.assert_called_once_with( + self.context, audit_template_id, eager=self.eager) + self.assertEqual(self.context, audit_template._context) + self.eager_load_audit_template_assert(audit_template, self.fake_goal) - def test_get_by_uuid(self): + @mock.patch.object(db_api.Connection, 'get_audit_template_by_uuid') + def test_get_by_uuid(self, mock_get_audit_template): + mock_get_audit_template.return_value = self.fake_audit_template uuid = self.fake_audit_template['uuid'] - with mock.patch.object(self.dbapi, 'get_audit_template_by_uuid', - autospec=True) as mock_get_audit_template: - mock_get_audit_template.return_value = self.fake_audit_template - audit_template = objects.AuditTemplate.get(self.context, uuid) - mock_get_audit_template.assert_called_once_with(self.context, uuid) - self.assertEqual(self.context, audit_template._context) + audit_template = objects.AuditTemplate.get( + self.context, uuid, eager=self.eager) + mock_get_audit_template.assert_called_once_with( + self.context, uuid, eager=self.eager) + self.assertEqual(self.context, audit_template._context) + self.eager_load_audit_template_assert(audit_template, self.fake_goal) - def test_get_by_name(self): + @mock.patch.object(db_api.Connection, 'get_audit_template_by_name') + def test_get_by_name(self, mock_get_audit_template): + mock_get_audit_template.return_value = self.fake_audit_template name = self.fake_audit_template['name'] - with mock.patch.object(self.dbapi, 'get_audit_template_by_name', - autospec=True) as mock_get_audit_template: - mock_get_audit_template.return_value = self.fake_audit_template - audit_template = objects.AuditTemplate.get_by_name( - self.context, - name) - mock_get_audit_template.assert_called_once_with(self.context, name) - self.assertEqual(self.context, audit_template._context) + audit_template = objects.AuditTemplate.get_by_name( + self.context, name, eager=self.eager) + mock_get_audit_template.assert_called_once_with( + self.context, name, eager=self.eager) + self.assertEqual(self.context, audit_template._context) + self.eager_load_audit_template_assert(audit_template, self.fake_goal) def test_get_bad_id_and_uuid(self): self.assertRaises(exception.InvalidIdentity, objects.AuditTemplate.get, - self.context, 'not-a-uuid') + self.context, 'not-a-uuid', eager=self.eager) - def test_list(self): - with mock.patch.object(self.dbapi, 'get_audit_template_list', - autospec=True) as mock_get_list: - mock_get_list.return_value = [self.fake_audit_template] - audit_templates = objects.AuditTemplate.list(self.context) - self.assertEqual(1, mock_get_list.call_count) - self.assertEqual(1, len(audit_templates)) - self.assertIsInstance(audit_templates[0], objects.AuditTemplate) - self.assertEqual(self.context, audit_templates[0]._context) + @mock.patch.object(db_api.Connection, 'get_audit_template_list') + def test_list(self, mock_get_list): + mock_get_list.return_value = [self.fake_audit_template] + audit_templates = objects.AuditTemplate.list( + self.context, eager=self.eager) + mock_get_list.assert_called_once_with( + self.context, eager=self.eager, filters=None, limit=None, + marker=None, sort_dir=None, sort_key=None) + self.assertEqual(1, len(audit_templates)) + self.assertIsInstance(audit_templates[0], objects.AuditTemplate) + self.assertEqual(self.context, audit_templates[0]._context) + for audit_template in audit_templates: + self.eager_load_audit_template_assert( + audit_template, self.fake_goal) - def test_create(self): - with mock.patch.object(self.dbapi, 'create_audit_template', - autospec=True) as mock_create_audit_template: - mock_create_audit_template.return_value = self.fake_audit_template - audit_template = objects.AuditTemplate(self.context, - **self.fake_audit_template) - audit_template.create() - mock_create_audit_template.assert_called_once_with( - self.fake_audit_template) - self.assertEqual(self.context, audit_template._context) - - def test_destroy(self): + @mock.patch.object(db_api.Connection, 'update_audit_template') + @mock.patch.object(db_api.Connection, 'get_audit_template_by_uuid') + def test_save(self, mock_get_audit_template, mock_update_audit_template): + mock_get_audit_template.return_value = self.fake_audit_template uuid = self.fake_audit_template['uuid'] - with mock.patch.object(self.dbapi, 'get_audit_template_by_uuid', - autospec=True) as mock_get_audit_template: - mock_get_audit_template.return_value = self.fake_audit_template - with mock.patch.object(self.dbapi, 'destroy_audit_template', - autospec=True) \ - as mock_destroy_audit_template: - audit_template = objects.AuditTemplate.get_by_uuid( - self.context, uuid) - audit_template.destroy() - mock_get_audit_template.assert_called_once_with( - self.context, uuid) - mock_destroy_audit_template.assert_called_once_with(uuid) - self.assertEqual(self.context, audit_template._context) + audit_template = objects.AuditTemplate.get_by_uuid( + self.context, uuid, eager=self.eager) + audit_template.goal_id = self.fake_goal.id + audit_template.save() - def test_save(self): + mock_get_audit_template.assert_called_once_with( + self.context, uuid, eager=self.eager) + mock_update_audit_template.assert_called_once_with( + uuid, {'goal_id': self.fake_goal.id}) + self.assertEqual(self.context, audit_template._context) + self.eager_load_audit_template_assert(audit_template, self.fake_goal) + + @mock.patch.object(db_api.Connection, 'get_audit_template_by_uuid') + def test_refresh(self, mock_get_audit_template): + returns = [dict(self.fake_audit_template, name="first name"), + dict(self.fake_audit_template, name="second name")] + mock_get_audit_template.side_effect = returns uuid = self.fake_audit_template['uuid'] - with mock.patch.object(self.dbapi, 'get_audit_template_by_uuid', - autospec=True) as mock_get_audit_template: - mock_get_audit_template.return_value = self.fake_audit_template - with mock.patch.object(self.dbapi, 'update_audit_template', - autospec=True) \ - as mock_update_audit_template: - audit_template = objects.AuditTemplate.get_by_uuid( - self.context, uuid) - audit_template.goal_id = self.fake_goal1.id - audit_template.save() + expected = [mock.call(self.context, uuid, eager=self.eager), + mock.call(self.context, uuid, eager=self.eager)] + audit_template = objects.AuditTemplate.get( + self.context, uuid, eager=self.eager) + self.assertEqual("first name", audit_template.name) + audit_template.refresh(eager=self.eager) + self.assertEqual("second name", audit_template.name) + self.assertEqual(expected, mock_get_audit_template.call_args_list) + self.assertEqual(self.context, audit_template._context) + self.eager_load_audit_template_assert(audit_template, self.fake_goal) - mock_get_audit_template.assert_called_once_with( - self.context, uuid) - mock_update_audit_template.assert_called_once_with( - uuid, {'goal_id': self.fake_goal1.id}) - self.assertEqual(self.context, audit_template._context) - def test_refresh(self): +class TestCreateDeleteAuditTemplateObject(base.DbTestCase): + + def setUp(self): + super(TestCreateDeleteAuditTemplateObject, self).setUp() + self.fake_audit_template = utils.get_test_audit_template() + + @mock.patch.object(db_api.Connection, 'create_audit_template') + def test_create(self, mock_create_audit_template): + goal = utils.create_test_goal() + self.fake_audit_template['goal_id'] = goal.id + mock_create_audit_template.return_value = self.fake_audit_template + audit_template = objects.AuditTemplate( + self.context, **self.fake_audit_template) + audit_template.create() + mock_create_audit_template.assert_called_once_with( + self.fake_audit_template) + self.assertEqual(self.context, audit_template._context) + + @mock.patch.object(db_api.Connection, 'soft_delete_audit_template') + @mock.patch.object(db_api.Connection, 'get_audit_template_by_uuid') + def test_soft_delete(self, mock_get_audit_template, + mock_soft_delete_audit_template): + mock_get_audit_template.return_value = self.fake_audit_template uuid = self.fake_audit_template['uuid'] - returns = [dict(self.fake_audit_template, - goal_id=self.fake_goal1.id), - dict(self.fake_audit_template, goal_id=self.fake_goal2.id)] - expected = [mock.call(self.context, uuid), - mock.call(self.context, uuid)] - with mock.patch.object(self.dbapi, 'get_audit_template_by_uuid', - side_effect=returns, - autospec=True) as mock_get_audit_template: - audit_template = objects.AuditTemplate.get(self.context, uuid) - self.assertEqual(1, audit_template.goal_id) - audit_template.refresh() - self.assertEqual(2, audit_template.goal_id) - self.assertEqual(expected, mock_get_audit_template.call_args_list) - self.assertEqual(self.context, audit_template._context) + audit_template = objects.AuditTemplate.get_by_uuid(self.context, uuid) + audit_template.soft_delete() + mock_get_audit_template.assert_called_once_with( + self.context, uuid, eager=False) + mock_soft_delete_audit_template.assert_called_once_with(uuid) + self.assertEqual(self.context, audit_template._context) - def test_soft_delete(self): + @mock.patch.object(db_api.Connection, 'destroy_audit_template') + @mock.patch.object(db_api.Connection, 'get_audit_template_by_uuid') + def test_destroy(self, mock_get_audit_template, + mock_destroy_audit_template): + mock_get_audit_template.return_value = self.fake_audit_template uuid = self.fake_audit_template['uuid'] - with mock.patch.object(self.dbapi, 'get_audit_template_by_uuid', - autospec=True) as mock_get_audit_template: - mock_get_audit_template.return_value = self.fake_audit_template - with mock.patch.object(self.dbapi, 'soft_delete_audit_template', - autospec=True) \ - as mock_soft_delete_audit_template: - audit_template = objects.AuditTemplate.get_by_uuid( - self.context, uuid) - audit_template.soft_delete() - mock_get_audit_template.assert_called_once_with( - self.context, uuid) - mock_soft_delete_audit_template.assert_called_once_with(uuid) - self.assertEqual(self.context, audit_template._context) + audit_template = objects.AuditTemplate.get_by_uuid(self.context, uuid) + audit_template.destroy() + mock_get_audit_template.assert_called_once_with( + self.context, uuid, eager=False) + mock_destroy_audit_template.assert_called_once_with(uuid) + self.assertEqual(self.context, audit_template._context) diff --git a/watcher/tests/objects/test_objects.py b/watcher/tests/objects/test_objects.py index d71445875..8857c6d3d 100644 --- a/watcher/tests/objects/test_objects.py +++ b/watcher/tests/objects/test_objects.py @@ -411,7 +411,7 @@ class TestObject(_LocalTest, _TestObject): expected_object_fingerprints = { 'Goal': '1.0-93881622db05e7b67a65ca885b4a022e', 'Strategy': '1.1-73f164491bdd4c034f48083a51bdeb7b', - 'AuditTemplate': '1.0-7432ee4d3ce0c7cbb9d11a4565ee8eb6', + 'AuditTemplate': '1.1-b291973ffc5efa2c61b24fe34fdccc0b', 'Audit': '1.0-ebfc5360d019baf583a10a8a27071c97', 'ActionPlan': '1.0-cc76fd7f0e8479aeff817dd266341de4', 'Action': '1.0-a78f69c0da98e13e601f9646f6b2f883',