diff --git a/os_vif/objects/base.py b/os_vif/objects/base.py index 8ac6f482..d2aa3420 100644 --- a/os_vif/objects/base.py +++ b/os_vif/objects/base.py @@ -16,3 +16,16 @@ from oslo_versionedobjects import base as ovo_base class VersionedObject(ovo_base.VersionedObject): OBJ_PROJECT_NAMESPACE = 'os_vif' + + +class VersionedObjectPrintableMixin(object): + """Mix-in to implement __str__ method for a versioned object + + If a versioned object needs to be printable in a easy-reading format, + inherit from this class. + """ + + def __str__(self): + if callable(getattr(self, 'obj_to_primitive', None)): + return str(self.obj_to_primitive()) + return super(VersionedObjectPrintableMixin, self).__str__() diff --git a/os_vif/objects/host_info.py b/os_vif/objects/host_info.py index 67b91ca0..2178e57e 100644 --- a/os_vif/objects/host_info.py +++ b/os_vif/objects/host_info.py @@ -44,7 +44,8 @@ def _get_common_version(object_name, max_version, min_version, exc_notmatch, @base.VersionedObjectRegistry.register class HostPortProfileInfo(osv_base.VersionedObject, - base.ComparableVersionedObject): + base.ComparableVersionedObject, + osv_base.VersionedObjectPrintableMixin): """ Class describing a PortProfile class and its supported versions """ @@ -73,7 +74,8 @@ class HostPortProfileInfo(osv_base.VersionedObject, @base.VersionedObjectRegistry.register -class HostVIFInfo(osv_base.VersionedObject, base.ComparableVersionedObject): +class HostVIFInfo(osv_base.VersionedObject, base.ComparableVersionedObject, + osv_base.VersionedObjectPrintableMixin): """ Class describing a VIF class and its supported versions """ @@ -114,8 +116,8 @@ class HostVIFInfo(osv_base.VersionedObject, base.ComparableVersionedObject): @base.VersionedObjectRegistry.register -class HostPluginInfo(osv_base.VersionedObject, - base.ComparableVersionedObject): +class HostPluginInfo(osv_base.VersionedObject, base.ComparableVersionedObject, + osv_base.VersionedObjectPrintableMixin): """ Class describing a plugin and its supported VIF classes """ @@ -152,7 +154,8 @@ class HostPluginInfo(osv_base.VersionedObject, @base.VersionedObjectRegistry.register -class HostInfo(osv_base.VersionedObject, base.ComparableVersionedObject): +class HostInfo(osv_base.VersionedObject, base.ComparableVersionedObject, + osv_base.VersionedObjectPrintableMixin): """ Class describing a host host and its supported plugin classes """ diff --git a/os_vif/tests/unit/test_base.py b/os_vif/tests/unit/test_base.py new file mode 100644 index 00000000..0d16be51 --- /dev/null +++ b/os_vif/tests/unit/test_base.py @@ -0,0 +1,77 @@ +# 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 copy +import mock +import six + +from oslo_serialization import jsonutils +from oslo_versionedobjects import base +from oslo_versionedobjects import fields + +from os_vif.objects import base as osv_base +from os_vif.tests.unit import base as test_base + + +class TestVersionedObjectPrintable(test_base.TestCase): + @base.VersionedObjectRegistry.register_if(False) + class OVOChild1(osv_base.VersionedObject, + osv_base.VersionedObjectPrintableMixin): + fields = { + "child1_field1": fields.ListOfIntegersField() + } + + @base.VersionedObjectRegistry.register_if(False) + class OVOParent(osv_base.VersionedObject, + osv_base.VersionedObjectPrintableMixin, + base.ComparableVersionedObject): + fields = { + "parent_field1": fields.ListOfObjectsField("OVOChild1"), + "parent_field2": fields.StringField(), + } + + def setUp(self): + super(TestVersionedObjectPrintable, self).setUp() + child1_1 = self.OVOChild1(child1_field1=[1, 2, 3]) + child1_2 = self.OVOChild1(child1_field1=[4, 5, 6]) + self.obj = self.OVOParent( + parent_field1=[child1_1, child1_2], + parent_field2="test string") + + def test_print_object(self): + out = str(self.obj) + self.assertIn("'child1_field1': [1, 2, 3]}", out) + self.assertIn("'child1_field1': [4, 5, 6]}", out) + cmp = str({'parent_field2': six.text_type("test string")}) + cmp = cmp.replace('{', '').replace('}', '') + self.assertIn(str(cmp), out) + + @mock.patch.object(base.VersionedObject, "obj_class_from_name", + side_effect=[OVOParent, OVOChild1, OVOChild1]) + def test_serialize_object(self, *mock): + """Test jsonutils serialization is not affected by this new mixin.""" + obj_orig = copy.deepcopy(self.obj) + obj_orig_primitive = obj_orig.obj_to_primitive() + str_orig_primitive = jsonutils.dumps(obj_orig_primitive) + obj_new_primitive = jsonutils.loads(str_orig_primitive) + obj_new = self.OVOParent.obj_from_primitive(obj_new_primitive) + self.assertEqual(obj_orig_primitive, obj_new_primitive) + self.assertEqual(obj_orig, obj_new) + + def test_import_non_ovo_class(self): + """Test VersionedObjectPrintable could be inherited by non-OVO classes. + """ + class NonOVOClass(osv_base.VersionedObjectPrintableMixin): + def __str__(self): + return "NonOVOClass __str__ method" + + self.assertEqual("NonOVOClass __str__ method", str(NonOVOClass()))