[Py34] Enable api.openstack.test_wsgi unit test

Issues:
- Method `webob.multidict.MultiDict.items` returns list object in py2 env[1]
  and listiterator in  py3 env[2]. ListIterator prevents changing values of
  headers in a loop(changes of item's order prevent skipping some headers).
- Statement `nova.utils.utf8(str(some_value))` did not work for bytes type in
  py3 env. Good example is `test_resource_headers_are_utf8` test. Int value 1
  became to b'b"b\'1\'"' after deserialization.
- Wrong checks for utf-8. (including check for encoding headers names, which
  is not encoded anywhere in the code)
- Wrong checks for `body` property of `webob.response.Response` cls. Method
  `_body__get` returns bytes[3]. There is no problem in python 2, since
  type(b"some") equals to type("some"), but it wrong for python 3.

[1] - https://github.com/Pylons/webob/blob/1.5.0b0/webob/multidict.py#L266-L267
[2] - https://github.com/Pylons/webob/blob/1.5.0b0/webob/multidict.py#L260-L264
[3] - https://github.com/Pylons/webob/blob/1.5.0b0/webob/response.py#L350

Related bp nova-python3-mitaka

Change-Id: I15150c8c8f204081b9b5d8bc28e622692d7d749a
This commit is contained in:
Andrey Kurilin 2015-10-05 18:18:48 +03:00 committed by Andrey Kurilin
parent 240df42859
commit cc1ff0051a
6 changed files with 116 additions and 71 deletions

View File

@ -297,7 +297,7 @@ class JSONDictSerializer(DictSerializer):
"""Default JSON request body serialization.""" """Default JSON request body serialization."""
def default(self, data): def default(self, data):
return jsonutils.dumps(data) return six.text_type(jsonutils.dumps(data))
def serializers(**serializers): def serializers(**serializers):
@ -457,14 +457,20 @@ class ResponseObject(object):
default_serializers) default_serializers)
serializer = _serializer() serializer = _serializer()
response = webob.Response() body = None
if self.obj is not None:
body = serializer.serialize(self.obj)
response = webob.Response(body=body)
if response.headers.get('Content-Length'):
# NOTE(andreykurilin): we need to encode 'Content-Length' header,
# since webob.Response auto sets it if "body" attr is presented.
# https://github.com/Pylons/webob/blob/1.5.0b0/webob/response.py#L147
response.headers['Content-Length'] = utils.utf8(
response.headers['Content-Length'])
response.status_int = self.code response.status_int = self.code
for hdr, value in self._headers.items(): for hdr, value in self._headers.items():
response.headers[hdr] = utils.utf8(str(value)) response.headers[hdr] = utils.utf8(value)
response.headers['Content-Type'] = utils.utf8(content_type) response.headers['Content-Type'] = utils.utf8(content_type)
if self.obj is not None:
response.body = serializer.serialize(self.obj)
return response return response
@property @property
@ -645,7 +651,7 @@ class Resource(wsgi.Application):
content_type = request.get_content_type() content_type = request.get_content_type()
except exception.InvalidContentType: except exception.InvalidContentType:
LOG.debug("Unrecognized Content-Type provided in request") LOG.debug("Unrecognized Content-Type provided in request")
return None, '' return None, b''
return content_type, request.body return content_type, request.body
@ -860,10 +866,9 @@ class Resource(wsgi.Application):
self.default_serializers) self.default_serializers)
if hasattr(response, 'headers'): if hasattr(response, 'headers'):
for hdr, val in list(response.headers.items()):
for hdr, val in response.headers.items():
# Headers must be utf-8 strings # Headers must be utf-8 strings
response.headers[hdr] = utils.utf8(str(val)) response.headers[hdr] = utils.utf8(val)
if not request.api_version_request.is_null(): if not request.api_version_request.is_null():
response.headers[API_VERSION_REQUEST_HEADER] = \ response.headers[API_VERSION_REQUEST_HEADER] = \
@ -1158,7 +1163,7 @@ class Fault(webob.exc.HTTPException):
def __init__(self, exception): def __init__(self, exception):
"""Create a Fault for the given webob.exc.exception.""" """Create a Fault for the given webob.exc.exception."""
self.wrapped_exc = exception self.wrapped_exc = exception
for key, value in self.wrapped_exc.headers.items(): for key, value in list(self.wrapped_exc.headers.items()):
self.wrapped_exc.headers[key] = str(value) self.wrapped_exc.headers[key] = str(value)
self.status_int = exception.status_int self.status_int = exception.status_int
@ -1195,8 +1200,9 @@ class Fault(webob.exc.HTTPException):
'application/json': JSONDictSerializer(), 'application/json': JSONDictSerializer(),
}[content_type] }[content_type]
self.wrapped_exc.body = serializer.serialize(fault_data)
self.wrapped_exc.content_type = content_type self.wrapped_exc.content_type = content_type
self.wrapped_exc.charset = 'UTF-8'
self.wrapped_exc.text = serializer.serialize(fault_data)
return self.wrapped_exc return self.wrapped_exc
@ -1245,7 +1251,8 @@ class RateLimitFault(webob.exc.HTTPException):
}[content_type] }[content_type]
content = serializer.serialize(self.content) content = serializer.serialize(self.content)
self.wrapped_exc.body = content self.wrapped_exc.charset = 'UTF-8'
self.wrapped_exc.content_type = content_type self.wrapped_exc.content_type = content_type
self.wrapped_exc.text = content
return self.wrapped_exc return self.wrapped_exc

View File

@ -23,6 +23,7 @@ from nova import exception
from nova import i18n from nova import i18n
from nova import test from nova import test
from nova.tests.unit.api.openstack import fakes from nova.tests.unit.api.openstack import fakes
from nova.tests.unit import matchers
from nova.tests.unit import utils from nova.tests.unit import utils
from oslo_serialization import jsonutils from oslo_serialization import jsonutils
@ -32,13 +33,13 @@ class RequestTest(test.NoDBTestCase):
def test_content_type_missing(self): def test_content_type_missing(self):
request = wsgi.Request.blank('/tests/123', method='POST') request = wsgi.Request.blank('/tests/123', method='POST')
request.body = "<body />" request.body = b"<body />"
self.assertIsNone(request.get_content_type()) self.assertIsNone(request.get_content_type())
def test_content_type_unsupported(self): def test_content_type_unsupported(self):
request = wsgi.Request.blank('/tests/123', method='POST') request = wsgi.Request.blank('/tests/123', method='POST')
request.headers["Content-Type"] = "text/html" request.headers["Content-Type"] = "text/html"
request.body = "asdf<br />" request.body = b"asdf<br />"
self.assertRaises(exception.InvalidContentType, self.assertRaises(exception.InvalidContentType,
request.get_content_type) request.get_content_type)
@ -250,7 +251,7 @@ class JSONDeserializerTest(test.NoDBTestCase):
self.assertEqual(deserializer.deserialize(data), as_dict) self.assertEqual(deserializer.deserialize(data), as_dict)
def test_json_valid_utf8(self): def test_json_valid_utf8(self):
data = """{"server": {"min_count": 1, "flavorRef": "1", data = b"""{"server": {"min_count": 1, "flavorRef": "1",
"name": "\xe6\xa6\x82\xe5\xbf\xb5", "name": "\xe6\xa6\x82\xe5\xbf\xb5",
"imageRef": "10bab10c-1304-47d", "imageRef": "10bab10c-1304-47d",
"max_count": 1}} """ "max_count": 1}} """
@ -269,7 +270,7 @@ class JSONDeserializerTest(test.NoDBTestCase):
def test_json_invalid_utf8(self): def test_json_invalid_utf8(self):
"""Send invalid utf-8 to JSONDeserializer.""" """Send invalid utf-8 to JSONDeserializer."""
data = """{"server": {"min_count": 1, "flavorRef": "1", data = b"""{"server": {"min_count": 1, "flavorRef": "1",
"name": "\xf0\x28\x8c\x28", "name": "\xf0\x28\x8c\x28",
"imageRef": "10bab10c-1304-47d", "imageRef": "10bab10c-1304-47d",
"max_count": 1}} """ "max_count": 1}} """
@ -301,7 +302,7 @@ class ResourceTest(test.NoDBTestCase):
app = fakes.TestRouterV21(Controller()) app = fakes.TestRouterV21(Controller())
req = webob.Request.blank('/tests') req = webob.Request.blank('/tests')
response = req.get_response(app) response = req.get_response(app)
self.assertEqual(response.body, 'success') self.assertEqual(b'success', response.body)
self.assertEqual(response.status_int, 200) self.assertEqual(response.status_int, 200)
@mock.patch("nova.api.openstack.api_version_request.max_api_version") @mock.patch("nova.api.openstack.api_version_request.max_api_version")
@ -320,7 +321,7 @@ class ResourceTest(test.NoDBTestCase):
req = webob.Request.blank('/tests') req = webob.Request.blank('/tests')
req.headers = {self.header_name: version} req.headers = {self.header_name: version}
response = req.get_response(app) response = req.get_response(app)
self.assertEqual(response.body, 'success') self.assertEqual(b'success', response.body)
self.assertEqual(response.status_int, 200) self.assertEqual(response.status_int, 200)
def test_resource_receives_api_version_request_invalid(self): def test_resource_receives_api_version_request_invalid(self):
@ -345,15 +346,15 @@ class ResourceTest(test.NoDBTestCase):
# the default method is GET # the default method is GET
req = webob.Request.blank('/tests') req = webob.Request.blank('/tests')
response = req.get_response(app) response = req.get_response(app)
self.assertEqual(response.body, 'success') self.assertEqual(b'success', response.body)
self.assertEqual(response.status_int, 200) self.assertEqual(response.status_int, 200)
req.body = '{"body": {"key": "value"}}' req.body = b'{"body": {"key": "value"}}'
response = req.get_response(app) response = req.get_response(app)
self.assertEqual(response.body, 'success') self.assertEqual(b'success', response.body)
self.assertEqual(response.status_int, 200) self.assertEqual(response.status_int, 200)
req.content_type = 'application/json' req.content_type = 'application/json'
response = req.get_response(app) response = req.get_response(app)
self.assertEqual(response.body, 'success') self.assertEqual(b'success', response.body)
self.assertEqual(response.status_int, 200) self.assertEqual(response.status_int, 200)
def test_resource_call_with_method_post(self): def test_resource_call_with_method_post(self):
@ -368,20 +369,20 @@ class ResourceTest(test.NoDBTestCase):
app = fakes.TestRouter(Controller()) app = fakes.TestRouter(Controller())
req = webob.Request.blank('/tests', method="POST", req = webob.Request.blank('/tests', method="POST",
content_type='application/json') content_type='application/json')
req.body = '{"body": {"key": "value"}}' req.body = b'{"body": {"key": "value"}}'
expected_body = {'body': { expected_body = {'body': {
"key": "value" "key": "value"
} }
} }
response = req.get_response(app) response = req.get_response(app)
self.assertEqual(response.status_int, 200) self.assertEqual(response.status_int, 200)
self.assertEqual(response.body, 'success') self.assertEqual(b'success', response.body)
# verify without body # verify without body
expected_body = None expected_body = None
req.body = None req.body = None
response = req.get_response(app) response = req.get_response(app)
self.assertEqual(response.status_int, 200) self.assertEqual(response.status_int, 200)
self.assertEqual(response.body, 'success') self.assertEqual(b'success', response.body)
# the body is validated in the controller # the body is validated in the controller
expected_body = {'body': None} expected_body = {'body': None}
response = req.get_response(app) response = req.get_response(app)
@ -402,13 +403,13 @@ class ResourceTest(test.NoDBTestCase):
app = fakes.TestRouter(Controller()) app = fakes.TestRouter(Controller())
req = webob.Request.blank('/tests/test_id', method="PUT", req = webob.Request.blank('/tests/test_id', method="PUT",
content_type='application/json') content_type='application/json')
req.body = '{"body": {"key": "value"}}' req.body = b'{"body": {"key": "value"}}'
expected_body = {'body': { expected_body = {'body': {
"key": "value" "key": "value"
} }
} }
response = req.get_response(app) response = req.get_response(app)
self.assertEqual(response.body, 'success') self.assertEqual(b'success', response.body)
self.assertEqual(response.status_int, 200) self.assertEqual(response.status_int, 200)
req.body = None req.body = None
expected_body = None expected_body = None
@ -416,7 +417,7 @@ class ResourceTest(test.NoDBTestCase):
self.assertEqual(response.status_int, 200) self.assertEqual(response.status_int, 200)
# verify no content_type is contained in the request # verify no content_type is contained in the request
req.content_type = None req.content_type = None
req.body = '{"body": {"key": "value"}}' req.body = b'{"body": {"key": "value"}}'
response = req.get_response(app) response = req.get_response(app)
expected_unsupported_type_body = {'badRequest': expected_unsupported_type_body = {'badRequest':
{'message': 'Unsupported Content-Type', 'code': 400}} {'message': 'Unsupported Content-Type', 'code': 400}}
@ -434,12 +435,12 @@ class ResourceTest(test.NoDBTestCase):
req = webob.Request.blank('/tests/test_id', method="DELETE") req = webob.Request.blank('/tests/test_id', method="DELETE")
response = req.get_response(app) response = req.get_response(app)
self.assertEqual(response.status_int, 200) self.assertEqual(response.status_int, 200)
self.assertEqual(response.body, 'success') self.assertEqual(b'success', response.body)
# ignore the body # ignore the body
req.body = '{"body": {"key": "value"}}' req.body = b'{"body": {"key": "value"}}'
response = req.get_response(app) response = req.get_response(app)
self.assertEqual(response.status_int, 200) self.assertEqual(response.status_int, 200)
self.assertEqual(response.body, 'success') self.assertEqual(b'success', response.body)
def test_resource_not_authorized(self): def test_resource_not_authorized(self):
class Controller(object): class Controller(object):
@ -552,11 +553,11 @@ class ResourceTest(test.NoDBTestCase):
request = wsgi.Request.blank('/', method='POST') request = wsgi.Request.blank('/', method='POST')
request.headers['Content-Type'] = 'application/none' request.headers['Content-Type'] = 'application/none'
request.body = 'foo' request.body = b'foo'
content_type, body = resource.get_body(request) content_type, body = resource.get_body(request)
self.assertIsNone(content_type) self.assertIsNone(content_type)
self.assertEqual(body, '') self.assertEqual(b'', body)
def test_get_body_no_content_type(self): def test_get_body_no_content_type(self):
class Controller(object): class Controller(object):
@ -567,11 +568,11 @@ class ResourceTest(test.NoDBTestCase):
resource = wsgi.Resource(controller) resource = wsgi.Resource(controller)
request = wsgi.Request.blank('/', method='POST') request = wsgi.Request.blank('/', method='POST')
request.body = 'foo' request.body = b'foo'
content_type, body = resource.get_body(request) content_type, body = resource.get_body(request)
self.assertIsNone(content_type) self.assertIsNone(content_type)
self.assertEqual(body, 'foo') self.assertEqual(b'foo', body)
def test_get_body_no_content_body(self): def test_get_body_no_content_body(self):
class Controller(object): class Controller(object):
@ -583,11 +584,11 @@ class ResourceTest(test.NoDBTestCase):
request = wsgi.Request.blank('/', method='POST') request = wsgi.Request.blank('/', method='POST')
request.headers['Content-Type'] = 'application/json' request.headers['Content-Type'] = 'application/json'
request.body = '' request.body = b''
content_type, body = resource.get_body(request) content_type, body = resource.get_body(request)
self.assertEqual('application/json', content_type) self.assertEqual('application/json', content_type)
self.assertEqual(body, '') self.assertEqual(b'', body)
def test_get_body(self): def test_get_body(self):
class Controller(object): class Controller(object):
@ -599,11 +600,11 @@ class ResourceTest(test.NoDBTestCase):
request = wsgi.Request.blank('/', method='POST') request = wsgi.Request.blank('/', method='POST')
request.headers['Content-Type'] = 'application/json' request.headers['Content-Type'] = 'application/json'
request.body = 'foo' request.body = b'foo'
content_type, body = resource.get_body(request) content_type, body = resource.get_body(request)
self.assertEqual(content_type, 'application/json') self.assertEqual(content_type, 'application/json')
self.assertEqual(body, 'foo') self.assertEqual(b'foo', body)
def test_get_request_id_with_dict_response_body(self): def test_get_request_id_with_dict_response_body(self):
class Controller(wsgi.Controller): class Controller(wsgi.Controller):
@ -614,7 +615,7 @@ class ResourceTest(test.NoDBTestCase):
app = fakes.TestRouter(Controller()) app = fakes.TestRouter(Controller())
response = req.get_response(app) response = req.get_response(app)
self.assertIn('nova.context', req.environ) self.assertIn('nova.context', req.environ)
self.assertEqual(response.body, '{"foo": "bar"}') self.assertEqual(b'{"foo": "bar"}', response.body)
self.assertEqual(response.status_int, 200) self.assertEqual(response.status_int, 200)
def test_no_request_id_with_str_response_body(self): def test_no_request_id_with_str_response_body(self):
@ -630,7 +631,7 @@ class ResourceTest(test.NoDBTestCase):
# our wsgi setup, ideally it would be there. # our wsgi setup, ideally it would be there.
expected_header = self.get_req_id_header_name(req) expected_header = self.get_req_id_header_name(req)
self.assertFalse(hasattr(response.headers, expected_header)) self.assertFalse(hasattr(response.headers, expected_header))
self.assertEqual(response.body, 'foo') self.assertEqual(b'foo', response.body)
self.assertEqual(response.status_int, 200) self.assertEqual(response.status_int, 200)
def test_get_request_id_no_response_body(self): def test_get_request_id_no_response_body(self):
@ -642,7 +643,7 @@ class ResourceTest(test.NoDBTestCase):
app = fakes.TestRouter(Controller()) app = fakes.TestRouter(Controller())
response = req.get_response(app) response = req.get_response(app)
self.assertIn('nova.context', req.environ) self.assertIn('nova.context', req.environ)
self.assertEqual(response.body, '') self.assertEqual(b'', response.body)
self.assertEqual(response.status_int, 200) self.assertEqual(response.status_int, 200)
def test_deserialize_badtype(self): def test_deserialize_badtype(self):
@ -1006,14 +1007,12 @@ class ResourceTest(test.NoDBTestCase):
req = webob.Request.blank('/tests') req = webob.Request.blank('/tests')
app = fakes.TestRouter(Controller()) app = fakes.TestRouter(Controller())
response = req.get_response(app) response = req.get_response(app)
for val in six.itervalues(response.headers):
for hdr, val in six.iteritems(response.headers):
# All headers must be utf8 # All headers must be utf8
self.assertIsInstance(hdr, str) self.assertThat(val, matchers.EncodedByUTF8())
self.assertIsInstance(val, str) self.assertEqual(b'1', response.headers['x-header1'])
self.assertEqual(response.headers['x-header1'], '1') self.assertEqual(b'header2', response.headers['x-header2'])
self.assertEqual(response.headers['x-header2'], 'header2') self.assertEqual(b'header3', response.headers['x-header3'])
self.assertEqual(response.headers['x-header3'], 'header3')
def test_resource_valid_utf8_body(self): def test_resource_valid_utf8_body(self):
class Controller(object): class Controller(object):
@ -1021,8 +1020,8 @@ class ResourceTest(test.NoDBTestCase):
return body return body
req = webob.Request.blank('/tests/test_id', method="PUT") req = webob.Request.blank('/tests/test_id', method="PUT")
body = """ {"name": "\xe6\xa6\x82\xe5\xbf\xb5" } """ body = b""" {"name": "\xe6\xa6\x82\xe5\xbf\xb5" } """
expected_body = '{"name": "\\u6982\\u5ff5"}' expected_body = b'{"name": "\\u6982\\u5ff5"}'
req.body = body req.body = body
req.headers['Content-Type'] = 'application/json' req.headers['Content-Type'] = 'application/json'
app = fakes.TestRouter(Controller()) app = fakes.TestRouter(Controller())
@ -1036,7 +1035,7 @@ class ResourceTest(test.NoDBTestCase):
return body return body
req = webob.Request.blank('/tests/test_id', method="PUT") req = webob.Request.blank('/tests/test_id', method="PUT")
body = """ {"name": "\xf0\x28\x8c\x28" } """ body = b""" {"name": "\xf0\x28\x8c\x28" } """
req.body = body req.body = body
req.headers['Content-Type'] = 'application/json' req.headers['Content-Type'] = 'application/json'
app = fakes.TestRouter(Controller()) app = fakes.TestRouter(Controller())
@ -1130,17 +1129,16 @@ class ResponseObjectTest(test.NoDBTestCase):
for content_type, mtype in wsgi._MEDIA_TYPE_MAP.items(): for content_type, mtype in wsgi._MEDIA_TYPE_MAP.items():
request = wsgi.Request.blank('/tests/123') request = wsgi.Request.blank('/tests/123')
response = robj.serialize(request, content_type) response = robj.serialize(request, content_type)
self.assertEqual(content_type.encode("utf-8"),
self.assertEqual(response.headers['Content-Type'], content_type) response.headers['Content-Type'])
for hdr, val in six.iteritems(response.headers): for hdr, val in six.iteritems(response.headers):
# All headers must be utf8 # All headers must be utf8
self.assertIsInstance(hdr, str) self.assertThat(val, matchers.EncodedByUTF8())
self.assertIsInstance(val, str) self.assertEqual(b'header1', response.headers['X-header1'])
self.assertEqual(response.headers['X-header1'], 'header1') self.assertEqual(b'header2', response.headers['X-header2'])
self.assertEqual(response.headers['X-header2'], 'header2') self.assertEqual(b'3', response.headers['X-header3'])
self.assertEqual(response.headers['X-header3'], '3')
self.assertEqual(response.status_int, 202) self.assertEqual(response.status_int, 202)
self.assertEqual(response.body, mtype) self.assertEqual(mtype.encode("utf-8"), response.body)
class ValidBodyTest(test.NoDBTestCase): class ValidBodyTest(test.NoDBTestCase):

View File

@ -21,6 +21,7 @@ import pprint
from lxml import etree from lxml import etree
import six import six
from testtools import content from testtools import content
import testtools.matchers
class DictKeysMismatch(object): class DictKeysMismatch(object):
@ -528,3 +529,23 @@ class XMLMatches(object):
actual_child_idx) actual_child_idx)
# The nodes match # The nodes match
return True return True
class EncodedByUTF8(object):
def match(self, obj):
if isinstance(obj, six.binary_type):
if hasattr(obj, "decode"):
try:
obj.decode("utf-8")
except UnicodeDecodeError:
return testtools.matchers.Mismatch(
"%s is not encoded in UTF-8." % obj)
else:
reason = ("Type of '%(obj)s' is '%(obj_type)s', "
"should be '%(correct_type)s'."
% {
"obj": obj,
"obj_type": type(obj).__name__,
"correct_type": six.binary_type.__name__
})
return testtools.matchers.Mismatch(reason)

View File

@ -1374,3 +1374,24 @@ class SpawnTestCase(SpawnNTestCase):
def setUp(self): def setUp(self):
super(SpawnTestCase, self).setUp() super(SpawnTestCase, self).setUp()
self.spawn_name = 'spawn' self.spawn_name = 'spawn'
class UT8TestCase(test.NoDBTestCase):
def test_none_value(self):
self.assertIsInstance(utils.utf8(None), type(None))
def test_bytes_value(self):
some_value = b"fake data"
return_value = utils.utf8(some_value)
# check that type of returned value doesn't changed
self.assertIsInstance(return_value, type(some_value))
self.assertEqual(some_value, return_value)
def test_not_text_type(self):
return_value = utils.utf8(1)
self.assertEqual(b"1", return_value)
self.assertIsInstance(return_value, six.binary_type)
def test_text_type_with_encoding(self):
some_value = 'test\u2026config'
self.assertEqual(some_value, utils.utf8(some_value).decode("utf-8"))

View File

@ -587,14 +587,17 @@ def xhtml_escape(value):
def utf8(value): def utf8(value):
"""Try to turn a string into utf-8 if possible. """Try to turn a string into utf-8 if possible.
Code is directly from the utf8 function in The original code was copied from the utf8 function in
http://github.com/facebook/tornado/blob/master/tornado/escape.py http://github.com/facebook/tornado/blob/master/tornado/escape.py
""" """
if isinstance(value, six.text_type): if value is None or isinstance(value, six.binary_type):
return value.encode('utf-8') return value
assert isinstance(value, str)
return value if not isinstance(value, six.text_type):
value = six.text_type(value)
return value.encode('utf-8')
def check_isinstance(obj, cls): def check_isinstance(obj, cls):

View File

@ -140,11 +140,6 @@ nova.tests.unit.api.openstack.compute.test_volumes.VolumeApiTestV21
nova.tests.unit.api.openstack.compute.test_volumes.VolumeAttachTestsV2 nova.tests.unit.api.openstack.compute.test_volumes.VolumeAttachTestsV2
nova.tests.unit.api.openstack.compute.test_volumes.VolumeAttachTestsV21 nova.tests.unit.api.openstack.compute.test_volumes.VolumeAttachTestsV21
nova.tests.unit.api.openstack.test_faults.TestFaultWrapper nova.tests.unit.api.openstack.test_faults.TestFaultWrapper
nova.tests.unit.api.openstack.test_faults.TestFaults
nova.tests.unit.api.openstack.test_wsgi.JSONDeserializerTest
nova.tests.unit.api.openstack.test_wsgi.RequestTest
nova.tests.unit.api.openstack.test_wsgi.ResourceTest
nova.tests.unit.api.openstack.test_wsgi.ResponseObjectTest
nova.tests.unit.api.test_compute_req_id.RequestIdTest nova.tests.unit.api.test_compute_req_id.RequestIdTest
nova.tests.unit.api.test_validator.ValidatorTestCase nova.tests.unit.api.test_validator.ValidatorTestCase
nova.tests.unit.api.test_wsgi.Test nova.tests.unit.api.test_wsgi.Test