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
This commit is contained in:
Isaku Yamahata 2018-04-16 23:05:53 -07:00 committed by Isaku Yamahata
parent 390cc07c8c
commit 0063aa33c6
3 changed files with 44 additions and 0 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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)