From 0063aa33c65def9245730754ab2dc2f1b09b76e0 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Mon, 16 Apr 2018 23:05:53 -0700 Subject: [PATCH] pecan.jsonify v1.3 adjustment From pecan v1.3, pecan.jsonify uses json.Encoder unconditionally so that jsonifying mock fails. Pecan v1.2 uses simplejson.Encoder as encoder which accidentally encodes MagicMock as {} due to check of '_asdict' attributes. Since pecan.jsonify uses __json__ magic method when it's defined, add __json__ method to mocks to return {} as json encode. Closes-bug: #1754978 Change-Id: Iac955a7de2a1b66b5b56a73f5cc8a4e75150f82e --- neutron/tests/tools.py | 40 +++++++++++++++++++ neutron/tests/unit/api/v2/test_base.py | 2 + .../tests/unit/extensions/test_providernet.py | 2 + 3 files changed, 44 insertions(+) diff --git a/neutron/tests/tools.py b/neutron/tests/tools.py index c4a03376359..dafe2e6cebc 100644 --- a/neutron/tests/tools.py +++ b/neutron/tests/tools.py @@ -146,6 +146,46 @@ def verify_mock_calls(mocked_call, expected_calls_and_values, mocked_call.assert_has_calls(expected_calls, any_order=any_order) +def _make_magic_method(method_mock): + # NOTE(yamahata): new environment needs to be created to keep actual + # method_mock for each callables. + def __call__(*args, **kwargs): + value_mock = method_mock._orig___call__(*args, **kwargs) + value_mock.__json__ = lambda: {} + return value_mock + + def _get_child_mock(**kwargs): + value_mock = method_mock._orig__get_child_mock(**kwargs) + value_mock.__json__ = lambda: {} + return value_mock + + return __call__, _get_child_mock + + +def make_mock_plugin_json_encodable(plugin_instance_mock): + # NOTE(yamahata): Make return value of plugin method json encodable + # e.g. the return value of plugin_instance.create_network() needs + # to be json encodable + # plugin instance -> method -> return value + # Mock MagicMock Mock + # plugin_instance_mock method_mock value_mock + # + # From v1.3 of pecan, pecan.jsonify uses json.Encoder unconditionally. + # pecan v1.2 uses simplejson.Encoder which accidentally encodes + # Mock as {} due to check of '_asdict' attributes. + # pecan.jsonify uses __json__ magic method for encoding when + # it's defined, so add __json__ method to return {} + for method_mock in plugin_instance_mock._mock_children.values(): + if not callable(method_mock): + continue + + method_mock._orig___call__ = method_mock.__call__ + method_mock._orig__get_child_mock = method_mock._get_child_mock + __call__, _get_child_mock = _make_magic_method(method_mock) + method_mock.__call__ = __call__ + method_mock._get_child_mock = _get_child_mock + + def get_subscribe_args(*args): # NOTE(yamahata): from neutron-lib 1.9.1, callback priority was added. # old signature: (callback, resource, event) diff --git a/neutron/tests/unit/api/v2/test_base.py b/neutron/tests/unit/api/v2/test_base.py index 5cb367345d9..42e35b74713 100644 --- a/neutron/tests/unit/api/v2/test_base.py +++ b/neutron/tests/unit/api/v2/test_base.py @@ -43,6 +43,7 @@ from neutron import quota from neutron.quota import resource_registry from neutron.tests import base from neutron.tests import fake_notifier +from neutron.tests import tools from neutron.tests.unit import dummy_plugin from neutron.tests.unit import testlib_api @@ -87,6 +88,7 @@ class APIv2TestBase(base.BaseTestCase): instance = self.plugin.return_value instance._NeutronPluginBaseV2__native_pagination_support = True instance._NeutronPluginBaseV2__native_sorting_support = True + tools.make_mock_plugin_json_encodable(instance) api = router.APIRouter() self.api = webtest.TestApp(api) diff --git a/neutron/tests/unit/extensions/test_providernet.py b/neutron/tests/unit/extensions/test_providernet.py index fe424c40fb0..9ef8f4e0db5 100644 --- a/neutron/tests/unit/extensions/test_providernet.py +++ b/neutron/tests/unit/extensions/test_providernet.py @@ -28,6 +28,7 @@ from neutron.api import extensions from neutron.api.v2 import router from neutron.extensions import providernet as pnet from neutron import quota +from neutron.tests import tools from neutron.tests.unit.api import test_extensions from neutron.tests.unit.api.v2 import test_base from neutron.tests.unit import testlib_api @@ -70,6 +71,7 @@ class ProvidernetExtensionTestCase(testlib_api.WebTestCase): instance.get_networks_count.return_value = 1 # Register mock plugin and enable the 'provider' extension instance.supported_extension_aliases = ["provider"] + tools.make_mock_plugin_json_encodable(instance) directory.add_plugin(constants.CORE, instance) ext_mgr = ProviderExtensionManager() self.ext_mdw = test_extensions.setup_extensions_middleware(ext_mgr)