Merge "Remove XML support"
This commit is contained in:
commit
a0bc00dc9c
@ -25,7 +25,6 @@ import six
|
|||||||
import webob.dec
|
import webob.dec
|
||||||
import webob.exc
|
import webob.exc
|
||||||
|
|
||||||
from neutron.api.v2 import attributes
|
|
||||||
from neutron.common import exceptions
|
from neutron.common import exceptions
|
||||||
import neutron.extensions
|
import neutron.extensions
|
||||||
from neutron import manager
|
from neutron import manager
|
||||||
@ -479,19 +478,9 @@ class ExtensionManager(object):
|
|||||||
attr_map[resource].update(resource_attrs)
|
attr_map[resource].update(resource_attrs)
|
||||||
else:
|
else:
|
||||||
attr_map[resource] = resource_attrs
|
attr_map[resource] = resource_attrs
|
||||||
if extended_attrs:
|
|
||||||
attributes.EXT_NSES[ext.get_alias()] = (
|
|
||||||
ext.get_namespace())
|
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
LOG.exception(_("Error fetching extended attributes for "
|
LOG.exception(_("Error fetching extended attributes for "
|
||||||
"extension '%s'"), ext.get_name())
|
"extension '%s'"), ext.get_name())
|
||||||
try:
|
|
||||||
comp_map = ext.get_alias_namespace_compatibility_map()
|
|
||||||
attributes.EXT_NSES_BC.update(comp_map)
|
|
||||||
except AttributeError:
|
|
||||||
LOG.info(_("Extension '%s' provides no backward "
|
|
||||||
"compatibility map for extended attributes"),
|
|
||||||
ext.get_name())
|
|
||||||
processed_exts.add(ext_name)
|
processed_exts.add(ext_name)
|
||||||
del exts_to_process[ext_name]
|
del exts_to_process[ext_name]
|
||||||
if len(processed_exts) == processed_ext_count:
|
if len(processed_exts) == processed_ext_count:
|
||||||
|
@ -762,16 +762,3 @@ PLURALS = {NETWORKS: NETWORK,
|
|||||||
'allocation_pools': 'allocation_pool',
|
'allocation_pools': 'allocation_pool',
|
||||||
'fixed_ips': 'fixed_ip',
|
'fixed_ips': 'fixed_ip',
|
||||||
'extensions': 'extension'}
|
'extensions': 'extension'}
|
||||||
EXT_NSES = {}
|
|
||||||
|
|
||||||
# Namespaces to be added for backward compatibility
|
|
||||||
# when existing extended resource attributes are
|
|
||||||
# provided by other extension than original one.
|
|
||||||
EXT_NSES_BC = {}
|
|
||||||
|
|
||||||
|
|
||||||
def get_attr_metadata():
|
|
||||||
return {'plurals': PLURALS,
|
|
||||||
'xmlns': constants.XML_NS_V20,
|
|
||||||
constants.EXT_NS: EXT_NSES,
|
|
||||||
constants.EXT_NS_COMP: EXT_NSES_BC}
|
|
||||||
|
@ -24,7 +24,6 @@ import six
|
|||||||
import webob.dec
|
import webob.dec
|
||||||
import webob.exc
|
import webob.exc
|
||||||
|
|
||||||
from neutron.api.v2 import attributes
|
|
||||||
from neutron.common import exceptions
|
from neutron.common import exceptions
|
||||||
from neutron.openstack.common import gettextutils
|
from neutron.openstack.common import gettextutils
|
||||||
from neutron.openstack.common import log as logging
|
from neutron.openstack.common import log as logging
|
||||||
@ -42,14 +41,9 @@ def Resource(controller, faults=None, deserializers=None, serializers=None):
|
|||||||
"""Represents an API entity resource and the associated serialization and
|
"""Represents an API entity resource and the associated serialization and
|
||||||
deserialization logic
|
deserialization logic
|
||||||
"""
|
"""
|
||||||
xml_deserializer = wsgi.XMLDeserializer(attributes.get_attr_metadata())
|
default_deserializers = {'application/json': wsgi.JSONDeserializer()}
|
||||||
default_deserializers = {'application/xml': xml_deserializer,
|
default_serializers = {'application/json': wsgi.JSONDictSerializer()}
|
||||||
'application/json': wsgi.JSONDeserializer()}
|
format_types = {'json': 'application/json'}
|
||||||
xml_serializer = wsgi.XMLDictSerializer(attributes.get_attr_metadata())
|
|
||||||
default_serializers = {'application/xml': xml_serializer,
|
|
||||||
'application/json': wsgi.JSONDictSerializer()}
|
|
||||||
format_types = {'xml': 'application/xml',
|
|
||||||
'json': 'application/json'}
|
|
||||||
action_status = dict(create=201, delete=204)
|
action_status = dict(create=201, delete=204)
|
||||||
|
|
||||||
default_deserializers.update(deserializers or {})
|
default_deserializers.update(deserializers or {})
|
||||||
|
@ -36,7 +36,7 @@ RESOURCES = {'network': 'networks',
|
|||||||
SUB_RESOURCES = {}
|
SUB_RESOURCES = {}
|
||||||
COLLECTION_ACTIONS = ['index', 'create']
|
COLLECTION_ACTIONS = ['index', 'create']
|
||||||
MEMBER_ACTIONS = ['show', 'update', 'delete']
|
MEMBER_ACTIONS = ['show', 'update', 'delete']
|
||||||
REQUIREMENTS = {'id': attributes.UUID_PATTERN, 'format': 'xml|json'}
|
REQUIREMENTS = {'id': attributes.UUID_PATTERN, 'format': 'json'}
|
||||||
|
|
||||||
|
|
||||||
class Index(wsgi.Application):
|
class Index(wsgi.Application):
|
||||||
@ -45,9 +45,7 @@ class Index(wsgi.Application):
|
|||||||
|
|
||||||
@webob.dec.wsgify(RequestClass=wsgi.Request)
|
@webob.dec.wsgify(RequestClass=wsgi.Request)
|
||||||
def __call__(self, req):
|
def __call__(self, req):
|
||||||
metadata = {'application/xml': {'attributes': {
|
metadata = {}
|
||||||
'resource': ['name', 'collection'],
|
|
||||||
'link': ['href', 'rel']}}}
|
|
||||||
|
|
||||||
layout = []
|
layout = []
|
||||||
for name, collection in self.resources.iteritems():
|
for name, collection in self.resources.iteritems():
|
||||||
|
@ -49,14 +49,7 @@ class Versions(object):
|
|||||||
builder = versions_view.get_view_builder(req)
|
builder = versions_view.get_view_builder(req)
|
||||||
versions = [builder.build(version) for version in version_objs]
|
versions = [builder.build(version) for version in version_objs]
|
||||||
response = dict(versions=versions)
|
response = dict(versions=versions)
|
||||||
metadata = {
|
metadata = {}
|
||||||
"application/xml": {
|
|
||||||
"attributes": {
|
|
||||||
"version": ["status", "id"],
|
|
||||||
"link": ["rel", "href"],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
content_type = req.best_match_content_type()
|
content_type = req.best_match_content_type()
|
||||||
body = (wsgi.Serializer(metadata=metadata).
|
body = (wsgi.Serializer(metadata=metadata).
|
||||||
|
@ -72,19 +72,6 @@ MAX_VXLAN_VNI = 2 ** 24 - 1
|
|||||||
|
|
||||||
FLOODING_ENTRY = ['00:00:00:00:00:00', '0.0.0.0']
|
FLOODING_ENTRY = ['00:00:00:00:00:00', '0.0.0.0']
|
||||||
|
|
||||||
EXT_NS_COMP = '_backward_comp_e_ns'
|
|
||||||
EXT_NS = '_extension_ns'
|
|
||||||
XML_NS_V20 = 'http://openstack.org/quantum/api/v2.0'
|
|
||||||
XSI_NAMESPACE = "http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
XSI_ATTR = "xsi:nil"
|
|
||||||
XSI_NIL_ATTR = "xmlns:xsi"
|
|
||||||
ATOM_NAMESPACE = "http://www.w3.org/2005/Atom"
|
|
||||||
ATOM_XMLNS = "xmlns:atom"
|
|
||||||
ATOM_LINK_NOTATION = "{%s}link" % ATOM_NAMESPACE
|
|
||||||
TYPE_XMLNS = "xmlns:quantum"
|
|
||||||
TYPE_ATTR = "quantum:type"
|
|
||||||
VIRTUAL_ROOT_KEY = "_v_root"
|
|
||||||
|
|
||||||
TYPE_BOOL = "bool"
|
TYPE_BOOL = "bool"
|
||||||
TYPE_INT = "int"
|
TYPE_INT = "int"
|
||||||
TYPE_LONG = "long"
|
TYPE_LONG = "long"
|
||||||
|
@ -203,10 +203,6 @@ class L3RouterApplianceVMTestCase(
|
|||||||
'neutron.db.l3_db.L3_NAT_dbonly_mixin._check_and_get_fip_assoc')
|
'neutron.db.l3_db.L3_NAT_dbonly_mixin._check_and_get_fip_assoc')
|
||||||
|
|
||||||
|
|
||||||
class L3RouterApplianceVMTestCaseXML(L3RouterApplianceVMTestCase):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
|
||||||
|
|
||||||
class CfgAgentRouterApplianceVMTestCase(L3RouterApplianceTestCaseBase,
|
class CfgAgentRouterApplianceVMTestCase(L3RouterApplianceTestCaseBase,
|
||||||
test_l3_plugin.L3AgentDbTestCaseBase):
|
test_l3_plugin.L3AgentDbTestCaseBase):
|
||||||
|
|
||||||
|
@ -1237,7 +1237,3 @@ class TestFirewallDBPlugin(FirewallPluginDbTestCase):
|
|||||||
expected_code=webob.exc.HTTPNotFound.code,
|
expected_code=webob.exc.HTTPNotFound.code,
|
||||||
expected_body=None,
|
expected_body=None,
|
||||||
body_data={'firewall_rule_id': None})
|
body_data={'firewall_rule_id': None})
|
||||||
|
|
||||||
|
|
||||||
class TestFirewallDBPluginXML(TestFirewallDBPlugin):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
@ -1584,7 +1584,3 @@ class TestLoadBalancer(LoadBalancerPluginDbTestCase):
|
|||||||
SystemExit,
|
SystemExit,
|
||||||
loadbalancer_plugin.LoadBalancerPlugin
|
loadbalancer_plugin.LoadBalancerPlugin
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestLoadBalancerXML(TestLoadBalancer):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
@ -294,7 +294,3 @@ class TestMetering(MeteringPluginDbTestCase):
|
|||||||
|
|
||||||
self._test_list_resources('metering-label-rule',
|
self._test_list_resources('metering-label-rule',
|
||||||
metering_label_rule)
|
metering_label_rule)
|
||||||
|
|
||||||
|
|
||||||
class TestMeteringDbXML(TestMetering):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
@ -1596,7 +1596,3 @@ class TestVpnaas(VPNPluginDbTestCase):
|
|||||||
)
|
)
|
||||||
delete_res = delete_req.get_response(self.ext_api)
|
delete_res = delete_req.get_response(self.ext_api)
|
||||||
self.assertEqual(409, delete_res.status_int)
|
self.assertEqual(409, delete_res.status_int)
|
||||||
|
|
||||||
|
|
||||||
class TestVpnaasXML(TestVpnaas):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
@ -752,15 +752,3 @@ class TestCiscoSubnetsV2(CiscoML2MechanismTestCase,
|
|||||||
res,
|
res,
|
||||||
'subnets',
|
'subnets',
|
||||||
wexc.HTTPInternalServerError.code)
|
wexc.HTTPInternalServerError.code)
|
||||||
|
|
||||||
|
|
||||||
class TestCiscoPortsV2XML(TestCiscoPortsV2):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
|
||||||
|
|
||||||
class TestCiscoNetworksV2XML(TestCiscoNetworksV2):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
|
||||||
|
|
||||||
class TestCiscoSubnetsV2XML(TestCiscoSubnetsV2):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
@ -89,17 +89,7 @@ class TestMl2SecurityGroups(Ml2SecurityGroupsTestCase,
|
|||||||
self.assertIsNone(port_dict)
|
self.assertIsNone(port_dict)
|
||||||
|
|
||||||
|
|
||||||
class TestMl2SecurityGroupsXML(TestMl2SecurityGroups):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
|
||||||
|
|
||||||
class TestMl2SGServerRpcCallBack(
|
class TestMl2SGServerRpcCallBack(
|
||||||
Ml2SecurityGroupsTestCase,
|
Ml2SecurityGroupsTestCase,
|
||||||
test_sg_rpc.SGServerRpcCallBackTestCase):
|
test_sg_rpc.SGServerRpcCallBackTestCase):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TestMl2SGServerRpcCallBackXML(
|
|
||||||
Ml2SecurityGroupsTestCase,
|
|
||||||
test_sg_rpc.SGServerRpcCallBackTestCaseXML):
|
|
||||||
pass
|
|
||||||
|
@ -56,10 +56,6 @@ class TestMlnxSecurityGroups(MlnxSecurityGroupsTestCase,
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TestMlnxSecurityGroupsXML(TestMlnxSecurityGroups):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
|
||||||
|
|
||||||
class TestMlnxSecurityGroupsDB(MlnxSecurityGroupsTestCase):
|
class TestMlnxSecurityGroupsDB(MlnxSecurityGroupsTestCase):
|
||||||
def test_security_group_get_port_from_device(self):
|
def test_security_group_get_port_from_device(self):
|
||||||
with self.network() as n:
|
with self.network() as n:
|
||||||
@ -94,7 +90,3 @@ class TestMlnxSecurityGroupsDB(MlnxSecurityGroupsTestCase):
|
|||||||
def test_security_group_get_port_from_device_with_no_port(self):
|
def test_security_group_get_port_from_device_with_no_port(self):
|
||||||
port_dict = mlnx_db.get_port_from_device('bad_device_id')
|
port_dict = mlnx_db.get_port_from_device('bad_device_id')
|
||||||
self.assertIsNone(port_dict)
|
self.assertIsNone(port_dict)
|
||||||
|
|
||||||
|
|
||||||
class TestMlnxSecurityGroupsDBXML(TestMlnxSecurityGroupsDB):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
@ -56,12 +56,6 @@ class TestNecSGServerRpcCallBack(
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TestNecSGServerRpcCallBackXML(
|
|
||||||
test_sg_rpc.SGServerRpcCallBackTestCaseXML,
|
|
||||||
NecSecurityGroupsTestCase):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class TestNecSecurityGroups(NecSecurityGroupsTestCase,
|
class TestNecSecurityGroups(NecSecurityGroupsTestCase,
|
||||||
test_sg.TestSecurityGroups,
|
test_sg.TestSecurityGroups,
|
||||||
test_sg_rpc.SGNotificationTestMixin):
|
test_sg_rpc.SGNotificationTestMixin):
|
||||||
@ -92,7 +86,3 @@ class TestNecSecurityGroups(NecSecurityGroupsTestCase,
|
|||||||
self.assertEqual([fixed_ips[0]['ip_address']],
|
self.assertEqual([fixed_ips[0]['ip_address']],
|
||||||
port_dict['fixed_ips'])
|
port_dict['fixed_ips'])
|
||||||
self._delete('ports', port_id)
|
self._delete('ports', port_id)
|
||||||
|
|
||||||
|
|
||||||
class TestNecSecurityGroupsXML(TestNecSecurityGroups):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
@ -70,12 +70,6 @@ class TestOneConvergenceSGServerRpcCallBack(
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TestOneConvergenceSGServerRpcCallBackXML(
|
|
||||||
OneConvergenceSecurityGroupsTestCase,
|
|
||||||
test_sg_rpc.SGServerRpcCallBackTestCaseXML):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class TestOneConvergenceSecurityGroups(OneConvergenceSecurityGroupsTestCase,
|
class TestOneConvergenceSecurityGroups(OneConvergenceSecurityGroupsTestCase,
|
||||||
test_sg.TestSecurityGroups,
|
test_sg.TestSecurityGroups,
|
||||||
test_sg_rpc.SGNotificationTestMixin):
|
test_sg_rpc.SGNotificationTestMixin):
|
||||||
@ -113,7 +107,3 @@ class TestOneConvergenceSecurityGroups(OneConvergenceSecurityGroupsTestCase,
|
|||||||
plugin = manager.NeutronManager.get_plugin()
|
plugin = manager.NeutronManager.get_plugin()
|
||||||
port_dict = plugin.get_port_from_device('bad_device_id')
|
port_dict = plugin.get_port_from_device('bad_device_id')
|
||||||
self.assertIsNone(port_dict)
|
self.assertIsNone(port_dict)
|
||||||
|
|
||||||
|
|
||||||
class TestOneConvergenceSecurityGroupsXML(TestOneConvergenceSecurityGroups):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
@ -1413,7 +1413,3 @@ class OvsL3AgentNotifierTestCase(test_l3_plugin.L3NatTestCaseMixin,
|
|||||||
mock.ANY, l3_notifier.make_msg(
|
mock.ANY, l3_notifier.make_msg(
|
||||||
'agent_updated', payload={'admin_state_up': False}),
|
'agent_updated', payload={'admin_state_up': False}),
|
||||||
topic='l3_agent.hosta')
|
topic='l3_agent.hosta')
|
||||||
|
|
||||||
|
|
||||||
class OvsAgentSchedulerTestCaseXML(OvsAgentSchedulerTestCase):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
@ -60,8 +60,3 @@ class SecurityGroupsTestCase(ext_sg.SecurityGroupDBTestCase):
|
|||||||
class TestSecurityGroups(ext_sg.TestSecurityGroups, SecurityGroupsTestCase):
|
class TestSecurityGroups(ext_sg.TestSecurityGroups, SecurityGroupsTestCase):
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TestSecurityGroupsXML(TestSecurityGroups):
|
|
||||||
|
|
||||||
fmt = 'xml'
|
|
||||||
|
@ -84,7 +84,3 @@ class TestRyuSecurityGroups(RyuSecurityGroupsTestCase,
|
|||||||
plugin = manager.NeutronManager.get_plugin()
|
plugin = manager.NeutronManager.get_plugin()
|
||||||
port_dict = plugin.get_port_from_device('bad_device_id')
|
port_dict = plugin.get_port_from_device('bad_device_id')
|
||||||
self.assertIsNone(port_dict)
|
self.assertIsNone(port_dict)
|
||||||
|
|
||||||
|
|
||||||
class TestRyuSecurityGroupsXML(TestRyuSecurityGroups):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
@ -215,7 +215,3 @@ class LBaaSAgentSchedulerTestCase(test_agent_ext_plugin.AgentDBTestMixIn,
|
|||||||
'fake_id',
|
'fake_id',
|
||||||
expected_code=exc.HTTPForbidden.code,
|
expected_code=exc.HTTPForbidden.code,
|
||||||
admin_context=False)
|
admin_context=False)
|
||||||
|
|
||||||
|
|
||||||
class LBaaSAgentSchedulerTestCaseXML(LBaaSAgentSchedulerTestCase):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
@ -456,7 +456,3 @@ class LoadBalancerExtensionTestCase(test_api_v2_extension.ExtensionTestCase):
|
|||||||
instance.delete_pool_health_monitor.assert_called_with(
|
instance.delete_pool_health_monitor.assert_called_with(
|
||||||
mock.ANY, health_monitor_id, pool_id='id1')
|
mock.ANY, health_monitor_id, pool_id='id1')
|
||||||
self.assertEqual(res.status_int, exc.HTTPNoContent.code)
|
self.assertEqual(res.status_int, exc.HTTPNoContent.code)
|
||||||
|
|
||||||
|
|
||||||
class LoadBalancerExtensionTestCaseXML(LoadBalancerExtensionTestCase):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
@ -127,10 +127,6 @@ class LBaaSQuotaExtensionDbTestCase(LBaaSQuotaExtensionTestCase):
|
|||||||
self.assertEqual(-1, quota['quota']['health_monitor'])
|
self.assertEqual(-1, quota['quota']['health_monitor'])
|
||||||
|
|
||||||
|
|
||||||
class LBaaSQuotaExtensionDbTestCaseXML(LBaaSQuotaExtensionDbTestCase):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
|
||||||
|
|
||||||
class LBaaSQuotaExtensionCfgTestCase(
|
class LBaaSQuotaExtensionCfgTestCase(
|
||||||
LBaaSQuotaExtensionTestCase):
|
LBaaSQuotaExtensionTestCase):
|
||||||
|
|
||||||
@ -160,7 +156,3 @@ class LBaaSQuotaExtensionCfgTestCase(
|
|||||||
self.serialize(quotas),
|
self.serialize(quotas),
|
||||||
expect_errors=True)
|
expect_errors=True)
|
||||||
self.assertEqual(403, res.status_int)
|
self.assertEqual(403, res.status_int)
|
||||||
|
|
||||||
|
|
||||||
class LBaaSQuotaExtensionCfgTestCaseXML(LBaaSQuotaExtensionCfgTestCase):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
@ -520,7 +520,3 @@ class VpnaasExtensionTestCase(test_api_v2_extension.ExtensionTestCase):
|
|||||||
def test_ipsec_site_connection_delete(self):
|
def test_ipsec_site_connection_delete(self):
|
||||||
"""Test case to delete a ipsec_site_connection."""
|
"""Test case to delete a ipsec_site_connection."""
|
||||||
self._test_entity_delete('ipsec_site_connection')
|
self._test_entity_delete('ipsec_site_connection')
|
||||||
|
|
||||||
|
|
||||||
class VpnaasExtensionTestCaseXML(VpnaasExtensionTestCase):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
@ -251,7 +251,3 @@ class AgentDBTestCase(AgentDBTestMixIn,
|
|||||||
agents = self._list_agents(
|
agents = self._list_agents(
|
||||||
query_string='binary=neutron-l3-agent&host=' + L3_HOSTB)
|
query_string='binary=neutron-l3-agent&host=' + L3_HOSTB)
|
||||||
self.assertFalse(agents['agents'][0]['alive'])
|
self.assertFalse(agents['agents'][0]['alive'])
|
||||||
|
|
||||||
|
|
||||||
class AgentDBTestCaseXML(AgentDBTestCase):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
@ -1196,10 +1196,6 @@ class SubresourceTest(base.BaseTestCase, testlib_plugin.PluginSetupHelper):
|
|||||||
|
|
||||||
# Note: since all resources use the same controller and validation
|
# Note: since all resources use the same controller and validation
|
||||||
# logic, we actually get really good coverage from testing just networks.
|
# logic, we actually get really good coverage from testing just networks.
|
||||||
class XMLV2TestCase(JSONV2TestCase):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
|
||||||
|
|
||||||
class V2Views(base.BaseTestCase):
|
class V2Views(base.BaseTestCase):
|
||||||
def _view(self, keys, collection, resource):
|
def _view(self, keys, collection, resource):
|
||||||
data = dict((key, 'value') for key in keys)
|
data = dict((key, 'value') for key in keys)
|
||||||
|
@ -42,8 +42,7 @@ class RequestTestCase(base.BaseTestCase):
|
|||||||
self.assertEqual(result, "application/json")
|
self.assertEqual(result, "application/json")
|
||||||
|
|
||||||
def test_content_type_from_accept(self):
|
def test_content_type_from_accept(self):
|
||||||
for content_type in ('application/xml',
|
content_type = 'application/json'
|
||||||
'application/json'):
|
|
||||||
request = wsgi.Request.blank('/tests/123')
|
request = wsgi.Request.blank('/tests/123')
|
||||||
request.headers["Accept"] = content_type
|
request.headers["Accept"] = content_type
|
||||||
result = request.best_match_content_type()
|
result = request.best_match_content_type()
|
||||||
@ -51,7 +50,7 @@ class RequestTestCase(base.BaseTestCase):
|
|||||||
|
|
||||||
def test_content_type_from_accept_best(self):
|
def test_content_type_from_accept_best(self):
|
||||||
request = wsgi.Request.blank('/tests/123')
|
request = wsgi.Request.blank('/tests/123')
|
||||||
request.headers["Accept"] = "application/xml, application/json"
|
request.headers["Accept"] = "application/json"
|
||||||
result = request.best_match_content_type()
|
result = request.best_match_content_type()
|
||||||
self.assertEqual(result, "application/json")
|
self.assertEqual(result, "application/json")
|
||||||
|
|
||||||
@ -59,13 +58,9 @@ class RequestTestCase(base.BaseTestCase):
|
|||||||
request.headers["Accept"] = ("application/json; q=0.3, "
|
request.headers["Accept"] = ("application/json; q=0.3, "
|
||||||
"application/xml; q=0.9")
|
"application/xml; q=0.9")
|
||||||
result = request.best_match_content_type()
|
result = request.best_match_content_type()
|
||||||
self.assertEqual(result, "application/xml")
|
self.assertEqual(result, "application/json")
|
||||||
|
|
||||||
def test_content_type_from_query_extension(self):
|
def test_content_type_from_query_extension(self):
|
||||||
request = wsgi.Request.blank('/tests/123.xml')
|
|
||||||
result = request.best_match_content_type()
|
|
||||||
self.assertEqual(result, "application/xml")
|
|
||||||
|
|
||||||
request = wsgi.Request.blank('/tests/123.json')
|
request = wsgi.Request.blank('/tests/123.json')
|
||||||
result = request.best_match_content_type()
|
result = request.best_match_content_type()
|
||||||
self.assertEqual(result, "application/json")
|
self.assertEqual(result, "application/json")
|
||||||
@ -75,10 +70,10 @@ class RequestTestCase(base.BaseTestCase):
|
|||||||
self.assertEqual(result, "application/json")
|
self.assertEqual(result, "application/json")
|
||||||
|
|
||||||
def test_content_type_accept_and_query_extension(self):
|
def test_content_type_accept_and_query_extension(self):
|
||||||
request = wsgi.Request.blank('/tests/123.xml')
|
request = wsgi.Request.blank('/tests/123.json')
|
||||||
request.headers["Accept"] = "application/json"
|
request.headers["Accept"] = "application/xml"
|
||||||
result = request.best_match_content_type()
|
result = request.best_match_content_type()
|
||||||
self.assertEqual(result, "application/xml")
|
self.assertEqual(result, "application/json")
|
||||||
|
|
||||||
def test_content_type_accept_default(self):
|
def test_content_type_accept_default(self):
|
||||||
request = wsgi.Request.blank('/tests/123.unsupported')
|
request = wsgi.Request.blank('/tests/123.unsupported')
|
||||||
@ -121,10 +116,7 @@ class ResourceTestCase(base.BaseTestCase):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_deserializer(req_format):
|
def _get_deserializer(req_format):
|
||||||
if req_format == 'json':
|
|
||||||
return wsgi.JSONDeserializer()
|
return wsgi.JSONDeserializer()
|
||||||
else:
|
|
||||||
return wsgi.XMLDeserializer()
|
|
||||||
|
|
||||||
def test_unmapped_neutron_error_with_json(self):
|
def test_unmapped_neutron_error_with_json(self):
|
||||||
msg = u'\u7f51\u7edc'
|
msg = u'\u7f51\u7edc'
|
||||||
@ -148,28 +140,6 @@ class ResourceTestCase(base.BaseTestCase):
|
|||||||
self.assertEqual(wsgi.JSONDeserializer().deserialize(res.body),
|
self.assertEqual(wsgi.JSONDeserializer().deserialize(res.body),
|
||||||
expected_res)
|
expected_res)
|
||||||
|
|
||||||
def test_unmapped_neutron_error_with_xml(self):
|
|
||||||
msg = u'\u7f51\u7edc'
|
|
||||||
|
|
||||||
class TestException(n_exc.NeutronException):
|
|
||||||
message = msg
|
|
||||||
expected_res = {'body': {
|
|
||||||
'NeutronError': {
|
|
||||||
'type': 'TestException',
|
|
||||||
'message': msg,
|
|
||||||
'detail': ''}}}
|
|
||||||
controller = mock.MagicMock()
|
|
||||||
controller.test.side_effect = TestException()
|
|
||||||
|
|
||||||
resource = webtest.TestApp(wsgi_resource.Resource(controller))
|
|
||||||
|
|
||||||
environ = {'wsgiorg.routing_args': (None, {'action': 'test',
|
|
||||||
'format': 'xml'})}
|
|
||||||
res = resource.get('', extra_environ=environ, expect_errors=True)
|
|
||||||
self.assertEqual(res.status_int, exc.HTTPInternalServerError.code)
|
|
||||||
self.assertEqual(wsgi.XMLDeserializer().deserialize(res.body),
|
|
||||||
expected_res)
|
|
||||||
|
|
||||||
@mock.patch('neutron.openstack.common.gettextutils.translate')
|
@mock.patch('neutron.openstack.common.gettextutils.translate')
|
||||||
def test_unmapped_neutron_error_localized(self, mock_translation):
|
def test_unmapped_neutron_error_localized(self, mock_translation):
|
||||||
gettextutils.install('blaa', lazy=True)
|
gettextutils.install('blaa', lazy=True)
|
||||||
@ -216,30 +186,6 @@ class ResourceTestCase(base.BaseTestCase):
|
|||||||
self.assertEqual(wsgi.JSONDeserializer().deserialize(res.body),
|
self.assertEqual(wsgi.JSONDeserializer().deserialize(res.body),
|
||||||
expected_res)
|
expected_res)
|
||||||
|
|
||||||
def test_mapped_neutron_error_with_xml(self):
|
|
||||||
msg = u'\u7f51\u7edc'
|
|
||||||
|
|
||||||
class TestException(n_exc.NeutronException):
|
|
||||||
message = msg
|
|
||||||
expected_res = {'body': {
|
|
||||||
'NeutronError': {
|
|
||||||
'type': 'TestException',
|
|
||||||
'message': msg,
|
|
||||||
'detail': ''}}}
|
|
||||||
controller = mock.MagicMock()
|
|
||||||
controller.test.side_effect = TestException()
|
|
||||||
|
|
||||||
faults = {TestException: exc.HTTPGatewayTimeout}
|
|
||||||
resource = webtest.TestApp(wsgi_resource.Resource(controller,
|
|
||||||
faults=faults))
|
|
||||||
|
|
||||||
environ = {'wsgiorg.routing_args': (None, {'action': 'test',
|
|
||||||
'format': 'xml'})}
|
|
||||||
res = resource.get('', extra_environ=environ, expect_errors=True)
|
|
||||||
self.assertEqual(res.status_int, exc.HTTPGatewayTimeout.code)
|
|
||||||
self.assertEqual(wsgi.XMLDeserializer().deserialize(res.body),
|
|
||||||
expected_res)
|
|
||||||
|
|
||||||
@mock.patch('neutron.openstack.common.gettextutils.translate')
|
@mock.patch('neutron.openstack.common.gettextutils.translate')
|
||||||
def test_mapped_neutron_error_localized(self, mock_translation):
|
def test_mapped_neutron_error_localized(self, mock_translation):
|
||||||
gettextutils.install('blaa', lazy=True)
|
gettextutils.install('blaa', lazy=True)
|
||||||
@ -308,9 +254,6 @@ class ResourceTestCase(base.BaseTestCase):
|
|||||||
def test_unhandled_error_with_json(self):
|
def test_unhandled_error_with_json(self):
|
||||||
self._test_unhandled_error()
|
self._test_unhandled_error()
|
||||||
|
|
||||||
def test_unhandled_error_with_xml(self):
|
|
||||||
self._test_unhandled_error(req_format='xml')
|
|
||||||
|
|
||||||
def _test_not_implemented_error(self, req_format='json'):
|
def _test_not_implemented_error(self, req_format='json'):
|
||||||
expected_res = {'body': {'NeutronError':
|
expected_res = {'body': {'NeutronError':
|
||||||
{'detail': '',
|
{'detail': '',
|
||||||
@ -330,9 +273,6 @@ class ResourceTestCase(base.BaseTestCase):
|
|||||||
def test_not_implemented_error_with_json(self):
|
def test_not_implemented_error_with_json(self):
|
||||||
self._test_not_implemented_error()
|
self._test_not_implemented_error()
|
||||||
|
|
||||||
def test_not_implemented_error_with_xml(self):
|
|
||||||
self._test_not_implemented_error(req_format='xml')
|
|
||||||
|
|
||||||
def test_status_200(self):
|
def test_status_200(self):
|
||||||
controller = mock.MagicMock()
|
controller = mock.MagicMock()
|
||||||
controller.test = lambda request: {'foo': 'bar'}
|
controller.test = lambda request: {'foo': 'bar'}
|
||||||
|
@ -4061,23 +4061,3 @@ class NeutronDbPluginV2AsMixinTestCase(testlib_api.SqlTestCase):
|
|||||||
self.net_data['network']['status'] = 'BUILD'
|
self.net_data['network']['status'] = 'BUILD'
|
||||||
net = self.plugin.create_network(self.context, self.net_data)
|
net = self.plugin.create_network(self.context, self.net_data)
|
||||||
self.assertEqual(net['status'], 'BUILD')
|
self.assertEqual(net['status'], 'BUILD')
|
||||||
|
|
||||||
|
|
||||||
class TestBasicGetXML(TestBasicGet):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
|
||||||
|
|
||||||
class TestNetworksV2XML(TestNetworksV2):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
|
||||||
|
|
||||||
class TestPortsV2XML(TestPortsV2):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
|
||||||
|
|
||||||
class TestSubnetsV2XML(TestSubnetsV2):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
|
||||||
|
|
||||||
class TestV2HTTPResponseXML(TestV2HTTPResponse):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
@ -282,7 +282,3 @@ class TestAllowedAddressPairs(AllowedAddressPairDBTestCase):
|
|||||||
port = self.deserialize(self.fmt, req.get_response(self.api))
|
port = self.deserialize(self.fmt, req.get_response(self.api))
|
||||||
self.assertEqual(port['port'][addr_pair.ADDRESS_PAIRS], [])
|
self.assertEqual(port['port'][addr_pair.ADDRESS_PAIRS], [])
|
||||||
self._delete('ports', port['port']['id'])
|
self._delete('ports', port['port']['id'])
|
||||||
|
|
||||||
|
|
||||||
class TestAllowedAddressPairsXML(TestAllowedAddressPairs):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
@ -180,7 +180,3 @@ class ExtNetDBTestCase(test_db_plugin.NeutronDbPluginV2TestCase):
|
|||||||
self.assertEqual(res.status_int, exc.HTTPNoContent.code)
|
self.assertEqual(res.status_int, exc.HTTPNoContent.code)
|
||||||
(l3_mock.delete_disassociated_floatingips
|
(l3_mock.delete_disassociated_floatingips
|
||||||
.assert_called_once_with(mock.ANY, net['network']['id']))
|
.assert_called_once_with(mock.ANY, net['network']['id']))
|
||||||
|
|
||||||
|
|
||||||
class ExtNetDBTestCaseXML(ExtNetDBTestCase):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
@ -469,10 +469,6 @@ class ExtraRouteDBIntTestCase(test_l3.L3NatDBIntTestCase,
|
|||||||
self.setup_notification_driver()
|
self.setup_notification_driver()
|
||||||
|
|
||||||
|
|
||||||
class ExtraRouteDBIntTestCaseXML(ExtraRouteDBIntTestCase):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
|
||||||
|
|
||||||
class ExtraRouteDBSepTestCase(test_l3.L3NatDBSepTestCase,
|
class ExtraRouteDBSepTestCase(test_l3.L3NatDBSepTestCase,
|
||||||
ExtraRouteDBTestCaseBase):
|
ExtraRouteDBTestCaseBase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -492,7 +488,3 @@ class ExtraRouteDBSepTestCase(test_l3.L3NatDBSepTestCase,
|
|||||||
service_plugins=service_plugins)
|
service_plugins=service_plugins)
|
||||||
|
|
||||||
self.setup_notification_driver()
|
self.setup_notification_driver()
|
||||||
|
|
||||||
|
|
||||||
class ExtraRouteDBSepTestCaseXML(ExtraRouteDBSepTestCase):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
@ -372,10 +372,6 @@ class FirewallExtensionTestCase(test_api_v2_extension.ExtensionTestCase):
|
|||||||
self.assertEqual(res, return_value)
|
self.assertEqual(res, return_value)
|
||||||
|
|
||||||
|
|
||||||
class FirewallExtensionTestCaseXML(FirewallExtensionTestCase):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
|
||||||
|
|
||||||
class TestFirewallAttributeValidators(base.BaseTestCase):
|
class TestFirewallAttributeValidators(base.BaseTestCase):
|
||||||
|
|
||||||
def test_validate_port_range(self):
|
def test_validate_port_range(self):
|
||||||
|
@ -168,10 +168,6 @@ class SecurityGroupsTestCase(test_db_plugin.NeutronDbPluginV2TestCase):
|
|||||||
self.assertEqual(security_group_rule[k], v)
|
self.assertEqual(security_group_rule[k], v)
|
||||||
|
|
||||||
|
|
||||||
class SecurityGroupsTestCaseXML(SecurityGroupsTestCase):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
|
||||||
|
|
||||||
class SecurityGroupTestPlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
class SecurityGroupTestPlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
securitygroups_db.SecurityGroupDbMixin):
|
securitygroups_db.SecurityGroupDbMixin):
|
||||||
"""Test plugin that implements necessary calls on create/delete port for
|
"""Test plugin that implements necessary calls on create/delete port for
|
||||||
@ -1445,7 +1441,3 @@ class TestConvertProtocol(base.BaseTestCase):
|
|||||||
for val in ['bad', '256', '-1']:
|
for val in ['bad', '256', '-1']:
|
||||||
self.assertRaises(ext_sg.SecurityGroupRuleInvalidProtocol,
|
self.assertRaises(ext_sg.SecurityGroupRuleInvalidProtocol,
|
||||||
ext_sg.convert_protocol, val)
|
ext_sg.convert_protocol, val)
|
||||||
|
|
||||||
|
|
||||||
class TestSecurityGroupsXML(TestSecurityGroups):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
@ -627,10 +627,6 @@ class ExtensionControllerTest(testlib_api.WebTestCase):
|
|||||||
self.assertEqual(response.status_int, 404)
|
self.assertEqual(response.status_int, 404)
|
||||||
|
|
||||||
|
|
||||||
class ExtensionControllerTestXML(ExtensionControllerTest):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
|
||||||
|
|
||||||
def app_factory(global_conf, **local_conf):
|
def app_factory(global_conf, **local_conf):
|
||||||
conf = global_conf.copy()
|
conf = global_conf.copy()
|
||||||
conf.update(local_conf)
|
conf.update(local_conf)
|
||||||
|
@ -214,10 +214,6 @@ class L3NatExtensionTestCase(test_api_v2_extension.ExtensionTestCase):
|
|||||||
self.assertEqual(res['subnet_id'], subnet_id)
|
self.assertEqual(res['subnet_id'], subnet_id)
|
||||||
|
|
||||||
|
|
||||||
class L3NatExtensionTestCaseXML(L3NatExtensionTestCase):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
|
||||||
|
|
||||||
# This base plugin class is for tests.
|
# This base plugin class is for tests.
|
||||||
class TestL3NatBasePlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
class TestL3NatBasePlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
external_net_db.External_net_db_mixin):
|
external_net_db.External_net_db_mixin):
|
||||||
@ -2144,11 +2140,3 @@ class L3NatDBSepTestCase(L3BaseForSepTests, L3NatTestCaseBase):
|
|||||||
|
|
||||||
"""Unit tests for a separate L3 routing service plugin."""
|
"""Unit tests for a separate L3 routing service plugin."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class L3NatDBIntTestCaseXML(L3NatDBIntTestCase):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
|
||||||
|
|
||||||
class L3NatDBSepTestCaseXML(L3NatDBSepTestCase):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
@ -320,10 +320,6 @@ class QuotaExtensionDbTestCase(QuotaExtensionTestCase):
|
|||||||
self.assertEqual(400, res.status_int)
|
self.assertEqual(400, res.status_int)
|
||||||
|
|
||||||
|
|
||||||
class QuotaExtensionDbTestCaseXML(QuotaExtensionDbTestCase):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
|
||||||
|
|
||||||
class QuotaExtensionCfgTestCase(QuotaExtensionTestCase):
|
class QuotaExtensionCfgTestCase(QuotaExtensionTestCase):
|
||||||
fmt = 'json'
|
fmt = 'json'
|
||||||
|
|
||||||
@ -378,10 +374,6 @@ class QuotaExtensionCfgTestCase(QuotaExtensionTestCase):
|
|||||||
self.assertEqual(403, res.status_int)
|
self.assertEqual(403, res.status_int)
|
||||||
|
|
||||||
|
|
||||||
class QuotaExtensionCfgTestCaseXML(QuotaExtensionCfgTestCase):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
|
||||||
|
|
||||||
class TestDbQuotaDriver(base.BaseTestCase):
|
class TestDbQuotaDriver(base.BaseTestCase):
|
||||||
"""Test for neutron.db.quota_db.DbQuotaDriver."""
|
"""Test for neutron.db.quota_db.DbQuotaDriver."""
|
||||||
|
|
||||||
|
@ -970,10 +970,6 @@ class SGServerRpcCallBackTestCase(test_sg.SecurityGroupDBTestCase):
|
|||||||
self._delete('ports', port_id2)
|
self._delete('ports', port_id2)
|
||||||
|
|
||||||
|
|
||||||
class SGServerRpcCallBackTestCaseXML(SGServerRpcCallBackTestCase):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
|
||||||
|
|
||||||
class SGAgentRpcCallBackMixinTestCase(base.BaseTestCase):
|
class SGAgentRpcCallBackMixinTestCase(base.BaseTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(SGAgentRpcCallBackMixinTestCase, self).setUp()
|
super(SGAgentRpcCallBackMixinTestCase, self).setUp()
|
||||||
|
@ -202,10 +202,6 @@ class ServiceTypeExtensionTestCase(ServiceTypeExtensionTestCaseBase):
|
|||||||
self.assertEqual(res.status_int, webexc.HTTPOk.code)
|
self.assertEqual(res.status_int, webexc.HTTPOk.code)
|
||||||
|
|
||||||
|
|
||||||
class ServiceTypeExtensionTestCaseXML(ServiceTypeExtensionTestCase):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
|
||||||
|
|
||||||
class ServiceTypeManagerExtTestCase(ServiceTypeExtensionTestCaseBase):
|
class ServiceTypeManagerExtTestCase(ServiceTypeExtensionTestCaseBase):
|
||||||
"""Tests ServiceTypemanager as a public API."""
|
"""Tests ServiceTypemanager as a public API."""
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -227,7 +223,3 @@ class ServiceTypeManagerExtTestCase(ServiceTypeExtensionTestCaseBase):
|
|||||||
data = self.deserialize(res)
|
data = self.deserialize(res)
|
||||||
self.assertIn('service_providers', data)
|
self.assertIn('service_providers', data)
|
||||||
self.assertEqual(len(data['service_providers']), 2)
|
self.assertEqual(len(data['service_providers']), 2)
|
||||||
|
|
||||||
|
|
||||||
class ServiceTypeManagerExtTestCaseXML(ServiceTypeManagerExtTestCase):
|
|
||||||
fmt = 'xml'
|
|
||||||
|
@ -23,8 +23,6 @@ import testtools
|
|||||||
import webob
|
import webob
|
||||||
import webob.exc
|
import webob.exc
|
||||||
|
|
||||||
from neutron.api.v2 import attributes
|
|
||||||
from neutron.common import constants
|
|
||||||
from neutron.common import exceptions as exception
|
from neutron.common import exceptions as exception
|
||||||
from neutron.tests import base
|
from neutron.tests import base
|
||||||
from neutron import wsgi
|
from neutron import wsgi
|
||||||
@ -154,33 +152,16 @@ class SerializerTest(base.BaseTestCase):
|
|||||||
"""Test serialize with content type json."""
|
"""Test serialize with content type json."""
|
||||||
input_data = {'servers': ['test=pass']}
|
input_data = {'servers': ['test=pass']}
|
||||||
content_type = 'application/json'
|
content_type = 'application/json'
|
||||||
serializer = wsgi.Serializer(default_xmlns="fake")
|
serializer = wsgi.Serializer()
|
||||||
result = serializer.serialize(input_data, content_type)
|
result = serializer.serialize(input_data, content_type)
|
||||||
|
|
||||||
self.assertEqual('{"servers": ["test=pass"]}', result)
|
self.assertEqual('{"servers": ["test=pass"]}', result)
|
||||||
|
|
||||||
def test_serialize_content_type_xml(self):
|
|
||||||
"""Test serialize with content type xml."""
|
|
||||||
input_data = {'servers': ['test=pass']}
|
|
||||||
content_type = 'application/xml'
|
|
||||||
serializer = wsgi.Serializer(default_xmlns="fake")
|
|
||||||
result = serializer.serialize(input_data, content_type)
|
|
||||||
expected = (
|
|
||||||
'<?xml version=\'1.0\''
|
|
||||||
' encoding=\'UTF-8\'?>\n'
|
|
||||||
'<servers xmlns="http://openstack.org/quantum/api/v2.0" '
|
|
||||||
'xmlns:quantum="http://openstack.org/quantum/api/v2.0" '
|
|
||||||
'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
|
|
||||||
'<server>test=pass</server></servers>'
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
def test_deserialize_raise_bad_request(self):
|
def test_deserialize_raise_bad_request(self):
|
||||||
"""Test serialize verifies that exception is raises."""
|
"""Test serialize verifies that exception is raises."""
|
||||||
content_type = 'application/unknown'
|
content_type = 'application/unknown'
|
||||||
data_string = 'test'
|
data_string = 'test'
|
||||||
serializer = wsgi.Serializer(default_xmlns="fake")
|
serializer = wsgi.Serializer()
|
||||||
|
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
webob.exc.HTTPBadRequest,
|
webob.exc.HTTPBadRequest,
|
||||||
@ -190,100 +171,11 @@ class SerializerTest(base.BaseTestCase):
|
|||||||
"""Test Serializer.deserialize with content type json."""
|
"""Test Serializer.deserialize with content type json."""
|
||||||
content_type = 'application/json'
|
content_type = 'application/json'
|
||||||
data_string = '{"servers": ["test=pass"]}'
|
data_string = '{"servers": ["test=pass"]}'
|
||||||
serializer = wsgi.Serializer(default_xmlns="fake")
|
serializer = wsgi.Serializer()
|
||||||
result = serializer.deserialize(data_string, content_type)
|
result = serializer.deserialize(data_string, content_type)
|
||||||
|
|
||||||
self.assertEqual({'body': {u'servers': [u'test=pass']}}, result)
|
self.assertEqual({'body': {u'servers': [u'test=pass']}}, result)
|
||||||
|
|
||||||
def test_deserialize_xml_content_type(self):
|
|
||||||
"""Test deserialize with content type xml."""
|
|
||||||
content_type = 'application/xml'
|
|
||||||
data_string = (
|
|
||||||
'<servers xmlns="fake">'
|
|
||||||
'<server>test=pass</server>'
|
|
||||||
'</servers>'
|
|
||||||
)
|
|
||||||
serializer = wsgi.Serializer(
|
|
||||||
default_xmlns="fake", metadata={'xmlns': 'fake'})
|
|
||||||
result = serializer.deserialize(data_string, content_type)
|
|
||||||
expected = {'body': {'servers': {'server': 'test=pass'}}}
|
|
||||||
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
def test_deserialize_xml_content_type_with_meta(self):
|
|
||||||
"""Test deserialize with content type xml with meta."""
|
|
||||||
content_type = 'application/xml'
|
|
||||||
data_string = (
|
|
||||||
'<servers>'
|
|
||||||
'<server name="s1">'
|
|
||||||
'<test test="a">passed</test>'
|
|
||||||
'</server>'
|
|
||||||
'</servers>'
|
|
||||||
)
|
|
||||||
|
|
||||||
metadata = {'plurals': {'servers': 'server'}, 'xmlns': 'fake'}
|
|
||||||
serializer = wsgi.Serializer(
|
|
||||||
default_xmlns="fake", metadata=metadata)
|
|
||||||
result = serializer.deserialize(data_string, content_type)
|
|
||||||
expected = {'body': {'servers': [{'name': 's1', 'test': 'passed'}]}}
|
|
||||||
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
def test_serialize_xml_root_key_is_dict(self):
|
|
||||||
"""Test Serializer.serialize with content type xml with meta dict."""
|
|
||||||
content_type = 'application/xml'
|
|
||||||
data = {'servers': {'network': (2, 3)}}
|
|
||||||
metadata = {'xmlns': 'fake'}
|
|
||||||
|
|
||||||
serializer = wsgi.Serializer(default_xmlns="fake", metadata=metadata)
|
|
||||||
result = serializer.serialize(data, content_type)
|
|
||||||
result = result.replace('\n', '')
|
|
||||||
expected = (
|
|
||||||
'<?xml version=\'1.0\' encoding=\'UTF-8\'?>'
|
|
||||||
'<servers xmlns="fake" xmlns:quantum="fake" '
|
|
||||||
'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
|
|
||||||
'<network>(2, 3)</network></servers>'
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(result, expected)
|
|
||||||
|
|
||||||
def test_serialize_xml_root_key_is_list(self):
|
|
||||||
"""Test serialize with content type xml with meta list."""
|
|
||||||
input_dict = {'servers': ['test=pass']}
|
|
||||||
content_type = 'application/xml'
|
|
||||||
metadata = {'application/xml': {
|
|
||||||
'xmlns': 'fake'}}
|
|
||||||
serializer = wsgi.Serializer(default_xmlns="fake", metadata=metadata)
|
|
||||||
result = serializer.serialize(input_dict, content_type)
|
|
||||||
result = result.replace('\n', '').replace(' ', '')
|
|
||||||
expected = (
|
|
||||||
'<?xmlversion=\'1.0\''
|
|
||||||
'encoding=\'UTF-8\'?>'
|
|
||||||
'<serversxmlns="http://openstack.org/quantum/api/v2.0"'
|
|
||||||
'xmlns:quantum="http://openstack.org/quantum/api/v2.0"'
|
|
||||||
'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
|
|
||||||
'<server>test=pass</server></servers>'
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(result, expected)
|
|
||||||
|
|
||||||
def test_serialize_xml_root_is_None(self):
|
|
||||||
input_dict = {'test': 'pass'}
|
|
||||||
content_type = 'application/xml'
|
|
||||||
serializer = wsgi.Serializer(default_xmlns="fake")
|
|
||||||
result = serializer.serialize(input_dict, content_type)
|
|
||||||
result = result.replace('\n', '').replace(' ', '')
|
|
||||||
expected = (
|
|
||||||
'<?xmlversion=\'1.0\''
|
|
||||||
'encoding=\'UTF-8\'?>'
|
|
||||||
'<testxmlns="http://openstack.org/quantum/api/v2.0"'
|
|
||||||
'xmlns:quantum="http://openstack.org/quantum/api/v2.0"'
|
|
||||||
'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
|
|
||||||
'pass</test>'
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(result, expected)
|
|
||||||
|
|
||||||
|
|
||||||
class RequestDeserializerTest(testtools.TestCase):
|
class RequestDeserializerTest(testtools.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -293,13 +185,7 @@ class RequestDeserializerTest(testtools.TestCase):
|
|||||||
def deserialize(self, data, action='default'):
|
def deserialize(self, data, action='default'):
|
||||||
return 'pew_json'
|
return 'pew_json'
|
||||||
|
|
||||||
class XMLDeserializer(object):
|
self.body_deserializers = {'application/json': JSONDeserializer()}
|
||||||
def deserialize(self, data, action='default'):
|
|
||||||
return 'pew_xml'
|
|
||||||
|
|
||||||
self.body_deserializers = {
|
|
||||||
'application/json': JSONDeserializer(),
|
|
||||||
'application/xml': XMLDeserializer()}
|
|
||||||
|
|
||||||
self.deserializer = wsgi.RequestDeserializer(self.body_deserializers)
|
self.deserializer = wsgi.RequestDeserializer(self.body_deserializers)
|
||||||
|
|
||||||
@ -307,15 +193,10 @@ class RequestDeserializerTest(testtools.TestCase):
|
|||||||
"""Test RequestDeserializer.get_body_deserializer."""
|
"""Test RequestDeserializer.get_body_deserializer."""
|
||||||
expected_json_serializer = self.deserializer.get_body_deserializer(
|
expected_json_serializer = self.deserializer.get_body_deserializer(
|
||||||
'application/json')
|
'application/json')
|
||||||
expected_xml_serializer = self.deserializer.get_body_deserializer(
|
|
||||||
'application/xml')
|
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
expected_json_serializer,
|
expected_json_serializer,
|
||||||
self.body_deserializers['application/json'])
|
self.body_deserializers['application/json'])
|
||||||
self.assertEqual(
|
|
||||||
expected_xml_serializer,
|
|
||||||
self.body_deserializers['application/xml'])
|
|
||||||
|
|
||||||
def test_get_expected_content_type(self):
|
def test_get_expected_content_type(self):
|
||||||
"""Test RequestDeserializer.get_expected_content_type."""
|
"""Test RequestDeserializer.get_expected_content_type."""
|
||||||
@ -345,9 +226,9 @@ class RequestDeserializerTest(testtools.TestCase):
|
|||||||
self.deserializer, 'get_action_args') as mock_method:
|
self.deserializer, 'get_action_args') as mock_method:
|
||||||
mock_method.return_value = {'action': 'create'}
|
mock_method.return_value = {'action': 'create'}
|
||||||
request = wsgi.Request.blank('/')
|
request = wsgi.Request.blank('/')
|
||||||
request.headers['Accept'] = 'application/xml'
|
request.headers['Accept'] = 'application/json'
|
||||||
deserialized = self.deserializer.deserialize(request)
|
deserialized = self.deserializer.deserialize(request)
|
||||||
expected = ('create', {}, 'application/xml')
|
expected = ('create', {}, 'application/json')
|
||||||
|
|
||||||
self.assertEqual(expected, deserialized)
|
self.assertEqual(expected, deserialized)
|
||||||
|
|
||||||
@ -368,17 +249,11 @@ class ResponseSerializerTest(testtools.TestCase):
|
|||||||
def serialize(self, data, action='default'):
|
def serialize(self, data, action='default'):
|
||||||
return 'pew_json'
|
return 'pew_json'
|
||||||
|
|
||||||
class XMLSerializer(object):
|
|
||||||
def serialize(self, data, action='default'):
|
|
||||||
return 'pew_xml'
|
|
||||||
|
|
||||||
class HeadersSerializer(object):
|
class HeadersSerializer(object):
|
||||||
def serialize(self, response, data, action):
|
def serialize(self, response, data, action):
|
||||||
response.status_int = 404
|
response.status_int = 404
|
||||||
|
|
||||||
self.body_serializers = {
|
self.body_serializers = {'application/json': JSONSerializer()}
|
||||||
'application/json': JSONSerializer(),
|
|
||||||
'application/xml': XMLSerializer()}
|
|
||||||
|
|
||||||
self.serializer = wsgi.ResponseSerializer(
|
self.serializer = wsgi.ResponseSerializer(
|
||||||
self.body_serializers, HeadersSerializer())
|
self.body_serializers, HeadersSerializer())
|
||||||
@ -410,13 +285,6 @@ class ResponseSerializerTest(testtools.TestCase):
|
|||||||
self.assertEqual(response.body, 'pew_json')
|
self.assertEqual(response.body, 'pew_json')
|
||||||
self.assertEqual(response.status_int, 404)
|
self.assertEqual(response.status_int, 404)
|
||||||
|
|
||||||
def test_serialize_xml_response(self):
|
|
||||||
response = self.serializer.serialize({}, 'application/xml')
|
|
||||||
|
|
||||||
self.assertEqual(response.headers['Content-Type'], 'application/xml')
|
|
||||||
self.assertEqual(response.body, 'pew_xml')
|
|
||||||
self.assertEqual(response.status_int, 404)
|
|
||||||
|
|
||||||
def test_serialize_response_None(self):
|
def test_serialize_response_None(self):
|
||||||
response = self.serializer.serialize(
|
response = self.serializer.serialize(
|
||||||
None, 'application/json')
|
None, 'application/json')
|
||||||
@ -455,12 +323,6 @@ class RequestTest(base.BaseTestCase):
|
|||||||
self.assertIsNone(request.get_content_type())
|
self.assertIsNone(request.get_content_type())
|
||||||
|
|
||||||
def test_content_type_from_accept(self):
|
def test_content_type_from_accept(self):
|
||||||
request = wsgi.Request.blank('/tests/123')
|
|
||||||
request.headers["Accept"] = "application/xml"
|
|
||||||
result = request.best_match_content_type()
|
|
||||||
|
|
||||||
self.assertEqual(result, "application/xml")
|
|
||||||
|
|
||||||
request = wsgi.Request.blank('/tests/123')
|
request = wsgi.Request.blank('/tests/123')
|
||||||
request.headers["Accept"] = "application/json"
|
request.headers["Accept"] = "application/json"
|
||||||
result = request.best_match_content_type()
|
result = request.best_match_content_type()
|
||||||
@ -468,24 +330,12 @@ class RequestTest(base.BaseTestCase):
|
|||||||
self.assertEqual(result, "application/json")
|
self.assertEqual(result, "application/json")
|
||||||
|
|
||||||
request = wsgi.Request.blank('/tests/123')
|
request = wsgi.Request.blank('/tests/123')
|
||||||
request.headers["Accept"] = "application/xml, application/json"
|
request.headers["Accept"] = ("application/json; q=0.3")
|
||||||
result = request.best_match_content_type()
|
result = request.best_match_content_type()
|
||||||
|
|
||||||
self.assertEqual(result, "application/json")
|
self.assertEqual(result, "application/json")
|
||||||
|
|
||||||
request = wsgi.Request.blank('/tests/123')
|
|
||||||
request.headers["Accept"] = ("application/json; q=0.3, "
|
|
||||||
"application/xml; q=0.9")
|
|
||||||
result = request.best_match_content_type()
|
|
||||||
|
|
||||||
self.assertEqual(result, "application/xml")
|
|
||||||
|
|
||||||
def test_content_type_from_query_extension(self):
|
def test_content_type_from_query_extension(self):
|
||||||
request = wsgi.Request.blank('/tests/123.xml')
|
|
||||||
result = request.best_match_content_type()
|
|
||||||
|
|
||||||
self.assertEqual(result, "application/xml")
|
|
||||||
|
|
||||||
request = wsgi.Request.blank('/tests/123.json')
|
request = wsgi.Request.blank('/tests/123.json')
|
||||||
result = request.best_match_content_type()
|
result = request.best_match_content_type()
|
||||||
|
|
||||||
@ -497,11 +347,11 @@ class RequestTest(base.BaseTestCase):
|
|||||||
self.assertEqual(result, "application/json")
|
self.assertEqual(result, "application/json")
|
||||||
|
|
||||||
def test_content_type_accept_and_query_extension(self):
|
def test_content_type_accept_and_query_extension(self):
|
||||||
request = wsgi.Request.blank('/tests/123.xml')
|
request = wsgi.Request.blank('/tests/123.json')
|
||||||
request.headers["Accept"] = "application/json"
|
request.headers["Accept"] = "application/json"
|
||||||
result = request.best_match_content_type()
|
result = request.best_match_content_type()
|
||||||
|
|
||||||
self.assertEqual(result, "application/xml")
|
self.assertEqual(result, "application/json")
|
||||||
|
|
||||||
def test_content_type_accept_default(self):
|
def test_content_type_accept_default(self):
|
||||||
request = wsgi.Request.blank('/tests/123.unsupported')
|
request = wsgi.Request.blank('/tests/123.unsupported')
|
||||||
@ -662,39 +512,6 @@ class JSONDeserializerTest(base.BaseTestCase):
|
|||||||
deserializer.deserialize(data), as_dict)
|
deserializer.deserialize(data), as_dict)
|
||||||
|
|
||||||
|
|
||||||
class XMLDeserializerTest(base.BaseTestCase):
|
|
||||||
def test_xml_empty(self):
|
|
||||||
xml = '<a></a>'
|
|
||||||
as_dict = {'body': {'a': ''}}
|
|
||||||
deserializer = wsgi.XMLDeserializer()
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
deserializer.deserialize(xml), as_dict)
|
|
||||||
|
|
||||||
def test_initialization(self):
|
|
||||||
xml = '<a><b>test</b></a>'
|
|
||||||
deserializer = wsgi.XMLDeserializer()
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
{'body': {u'a': {u'b': u'test'}}}, deserializer(xml))
|
|
||||||
|
|
||||||
def test_default_raise_Malformed_Exception(self):
|
|
||||||
"""Verify that exception MalformedRequestBody is raised."""
|
|
||||||
data_string = ""
|
|
||||||
deserializer = wsgi.XMLDeserializer()
|
|
||||||
|
|
||||||
self.assertRaises(
|
|
||||||
exception.MalformedRequestBody, deserializer.default, data_string)
|
|
||||||
|
|
||||||
def test_xml_with_utf8(self):
|
|
||||||
xml = '<a>\xe7\xbd\x91\xe7\xbb\x9c</a>'
|
|
||||||
as_dict = {'body': {'a': u'\u7f51\u7edc'}}
|
|
||||||
deserializer = wsgi.XMLDeserializer()
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
deserializer.deserialize(xml), as_dict)
|
|
||||||
|
|
||||||
|
|
||||||
class RequestHeadersDeserializerTest(base.BaseTestCase):
|
class RequestHeadersDeserializerTest(base.BaseTestCase):
|
||||||
|
|
||||||
def test_default(self):
|
def test_default(self):
|
||||||
@ -811,7 +628,7 @@ class ResourceTest(base.BaseTestCase):
|
|||||||
return 'off'
|
return 'off'
|
||||||
resource = wsgi.Resource(Controller(), my_fault_body_function)
|
resource = wsgi.Resource(Controller(), my_fault_body_function)
|
||||||
request = wsgi.Request.blank(
|
request = wsgi.Request.blank(
|
||||||
"/", method='POST', headers={'Content-Type': "xml"})
|
"/", method='POST', headers={'Content-Type': "json"})
|
||||||
|
|
||||||
response = resource.dispatch(
|
response = resource.dispatch(
|
||||||
request, action='index', action_args='test')
|
request, action='index', action_args='test')
|
||||||
@ -829,7 +646,7 @@ class ResourceTest(base.BaseTestCase):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.url = 'http://where.no'
|
self.url = 'http://where.no'
|
||||||
self.environ = 'environ'
|
self.environ = 'environ'
|
||||||
self.body = '{"Content-Type": "xml"}'
|
self.body = '{"Content-Type": "json"}'
|
||||||
|
|
||||||
def method(self):
|
def method(self):
|
||||||
pass
|
pass
|
||||||
@ -867,212 +684,6 @@ class FaultTest(base.BaseTestCase):
|
|||||||
self.assertEqual(415, response.status_int)
|
self.assertEqual(415, response.status_int)
|
||||||
|
|
||||||
|
|
||||||
class XMLDictSerializerTest(base.BaseTestCase):
|
|
||||||
def test_xml(self):
|
|
||||||
NETWORK = {'network': {'test': None,
|
|
||||||
'tenant_id': 'test-tenant',
|
|
||||||
'name': 'net1',
|
|
||||||
'admin_state_up': True,
|
|
||||||
'subnets': [],
|
|
||||||
'dict': {},
|
|
||||||
'int': 3,
|
|
||||||
'long': 4L,
|
|
||||||
'float': 5.0,
|
|
||||||
'prefix:external': True,
|
|
||||||
'tests': [{'test1': 'value1'},
|
|
||||||
{'test2': 2, 'test3': 3}]}}
|
|
||||||
# XML is:
|
|
||||||
# <network xmlns="http://openstack.org/quantum/api/v2.0"
|
|
||||||
# xmlns:prefix="http://xxxx.yy.com"
|
|
||||||
# xmlns:quantum="http://openstack.org/quantum/api/v2.0"
|
|
||||||
# xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
||||||
# <subnets quantum:type="list" /> # Empty List
|
|
||||||
# <int quantum:type="int">3</int> # Integer text
|
|
||||||
# <int quantum:type="long">4</int> # Long text
|
|
||||||
# <int quantum:type="float">5.0</int> # Float text
|
|
||||||
# <dict quantum:type="dict" /> # Empty Dict
|
|
||||||
# <name>net1</name>
|
|
||||||
# <admin_state_up quantum:type="bool">True</admin_state_up> # Bool
|
|
||||||
# <test xsi:nil="true" /> # None
|
|
||||||
# <tenant_id>test-tenant</tenant_id>
|
|
||||||
# # We must have a namespace defined in root for prefix:external
|
|
||||||
# <prefix:external quantum:type="bool">True</prefix:external>
|
|
||||||
# <tests> # List
|
|
||||||
# <test><test1>value1</test1></test>
|
|
||||||
# <test><test3 quantum:type="int">3</test3>
|
|
||||||
# <test2 quantum:type="int">2</test2>
|
|
||||||
# </test></tests>
|
|
||||||
# </network>
|
|
||||||
|
|
||||||
metadata = attributes.get_attr_metadata()
|
|
||||||
ns = {'prefix': 'http://xxxx.yy.com'}
|
|
||||||
metadata[constants.EXT_NS] = ns
|
|
||||||
metadata['plurals'] = {'tests': 'test'}
|
|
||||||
serializer = wsgi.XMLDictSerializer(metadata)
|
|
||||||
result = serializer.serialize(NETWORK)
|
|
||||||
deserializer = wsgi.XMLDeserializer(metadata)
|
|
||||||
new_net = deserializer.deserialize(result)['body']
|
|
||||||
self.assertEqual(NETWORK, new_net)
|
|
||||||
|
|
||||||
def test_None(self):
|
|
||||||
data = None
|
|
||||||
# Since it is None, we use xsi:nil='true'.
|
|
||||||
# In addition, we use an
|
|
||||||
# virtual XML root _v_root to wrap the XML doc.
|
|
||||||
# XML is:
|
|
||||||
# <_v_root xsi:nil="true"
|
|
||||||
# xmlns="http://openstack.org/quantum/api/v2.0"
|
|
||||||
# xmlns:quantum="http://openstack.org/quantum/api/v2.0"
|
|
||||||
# xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
|
|
||||||
serializer = wsgi.XMLDictSerializer(attributes.get_attr_metadata())
|
|
||||||
result = serializer.serialize(data)
|
|
||||||
deserializer = wsgi.XMLDeserializer(attributes.get_attr_metadata())
|
|
||||||
new_data = deserializer.deserialize(result)['body']
|
|
||||||
self.assertIsNone(new_data)
|
|
||||||
|
|
||||||
def test_empty_dic_xml(self):
|
|
||||||
data = {}
|
|
||||||
# Since it is an empty dict, we use quantum:type='dict' and
|
|
||||||
# an empty XML element to represent it. In addition, we use an
|
|
||||||
# virtual XML root _v_root to wrap the XML doc.
|
|
||||||
# XML is:
|
|
||||||
# <_v_root quantum:type="dict"
|
|
||||||
# xmlns="http://openstack.org/quantum/api/v2.0"
|
|
||||||
# xmlns:quantum="http://openstack.org/quantum/api/v2.0"
|
|
||||||
# xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
|
|
||||||
serializer = wsgi.XMLDictSerializer(attributes.get_attr_metadata())
|
|
||||||
result = serializer.serialize(data)
|
|
||||||
deserializer = wsgi.XMLDeserializer(attributes.get_attr_metadata())
|
|
||||||
new_data = deserializer.deserialize(result)['body']
|
|
||||||
self.assertEqual(data, new_data)
|
|
||||||
|
|
||||||
def test_non_root_one_item_dic_xml(self):
|
|
||||||
data = {'test1': 1}
|
|
||||||
# We have a key in this dict, and its value is an integer.
|
|
||||||
# XML is:
|
|
||||||
# <test1 quantum:type="int"
|
|
||||||
# xmlns="http://openstack.org/quantum/api/v2.0"
|
|
||||||
# xmlns:quantum="http://openstack.org/quantum/api/v2.0"
|
|
||||||
# xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
||||||
# 1</test1>
|
|
||||||
|
|
||||||
serializer = wsgi.XMLDictSerializer(attributes.get_attr_metadata())
|
|
||||||
result = serializer.serialize(data)
|
|
||||||
deserializer = wsgi.XMLDeserializer(attributes.get_attr_metadata())
|
|
||||||
new_data = deserializer.deserialize(result)['body']
|
|
||||||
self.assertEqual(data, new_data)
|
|
||||||
|
|
||||||
def test_non_root_two_items_dic_xml(self):
|
|
||||||
data = {'test1': 1, 'test2': '2'}
|
|
||||||
# We have no root element in this data, We will use a virtual
|
|
||||||
# root element _v_root to wrap the doct.
|
|
||||||
# The XML is:
|
|
||||||
# <_v_root xmlns="http://openstack.org/quantum/api/v2.0"
|
|
||||||
# xmlns:quantum="http://openstack.org/quantum/api/v2.0"
|
|
||||||
# xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
||||||
# <test1 quantum:type="int">1</test1><test2>2</test2>
|
|
||||||
# </_v_root>
|
|
||||||
|
|
||||||
serializer = wsgi.XMLDictSerializer(attributes.get_attr_metadata())
|
|
||||||
result = serializer.serialize(data)
|
|
||||||
deserializer = wsgi.XMLDeserializer(attributes.get_attr_metadata())
|
|
||||||
new_data = deserializer.deserialize(result)['body']
|
|
||||||
self.assertEqual(data, new_data)
|
|
||||||
|
|
||||||
def test_xml_root_key_is_list(self):
|
|
||||||
input_dict = {'servers': ['test-pass']}
|
|
||||||
serializer = wsgi.XMLDictSerializer(xmlns="fake")
|
|
||||||
result = serializer.default(input_dict)
|
|
||||||
result = result.replace('\n', '').replace(' ', '')
|
|
||||||
expected = (
|
|
||||||
'<?xmlversion=\'1.0\'encoding=\'UTF-8\'?>'
|
|
||||||
'<serversxmlns="fake"xmlns:quantum="fake"'
|
|
||||||
'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
|
|
||||||
'<server>test-pass</server></servers>'
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(result, expected)
|
|
||||||
|
|
||||||
def test_xml_meta_contains_node_name_list(self):
|
|
||||||
input_dict = {'servers': ['test-pass']}
|
|
||||||
servers = {'nodename': 'test',
|
|
||||||
'item_name': 'test',
|
|
||||||
'item_key': 'test'}
|
|
||||||
metadata = {'list_collections': {'servers': servers}}
|
|
||||||
serializer = wsgi.XMLDictSerializer(xmlns="fake", metadata=metadata)
|
|
||||||
result = serializer.default(input_dict)
|
|
||||||
result = result.replace('\n', '').replace(' ', '')
|
|
||||||
expected = (
|
|
||||||
'<?xmlversion=\'1.0\'encoding=\'UTF-8\'?>'
|
|
||||||
'<serversxmlns="fake"xmlns:quantum="fake"'
|
|
||||||
'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
|
|
||||||
'<server>test-pass</server></servers>'
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(result, expected)
|
|
||||||
|
|
||||||
def test_xml_meta_contains_node_name_dict(self):
|
|
||||||
input_dict = {'servers': {'a': {'2': '3'}}}
|
|
||||||
servers = {'servers': {
|
|
||||||
'nodename': 'test',
|
|
||||||
'item_name': 'test',
|
|
||||||
'item_key': 'test'}}
|
|
||||||
metadata = {'dict_collections': servers}
|
|
||||||
serializer = wsgi.XMLDictSerializer(xmlns="fake", metadata=metadata)
|
|
||||||
result = serializer.default(input_dict)
|
|
||||||
result = result.replace('\n', '').replace(' ', '')
|
|
||||||
expected = (
|
|
||||||
'<?xmlversion=\'1.0\'encoding=\'UTF-8\'?>'
|
|
||||||
'<serversxmlns="fake"xmlns:quantum="fake"'
|
|
||||||
'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
|
|
||||||
'<a><2>3</2></a></servers>'
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(result, expected)
|
|
||||||
|
|
||||||
def test_call(self):
|
|
||||||
data = {'servers': {'a': {'2': '3'}}}
|
|
||||||
serializer = wsgi.XMLDictSerializer()
|
|
||||||
expected = (
|
|
||||||
'<?xmlversion=\'1.0\'encoding=\'UTF-8\'?>'
|
|
||||||
'<serversxmlns="http://openstack.org/quantum/api/v2.0"'
|
|
||||||
'xmlns:quantum="http://openstack.org/quantum/api/v2.0"'
|
|
||||||
'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
|
|
||||||
'<a><2>3</2></a></servers>'
|
|
||||||
)
|
|
||||||
result = serializer(data)
|
|
||||||
result = result.replace('\n', '').replace(' ', '')
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
def test_xml_with_utf8(self):
|
|
||||||
data = {'servers': '\xe7\xbd\x91\xe7\xbb\x9c'}
|
|
||||||
serializer = wsgi.XMLDictSerializer()
|
|
||||||
expected = (
|
|
||||||
'<?xmlversion=\'1.0\'encoding=\'UTF-8\'?>'
|
|
||||||
'<serversxmlns="http://openstack.org/quantum/api/v2.0"'
|
|
||||||
'xmlns:quantum="http://openstack.org/quantum/api/v2.0"'
|
|
||||||
'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
|
|
||||||
'\xe7\xbd\x91\xe7\xbb\x9c</servers>'
|
|
||||||
)
|
|
||||||
result = serializer(data)
|
|
||||||
result = result.replace('\n', '').replace(' ', '')
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
def test_xml_with_unicode(self):
|
|
||||||
data = {'servers': u'\u7f51\u7edc'}
|
|
||||||
serializer = wsgi.XMLDictSerializer()
|
|
||||||
expected = (
|
|
||||||
'<?xmlversion=\'1.0\'encoding=\'UTF-8\'?>'
|
|
||||||
'<serversxmlns="http://openstack.org/quantum/api/v2.0"'
|
|
||||||
'xmlns:quantum="http://openstack.org/quantum/api/v2.0"'
|
|
||||||
'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
|
|
||||||
'\xe7\xbd\x91\xe7\xbb\x9c</servers>'
|
|
||||||
)
|
|
||||||
result = serializer(data)
|
|
||||||
result = result.replace('\n', '').replace(' ', '')
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
|
|
||||||
class TestWSGIServerWithSSL(base.BaseTestCase):
|
class TestWSGIServerWithSSL(base.BaseTestCase):
|
||||||
"""WSGI server tests."""
|
"""WSGI server tests."""
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
|
|
||||||
import testtools
|
import testtools
|
||||||
|
|
||||||
from neutron.api.v2 import attributes
|
|
||||||
from neutron.db import api as db_api
|
from neutron.db import api as db_api
|
||||||
# Import all data models
|
# Import all data models
|
||||||
from neutron.db.migration.models import head # noqa
|
from neutron.db.migration.models import head # noqa
|
||||||
@ -81,11 +80,8 @@ class WebTestCase(SqlTestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(WebTestCase, self).setUp()
|
super(WebTestCase, self).setUp()
|
||||||
json_deserializer = wsgi.JSONDeserializer()
|
json_deserializer = wsgi.JSONDeserializer()
|
||||||
xml_deserializer = wsgi.XMLDeserializer(
|
|
||||||
attributes.get_attr_metadata())
|
|
||||||
self._deserializers = {
|
self._deserializers = {
|
||||||
'application/json': json_deserializer,
|
'application/json': json_deserializer,
|
||||||
'application/xml': xml_deserializer,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def deserialize(self, response):
|
def deserialize(self, response):
|
||||||
@ -95,8 +91,7 @@ class WebTestCase(SqlTestCase):
|
|||||||
|
|
||||||
def serialize(self, data):
|
def serialize(self, data):
|
||||||
ctype = 'application/%s' % self.fmt
|
ctype = 'application/%s' % self.fmt
|
||||||
result = wsgi.Serializer(
|
result = wsgi.Serializer().serialize(data, ctype)
|
||||||
attributes.get_attr_metadata()).serialize(data, ctype)
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
350
neutron/wsgi.py
350
neutron/wsgi.py
@ -24,8 +24,6 @@ import socket
|
|||||||
import ssl
|
import ssl
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from xml.etree import ElementTree as etree
|
|
||||||
from xml.parsers import expat
|
|
||||||
|
|
||||||
import eventlet.wsgi
|
import eventlet.wsgi
|
||||||
eventlet.patcher.monkey_patch(all=False, socket=True, thread=True)
|
eventlet.patcher.monkey_patch(all=False, socket=True, thread=True)
|
||||||
@ -34,7 +32,6 @@ import routes.middleware
|
|||||||
import webob.dec
|
import webob.dec
|
||||||
import webob.exc
|
import webob.exc
|
||||||
|
|
||||||
from neutron.common import constants
|
|
||||||
from neutron.common import exceptions as exception
|
from neutron.common import exceptions as exception
|
||||||
from neutron import context
|
from neutron import context
|
||||||
from neutron.db import api
|
from neutron.db import api
|
||||||
@ -313,7 +310,7 @@ class Request(webob.Request):
|
|||||||
"""Determine the most acceptable content-type.
|
"""Determine the most acceptable content-type.
|
||||||
|
|
||||||
Based on:
|
Based on:
|
||||||
1) URI extension (.json/.xml)
|
1) URI extension (.json)
|
||||||
2) Content-type header
|
2) Content-type header
|
||||||
3) Accept* headers
|
3) Accept* headers
|
||||||
"""
|
"""
|
||||||
@ -321,21 +318,21 @@ class Request(webob.Request):
|
|||||||
parts = self.path.rsplit('.', 1)
|
parts = self.path.rsplit('.', 1)
|
||||||
if len(parts) > 1:
|
if len(parts) > 1:
|
||||||
_format = parts[1]
|
_format = parts[1]
|
||||||
if _format in ['json', 'xml']:
|
if _format in ['json']:
|
||||||
return 'application/{0}'.format(_format)
|
return 'application/{0}'.format(_format)
|
||||||
|
|
||||||
#Then look up content header
|
#Then look up content header
|
||||||
type_from_header = self.get_content_type()
|
type_from_header = self.get_content_type()
|
||||||
if type_from_header:
|
if type_from_header:
|
||||||
return type_from_header
|
return type_from_header
|
||||||
ctypes = ['application/json', 'application/xml']
|
ctypes = ['application/json']
|
||||||
|
|
||||||
#Finally search in Accept-* headers
|
#Finally search in Accept-* headers
|
||||||
bm = self.accept.best_match(ctypes)
|
bm = self.accept.best_match(ctypes)
|
||||||
return bm or 'application/json'
|
return bm or 'application/json'
|
||||||
|
|
||||||
def get_content_type(self):
|
def get_content_type(self):
|
||||||
allowed_types = ("application/xml", "application/json")
|
allowed_types = ("application/json")
|
||||||
if "Content-Type" not in self.headers:
|
if "Content-Type" not in self.headers:
|
||||||
LOG.debug(_("Missing Content-Type"))
|
LOG.debug(_("Missing Content-Type"))
|
||||||
return None
|
return None
|
||||||
@ -394,154 +391,6 @@ class JSONDictSerializer(DictSerializer):
|
|||||||
return jsonutils.dumps(data, default=sanitizer)
|
return jsonutils.dumps(data, default=sanitizer)
|
||||||
|
|
||||||
|
|
||||||
class XMLDictSerializer(DictSerializer):
|
|
||||||
|
|
||||||
def __init__(self, metadata=None, xmlns=None):
|
|
||||||
"""Object initialization.
|
|
||||||
|
|
||||||
:param metadata: information needed to deserialize xml into
|
|
||||||
a dictionary.
|
|
||||||
:param xmlns: XML namespace to include with serialized xml
|
|
||||||
"""
|
|
||||||
super(XMLDictSerializer, self).__init__()
|
|
||||||
self.metadata = metadata or {}
|
|
||||||
if not xmlns:
|
|
||||||
xmlns = self.metadata.get('xmlns')
|
|
||||||
if not xmlns:
|
|
||||||
xmlns = constants.XML_NS_V20
|
|
||||||
self.xmlns = xmlns
|
|
||||||
|
|
||||||
def default(self, data):
|
|
||||||
"""Return data as XML string.
|
|
||||||
|
|
||||||
:param data: expect data to contain a single key as XML root, or
|
|
||||||
contain another '*_links' key as atom links. Other
|
|
||||||
case will use 'VIRTUAL_ROOT_KEY' as XML root.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
links = None
|
|
||||||
has_atom = False
|
|
||||||
if data is None:
|
|
||||||
root_key = constants.VIRTUAL_ROOT_KEY
|
|
||||||
root_value = None
|
|
||||||
else:
|
|
||||||
link_keys = [k for k in data.iterkeys() or []
|
|
||||||
if k.endswith('_links')]
|
|
||||||
if link_keys:
|
|
||||||
links = data.pop(link_keys[0], None)
|
|
||||||
has_atom = True
|
|
||||||
root_key = (len(data) == 1 and
|
|
||||||
data.keys()[0] or constants.VIRTUAL_ROOT_KEY)
|
|
||||||
root_value = data.get(root_key, data)
|
|
||||||
doc = etree.Element("_temp_root")
|
|
||||||
used_prefixes = []
|
|
||||||
self._to_xml_node(doc, self.metadata, root_key,
|
|
||||||
root_value, used_prefixes)
|
|
||||||
if links:
|
|
||||||
self._create_link_nodes(list(doc)[0], links)
|
|
||||||
return self.to_xml_string(list(doc)[0], used_prefixes, has_atom)
|
|
||||||
except AttributeError as e:
|
|
||||||
LOG.exception(str(e))
|
|
||||||
return ''
|
|
||||||
|
|
||||||
def __call__(self, data):
|
|
||||||
# Provides a migration path to a cleaner WSGI layer, this
|
|
||||||
# "default" stuff and extreme extensibility isn't being used
|
|
||||||
# like originally intended
|
|
||||||
return self.default(data)
|
|
||||||
|
|
||||||
def to_xml_string(self, node, used_prefixes, has_atom=False):
|
|
||||||
self._add_xmlns(node, used_prefixes, has_atom)
|
|
||||||
return etree.tostring(node, encoding='UTF-8')
|
|
||||||
|
|
||||||
#NOTE (ameade): the has_atom should be removed after all of the
|
|
||||||
# xml serializers and view builders have been updated to the current
|
|
||||||
# spec that required all responses include the xmlns:atom, the has_atom
|
|
||||||
# flag is to prevent current tests from breaking
|
|
||||||
def _add_xmlns(self, node, used_prefixes, has_atom=False):
|
|
||||||
node.set('xmlns', self.xmlns)
|
|
||||||
node.set(constants.TYPE_XMLNS, self.xmlns)
|
|
||||||
if has_atom:
|
|
||||||
node.set(constants.ATOM_XMLNS, constants.ATOM_NAMESPACE)
|
|
||||||
node.set(constants.XSI_NIL_ATTR, constants.XSI_NAMESPACE)
|
|
||||||
ext_ns = self.metadata.get(constants.EXT_NS, {})
|
|
||||||
ext_ns_bc = self.metadata.get(constants.EXT_NS_COMP, {})
|
|
||||||
for prefix in used_prefixes:
|
|
||||||
if prefix in ext_ns:
|
|
||||||
node.set('xmlns:' + prefix, ext_ns[prefix])
|
|
||||||
if prefix in ext_ns_bc:
|
|
||||||
node.set('xmlns:' + prefix, ext_ns_bc[prefix])
|
|
||||||
|
|
||||||
def _to_xml_node(self, parent, metadata, nodename, data, used_prefixes):
|
|
||||||
"""Recursive method to convert data members to XML nodes."""
|
|
||||||
result = etree.SubElement(parent, nodename)
|
|
||||||
if ":" in nodename:
|
|
||||||
used_prefixes.append(nodename.split(":", 1)[0])
|
|
||||||
#TODO(bcwaldon): accomplish this without a type-check
|
|
||||||
if isinstance(data, list):
|
|
||||||
if not data:
|
|
||||||
result.set(
|
|
||||||
constants.TYPE_ATTR,
|
|
||||||
constants.TYPE_LIST)
|
|
||||||
return result
|
|
||||||
singular = metadata.get('plurals', {}).get(nodename, None)
|
|
||||||
if singular is None:
|
|
||||||
if nodename.endswith('s'):
|
|
||||||
singular = nodename[:-1]
|
|
||||||
else:
|
|
||||||
singular = 'item'
|
|
||||||
for item in data:
|
|
||||||
self._to_xml_node(result, metadata, singular, item,
|
|
||||||
used_prefixes)
|
|
||||||
#TODO(bcwaldon): accomplish this without a type-check
|
|
||||||
elif isinstance(data, dict):
|
|
||||||
if not data:
|
|
||||||
result.set(
|
|
||||||
constants.TYPE_ATTR,
|
|
||||||
constants.TYPE_DICT)
|
|
||||||
return result
|
|
||||||
attrs = metadata.get('attributes', {}).get(nodename, {})
|
|
||||||
for k, v in data.items():
|
|
||||||
if k in attrs:
|
|
||||||
result.set(k, str(v))
|
|
||||||
else:
|
|
||||||
self._to_xml_node(result, metadata, k, v,
|
|
||||||
used_prefixes)
|
|
||||||
elif data is None:
|
|
||||||
result.set(constants.XSI_ATTR, 'true')
|
|
||||||
else:
|
|
||||||
if isinstance(data, bool):
|
|
||||||
result.set(
|
|
||||||
constants.TYPE_ATTR,
|
|
||||||
constants.TYPE_BOOL)
|
|
||||||
elif isinstance(data, int):
|
|
||||||
result.set(
|
|
||||||
constants.TYPE_ATTR,
|
|
||||||
constants.TYPE_INT)
|
|
||||||
elif isinstance(data, long):
|
|
||||||
result.set(
|
|
||||||
constants.TYPE_ATTR,
|
|
||||||
constants.TYPE_LONG)
|
|
||||||
elif isinstance(data, float):
|
|
||||||
result.set(
|
|
||||||
constants.TYPE_ATTR,
|
|
||||||
constants.TYPE_FLOAT)
|
|
||||||
LOG.debug(_("Data %(data)s type is %(type)s"),
|
|
||||||
{'data': data,
|
|
||||||
'type': type(data)})
|
|
||||||
if isinstance(data, str):
|
|
||||||
result.text = unicode(data, 'utf-8')
|
|
||||||
else:
|
|
||||||
result.text = unicode(data)
|
|
||||||
return result
|
|
||||||
|
|
||||||
def _create_link_nodes(self, xml_doc, links):
|
|
||||||
for link in links:
|
|
||||||
link_node = etree.SubElement(xml_doc, 'atom:link')
|
|
||||||
link_node.set('rel', link['rel'])
|
|
||||||
link_node.set('href', link['href'])
|
|
||||||
|
|
||||||
|
|
||||||
class ResponseHeaderSerializer(ActionDispatcher):
|
class ResponseHeaderSerializer(ActionDispatcher):
|
||||||
"""Default response headers serialization."""
|
"""Default response headers serialization."""
|
||||||
|
|
||||||
@ -557,7 +406,6 @@ class ResponseSerializer(object):
|
|||||||
|
|
||||||
def __init__(self, body_serializers=None, headers_serializer=None):
|
def __init__(self, body_serializers=None, headers_serializer=None):
|
||||||
self.body_serializers = {
|
self.body_serializers = {
|
||||||
'application/xml': XMLDictSerializer(),
|
|
||||||
'application/json': JSONDictSerializer(),
|
'application/json': JSONDictSerializer(),
|
||||||
}
|
}
|
||||||
self.body_serializers.update(body_serializers or {})
|
self.body_serializers.update(body_serializers or {})
|
||||||
@ -616,156 +464,6 @@ class JSONDeserializer(TextDeserializer):
|
|||||||
return {'body': self._from_json(datastring)}
|
return {'body': self._from_json(datastring)}
|
||||||
|
|
||||||
|
|
||||||
class ProtectedXMLParser(etree.XMLParser):
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
etree.XMLParser.__init__(self, *args, **kwargs)
|
|
||||||
self._parser.StartDoctypeDeclHandler = self.start_doctype_decl
|
|
||||||
|
|
||||||
def start_doctype_decl(self, name, sysid, pubid, internal):
|
|
||||||
raise ValueError(_("Inline DTD forbidden"))
|
|
||||||
|
|
||||||
def doctype(self, name, pubid, system):
|
|
||||||
raise ValueError(_("Inline DTD forbidden"))
|
|
||||||
|
|
||||||
|
|
||||||
class XMLDeserializer(TextDeserializer):
|
|
||||||
|
|
||||||
def __init__(self, metadata=None):
|
|
||||||
"""Object initialization.
|
|
||||||
|
|
||||||
:param metadata: information needed to deserialize xml into
|
|
||||||
a dictionary.
|
|
||||||
"""
|
|
||||||
super(XMLDeserializer, self).__init__()
|
|
||||||
self.metadata = metadata or {}
|
|
||||||
xmlns = self.metadata.get('xmlns')
|
|
||||||
if not xmlns:
|
|
||||||
xmlns = constants.XML_NS_V20
|
|
||||||
self.xmlns = xmlns
|
|
||||||
|
|
||||||
def _get_key(self, tag):
|
|
||||||
tags = tag.split("}", 1)
|
|
||||||
if len(tags) == 2:
|
|
||||||
ns = tags[0][1:]
|
|
||||||
bare_tag = tags[1]
|
|
||||||
ext_ns = self.metadata.get(constants.EXT_NS, {})
|
|
||||||
if ns == self.xmlns:
|
|
||||||
return bare_tag
|
|
||||||
for prefix, _ns in ext_ns.items():
|
|
||||||
if ns == _ns:
|
|
||||||
return prefix + ":" + bare_tag
|
|
||||||
ext_ns_bc = self.metadata.get(constants.EXT_NS_COMP, {})
|
|
||||||
for prefix, _ns in ext_ns_bc.items():
|
|
||||||
if ns == _ns:
|
|
||||||
return prefix + ":" + bare_tag
|
|
||||||
else:
|
|
||||||
return tag
|
|
||||||
|
|
||||||
def _get_links(self, root_tag, node):
|
|
||||||
link_nodes = node.findall(constants.ATOM_LINK_NOTATION)
|
|
||||||
root_tag = self._get_key(node.tag)
|
|
||||||
link_key = "%s_links" % root_tag
|
|
||||||
link_list = []
|
|
||||||
for link in link_nodes:
|
|
||||||
link_list.append({'rel': link.get('rel'),
|
|
||||||
'href': link.get('href')})
|
|
||||||
# Remove link node in order to avoid link node process as
|
|
||||||
# an item in _from_xml_node
|
|
||||||
node.remove(link)
|
|
||||||
return link_list and {link_key: link_list} or {}
|
|
||||||
|
|
||||||
def _parseXML(self, text):
|
|
||||||
parser = ProtectedXMLParser()
|
|
||||||
parser.feed(text)
|
|
||||||
return parser.close()
|
|
||||||
|
|
||||||
def _from_xml(self, datastring):
|
|
||||||
if datastring is None:
|
|
||||||
return None
|
|
||||||
plurals = set(self.metadata.get('plurals', {}))
|
|
||||||
try:
|
|
||||||
node = self._parseXML(datastring)
|
|
||||||
root_tag = self._get_key(node.tag)
|
|
||||||
# Deserialize link node was needed by unit test for verifying
|
|
||||||
# the request's response
|
|
||||||
links = self._get_links(root_tag, node)
|
|
||||||
result = self._from_xml_node(node, plurals)
|
|
||||||
# root_tag = constants.VIRTUAL_ROOT_KEY and links is not None
|
|
||||||
# is not possible because of the way data are serialized.
|
|
||||||
if root_tag == constants.VIRTUAL_ROOT_KEY:
|
|
||||||
return result
|
|
||||||
return dict({root_tag: result}, **links)
|
|
||||||
except Exception as e:
|
|
||||||
with excutils.save_and_reraise_exception():
|
|
||||||
parseError = False
|
|
||||||
# Python2.7
|
|
||||||
if (hasattr(etree, 'ParseError') and
|
|
||||||
isinstance(e, getattr(etree, 'ParseError'))):
|
|
||||||
parseError = True
|
|
||||||
# Python2.6
|
|
||||||
elif isinstance(e, expat.ExpatError):
|
|
||||||
parseError = True
|
|
||||||
if parseError:
|
|
||||||
msg = _("Cannot understand XML")
|
|
||||||
raise exception.MalformedRequestBody(reason=msg)
|
|
||||||
|
|
||||||
def _from_xml_node(self, node, listnames):
|
|
||||||
"""Convert a minidom node to a simple Python type.
|
|
||||||
|
|
||||||
:param listnames: list of XML node names whose subnodes should
|
|
||||||
be considered list items.
|
|
||||||
|
|
||||||
"""
|
|
||||||
attrNil = node.get(str(etree.QName(constants.XSI_NAMESPACE, "nil")))
|
|
||||||
attrType = node.get(str(etree.QName(
|
|
||||||
self.metadata.get('xmlns'), "type")))
|
|
||||||
if (attrNil and attrNil.lower() == 'true'):
|
|
||||||
return None
|
|
||||||
elif not len(node) and not node.text:
|
|
||||||
if (attrType and attrType == constants.TYPE_DICT):
|
|
||||||
return {}
|
|
||||||
elif (attrType and attrType == constants.TYPE_LIST):
|
|
||||||
return []
|
|
||||||
else:
|
|
||||||
return ''
|
|
||||||
elif (len(node) == 0 and node.text):
|
|
||||||
converters = {constants.TYPE_BOOL:
|
|
||||||
lambda x: x.lower() == 'true',
|
|
||||||
constants.TYPE_INT:
|
|
||||||
lambda x: int(x),
|
|
||||||
constants.TYPE_LONG:
|
|
||||||
lambda x: long(x),
|
|
||||||
constants.TYPE_FLOAT:
|
|
||||||
lambda x: float(x)}
|
|
||||||
if attrType and attrType in converters:
|
|
||||||
return converters[attrType](node.text)
|
|
||||||
else:
|
|
||||||
return node.text
|
|
||||||
elif self._get_key(node.tag) in listnames:
|
|
||||||
return [self._from_xml_node(n, listnames) for n in node]
|
|
||||||
else:
|
|
||||||
result = dict()
|
|
||||||
for attr in node.keys():
|
|
||||||
if (attr == 'xmlns' or
|
|
||||||
attr.startswith('xmlns:') or
|
|
||||||
attr == constants.XSI_ATTR or
|
|
||||||
attr == constants.TYPE_ATTR):
|
|
||||||
continue
|
|
||||||
result[self._get_key(attr)] = node.get(attr)
|
|
||||||
children = list(node)
|
|
||||||
for child in children:
|
|
||||||
result[self._get_key(child.tag)] = self._from_xml_node(
|
|
||||||
child, listnames)
|
|
||||||
return result
|
|
||||||
|
|
||||||
def default(self, datastring):
|
|
||||||
return {'body': self._from_xml(datastring)}
|
|
||||||
|
|
||||||
def __call__(self, datastring):
|
|
||||||
# Adding a migration path to allow us to remove unncessary classes
|
|
||||||
return self.default(datastring)
|
|
||||||
|
|
||||||
|
|
||||||
class RequestHeadersDeserializer(ActionDispatcher):
|
class RequestHeadersDeserializer(ActionDispatcher):
|
||||||
"""Default request headers deserializer."""
|
"""Default request headers deserializer."""
|
||||||
|
|
||||||
@ -781,7 +479,6 @@ class RequestDeserializer(object):
|
|||||||
|
|
||||||
def __init__(self, body_deserializers=None, headers_deserializer=None):
|
def __init__(self, body_deserializers=None, headers_deserializer=None):
|
||||||
self.body_deserializers = {
|
self.body_deserializers = {
|
||||||
'application/xml': XMLDeserializer(),
|
|
||||||
'application/json': JSONDeserializer(),
|
'application/json': JSONDeserializer(),
|
||||||
}
|
}
|
||||||
self.body_deserializers.update(body_deserializers or {})
|
self.body_deserializers.update(body_deserializers or {})
|
||||||
@ -1057,10 +754,6 @@ class Resource(Application):
|
|||||||
self.deserializer = deserializer or RequestDeserializer()
|
self.deserializer = deserializer or RequestDeserializer()
|
||||||
self.serializer = serializer or ResponseSerializer()
|
self.serializer = serializer or ResponseSerializer()
|
||||||
self._fault_body_function = fault_body_function
|
self._fault_body_function = fault_body_function
|
||||||
# use serializer's xmlns for populating Fault generator xmlns
|
|
||||||
xml_serializer = self.serializer.body_serializers['application/xml']
|
|
||||||
if hasattr(xml_serializer, 'xmlns'):
|
|
||||||
self._xmlns = xml_serializer.xmlns
|
|
||||||
|
|
||||||
@webob.dec.wsgify(RequestClass=Request)
|
@webob.dec.wsgify(RequestClass=Request)
|
||||||
def __call__(self, request):
|
def __call__(self, request):
|
||||||
@ -1074,26 +767,21 @@ class Resource(Application):
|
|||||||
except exception.InvalidContentType:
|
except exception.InvalidContentType:
|
||||||
msg = _("Unsupported Content-Type")
|
msg = _("Unsupported Content-Type")
|
||||||
LOG.exception(_("InvalidContentType: %s"), msg)
|
LOG.exception(_("InvalidContentType: %s"), msg)
|
||||||
return Fault(webob.exc.HTTPBadRequest(explanation=msg),
|
return Fault(webob.exc.HTTPBadRequest(explanation=msg))
|
||||||
self._xmlns)
|
|
||||||
except exception.MalformedRequestBody:
|
except exception.MalformedRequestBody:
|
||||||
msg = _("Malformed request body")
|
msg = _("Malformed request body")
|
||||||
LOG.exception(_("MalformedRequestBody: %s"), msg)
|
LOG.exception(_("MalformedRequestBody: %s"), msg)
|
||||||
return Fault(webob.exc.HTTPBadRequest(explanation=msg),
|
return Fault(webob.exc.HTTPBadRequest(explanation=msg))
|
||||||
self._xmlns)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
action_result = self.dispatch(request, action, args)
|
action_result = self.dispatch(request, action, args)
|
||||||
except webob.exc.HTTPException as ex:
|
except webob.exc.HTTPException as ex:
|
||||||
LOG.info(_("HTTP exception thrown: %s"), unicode(ex))
|
LOG.info(_("HTTP exception thrown: %s"), unicode(ex))
|
||||||
action_result = Fault(ex,
|
action_result = Fault(ex, self._fault_body_function)
|
||||||
self._xmlns,
|
|
||||||
self._fault_body_function)
|
|
||||||
except Exception:
|
except Exception:
|
||||||
LOG.exception(_("Internal error"))
|
LOG.exception(_("Internal error"))
|
||||||
# Do not include the traceback to avoid returning it to clients.
|
# Do not include the traceback to avoid returning it to clients.
|
||||||
action_result = Fault(webob.exc.HTTPServerError(),
|
action_result = Fault(webob.exc.HTTPServerError(),
|
||||||
self._xmlns,
|
|
||||||
self._fault_body_function)
|
self._fault_body_function)
|
||||||
|
|
||||||
if isinstance(action_result, dict) or action_result is None:
|
if isinstance(action_result, dict) or action_result is None:
|
||||||
@ -1124,8 +812,7 @@ class Resource(Application):
|
|||||||
return controller_method(request=request, **action_args)
|
return controller_method(request=request, **action_args)
|
||||||
except TypeError as exc:
|
except TypeError as exc:
|
||||||
LOG.exception(exc)
|
LOG.exception(exc)
|
||||||
return Fault(webob.exc.HTTPBadRequest(),
|
return Fault(webob.exc.HTTPBadRequest())
|
||||||
self._xmlns)
|
|
||||||
|
|
||||||
|
|
||||||
def _default_body_function(wrapped_exc):
|
def _default_body_function(wrapped_exc):
|
||||||
@ -1142,11 +829,10 @@ def _default_body_function(wrapped_exc):
|
|||||||
class Fault(webob.exc.HTTPException):
|
class Fault(webob.exc.HTTPException):
|
||||||
"""Generates an HTTP response from a webob HTTP exception."""
|
"""Generates an HTTP response from a webob HTTP exception."""
|
||||||
|
|
||||||
def __init__(self, exception, xmlns=None, body_function=None):
|
def __init__(self, exception, body_function=None):
|
||||||
"""Creates a Fault for the given webob.exc.exception."""
|
"""Creates a Fault for the given webob.exc.exception."""
|
||||||
self.wrapped_exc = exception
|
self.wrapped_exc = exception
|
||||||
self.status_int = self.wrapped_exc.status_int
|
self.status_int = self.wrapped_exc.status_int
|
||||||
self._xmlns = xmlns
|
|
||||||
self._body_function = body_function or _default_body_function
|
self._body_function = body_function or _default_body_function
|
||||||
|
|
||||||
@webob.dec.wsgify(RequestClass=Request)
|
@webob.dec.wsgify(RequestClass=Request)
|
||||||
@ -1154,10 +840,8 @@ class Fault(webob.exc.HTTPException):
|
|||||||
"""Generate a WSGI response based on the exception passed to ctor."""
|
"""Generate a WSGI response based on the exception passed to ctor."""
|
||||||
# Replace the body with fault details.
|
# Replace the body with fault details.
|
||||||
fault_data, metadata = self._body_function(self.wrapped_exc)
|
fault_data, metadata = self._body_function(self.wrapped_exc)
|
||||||
xml_serializer = XMLDictSerializer(metadata, self._xmlns)
|
|
||||||
content_type = req.best_match_content_type()
|
content_type = req.best_match_content_type()
|
||||||
serializer = {
|
serializer = {
|
||||||
'application/xml': xml_serializer,
|
|
||||||
'application/json': JSONDictSerializer(),
|
'application/json': JSONDictSerializer(),
|
||||||
}[content_type]
|
}[content_type]
|
||||||
|
|
||||||
@ -1200,8 +884,7 @@ class Controller(object):
|
|||||||
else:
|
else:
|
||||||
status = 200
|
status = 200
|
||||||
content_type = req.best_match_content_type()
|
content_type = req.best_match_content_type()
|
||||||
default_xmlns = self.get_default_xmlns(req)
|
body = self._serialize(result, content_type)
|
||||||
body = self._serialize(result, content_type, default_xmlns)
|
|
||||||
|
|
||||||
response = webob.Response(status=status,
|
response = webob.Response(status=status,
|
||||||
content_type=content_type,
|
content_type=content_type,
|
||||||
@ -1213,7 +896,7 @@ class Controller(object):
|
|||||||
else:
|
else:
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _serialize(self, data, content_type, default_xmlns):
|
def _serialize(self, data, content_type):
|
||||||
"""Serialize the given dict to the provided content_type.
|
"""Serialize the given dict to the provided content_type.
|
||||||
|
|
||||||
Uses self._serialization_metadata if it exists, which is a dict mapping
|
Uses self._serialization_metadata if it exists, which is a dict mapping
|
||||||
@ -1222,7 +905,7 @@ class Controller(object):
|
|||||||
"""
|
"""
|
||||||
_metadata = getattr(type(self), '_serialization_metadata', {})
|
_metadata = getattr(type(self), '_serialization_metadata', {})
|
||||||
|
|
||||||
serializer = Serializer(_metadata, default_xmlns)
|
serializer = Serializer(_metadata)
|
||||||
try:
|
try:
|
||||||
return serializer.serialize(data, content_type)
|
return serializer.serialize(data, content_type)
|
||||||
except exception.InvalidContentType:
|
except exception.InvalidContentType:
|
||||||
@ -1240,17 +923,13 @@ class Controller(object):
|
|||||||
serializer = Serializer(_metadata)
|
serializer = Serializer(_metadata)
|
||||||
return serializer.deserialize(data, content_type)['body']
|
return serializer.deserialize(data, content_type)['body']
|
||||||
|
|
||||||
def get_default_xmlns(self, req):
|
|
||||||
"""Provide the XML namespace to use if none is otherwise specified."""
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
# NOTE(salvatore-orlando): this class will go once the
|
# NOTE(salvatore-orlando): this class will go once the
|
||||||
# extension API framework is updated
|
# extension API framework is updated
|
||||||
class Serializer(object):
|
class Serializer(object):
|
||||||
"""Serializes and deserializes dictionaries to certain MIME types."""
|
"""Serializes and deserializes dictionaries to certain MIME types."""
|
||||||
|
|
||||||
def __init__(self, metadata=None, default_xmlns=None):
|
def __init__(self, metadata=None):
|
||||||
"""Create a serializer based on the given WSGI environment.
|
"""Create a serializer based on the given WSGI environment.
|
||||||
|
|
||||||
'metadata' is an optional dict mapping MIME types to information
|
'metadata' is an optional dict mapping MIME types to information
|
||||||
@ -1258,12 +937,10 @@ class Serializer(object):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
self.metadata = metadata or {}
|
self.metadata = metadata or {}
|
||||||
self.default_xmlns = default_xmlns
|
|
||||||
|
|
||||||
def _get_serialize_handler(self, content_type):
|
def _get_serialize_handler(self, content_type):
|
||||||
handlers = {
|
handlers = {
|
||||||
'application/json': JSONDictSerializer(),
|
'application/json': JSONDictSerializer(),
|
||||||
'application/xml': XMLDictSerializer(self.metadata),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -1290,7 +967,6 @@ class Serializer(object):
|
|||||||
def get_deserialize_handler(self, content_type):
|
def get_deserialize_handler(self, content_type):
|
||||||
handlers = {
|
handlers = {
|
||||||
'application/json': JSONDeserializer(),
|
'application/json': JSONDeserializer(),
|
||||||
'application/xml': XMLDeserializer(self.metadata),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
Loading…
Reference in New Issue
Block a user