Merge "Refactored Watcher objects to use OVO"
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
# Copyright 2010 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# 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 watcher import objects
|
||||
|
||||
# NOTE(comstud): Make sure we have all of the objects loaded. We do this
|
||||
# at module import time, because we may be using mock decorators in our
|
||||
# tests that run at import time.
|
||||
objects.register_all()
|
||||
|
||||
@@ -64,7 +64,7 @@ class FunctionalTest(base.DbTestCase):
|
||||
|
||||
def _make_app(self, enable_acl=False):
|
||||
# Determine where we are so we can set up paths in the config
|
||||
root_dir = self.path_get()
|
||||
root_dir = self.get_path()
|
||||
|
||||
self.config = {
|
||||
'app': {
|
||||
|
||||
@@ -250,7 +250,7 @@ class TestPatch(api_base.FunctionalTest):
|
||||
def setUp(self):
|
||||
super(TestPatch, self).setUp()
|
||||
obj_utils.create_test_audit_template(self.context)
|
||||
self.audit = obj_utils.create_test_audit(self.context)
|
||||
self.audit = obj_utils.create_test_audit(self.context, )
|
||||
p = mock.patch.object(db_api.BaseConnection, 'update_audit')
|
||||
self.mock_audit_update = p.start()
|
||||
self.mock_audit_update.side_effect = self._simulate_rpc_audit_update
|
||||
@@ -313,15 +313,15 @@ class TestPatch(api_base.FunctionalTest):
|
||||
|
||||
def test_remove_ok(self):
|
||||
response = self.get_json('/audits/%s' % self.audit.uuid)
|
||||
self.assertIsNotNone(response['state'])
|
||||
self.assertIsNotNone(response['interval'])
|
||||
|
||||
response = self.patch_json('/audits/%s' % self.audit.uuid,
|
||||
[{'path': '/state', 'op': 'remove'}])
|
||||
[{'path': '/interval', 'op': 'remove'}])
|
||||
self.assertEqual('application/json', response.content_type)
|
||||
self.assertEqual(200, response.status_code)
|
||||
|
||||
response = self.get_json('/audits/%s' % self.audit.uuid)
|
||||
self.assertIsNone(response['state'])
|
||||
self.assertIsNone(response['interval'])
|
||||
|
||||
def test_remove_uuid(self):
|
||||
response = self.patch_json('/audits/%s' % self.audit.uuid,
|
||||
|
||||
@@ -80,7 +80,7 @@ class TestDefaultWorkFlowEngine(base.DbTestCase):
|
||||
'next': next,
|
||||
}
|
||||
new_action = objects.Action(self.context, **action)
|
||||
new_action.create(self.context)
|
||||
new_action.create()
|
||||
new_action.save()
|
||||
|
||||
return new_action
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2010-2011 OpenStack Foundation
|
||||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
@@ -35,8 +33,11 @@ from watcher.tests import policy_fixture
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
log.register_options(CONF)
|
||||
CONF.set_override('use_stderr', False, enforce_type=True)
|
||||
try:
|
||||
log.register_options(CONF)
|
||||
except cfg.ArgsAlreadyParsedError:
|
||||
pass
|
||||
CONF.set_override('use_stderr', False)
|
||||
|
||||
|
||||
class BaseTestCase(testscenarios.WithScenarios, base.BaseTestCase):
|
||||
@@ -76,6 +77,9 @@ class TestCase(BaseTestCase):
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
objects_base.WatcherObject.indirection_api = None
|
||||
|
||||
self.context = watcher_context.RequestContext(
|
||||
auth_token_info=self.token_info,
|
||||
project_id='fake_project',
|
||||
@@ -104,19 +108,21 @@ class TestCase(BaseTestCase):
|
||||
self._reset_singletons()
|
||||
|
||||
self._base_test_obj_backup = copy.copy(
|
||||
objects_base.WatcherObject._obj_classes)
|
||||
objects_base.WatcherObjectRegistry._registry._obj_classes)
|
||||
self.addCleanup(self._restore_obj_registry)
|
||||
self.addCleanup(self._reset_singletons)
|
||||
|
||||
def _reset_singletons(self):
|
||||
service.Singleton._instances.clear()
|
||||
|
||||
def _restore_obj_registry(self):
|
||||
objects_base.WatcherObject._obj_classes = self._base_test_obj_backup
|
||||
def reset_pecan():
|
||||
pecan.set_config({}, overwrite=True)
|
||||
|
||||
def tearDown(self):
|
||||
super(TestCase, self).tearDown()
|
||||
pecan.set_config({}, overwrite=True)
|
||||
self.addCleanup(reset_pecan)
|
||||
|
||||
def _restore_obj_registry(self):
|
||||
objects_base.WatcherObjectRegistry._registry._obj_classes = (
|
||||
self._base_test_obj_backup)
|
||||
|
||||
def config(self, **kw):
|
||||
"""Override config options for a test."""
|
||||
@@ -124,7 +130,7 @@ class TestCase(BaseTestCase):
|
||||
for k, v in kw.items():
|
||||
CONF.set_override(k, v, group, enforce_type=True)
|
||||
|
||||
def path_get(self, project_file=None):
|
||||
def get_path(self, project_file=None):
|
||||
"""Get the absolute path to a file. Used for testing the API.
|
||||
|
||||
:param project_file: File whose path to return. Default: None.
|
||||
|
||||
@@ -20,6 +20,7 @@ import freezegun
|
||||
import mock
|
||||
|
||||
from watcher.common import context as watcher_context
|
||||
from watcher.common import utils
|
||||
from watcher.db import purge
|
||||
from watcher.db.sqlalchemy import api as dbapi
|
||||
from watcher.tests.db import base
|
||||
@@ -101,27 +102,33 @@ class TestPurgeCommand(base.DbTestCase):
|
||||
|
||||
with freezegun.freeze_time(self.expired_date):
|
||||
self.goal1 = obj_utils.create_test_goal(
|
||||
self.context, id=self._generate_id(), uuid=None,
|
||||
self.context, id=self._generate_id(),
|
||||
uuid=utils.generate_uuid(),
|
||||
name=goal1_name, display_name=goal1_name.lower())
|
||||
self.goal2 = obj_utils.create_test_goal(
|
||||
self.context, id=self._generate_id(), uuid=None,
|
||||
self.context, id=self._generate_id(),
|
||||
uuid=utils.generate_uuid(),
|
||||
name=goal2_name, display_name=goal2_name.lower())
|
||||
self.goal3 = obj_utils.create_test_goal(
|
||||
self.context, id=self._generate_id(), uuid=None,
|
||||
self.context, id=self._generate_id(),
|
||||
uuid=utils.generate_uuid(),
|
||||
name=goal3_name, display_name=goal3_name.lower())
|
||||
self.goal1.soft_delete()
|
||||
|
||||
with freezegun.freeze_time(self.expired_date):
|
||||
self.strategy1 = obj_utils.create_test_strategy(
|
||||
self.context, id=self._generate_id(), uuid=None,
|
||||
self.context, id=self._generate_id(),
|
||||
uuid=utils.generate_uuid(),
|
||||
name=strategy1_name, display_name=strategy1_name.lower(),
|
||||
goal_id=self.goal1.id)
|
||||
self.strategy2 = obj_utils.create_test_strategy(
|
||||
self.context, id=self._generate_id(), uuid=None,
|
||||
self.context, id=self._generate_id(),
|
||||
uuid=utils.generate_uuid(),
|
||||
name=strategy2_name, display_name=strategy2_name.lower(),
|
||||
goal_id=self.goal2.id)
|
||||
self.strategy3 = obj_utils.create_test_strategy(
|
||||
self.context, id=self._generate_id(), uuid=None,
|
||||
self.context, id=self._generate_id(),
|
||||
uuid=utils.generate_uuid(),
|
||||
name=strategy3_name, display_name=strategy3_name.lower(),
|
||||
goal_id=self.goal3.id)
|
||||
self.strategy1.soft_delete()
|
||||
@@ -129,50 +136,61 @@ class TestPurgeCommand(base.DbTestCase):
|
||||
with freezegun.freeze_time(self.expired_date):
|
||||
self.audit_template1 = obj_utils.create_test_audit_template(
|
||||
self.context, name=self.audit_template1_name,
|
||||
id=self._generate_id(), uuid=None, goal_id=self.goal1.id,
|
||||
id=self._generate_id(),
|
||||
uuid=utils.generate_uuid(), goal_id=self.goal1.id,
|
||||
strategy_id=self.strategy1.id)
|
||||
self.audit_template2 = obj_utils.create_test_audit_template(
|
||||
self.context, name=self.audit_template2_name,
|
||||
id=self._generate_id(), uuid=None, goal_id=self.goal2.id,
|
||||
id=self._generate_id(),
|
||||
uuid=utils.generate_uuid(), goal_id=self.goal2.id,
|
||||
strategy_id=self.strategy2.id)
|
||||
self.audit_template3 = obj_utils.create_test_audit_template(
|
||||
self.context, name=self.audit_template3_name,
|
||||
id=self._generate_id(), uuid=None, goal_id=self.goal3.id,
|
||||
id=self._generate_id(),
|
||||
uuid=utils.generate_uuid(), goal_id=self.goal3.id,
|
||||
strategy_id=self.strategy3.id)
|
||||
self.audit_template1.soft_delete()
|
||||
|
||||
with freezegun.freeze_time(self.expired_date):
|
||||
self.audit1 = obj_utils.create_test_audit(
|
||||
self.context, id=self._generate_id(), uuid=None,
|
||||
self.context, id=self._generate_id(),
|
||||
uuid=utils.generate_uuid(),
|
||||
goal_id=self.goal1.id, strategy_id=self.strategy1.id)
|
||||
self.audit2 = obj_utils.create_test_audit(
|
||||
self.context, id=self._generate_id(), uuid=None,
|
||||
self.context, id=self._generate_id(),
|
||||
uuid=utils.generate_uuid(),
|
||||
goal_id=self.goal2.id, strategy_id=self.strategy2.id)
|
||||
self.audit3 = obj_utils.create_test_audit(
|
||||
self.context, id=self._generate_id(), uuid=None,
|
||||
self.context, id=self._generate_id(),
|
||||
uuid=utils.generate_uuid(),
|
||||
goal_id=self.goal3.id, strategy_id=self.strategy3.id)
|
||||
self.audit1.soft_delete()
|
||||
|
||||
with freezegun.freeze_time(self.expired_date):
|
||||
self.action_plan1 = obj_utils.create_test_action_plan(
|
||||
self.context, id=self._generate_id(), uuid=None,
|
||||
audit_id=self.audit1.id, strategy_id=self.strategy1.id)
|
||||
self.context, audit_id=self.audit1.id,
|
||||
id=self._generate_id(), uuid=utils.generate_uuid(),
|
||||
strategy_id=self.strategy1.id)
|
||||
self.action_plan2 = obj_utils.create_test_action_plan(
|
||||
self.context, id=self._generate_id(), uuid=None,
|
||||
audit_id=self.audit2.id, strategy_id=self.strategy2.id)
|
||||
self.context, audit_id=self.audit2.id,
|
||||
id=self._generate_id(),
|
||||
strategy_id=self.strategy2.id,
|
||||
uuid=utils.generate_uuid())
|
||||
self.action_plan3 = obj_utils.create_test_action_plan(
|
||||
self.context, id=self._generate_id(), uuid=None,
|
||||
audit_id=self.audit3.id, strategy_id=self.strategy3.id)
|
||||
self.context, audit_id=self.audit3.id,
|
||||
id=self._generate_id(), uuid=utils.generate_uuid(),
|
||||
strategy_id=self.strategy3.id)
|
||||
|
||||
self.action1 = obj_utils.create_test_action(
|
||||
self.context, action_plan_id=self.action_plan1.id,
|
||||
id=self._generate_id(), uuid=None)
|
||||
id=self._generate_id(),
|
||||
uuid=utils.generate_uuid())
|
||||
self.action2 = obj_utils.create_test_action(
|
||||
self.context, action_plan_id=self.action_plan2.id,
|
||||
id=self._generate_id(), uuid=None)
|
||||
id=self._generate_id(), uuid=utils.generate_uuid())
|
||||
self.action3 = obj_utils.create_test_action(
|
||||
self.context, action_plan_id=self.action_plan3.id,
|
||||
id=self._generate_id(), uuid=None)
|
||||
id=self._generate_id(), uuid=utils.generate_uuid())
|
||||
self.action_plan1.soft_delete()
|
||||
|
||||
@mock.patch.object(dbapi.Connection, "destroy_action")
|
||||
@@ -249,30 +267,38 @@ class TestPurgeCommand(base.DbTestCase):
|
||||
audit_template4 = obj_utils.create_test_audit_template(
|
||||
self.context, goal_id=404, # Does not exist
|
||||
name=self.generate_unique_name(prefix="Audit Template 4 "),
|
||||
strategy_id=None, id=self._generate_id(), uuid=None)
|
||||
strategy_id=None, id=self._generate_id(),
|
||||
uuid=utils.generate_uuid())
|
||||
audit4 = obj_utils.create_test_audit(
|
||||
self.context, audit_template_id=audit_template4.id,
|
||||
id=self._generate_id(), uuid=None)
|
||||
id=self._generate_id(),
|
||||
uuid=utils.generate_uuid())
|
||||
action_plan4 = obj_utils.create_test_action_plan(
|
||||
self.context, audit_id=audit4.id,
|
||||
id=self._generate_id(), uuid=None)
|
||||
id=self._generate_id(),
|
||||
uuid=utils.generate_uuid())
|
||||
action4 = obj_utils.create_test_action(
|
||||
self.context, action_plan_id=action_plan4.id,
|
||||
id=self._generate_id(), uuid=None)
|
||||
id=self._generate_id(),
|
||||
uuid=utils.generate_uuid())
|
||||
|
||||
audit_template5 = obj_utils.create_test_audit_template(
|
||||
self.context, goal_id=self.goal1.id,
|
||||
name=self.generate_unique_name(prefix="Audit Template 5 "),
|
||||
strategy_id=None, id=self._generate_id(), uuid=None)
|
||||
strategy_id=None, id=self._generate_id(),
|
||||
uuid=utils.generate_uuid())
|
||||
audit5 = obj_utils.create_test_audit(
|
||||
self.context, audit_template_id=audit_template5.id,
|
||||
id=self._generate_id(), uuid=None)
|
||||
id=self._generate_id(),
|
||||
uuid=utils.generate_uuid())
|
||||
action_plan5 = obj_utils.create_test_action_plan(
|
||||
self.context, audit_id=audit5.id,
|
||||
id=self._generate_id(), uuid=None)
|
||||
id=self._generate_id(),
|
||||
uuid=utils.generate_uuid())
|
||||
action5 = obj_utils.create_test_action(
|
||||
self.context, action_plan_id=action_plan5.id,
|
||||
id=self._generate_id(), uuid=None)
|
||||
id=self._generate_id(),
|
||||
uuid=utils.generate_uuid())
|
||||
|
||||
self.goal2.soft_delete()
|
||||
self.strategy2.soft_delete()
|
||||
@@ -338,30 +364,38 @@ class TestPurgeCommand(base.DbTestCase):
|
||||
audit_template4 = obj_utils.create_test_audit_template(
|
||||
self.context, goal_id=404, # Does not exist
|
||||
name=self.generate_unique_name(prefix="Audit Template 4 "),
|
||||
strategy_id=None, id=self._generate_id(), uuid=None)
|
||||
strategy_id=None, id=self._generate_id(),
|
||||
uuid=utils.generate_uuid())
|
||||
audit4 = obj_utils.create_test_audit(
|
||||
self.context, audit_template_id=audit_template4.id,
|
||||
id=self._generate_id(), uuid=None)
|
||||
id=self._generate_id(),
|
||||
uuid=utils.generate_uuid())
|
||||
action_plan4 = obj_utils.create_test_action_plan(
|
||||
self.context, audit_id=audit4.id,
|
||||
id=self._generate_id(), uuid=None)
|
||||
id=self._generate_id(),
|
||||
uuid=utils.generate_uuid())
|
||||
action4 = obj_utils.create_test_action(
|
||||
self.context, action_plan_id=action_plan4.id,
|
||||
id=self._generate_id(), uuid=None)
|
||||
id=self._generate_id(),
|
||||
uuid=utils.generate_uuid())
|
||||
|
||||
audit_template5 = obj_utils.create_test_audit_template(
|
||||
self.context, goal_id=self.goal1.id,
|
||||
name=self.generate_unique_name(prefix="Audit Template 5 "),
|
||||
strategy_id=None, id=self._generate_id(), uuid=None)
|
||||
strategy_id=None, id=self._generate_id(),
|
||||
uuid=utils.generate_uuid())
|
||||
audit5 = obj_utils.create_test_audit(
|
||||
self.context, audit_template_id=audit_template5.id,
|
||||
id=self._generate_id(), uuid=None)
|
||||
id=self._generate_id(),
|
||||
uuid=utils.generate_uuid())
|
||||
action_plan5 = obj_utils.create_test_action_plan(
|
||||
self.context, audit_id=audit5.id,
|
||||
id=self._generate_id(), uuid=None)
|
||||
id=self._generate_id(),
|
||||
uuid=utils.generate_uuid())
|
||||
action5 = obj_utils.create_test_action(
|
||||
self.context, action_plan_id=action_plan5.id,
|
||||
id=self._generate_id(), uuid=None)
|
||||
id=self._generate_id(),
|
||||
uuid=utils.generate_uuid())
|
||||
|
||||
self.goal2.soft_delete()
|
||||
self.strategy2.soft_delete()
|
||||
|
||||
@@ -56,7 +56,7 @@ def get_test_audit(**kwargs):
|
||||
'id': kwargs.get('id', 1),
|
||||
'uuid': kwargs.get('uuid', '10a47dd1-4874-4298-91cf-eff046dbdb8d'),
|
||||
'audit_type': kwargs.get('audit_type', 'ONESHOT'),
|
||||
'state': kwargs.get('state'),
|
||||
'state': kwargs.get('state', objects.audit.State.PENDING),
|
||||
'created_at': kwargs.get('created_at'),
|
||||
'updated_at': kwargs.get('updated_at'),
|
||||
'deleted_at': kwargs.get('deleted_at'),
|
||||
|
||||
@@ -21,7 +21,6 @@ from watcher.common import utils
|
||||
from watcher.decision_engine.loading import default
|
||||
from watcher.decision_engine import sync
|
||||
from watcher import objects
|
||||
from watcher.objects import action_plan as ap_objects
|
||||
from watcher.tests.db import base
|
||||
from watcher.tests.decision_engine import fake_goals
|
||||
from watcher.tests.decision_engine import fake_strategies
|
||||
@@ -329,22 +328,30 @@ class TestSyncer(base.DbTestCase):
|
||||
# Should stay unmodified after sync()
|
||||
audit1 = objects.Audit(
|
||||
self.ctx, id=1, uuid=utils.generate_uuid(),
|
||||
audit_type=objects.audit.AuditType.ONESHOT.value,
|
||||
state=objects.audit.State.PENDING,
|
||||
goal_id=goal1.id, strategy_id=strategy1.id)
|
||||
# Should be modified by the sync() because its associated goal
|
||||
# has been modified (compared to the defined fake goals)
|
||||
audit2 = objects.Audit(
|
||||
self.ctx, id=2, uuid=utils.generate_uuid(),
|
||||
audit_type=objects.audit.AuditType.ONESHOT.value,
|
||||
state=objects.audit.State.PENDING,
|
||||
goal_id=goal2.id, strategy_id=strategy2.id)
|
||||
# Should be modified by the sync() because its associated strategy
|
||||
# has been modified (compared to the defined fake strategies)
|
||||
audit3 = objects.Audit(
|
||||
self.ctx, id=3, uuid=utils.generate_uuid(),
|
||||
audit_type=objects.audit.AuditType.ONESHOT.value,
|
||||
state=objects.audit.State.PENDING,
|
||||
goal_id=goal1.id, strategy_id=strategy3.id)
|
||||
# Modified because of both because its associated goal and associated
|
||||
# strategy should be modified (compared to the defined fake
|
||||
# goals/strategies)
|
||||
audit4 = objects.Audit(
|
||||
self.ctx, id=4, uuid=utils.generate_uuid(),
|
||||
audit_type=objects.audit.AuditType.ONESHOT.value,
|
||||
state=objects.audit.State.PENDING,
|
||||
goal_id=goal2.id, strategy_id=strategy4.id)
|
||||
|
||||
audit1.create()
|
||||
@@ -483,7 +490,7 @@ class TestSyncer(base.DbTestCase):
|
||||
set([action_plan2.id, action_plan3.id, action_plan4.id]),
|
||||
set(modified_action_plans))
|
||||
self.assertTrue(
|
||||
all(ap.state == ap_objects.State.CANCELLED
|
||||
all(ap.state == objects.action_plan.State.CANCELLED
|
||||
for ap in modified_action_plans.values()))
|
||||
self.assertEqual(set([action_plan1.id]), set(unmodified_action_plans))
|
||||
|
||||
@@ -551,10 +558,14 @@ class TestSyncer(base.DbTestCase):
|
||||
# Should stay unmodified after sync()
|
||||
audit1 = objects.Audit(
|
||||
self.ctx, id=1, uuid=utils.generate_uuid(),
|
||||
audit_type=objects.audit.AuditType.ONESHOT.value,
|
||||
state=objects.audit.State.PENDING,
|
||||
goal_id=goal1.id, strategy_id=strategy1.id)
|
||||
# Stale after syncing because the goal has been soft deleted
|
||||
audit2 = objects.Audit(
|
||||
self.ctx, id=2, uuid=utils.generate_uuid(),
|
||||
audit_type=objects.audit.AuditType.ONESHOT.value,
|
||||
state=objects.audit.State.PENDING,
|
||||
goal_id=goal2.id, strategy_id=strategy2.id)
|
||||
audit1.create()
|
||||
audit2.create()
|
||||
@@ -651,6 +662,6 @@ class TestSyncer(base.DbTestCase):
|
||||
|
||||
self.assertEqual(set([action_plan2.id]), set(modified_action_plans))
|
||||
self.assertTrue(
|
||||
all(ap.state == ap_objects.State.CANCELLED
|
||||
all(ap.state == objects.action_plan.State.CANCELLED
|
||||
for ap in modified_action_plans.values()))
|
||||
self.assertEqual(set([action_plan1.id]), set(unmodified_action_plans))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright 2015 IBM Corp.
|
||||
# Copyright 2013 IBM Corp.
|
||||
#
|
||||
# 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
|
||||
@@ -12,32 +12,38 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import contextlib
|
||||
import datetime
|
||||
import gettext
|
||||
|
||||
import iso8601
|
||||
import netaddr
|
||||
from oslo_utils import timeutils
|
||||
|
||||
import mock
|
||||
from oslo_versionedobjects import base as object_base
|
||||
from oslo_versionedobjects import exception as object_exception
|
||||
from oslo_versionedobjects import fixture as object_fixture
|
||||
import six
|
||||
|
||||
from watcher.common import context
|
||||
from watcher.objects import base
|
||||
from watcher.objects import utils
|
||||
from watcher.objects import fields
|
||||
from watcher.tests import base as test_base
|
||||
|
||||
gettext.install('watcher')
|
||||
|
||||
|
||||
class MyObj(base.WatcherObject):
|
||||
VERSION = '1.0'
|
||||
@base.WatcherObjectRegistry.register
|
||||
class MyObj(base.WatcherPersistentObject, base.WatcherObject,
|
||||
base.WatcherObjectDictCompat):
|
||||
VERSION = '1.5'
|
||||
|
||||
fields = {'foo': int,
|
||||
'bar': str,
|
||||
'missing': str,
|
||||
}
|
||||
fields = {'foo': fields.IntegerField(),
|
||||
'bar': fields.StringField(),
|
||||
'missing': fields.StringField()}
|
||||
|
||||
def obj_load_attr(self, attrname):
|
||||
setattr(self, attrname, 'loaded!')
|
||||
|
||||
@object_base.remotable_classmethod
|
||||
def query(cls, context):
|
||||
obj = cls(context)
|
||||
obj.foo = 1
|
||||
@@ -45,24 +51,29 @@ class MyObj(base.WatcherObject):
|
||||
obj.obj_reset_changes()
|
||||
return obj
|
||||
|
||||
def marco(self, context):
|
||||
@object_base.remotable
|
||||
def marco(self, context=None):
|
||||
return 'polo'
|
||||
|
||||
def update_test(self, context):
|
||||
if context.project_id == 'alternate':
|
||||
@object_base.remotable
|
||||
def update_test(self, context=None):
|
||||
if context and context.user == 'alternate':
|
||||
self.bar = 'alternate-context'
|
||||
else:
|
||||
self.bar = 'updated'
|
||||
|
||||
def save(self, context):
|
||||
@object_base.remotable
|
||||
def save(self, context=None):
|
||||
self.obj_reset_changes()
|
||||
|
||||
def refresh(self, context):
|
||||
@object_base.remotable
|
||||
def refresh(self, context=None):
|
||||
self.foo = 321
|
||||
self.bar = 'refreshed'
|
||||
self.obj_reset_changes()
|
||||
|
||||
def modify_save_modify(self, context):
|
||||
@object_base.remotable
|
||||
def modify_save_modify(self, context=None):
|
||||
self.bar = 'meow'
|
||||
self.save()
|
||||
self.foo = 42
|
||||
@@ -73,232 +84,361 @@ class MyObj2(object):
|
||||
def obj_name(cls):
|
||||
return 'MyObj'
|
||||
|
||||
@object_base.remotable_classmethod
|
||||
def get(cls, *args, **kwargs):
|
||||
pass
|
||||
|
||||
|
||||
class DummySubclassedObject(MyObj):
|
||||
fields = {'new_field': str}
|
||||
@base.WatcherObjectRegistry.register_if(False)
|
||||
class WatcherTestSubclassedObject(MyObj):
|
||||
fields = {'new_field': fields.StringField()}
|
||||
|
||||
|
||||
class TestMetaclass(test_base.TestCase):
|
||||
def test_obj_tracking(self):
|
||||
|
||||
@six.add_metaclass(base.WatcherObjectMetaclass)
|
||||
class NewBaseClass(object):
|
||||
fields = {}
|
||||
|
||||
@classmethod
|
||||
def obj_name(cls):
|
||||
return cls.__name__
|
||||
|
||||
class Test1(NewBaseClass):
|
||||
@staticmethod
|
||||
def obj_name():
|
||||
return 'fake1'
|
||||
|
||||
class Test2(NewBaseClass):
|
||||
pass
|
||||
|
||||
class Test2v2(NewBaseClass):
|
||||
@staticmethod
|
||||
def obj_name():
|
||||
return 'Test2'
|
||||
|
||||
expected = {'fake1': [Test1], 'Test2': [Test2, Test2v2]}
|
||||
|
||||
self.assertEqual(expected, NewBaseClass._obj_classes)
|
||||
# The following should work, also.
|
||||
self.assertEqual(expected, Test1._obj_classes)
|
||||
self.assertEqual(expected, Test2._obj_classes)
|
||||
class _LocalTest(test_base.TestCase):
|
||||
def setUp(self):
|
||||
super(_LocalTest, self).setUp()
|
||||
# Just in case
|
||||
base.WatcherObject.indirection_api = None
|
||||
|
||||
|
||||
class TestUtils(test_base.TestCase):
|
||||
|
||||
def test_datetime_or_none(self):
|
||||
naive_dt = datetime.datetime.now()
|
||||
dt = timeutils.parse_isotime(timeutils.isotime(naive_dt))
|
||||
self.assertEqual(dt, utils.datetime_or_none(dt, tzinfo_aware=True))
|
||||
self.assertEqual(naive_dt.replace(tzinfo=iso8601.iso8601.Utc(),
|
||||
microsecond=0),
|
||||
utils.datetime_or_none(dt, tzinfo_aware=True))
|
||||
self.assertIsNone(utils.datetime_or_none(None))
|
||||
self.assertRaises(ValueError, utils.datetime_or_none, 'foo')
|
||||
|
||||
def test_datetime_or_none_tzinfo_naive(self):
|
||||
naive_dt = datetime.datetime.utcnow()
|
||||
self.assertEqual(naive_dt, utils.datetime_or_none(naive_dt,
|
||||
tzinfo_aware=False))
|
||||
self.assertIsNone(utils.datetime_or_none(None))
|
||||
self.assertRaises(ValueError, utils.datetime_or_none, 'foo')
|
||||
|
||||
def test_datetime_or_str_or_none(self):
|
||||
dts = timeutils.isotime()
|
||||
dt = timeutils.parse_isotime(dts)
|
||||
self.assertEqual(dt, utils.datetime_or_str_or_none(dt,
|
||||
tzinfo_aware=True))
|
||||
self.assertIsNone(utils.datetime_or_str_or_none(None,
|
||||
tzinfo_aware=True))
|
||||
self.assertEqual(dt, utils.datetime_or_str_or_none(dts,
|
||||
tzinfo_aware=True))
|
||||
self.assertRaises(ValueError, utils.datetime_or_str_or_none, 'foo')
|
||||
|
||||
def test_int_or_none(self):
|
||||
self.assertEqual(1, utils.int_or_none(1))
|
||||
self.assertEqual(1, utils.int_or_none('1'))
|
||||
self.assertIsNone(utils.int_or_none(None))
|
||||
self.assertRaises(ValueError, utils.int_or_none, 'foo')
|
||||
|
||||
def test_str_or_none(self):
|
||||
class Obj(object):
|
||||
pass
|
||||
self.assertEqual('foo', utils.str_or_none('foo'))
|
||||
self.assertEqual('1', utils.str_or_none(1))
|
||||
self.assertIsNone(utils.str_or_none(None))
|
||||
|
||||
def test_ip_or_none(self):
|
||||
ip4 = netaddr.IPAddress('1.2.3.4', 4)
|
||||
ip6 = netaddr.IPAddress('1::2', 6)
|
||||
self.assertEqual(ip4, utils.ip_or_none(4)('1.2.3.4'))
|
||||
self.assertEqual(ip6, utils.ip_or_none(6)('1::2'))
|
||||
self.assertIsNone(utils.ip_or_none(4)(None))
|
||||
self.assertIsNone(utils.ip_or_none(6)(None))
|
||||
self.assertRaises(netaddr.AddrFormatError, utils.ip_or_none(4), 'foo')
|
||||
self.assertRaises(netaddr.AddrFormatError, utils.ip_or_none(6), 'foo')
|
||||
|
||||
def test_dt_serializer(self):
|
||||
class Obj(object):
|
||||
foo = utils.dt_serializer('bar')
|
||||
|
||||
obj = Obj()
|
||||
obj.bar = timeutils.parse_isotime('1955-11-05T00:00:00Z')
|
||||
self.assertEqual('1955-11-05T00:00:00Z', obj.foo())
|
||||
obj.bar = None
|
||||
self.assertIsNone(obj.foo())
|
||||
obj.bar = 'foo'
|
||||
self.assertRaises(AttributeError, obj.foo)
|
||||
|
||||
def test_dt_deserializer(self):
|
||||
dt = timeutils.parse_isotime('1955-11-05T00:00:00Z')
|
||||
self.assertEqual(dt, utils.dt_deserializer(timeutils.isotime(dt)))
|
||||
self.assertIsNone(utils.dt_deserializer(None))
|
||||
self.assertRaises(ValueError, utils.dt_deserializer, 'foo')
|
||||
|
||||
def test_obj_to_primitive_list(self):
|
||||
class MyList(base.ObjectListBase, base.WatcherObject):
|
||||
pass
|
||||
mylist = MyList(self.context)
|
||||
mylist.objects = [1, 2, 3]
|
||||
self.assertEqual([1, 2, 3], base.obj_to_primitive(mylist))
|
||||
|
||||
def test_obj_to_primitive_dict(self):
|
||||
myobj = MyObj(self.context)
|
||||
myobj.foo = 1
|
||||
myobj.bar = 'foo'
|
||||
self.assertEqual({'foo': 1, 'bar': 'foo'},
|
||||
base.obj_to_primitive(myobj))
|
||||
|
||||
def test_obj_to_primitive_recursive(self):
|
||||
class MyList(base.ObjectListBase, base.WatcherObject):
|
||||
pass
|
||||
|
||||
mylist = MyList(self.context)
|
||||
mylist.objects = [MyObj(self.context), MyObj(self.context)]
|
||||
for i, value in enumerate(mylist):
|
||||
value.foo = i
|
||||
self.assertEqual([{'foo': 0}, {'foo': 1}],
|
||||
base.obj_to_primitive(mylist))
|
||||
@contextlib.contextmanager
|
||||
def things_temporarily_local():
|
||||
# Temporarily go non-remote so the conductor handles
|
||||
# this request directly
|
||||
_api = base.WatcherObject.indirection_api
|
||||
base.WatcherObject.indirection_api = None
|
||||
yield
|
||||
base.WatcherObject.indirection_api = _api
|
||||
|
||||
|
||||
class TestObjectListBase(test_base.TestCase):
|
||||
class _TestObject(object):
|
||||
def test_hydration_type_error(self):
|
||||
primitive = {'watcher_object.name': 'MyObj',
|
||||
'watcher_object.namespace': 'watcher',
|
||||
'watcher_object.version': '1.5',
|
||||
'watcher_object.data': {'foo': 'a'}}
|
||||
self.assertRaises(ValueError, MyObj.obj_from_primitive, primitive)
|
||||
|
||||
def test_list_like_operations(self):
|
||||
class Foo(base.ObjectListBase, base.WatcherObject):
|
||||
pass
|
||||
def test_hydration(self):
|
||||
primitive = {'watcher_object.name': 'MyObj',
|
||||
'watcher_object.namespace': 'watcher',
|
||||
'watcher_object.version': '1.5',
|
||||
'watcher_object.data': {'foo': 1}}
|
||||
obj = MyObj.obj_from_primitive(primitive)
|
||||
self.assertEqual(1, obj.foo)
|
||||
|
||||
objlist = Foo(self.context)
|
||||
objlist._context = 'foo'
|
||||
objlist.objects = [1, 2, 3]
|
||||
self.assertEqual(list(objlist), objlist.objects)
|
||||
self.assertEqual(3, len(objlist))
|
||||
self.assertIn(2, objlist)
|
||||
self.assertEqual([1], list(objlist[:1]))
|
||||
self.assertEqual('foo', objlist[:1]._context)
|
||||
self.assertEqual(3, objlist[2])
|
||||
self.assertEqual(1, objlist.count(1))
|
||||
self.assertEqual(1, objlist.index(2))
|
||||
def test_hydration_bad_ns(self):
|
||||
primitive = {'watcher_object.name': 'MyObj',
|
||||
'watcher_object.namespace': 'foo',
|
||||
'watcher_object.version': '1.5',
|
||||
'watcher_object.data': {'foo': 1}}
|
||||
self.assertRaises(object_exception.UnsupportedObjectError,
|
||||
MyObj.obj_from_primitive, primitive)
|
||||
|
||||
def test_serialization(self):
|
||||
class Foo(base.ObjectListBase, base.WatcherObject):
|
||||
pass
|
||||
|
||||
class Bar(base.WatcherObject):
|
||||
fields = {'foo': str}
|
||||
|
||||
obj = Foo(self.context)
|
||||
obj.objects = []
|
||||
for i in 'abc':
|
||||
bar = Bar(self.context)
|
||||
bar.foo = i
|
||||
obj.objects.append(bar)
|
||||
|
||||
obj2 = base.WatcherObject.obj_from_primitive(obj.obj_to_primitive())
|
||||
self.assertFalse(obj is obj2)
|
||||
self.assertEqual([x.foo for x in obj],
|
||||
[y.foo for y in obj2])
|
||||
|
||||
def _test_object_list_version_mappings(self, list_obj_class):
|
||||
# Figure out what sort of object this list is for
|
||||
list_field = list_obj_class.fields['objects']
|
||||
item_obj_field = list_field._type._element_type
|
||||
item_obj_name = item_obj_field._type._obj_name
|
||||
|
||||
# Look through all object classes of this type and make sure that
|
||||
# the versions we find are covered by the parent list class
|
||||
for item_class in base.WatcherObject._obj_classes[item_obj_name]:
|
||||
self.assertIn(
|
||||
item_class.VERSION,
|
||||
list_obj_class.child_versions.values())
|
||||
|
||||
def test_object_version_mappings(self):
|
||||
# Find all object list classes and make sure that they at least handle
|
||||
# all the current object versions
|
||||
for obj_classes in base.WatcherObject._obj_classes.values():
|
||||
for obj_class in obj_classes:
|
||||
if issubclass(obj_class, base.ObjectListBase):
|
||||
self._test_object_list_version_mappings(obj_class)
|
||||
|
||||
def test_list_changes(self):
|
||||
class Foo(base.ObjectListBase, base.WatcherObject):
|
||||
pass
|
||||
|
||||
class Bar(base.WatcherObject):
|
||||
fields = {'foo': str}
|
||||
|
||||
obj = Foo(self.context, objects=[])
|
||||
self.assertEqual(set(['objects']), obj.obj_what_changed())
|
||||
obj.objects.append(Bar(self.context, foo='test'))
|
||||
self.assertEqual(set(['objects']), obj.obj_what_changed())
|
||||
def test_dehydration(self):
|
||||
expected = {'watcher_object.name': 'MyObj',
|
||||
'watcher_object.namespace': 'watcher',
|
||||
'watcher_object.version': '1.5',
|
||||
'watcher_object.data': {'foo': 1}}
|
||||
obj = MyObj(self.context)
|
||||
obj.foo = 1
|
||||
obj.obj_reset_changes()
|
||||
# This should still look dirty because the child is dirty
|
||||
self.assertEqual(set(['objects']), obj.obj_what_changed())
|
||||
obj.objects[0].obj_reset_changes()
|
||||
# This should now look clean because the child is clean
|
||||
self.assertEqual(set(), obj.obj_what_changed())
|
||||
self.assertEqual(expected, obj.obj_to_primitive())
|
||||
|
||||
def test_get_updates(self):
|
||||
obj = MyObj(self.context)
|
||||
self.assertEqual({}, obj.obj_get_changes())
|
||||
obj.foo = 123
|
||||
self.assertEqual({'foo': 123}, obj.obj_get_changes())
|
||||
obj.bar = 'test'
|
||||
self.assertEqual({'foo': 123, 'bar': 'test'}, obj.obj_get_changes())
|
||||
obj.obj_reset_changes()
|
||||
self.assertEqual({}, obj.obj_get_changes())
|
||||
|
||||
def test_object_property(self):
|
||||
obj = MyObj(self.context, foo=1)
|
||||
self.assertEqual(1, obj.foo)
|
||||
|
||||
def test_object_property_type_error(self):
|
||||
obj = MyObj(self.context)
|
||||
|
||||
def fail():
|
||||
obj.foo = 'a'
|
||||
self.assertRaises(ValueError, fail)
|
||||
|
||||
def test_load(self):
|
||||
obj = MyObj(self.context)
|
||||
self.assertEqual('loaded!', obj.bar)
|
||||
|
||||
def test_load_in_base(self):
|
||||
@base.WatcherObjectRegistry.register_if(False)
|
||||
class Foo(base.WatcherPersistentObject, base.WatcherObject,
|
||||
base.WatcherObjectDictCompat):
|
||||
fields = {'foobar': fields.IntegerField()}
|
||||
obj = Foo(self.context)
|
||||
|
||||
self.assertRaisesRegex(
|
||||
NotImplementedError, "Cannot load 'foobar' in the base class",
|
||||
getattr, obj, 'foobar')
|
||||
|
||||
def test_loaded_in_primitive(self):
|
||||
obj = MyObj(self.context)
|
||||
obj.foo = 1
|
||||
obj.obj_reset_changes()
|
||||
self.assertEqual('loaded!', obj.bar)
|
||||
expected = {'watcher_object.name': 'MyObj',
|
||||
'watcher_object.namespace': 'watcher',
|
||||
'watcher_object.version': '1.5',
|
||||
'watcher_object.changes': ['bar'],
|
||||
'watcher_object.data': {'foo': 1,
|
||||
'bar': 'loaded!'}}
|
||||
self.assertEqual(expected, obj.obj_to_primitive())
|
||||
|
||||
def test_changes_in_primitive(self):
|
||||
obj = MyObj(self.context)
|
||||
obj.foo = 123
|
||||
self.assertEqual(set(['foo']), obj.obj_what_changed())
|
||||
primitive = obj.obj_to_primitive()
|
||||
self.assertIn('watcher_object.changes', primitive)
|
||||
obj2 = MyObj.obj_from_primitive(primitive)
|
||||
self.assertEqual(set(['foo']), obj2.obj_what_changed())
|
||||
obj2.obj_reset_changes()
|
||||
self.assertEqual(set(), obj2.obj_what_changed())
|
||||
|
||||
def test_unknown_objtype(self):
|
||||
self.assertRaises(object_exception.UnsupportedObjectError,
|
||||
base.WatcherObject.obj_class_from_name, 'foo', '1.0')
|
||||
|
||||
def test_with_alternate_context(self):
|
||||
ctxt1 = context.RequestContext('foo', 'foo')
|
||||
ctxt2 = context.RequestContext(user='alternate')
|
||||
obj = MyObj.query(ctxt1)
|
||||
obj.update_test(ctxt2)
|
||||
self.assertEqual('alternate-context', obj.bar)
|
||||
|
||||
def test_orphaned_object(self):
|
||||
obj = MyObj.query(self.context)
|
||||
obj._context = None
|
||||
self.assertRaises(object_exception.OrphanedObjectError,
|
||||
obj.update_test)
|
||||
|
||||
def test_changed_1(self):
|
||||
obj = MyObj.query(self.context)
|
||||
obj.foo = 123
|
||||
self.assertEqual(set(['foo']), obj.obj_what_changed())
|
||||
obj.update_test(self.context)
|
||||
self.assertEqual(set(['foo', 'bar']), obj.obj_what_changed())
|
||||
self.assertEqual(123, obj.foo)
|
||||
|
||||
def test_changed_2(self):
|
||||
obj = MyObj.query(self.context)
|
||||
obj.foo = 123
|
||||
self.assertEqual(set(['foo']), obj.obj_what_changed())
|
||||
obj.save()
|
||||
self.assertEqual(set([]), obj.obj_what_changed())
|
||||
self.assertEqual(123, obj.foo)
|
||||
|
||||
def test_changed_3(self):
|
||||
obj = MyObj.query(self.context)
|
||||
obj.foo = 123
|
||||
self.assertEqual(set(['foo']), obj.obj_what_changed())
|
||||
obj.refresh()
|
||||
self.assertEqual(set([]), obj.obj_what_changed())
|
||||
self.assertEqual(321, obj.foo)
|
||||
self.assertEqual('refreshed', obj.bar)
|
||||
|
||||
def test_changed_4(self):
|
||||
obj = MyObj.query(self.context)
|
||||
obj.bar = 'something'
|
||||
self.assertEqual(set(['bar']), obj.obj_what_changed())
|
||||
obj.modify_save_modify(self.context)
|
||||
self.assertEqual(set(['foo']), obj.obj_what_changed())
|
||||
self.assertEqual(42, obj.foo)
|
||||
self.assertEqual('meow', obj.bar)
|
||||
|
||||
def test_static_result(self):
|
||||
obj = MyObj.query(self.context)
|
||||
self.assertEqual('bar', obj.bar)
|
||||
result = obj.marco()
|
||||
self.assertEqual('polo', result)
|
||||
|
||||
def test_updates(self):
|
||||
obj = MyObj.query(self.context)
|
||||
self.assertEqual(1, obj.foo)
|
||||
obj.update_test()
|
||||
self.assertEqual('updated', obj.bar)
|
||||
|
||||
def test_base_attributes(self):
|
||||
dt = datetime.datetime(1955, 11, 5, 0, 0, tzinfo=iso8601.iso8601.Utc())
|
||||
datatime = fields.DateTimeField()
|
||||
obj = MyObj(self.context)
|
||||
obj.created_at = dt
|
||||
obj.updated_at = dt
|
||||
expected = {'watcher_object.name': 'MyObj',
|
||||
'watcher_object.namespace': 'watcher',
|
||||
'watcher_object.version': '1.5',
|
||||
'watcher_object.changes':
|
||||
['created_at', 'updated_at'],
|
||||
'watcher_object.data':
|
||||
{'created_at': datatime.stringify(dt),
|
||||
'updated_at': datatime.stringify(dt),
|
||||
}
|
||||
}
|
||||
actual = obj.obj_to_primitive()
|
||||
# watcher_object.changes is built from a set and order is undefined
|
||||
self.assertEqual(sorted(expected['watcher_object.changes']),
|
||||
sorted(actual['watcher_object.changes']))
|
||||
del expected[
|
||||
'watcher_object.changes'], actual['watcher_object.changes']
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
def test_contains(self):
|
||||
obj = MyObj(self.context)
|
||||
self.assertNotIn('foo', obj)
|
||||
obj.foo = 1
|
||||
self.assertIn('foo', obj)
|
||||
self.assertNotIn('does_not_exist', obj)
|
||||
|
||||
def test_obj_attr_is_set(self):
|
||||
obj = MyObj(self.context, foo=1)
|
||||
self.assertTrue(obj.obj_attr_is_set('foo'))
|
||||
self.assertFalse(obj.obj_attr_is_set('bar'))
|
||||
self.assertRaises(AttributeError, obj.obj_attr_is_set, 'bang')
|
||||
|
||||
def test_get(self):
|
||||
obj = MyObj(self.context, foo=1)
|
||||
# Foo has value, should not get the default
|
||||
self.assertEqual(obj.get('foo', 2), 1)
|
||||
# Foo has value, should return the value without error
|
||||
self.assertEqual(obj.get('foo'), 1)
|
||||
# Bar is not loaded, so we should get the default
|
||||
self.assertEqual(obj.get('bar', 'not-loaded'), 'not-loaded')
|
||||
# Bar without a default should lazy-load
|
||||
self.assertEqual(obj.get('bar'), 'loaded!')
|
||||
# Bar now has a default, but loaded value should be returned
|
||||
self.assertEqual(obj.get('bar', 'not-loaded'), 'loaded!')
|
||||
# Invalid attribute should raise AttributeError
|
||||
self.assertRaises(AttributeError, obj.get, 'nothing')
|
||||
# ...even with a default
|
||||
self.assertRaises(AttributeError, obj.get, 'nothing', 3)
|
||||
|
||||
def test_object_inheritance(self):
|
||||
base_fields = (
|
||||
list(base.WatcherObject.fields) +
|
||||
list(base.WatcherPersistentObject.fields))
|
||||
myobj_fields = ['foo', 'bar', 'missing'] + base_fields
|
||||
myobj3_fields = ['new_field']
|
||||
self.assertTrue(issubclass(WatcherTestSubclassedObject, MyObj))
|
||||
self.assertEqual(len(myobj_fields), len(MyObj.fields))
|
||||
self.assertEqual(set(myobj_fields), set(MyObj.fields.keys()))
|
||||
self.assertEqual(len(myobj_fields) + len(myobj3_fields),
|
||||
len(WatcherTestSubclassedObject.fields))
|
||||
self.assertEqual(set(myobj_fields) | set(myobj3_fields),
|
||||
set(WatcherTestSubclassedObject.fields.keys()))
|
||||
|
||||
def test_get_changes(self):
|
||||
obj = MyObj(self.context)
|
||||
self.assertEqual({}, obj.obj_get_changes())
|
||||
obj.foo = 123
|
||||
self.assertEqual({'foo': 123}, obj.obj_get_changes())
|
||||
obj.bar = 'test'
|
||||
self.assertEqual({'foo': 123, 'bar': 'test'}, obj.obj_get_changes())
|
||||
obj.obj_reset_changes()
|
||||
self.assertEqual({}, obj.obj_get_changes())
|
||||
|
||||
def test_obj_fields(self):
|
||||
@base.WatcherObjectRegistry.register_if(False)
|
||||
class TestObj(base.WatcherPersistentObject, base.WatcherObject,
|
||||
base.WatcherObjectDictCompat):
|
||||
fields = {'foo': fields.IntegerField()}
|
||||
obj_extra_fields = ['bar']
|
||||
|
||||
@property
|
||||
def bar(self):
|
||||
return 'this is bar'
|
||||
|
||||
obj = TestObj(self.context)
|
||||
self.assertEqual(set(['created_at', 'updated_at', 'deleted_at',
|
||||
'foo', 'bar']),
|
||||
set(obj.obj_fields))
|
||||
|
||||
def test_refresh_object(self):
|
||||
@base.WatcherObjectRegistry.register_if(False)
|
||||
class TestObj(base.WatcherPersistentObject, base.WatcherObject,
|
||||
base.WatcherObjectDictCompat):
|
||||
fields = {'foo': fields.IntegerField(),
|
||||
'bar': fields.StringField()}
|
||||
|
||||
obj = TestObj(self.context)
|
||||
current_obj = TestObj(self.context)
|
||||
obj.foo = 10
|
||||
obj.bar = 'obj.bar'
|
||||
current_obj.foo = 2
|
||||
current_obj.bar = 'current.bar'
|
||||
obj.obj_refresh(current_obj)
|
||||
self.assertEqual(obj.foo, 2)
|
||||
self.assertEqual(obj.bar, 'current.bar')
|
||||
|
||||
def test_obj_constructor(self):
|
||||
obj = MyObj(self.context, foo=123, bar='abc')
|
||||
self.assertEqual(123, obj.foo)
|
||||
self.assertEqual('abc', obj.bar)
|
||||
self.assertEqual(set(['foo', 'bar']), obj.obj_what_changed())
|
||||
|
||||
def test_assign_value_without_DictCompat(self):
|
||||
class TestObj(base.WatcherObject):
|
||||
fields = {'foo': fields.IntegerField(),
|
||||
'bar': fields.StringField()}
|
||||
obj = TestObj(self.context)
|
||||
obj.foo = 10
|
||||
err_message = ''
|
||||
try:
|
||||
obj['bar'] = 'value'
|
||||
except TypeError as e:
|
||||
err_message = six.text_type(e)
|
||||
finally:
|
||||
self.assertIn("'TestObj' object does not support item assignment",
|
||||
err_message)
|
||||
|
||||
|
||||
class TestObject(_LocalTest, _TestObject):
|
||||
pass
|
||||
|
||||
|
||||
# The hashes are help developers to check if the change of objects need a
|
||||
# version bump. It is md5 hash of object fields and remotable methods.
|
||||
# The fingerprint values should only be changed if there is a version bump.
|
||||
expected_object_fingerprints = {
|
||||
'Goal': '1.0-93881622db05e7b67a65ca885b4a022e',
|
||||
'Strategy': '1.0-e60f62cc854c6e63fb1c3befbfc8629e',
|
||||
'AuditTemplate': '1.0-7432ee4d3ce0c7cbb9d11a4565ee8eb6',
|
||||
'Audit': '1.0-ebfc5360d019baf583a10a8a27071c97',
|
||||
'ActionPlan': '1.0-cc76fd7f0e8479aeff817dd266341de4',
|
||||
'Action': '1.0-a78f69c0da98e13e601f9646f6b2f883',
|
||||
'EfficacyIndicator': '1.0-655b71234a82bc7478aff964639c4bb0',
|
||||
'ScoringEngine': '1.0-4abbe833544000728e17bd9e83f97576',
|
||||
'Service': '1.0-4b35b99ada9677a882c9de2b30212f35',
|
||||
'MyObj': '1.5-23c516d1e842f365f694e688d34e47c3',
|
||||
}
|
||||
|
||||
|
||||
class TestObjectVersions(test_base.TestCase):
|
||||
|
||||
def test_object_version_check(self):
|
||||
classes = base.WatcherObjectRegistry.obj_classes()
|
||||
checker = object_fixture.ObjectVersionChecker(obj_classes=classes)
|
||||
# Compute the difference between actual fingerprints and
|
||||
# expect fingerprints. expect = actual = {} if there is no change.
|
||||
expect, actual = checker.test_hashes(expected_object_fingerprints)
|
||||
self.assertEqual(expect, actual,
|
||||
"Some objects fields or remotable methods have been "
|
||||
"modified. Please make sure the version of those "
|
||||
"objects have been bumped and then update "
|
||||
"expected_object_fingerprints with the new hashes. ")
|
||||
|
||||
|
||||
class TestObjectSerializer(test_base.TestCase):
|
||||
|
||||
def test_serialize_entity_primitive(self):
|
||||
ser = base.WatcherObjectSerializer()
|
||||
for thing in (1, 'foo', [1, 2], {'foo': 'bar'}):
|
||||
self.assertEqual(thing, ser.serialize_entity(None, thing))
|
||||
|
||||
def test_deserialize_entity_primitive(self):
|
||||
ser = base.WatcherObjectSerializer()
|
||||
for thing in (1, 'foo', [1, 2], {'foo': 'bar'}):
|
||||
self.assertEqual(thing, ser.deserialize_entity(None, thing))
|
||||
|
||||
def test_object_serialization(self):
|
||||
ser = base.WatcherObjectSerializer()
|
||||
obj = MyObj(self.context)
|
||||
@@ -321,3 +461,83 @@ class TestObjectSerializer(test_base.TestCase):
|
||||
self.assertEqual(1, len(thing2))
|
||||
for item in thing2:
|
||||
self.assertIsInstance(item, MyObj)
|
||||
|
||||
@mock.patch('watcher.objects.base.WatcherObject.indirection_api')
|
||||
def _test_deserialize_entity_newer(self, obj_version, backported_to,
|
||||
mock_indirection_api,
|
||||
my_version='1.6'):
|
||||
ser = base.WatcherObjectSerializer()
|
||||
mock_indirection_api.object_backport_versions.return_value \
|
||||
= 'backported'
|
||||
|
||||
@base.WatcherObjectRegistry.register
|
||||
class MyTestObj(MyObj):
|
||||
VERSION = my_version
|
||||
|
||||
obj = MyTestObj(self.context)
|
||||
obj.VERSION = obj_version
|
||||
primitive = obj.obj_to_primitive()
|
||||
result = ser.deserialize_entity(self.context, primitive)
|
||||
if backported_to is None:
|
||||
self.assertFalse(
|
||||
mock_indirection_api.object_backport_versions.called)
|
||||
else:
|
||||
self.assertEqual('backported', result)
|
||||
versions = object_base.obj_tree_get_versions('MyTestObj')
|
||||
mock_indirection_api.object_backport_versions.assert_called_with(
|
||||
self.context, primitive, versions)
|
||||
|
||||
def test_deserialize_entity_newer_version_backports(self):
|
||||
"Test object with unsupported (newer) version"
|
||||
self._test_deserialize_entity_newer('1.25', '1.6')
|
||||
|
||||
def test_deserialize_entity_same_revision_does_not_backport(self):
|
||||
"Test object with supported revision"
|
||||
self._test_deserialize_entity_newer('1.6', None)
|
||||
|
||||
def test_deserialize_entity_newer_revision_does_not_backport_zero(self):
|
||||
"Test object with supported revision"
|
||||
self._test_deserialize_entity_newer('1.6.0', None)
|
||||
|
||||
def test_deserialize_entity_newer_revision_does_not_backport(self):
|
||||
"Test object with supported (newer) revision"
|
||||
self._test_deserialize_entity_newer('1.6.1', None)
|
||||
|
||||
def test_deserialize_entity_newer_version_passes_revision(self):
|
||||
"Test object with unsupported (newer) version and revision"
|
||||
self._test_deserialize_entity_newer('1.7', '1.6.1', my_version='1.6.1')
|
||||
|
||||
|
||||
class TestRegistry(test_base.TestCase):
|
||||
|
||||
@mock.patch('watcher.objects.base.objects')
|
||||
def test_hook_chooses_newer_properly(self, mock_objects):
|
||||
reg = base.WatcherObjectRegistry()
|
||||
reg.registration_hook(MyObj, 0)
|
||||
|
||||
class MyNewerObj(object):
|
||||
VERSION = '1.123'
|
||||
|
||||
@classmethod
|
||||
def obj_name(cls):
|
||||
return 'MyObj'
|
||||
|
||||
self.assertEqual(MyObj, mock_objects.MyObj)
|
||||
reg.registration_hook(MyNewerObj, 0)
|
||||
self.assertEqual(MyNewerObj, mock_objects.MyObj)
|
||||
|
||||
@mock.patch('watcher.objects.base.objects')
|
||||
def test_hook_keeps_newer_properly(self, mock_objects):
|
||||
reg = base.WatcherObjectRegistry()
|
||||
reg.registration_hook(MyObj, 0)
|
||||
|
||||
class MyOlderObj(object):
|
||||
VERSION = '1.1'
|
||||
|
||||
@classmethod
|
||||
def obj_name(cls):
|
||||
return 'MyObj'
|
||||
|
||||
self.assertEqual(MyObj, mock_objects.MyObj)
|
||||
reg.registration_hook(MyOlderObj, 0)
|
||||
self.assertEqual(MyObj, mock_objects.MyObj)
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
from testtools import matchers
|
||||
|
||||
from watcher import objects
|
||||
from watcher.tests.db import base
|
||||
@@ -43,7 +42,7 @@ class TestServiceObject(base.DbTestCase):
|
||||
mock_get_list.return_value = [self.fake_service]
|
||||
services = objects.Service.list(self.context)
|
||||
self.assertEqual(1, mock_get_list.call_count, 1)
|
||||
self.assertThat(services, matchers.HasLength(1))
|
||||
self.assertEqual(1, len(services))
|
||||
self.assertIsInstance(services[0], objects.Service)
|
||||
self.assertEqual(self.context, services[0]._context)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user