From 074268f74c1ed0acb386eaba25249ac3f0885b94 Mon Sep 17 00:00:00 2001 From: Martin Hickey Date: Tue, 15 Dec 2015 17:42:39 +0000 Subject: [PATCH] Add test for Neutron object versions Adds a test to Neutron to check object versions for any changes to objects. It prompts the developer to update the version of the changed object. It uses oslo.versionedobjects. Change-Id: I99454b28ae0b5fa663354eeccdf709d4030a280b Co-Authored-By: Ryan Rossiter --- neutron/objects/qos/policy.py | 2 + neutron/objects/qos/rule.py | 2 + neutron/objects/qos/rule_type.py | 2 + .../api/rpc/handlers/test_resources_rpc.py | 22 ++++++++- neutron/tests/unit/objects/test_base.py | 4 +- neutron/tests/unit/objects/test_objects.py | 48 +++++++++++++++++++ tools/check_unit_test_structure.sh | 2 + tox.ini | 2 +- 8 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 neutron/tests/unit/objects/test_objects.py diff --git a/neutron/objects/qos/policy.py b/neutron/objects/qos/policy.py index dfdc66848d7..110a921f6aa 100644 --- a/neutron/objects/qos/policy.py +++ b/neutron/objects/qos/policy.py @@ -27,6 +27,8 @@ from neutron.objects.qos import rule as rule_obj_impl @obj_base.VersionedObjectRegistry.register class QosPolicy(base.NeutronDbObject): + # Version 1.0: Initial version + VERSION = '1.0' db_model = qos_db_model.QosPolicy diff --git a/neutron/objects/qos/rule.py b/neutron/objects/qos/rule.py index 2362fb7be99..1cf90eb04ed 100644 --- a/neutron/objects/qos/rule.py +++ b/neutron/objects/qos/rule.py @@ -77,6 +77,8 @@ class QosRule(base.NeutronDbObject): @obj_base.VersionedObjectRegistry.register class QosBandwidthLimitRule(QosRule): + # Version 1.0: Initial version + VERSION = '1.0' db_model = qos_db_model.QosBandwidthLimitRule diff --git a/neutron/objects/qos/rule_type.py b/neutron/objects/qos/rule_type.py index fb0754b9394..bb5d9bd7407 100644 --- a/neutron/objects/qos/rule_type.py +++ b/neutron/objects/qos/rule_type.py @@ -28,6 +28,8 @@ class RuleTypeField(obj_fields.BaseEnumField): @obj_base.VersionedObjectRegistry.register class QosRuleType(base.NeutronObject): + # Version 1.0: Initial version + VERSION = '1.0' fields = { 'type': RuleTypeField(), diff --git a/neutron/tests/unit/api/rpc/handlers/test_resources_rpc.py b/neutron/tests/unit/api/rpc/handlers/test_resources_rpc.py index 179bf5150cf..bd32fe01bd1 100755 --- a/neutron/tests/unit/api/rpc/handlers/test_resources_rpc.py +++ b/neutron/tests/unit/api/rpc/handlers/test_resources_rpc.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import copy + import mock from oslo_versionedobjects import base as obj_base from oslo_versionedobjects import fields as obj_fields @@ -38,8 +40,9 @@ def _create_test_resource(context=None): return resource -@obj_base.VersionedObjectRegistry.register class FakeResource(objects_base.NeutronObject): + # Version 1.0: Initial version + VERSION = '1.0' fields = { 'id': obj_fields.UUIDField(), @@ -55,8 +58,22 @@ class ResourcesRpcBaseTestCase(base.BaseTestCase): def setUp(self): super(ResourcesRpcBaseTestCase, self).setUp() + + # TODO(mhickey) This is using temp registry pattern. The + # pattern solution is to backup the object registry, register + # a class locally, and then restore the original registry. + # Refer to https://review.openstack.org/#/c/263800/ for more + # details. This code should be updated when the patch is merged. + self._base_test_backup = copy.copy( + obj_base.VersionedObjectRegistry._registry._obj_classes) + self.addCleanup(self._restore_obj_registry) + self.context = context.get_admin_context() + def _restore_obj_registry(self): + obj_base.VersionedObjectRegistry._registry._obj_classes = ( + self._base_test_backup) + class _ValidateResourceTypeTestCase(base.BaseTestCase): def setUp(self): @@ -103,6 +120,7 @@ class ResourcesPullRpcApiTestCase(ResourcesRpcBaseTestCase): self.assertIs(self.rpc, resources_rpc.ResourcesPullRpcApi()) def test_pull(self): + obj_base.VersionedObjectRegistry.register(FakeResource) expected_obj = _create_test_resource(self.context) resource_id = expected_obj.id self.cctxt_mock.call.return_value = expected_obj.obj_to_primitive() @@ -128,6 +146,7 @@ class ResourcesPullRpcCallbackTestCase(ResourcesRpcBaseTestCase): def setUp(self): super(ResourcesPullRpcCallbackTestCase, self).setUp() + obj_base.VersionedObjectRegistry.register(FakeResource) self.callbacks = resources_rpc.ResourcesPullRpcCallback() self.resource_obj = _create_test_resource(self.context) @@ -207,6 +226,7 @@ class ResourcesPushRpcCallbackTestCase(ResourcesRpcBaseTestCase): @mock.patch.object(resources_rpc.cons_registry, 'push') def test_push(self, reg_push_mock): + obj_base.VersionedObjectRegistry.register(FakeResource) self.callbacks.push(self.context, self.resource_prim, 'TYPE') reg_push_mock.assert_called_once_with(self.resource_obj.obj_name(), self.resource_obj, 'TYPE') diff --git a/neutron/tests/unit/objects/test_base.py b/neutron/tests/unit/objects/test_base.py index 00afb8a62ee..34743ac5f94 100644 --- a/neutron/tests/unit/objects/test_base.py +++ b/neutron/tests/unit/objects/test_base.py @@ -36,8 +36,10 @@ class FakeModel(object): pass -@obj_base.VersionedObjectRegistry.register +@obj_base.VersionedObjectRegistry.register_if(False) class FakeNeutronObject(base.NeutronDbObject): + # Version 1.0: Initial version + VERSION = '1.0' db_model = FakeModel diff --git a/neutron/tests/unit/objects/test_objects.py b/neutron/tests/unit/objects/test_objects.py new file mode 100644 index 00000000000..341fc0fa26f --- /dev/null +++ b/neutron/tests/unit/objects/test_objects.py @@ -0,0 +1,48 @@ +# Copyright 2015 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 +# 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. + +import os +import pprint + +from oslo_versionedobjects import base as obj_base +from oslo_versionedobjects import fixture + +from neutron.tests import base as test_base + + +# NOTE: The hashes in this list should only be changed if they come with a +# corresponding version bump in the affected objects. +object_data = { + 'QosBandwidthLimitRule': '1.0-4e44a8f5c2895ab1278399f87b40a13d', + 'QosRuleType': '1.0-d0df298d49eeffab91af18d1a4cf7eaf', + 'QosPolicy': '1.0-721fa60ea8f0e8f15d456d6e917dfe59', +} + + +class TestObjectVersions(test_base.BaseTestCase): + + def test_versions(self): + checker = fixture.ObjectVersionChecker( + obj_base.VersionedObjectRegistry.obj_classes()) + fingerprints = checker.get_hashes() + + if os.getenv('GENERATE_HASHES'): + file('object_hashes.txt', 'w').write( + pprint.pformat(fingerprints)) + + expected, actual = checker.test_hashes(object_data) + self.assertEqual(expected, actual, + 'Some objects have changed; please make sure the ' + 'versions have been bumped, and then update their ' + 'hashes in the object_data map in this test module.') diff --git a/tools/check_unit_test_structure.sh b/tools/check_unit_test_structure.sh index 9ada2e3bb94..d47eba8103d 100755 --- a/tools/check_unit_test_structure.sh +++ b/tools/check_unit_test_structure.sh @@ -14,6 +14,8 @@ ignore_regexes=( # The following vendor plugins are not required to confrm to the # structural requirements. "^plugins/ibm.*$" + # The following test is required for oslo.versionedobjects + "^objects/test_objects.py$" # The following open source plugin tests are not actually unit # tests and are ignored pending their relocation to the functional # test tree. diff --git a/tox.ini b/tox.ini index 9710cb9a521..879122a5258 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,7 @@ skipsdist = True [testenv] setenv = VIRTUAL_ENV={envdir} -passenv = TRACE_FAILONLY +passenv = TRACE_FAILONLY GENERATE_HASHES usedevelop = True install_command = constraints: {[testenv:common-constraints]install_command}