From 334f2215f0533e8181d40cd086e927e7913739f2 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Mon, 11 Jul 2011 12:31:38 -0400 Subject: minor refactoring --- nova/api/openstack/wsgi.py | 52 +++++++++++++++------- nova/tests/api/openstack/test_wsgi.py | 83 ++++++++++++++++++++++++----------- 2 files changed, 94 insertions(+), 41 deletions(-) diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py index 7a8376722..9a273bf6e 100644 --- a/nova/api/openstack/wsgi.py +++ b/nova/api/openstack/wsgi.py @@ -57,16 +57,26 @@ class Request(webob.Request): return content_type -class TextDeserializer(object): - """Custom request body deserialization based on controller action name.""" +class ActionDispatcher(object): + """Maps method name to local methods through action name.""" - def deserialize(self, datastring, action='default'): - """Find local deserialization method and parse request body.""" + def dispatch(self, *args, **kwargs): + """Find and call local method.""" + action = kwargs.pop('action', 'default') action_method = getattr(self, str(action), self.default) - return action_method(datastring) + return action_method(*args, **kwargs) + + def default(self, data): + raise NotImplementedError() + + +class TextDeserializer(ActionDispatcher): + """Default request body deserialization""" + + def deserialize(self, datastring, action='default'): + return self.dispatch(datastring, action=action) def default(self, datastring): - """Default deserialization code should live here""" return {} @@ -128,8 +138,13 @@ class XMLDeserializer(TextDeserializer): return {'body': self._from_xml(datastring)} -class RequestHeadersDeserializer(object): +class RequestHeadersDeserializer(ActionDispatcher): + """Default request headers deserializer""" + def deserialize(self, request, action): + return self.dispatch(request, action=action) + + def default(self, request): return {} @@ -220,20 +235,18 @@ class RequestDeserializer(object): return args -class DictSerializer(object): - """Custom response body serialization based on controller action name.""" +class DictSerializer(ActionDispatcher): + """Default request body serialization""" def serialize(self, data, action='default'): - """Find local serialization method and encode response body.""" - action_method = getattr(self, str(action), self.default) - return action_method(data) + return self.dispatch(data, action=action) def default(self, data): - """Default serialization code should live here""" - raise NotImplementedError() + return "" class JSONDictSerializer(DictSerializer): + """Default JSON request body serialization""" def default(self, data): return utils.dumps(data) @@ -320,8 +333,13 @@ class XMLDictSerializer(DictSerializer): return result -class ResponseHeadersSerializer(object): +class ResponseHeadersSerializer(ActionDispatcher): + """Default response headers serialization""" + def serialize(self, response, data, action): + self.dispatch(response, data, action=action) + + def default(self, response, data): response.status_int = 200 @@ -410,7 +428,9 @@ class Resource(wsgi.Application): #TODO(bcwaldon): find a more elegant way to pass through non-dict types if type(action_result) is dict: - response = self.serializer.serialize(action_result, accept, action) + response = self.serializer.serialize(action_result, + accept, + action=action) else: response = action_result diff --git a/nova/tests/api/openstack/test_wsgi.py b/nova/tests/api/openstack/test_wsgi.py index 938637207..9b68f76b0 100644 --- a/nova/tests/api/openstack/test_wsgi.py +++ b/nova/tests/api/openstack/test_wsgi.py @@ -75,24 +75,48 @@ class RequestTest(test.TestCase): self.assertEqual(result, "application/json") -class DictSerializerTest(test.TestCase): +class ActionDispatcherTest(test.TestCase): def test_dispatch(self): - serializer = wsgi.DictSerializer() + serializer = wsgi.ActionDispatcher() + serializer.create = lambda x: 'pants' + self.assertEqual(serializer.dispatch({}, action='create'), 'pants') + + def test_dispatch_action_None(self): + serializer = wsgi.ActionDispatcher() serializer.create = lambda x: 'pants' serializer.default = lambda x: 'trousers' - self.assertEqual(serializer.serialize({}, 'create'), 'pants') + self.assertEqual(serializer.dispatch({}, action=None), 'trousers') def test_dispatch_default(self): - serializer = wsgi.DictSerializer() + serializer = wsgi.ActionDispatcher() serializer.create = lambda x: 'pants' serializer.default = lambda x: 'trousers' - self.assertEqual(serializer.serialize({}, 'update'), 'trousers') + self.assertEqual(serializer.dispatch({}, action='update'), 'trousers') - def test_dispatch_action_None(self): + +class ResponseHeadersSerializerTest(test.TestCase): + def test_default(self): + serializer = wsgi.ResponseHeadersSerializer() + response = webob.Response() + serializer.serialize(response, {'v': '123'}, 'asdf') + self.assertEqual(response.status_int, 200) + + def test_custom(self): + class Serializer(wsgi.ResponseHeadersSerializer): + def update(self, response, data): + response.status_int = 404 + response.headers['X-Custom-Header'] = data['v'] + serializer = Serializer() + response = webob.Response() + serializer.serialize(response, {'v': '123'}, 'update') + self.assertEqual(response.status_int, 404) + self.assertEqual(response.headers['X-Custom-Header'], '123') + + +class DictSerializerTest(test.TestCase): + def test_dispatch_default(self): serializer = wsgi.DictSerializer() - serializer.create = lambda x: 'pants' - serializer.default = lambda x: 'trousers' - self.assertEqual(serializer.serialize({}, None), 'trousers') + self.assertEqual(serializer.serialize({}, 'update'), '') class XMLDictSerializerTest(test.TestCase): @@ -116,23 +140,9 @@ class JSONDictSerializerTest(test.TestCase): class TextDeserializerTest(test.TestCase): - def test_dispatch(self): - deserializer = wsgi.TextDeserializer() - deserializer.create = lambda x: 'pants' - deserializer.default = lambda x: 'trousers' - self.assertEqual(deserializer.deserialize({}, 'create'), 'pants') - def test_dispatch_default(self): deserializer = wsgi.TextDeserializer() - deserializer.create = lambda x: 'pants' - deserializer.default = lambda x: 'trousers' - self.assertEqual(deserializer.deserialize({}, 'update'), 'trousers') - - def test_dispatch_action_None(self): - deserializer = wsgi.TextDeserializer() - deserializer.create = lambda x: 'pants' - deserializer.default = lambda x: 'trousers' - self.assertEqual(deserializer.deserialize({}, None), 'trousers') + self.assertEqual(deserializer.deserialize({}, 'update'), {}) class JSONDeserializerTest(test.TestCase): @@ -189,6 +199,22 @@ class XMLDeserializerTest(test.TestCase): self.assertEqual(deserializer.deserialize(xml), as_dict) +class RequestHeadersDeserializerTest(test.TestCase): + def test_default(self): + deserializer = wsgi.RequestHeadersDeserializer() + req = wsgi.Request.blank('/') + self.assertEqual(deserializer.deserialize(req, 'asdf'), {}) + + def test_custom(self): + class Deserializer(wsgi.RequestHeadersDeserializer): + def update(self, request): + return {'a': request.headers['X-Custom-Header']} + deserializer = Deserializer() + req = wsgi.Request.blank('/') + req.headers['X-Custom-Header'] = 'b' + self.assertEqual(deserializer.deserialize(req, 'update'), {'a': 'b'}) + + class ResponseSerializerTest(test.TestCase): def setUp(self): class JSONSerializer(object): @@ -199,12 +225,17 @@ class ResponseSerializerTest(test.TestCase): def serialize(self, data, action='default'): return 'pew_xml' + class HeadersSerializer(object): + def serialize(self, response, data, action): + response.status_int = 404 + self.body_serializers = { 'application/json': JSONSerializer(), 'application/XML': XMLSerializer(), } - self.serializer = wsgi.ResponseSerializer(self.body_serializers) + self.serializer = wsgi.ResponseSerializer(self.body_serializers, + HeadersSerializer()) def tearDown(self): pass @@ -223,6 +254,7 @@ class ResponseSerializerTest(test.TestCase): response = self.serializer.serialize({}, 'application/json') self.assertEqual(response.headers['Content-Type'], 'application/json') self.assertEqual(response.body, 'pew_json') + self.assertEqual(response.status_int, 404) def test_serialize_response_dict_to_unknown_content_type(self): self.assertRaises(exception.InvalidContentType, @@ -230,6 +262,7 @@ class ResponseSerializerTest(test.TestCase): {}, 'application/unknown') + class RequestDeserializerTest(test.TestCase): def setUp(self): class JSONDeserializer(object): -- cgit From ac894f7d4dfde9c4d818007e105860661b00fd04 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Mon, 11 Jul 2011 12:33:53 -0400 Subject: pep8 --- nova/tests/api/openstack/test_wsgi.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nova/tests/api/openstack/test_wsgi.py b/nova/tests/api/openstack/test_wsgi.py index 9b68f76b0..5bdda7c7e 100644 --- a/nova/tests/api/openstack/test_wsgi.py +++ b/nova/tests/api/openstack/test_wsgi.py @@ -262,7 +262,6 @@ class ResponseSerializerTest(test.TestCase): {}, 'application/unknown') - class RequestDeserializerTest(test.TestCase): def setUp(self): class JSONDeserializer(object): -- cgit From ad23d0f354b8698b5314ed2a55e5a4d17abffba0 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Mon, 11 Jul 2011 13:16:22 -0400 Subject: allowing controllers to return Nonew --- nova/api/openstack/wsgi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py index 9a273bf6e..8eff9e441 100644 --- a/nova/api/openstack/wsgi.py +++ b/nova/api/openstack/wsgi.py @@ -427,7 +427,7 @@ class Resource(wsgi.Application): action_result = self.dispatch(request, action, args) #TODO(bcwaldon): find a more elegant way to pass through non-dict types - if type(action_result) is dict: + if type(action_result) is dict or action_result is None: response = self.serializer.serialize(action_result, accept, action=action) -- cgit