py3: Add json attribute to HTTP response objects

Add a json attribute to CreatedResponse and JSONResponse of
openstack_dashboard.api.rest.utils.

This patch changes unit tests: they now compare deserialized JSON
data instead of comparing the serialized JSON data which depends on
the exact hash function

This change makes the code more readable, but it was written to port
openstack_dashboard to Python 3. On Python 3, the hash function is
now randomized by default, so dictionary items are serialized in a
random order by JSON. Moreover, the hash function is different on
Python 2 and Python 3, so setting PYTHONHASHSEED=0 in tox.ini is not
enough to have a reliable JSON serialized ouput in all cases.

Fix also NaNJSONEncoder: On Python 3, don't try to decode bytes from
the encoder encoding, since the JSON encoder has no more encoding on
Python 3: it produces an Unicode string.

Partial-Implements: blueprint porting-python3
Change-Id: I8503ee530d4122b2ce733d02023454796934c8e6
Co-Authored-By: Richard Jones <r1chardj0n3s@gmail.com>
This commit is contained in:
Victor Stinner 2015-08-28 12:23:23 +02:00
parent 8a9ee8d380
commit ee426f91d6
13 changed files with 142 additions and 124 deletions

View File

@ -15,6 +15,7 @@ import json
import json.encoder as encoder
from django.utils.translation import ugettext_lazy as _
import six
class NaNJSONEncoder(json.JSONEncoder):
@ -41,7 +42,9 @@ class NaNJSONEncoder(json.JSONEncoder):
else:
_encoder = encoder.encode_basestring
if self.encoding != 'utf-8':
# On Python 3, JSONEncoder has no more encoding attribute, it produces
# an Unicode string
if six.PY2 and self.encoding != 'utf-8':
def _encoder(o, _orig_encoder=_encoder, _encoding=self.encoding):
if isinstance(o, str):
o = o.decode(_encoding)

View File

@ -35,7 +35,17 @@ http_errors = exceptions.UNAUTHORIZED + exceptions.NOT_FOUND + \
exceptions.RECOVERABLE + (AjaxError, )
class CreatedResponse(http.HttpResponse):
class _RestResponse(http.HttpResponse):
@property
def json(self):
content_type = self['Content-Type']
if content_type != 'application/json':
raise ValueError("content type is %s" % content_type)
body = self.content.decode('utf-8')
return json.loads(body)
class CreatedResponse(_RestResponse):
def __init__(self, location, data=None):
if data is not None:
content = jsonutils.dumps(data, sort_keys=settings.DEBUG)
@ -48,7 +58,7 @@ class CreatedResponse(http.HttpResponse):
self['Location'] = location
class JSONResponse(http.HttpResponse):
class JSONResponse(_RestResponse):
def __init__(self, data, status=200, json_encoder=json.JSONEncoder):
if status == 204:
content = ''

View File

@ -40,8 +40,8 @@ class CinderRestTestCase(test.TestCase):
]
response = cinder.Volumes().get(request)
self.assertStatusCode(response, 200)
self.assertEqual(response.content,
'{"items": [{"id": "one"}, {"id": "two"}]}')
self.assertEqual(response.json,
{"items": [{"id": "one"}, {"id": "two"}]})
if all:
cc.volume_list.assert_called_once_with(request,
{'all_tenants': 1})
@ -58,8 +58,8 @@ class CinderRestTestCase(test.TestCase):
]
response = cinder.VolumeSnapshots().get(request)
self.assertStatusCode(response, 200)
self.assertEqual(response.content,
'{"items": [{"id": "one"}, {"id": "two"}]}')
self.assertEqual(response.json,
{"items": [{"id": "one"}, {"id": "two"}]})
cc.volume_snapshot_list.assert_called_once_with(request,
search_opts={})
@ -73,7 +73,7 @@ class CinderRestTestCase(test.TestCase):
]
response = cinder.VolumeSnapshots().get(request)
self.assertStatusCode(response, 200)
self.assertEqual(response.content,
'{"items": [{"id": "one"}, {"id": "two"}]}')
self.assertEqual(response.json,
{"items": [{"id": "one"}, {"id": "two"}]})
cc.volume_snapshot_list.assert_called_once_with(request,
search_opts=filters)

View File

@ -35,7 +35,7 @@ class ImagesRestTestCase(test.TestCase):
response = glance.ImageProperties().get(request, "1")
self.assertStatusCode(response, 200)
self.assertEqual(response.content, '{"a": "1", "b": "2"}')
self.assertEqual(response.json, {"a": "1", "b": "2"})
gc.image_get.assert_called_once_with(request, "1")
@mock.patch.object(glance.api, 'glance')
@ -46,7 +46,7 @@ class ImagesRestTestCase(test.TestCase):
response = glance.ImageProperties().patch(request, '1')
self.assertStatusCode(response, 204)
self.assertEqual(response.content, '')
self.assertEqual(response.content, b'')
gc.image_update_properties.assert_called_once_with(
request, '1', ['c', 'd'], a='1', b='2'
)
@ -69,9 +69,9 @@ class ImagesRestTestCase(test.TestCase):
response = glance.Images().get(request)
self.assertStatusCode(response, 200)
self.assertEqual(response.content,
'{"items": [{"name": "fedora"}, {"name": "cirros"}]'
', "has_more_data": false, "has_prev_data": false}')
self.assertEqual(response.json,
{"items": [{"name": "fedora"}, {"name": "cirros"}],
"has_more_data": False, "has_prev_data": False})
gc.image_list_detailed.assert_called_once_with(request,
filters=filters,
**kwargs)
@ -85,9 +85,9 @@ class ImagesRestTestCase(test.TestCase):
response = glance.MetadefsNamespaces().get(request)
self.assertStatusCode(response, 200)
self.assertEqual(response.content,
'{"items": [{"namespace": "1"}, {"namespace": "2"}]'
', "has_more_data": false, "has_prev_data": false}')
self.assertEqual(response.json,
{"items": [{"namespace": "1"}, {"namespace": "2"}],
"has_more_data": False, "has_prev_data": False})
gc.metadefs_namespace_full_list.assert_called_once_with(
request, filters={}
)
@ -109,9 +109,9 @@ class ImagesRestTestCase(test.TestCase):
response = glance.MetadefsNamespaces().get(request)
self.assertStatusCode(response, 200)
self.assertEqual(response.content,
'{"items": [{"namespace": "1"}, {"namespace": "2"}]'
', "has_more_data": false, "has_prev_data": false}')
self.assertEqual(response.json,
{"items": [{"namespace": "1"}, {"namespace": "2"}],
"has_more_data": False, "has_prev_data": False})
gc.metadefs_namespace_full_list.assert_called_once_with(
request, filters=filters, **kwargs
)

View File

@ -24,6 +24,6 @@ class ValidateRestTestCase(test.TestCase):
hc.template_validate.return_value = ({'Description': 'foo'})
response = heat.Validate().post(request)
self.assertStatusCode(response, 200)
self.assertEqual(response.content, '{"Description": "foo"}')
self.assertEqual(response.json, {"Description": "foo"})
kwargs = json.loads(body)
hc.template_validate.assert_called_once_with(request, **kwargs)

View File

@ -11,11 +11,11 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import mock
from django.conf import settings
import mock
from oslo_serialization import jsonutils
import six
from openstack_dashboard.api.rest import keystone
from openstack_dashboard.test import helpers as test
@ -31,7 +31,7 @@ class KeystoneRestTestCase(test.TestCase):
kc.get_version.return_value = '2.0'
response = keystone.Version().get(request)
self.assertStatusCode(response, 200)
self.assertEqual(response.content, '{"version": "2.0"}')
self.assertEqual(response.json, {"version": "2.0"})
kc.get_version.assert_called_once_with()
#
@ -43,7 +43,7 @@ class KeystoneRestTestCase(test.TestCase):
kc.user_get.return_value.to_dict.return_value = {'name': 'Ni!'}
response = keystone.User().get(request, 'the_id')
self.assertStatusCode(response, 200)
self.assertEqual(response.content, '{"name": "Ni!"}')
self.assertEqual(response.json, {"name": "Ni!"})
kc.user_get.assert_called_once_with(request, 'the_id')
@mock.patch.object(keystone.api, 'keystone')
@ -52,7 +52,7 @@ class KeystoneRestTestCase(test.TestCase):
kc.user_get.return_value.to_dict.return_value = {'name': 'Ni!'}
response = keystone.User().get(request, 'current')
self.assertStatusCode(response, 200)
self.assertEqual(response.content, '{"name": "Ni!"}')
self.assertEqual(response.json, {"name": "Ni!"})
kc.user_get.assert_called_once_with(request, 'current_id')
@mock.patch.object(keystone.api, 'keystone')
@ -67,8 +67,8 @@ class KeystoneRestTestCase(test.TestCase):
]
response = keystone.Users().get(request)
self.assertStatusCode(response, 200)
self.assertEqual(response.content,
'{"items": [{"name": "Ni!"}, {"name": "Ptang!"}]}')
self.assertEqual(response.json,
{"items": [{"name": "Ni!"}, {"name": "Ptang!"}]})
kc.user_list.assert_called_once_with(request, project=None,
domain='the_domain', group=None,
filters=None)
@ -86,8 +86,8 @@ class KeystoneRestTestCase(test.TestCase):
]
response = keystone.Users().get(request)
self.assertStatusCode(response, 200)
self.assertEqual(response.content,
'{"items": [{"name": "Ni!"}, {"name": "Ptang!"}]}')
self.assertEqual(response.json,
{"items": [{"name": "Ni!"}, {"name": "Ptang!"}]})
kc.user_list.assert_called_once_with(request, project=None,
domain='the_domain', group=None,
filters=filters)
@ -149,8 +149,8 @@ class KeystoneRestTestCase(test.TestCase):
self.assertStatusCode(response, 201)
self.assertEqual(response['location'],
'/api/keystone/users/user123')
self.assertEqual(response.content, '{"id": "user123", '
'"name": "bob"}')
self.assertEqual(response.json,
{"id": "user123", "name": "bob"})
kc.user_create.assert_called_once_with(request, **add_user_call)
@mock.patch.object(keystone.api, 'keystone')
@ -161,7 +161,7 @@ class KeystoneRestTestCase(test.TestCase):
response = keystone.Users().delete(request)
self.assertStatusCode(response, 204)
self.assertEqual(response.content, '')
self.assertEqual(response.content, b'')
kc.user_delete.assert_has_calls([
mock.call(request, 'id1'),
mock.call(request, 'id2'),
@ -173,7 +173,7 @@ class KeystoneRestTestCase(test.TestCase):
request = self.mock_rest_request()
response = keystone.User().delete(request, 'the_id')
self.assertStatusCode(response, 204)
self.assertEqual(response.content, '')
self.assertEqual(response.content, b'')
kc.user_delete.assert_called_once_with(request, 'the_id')
@mock.patch.object(keystone.api, 'keystone')
@ -185,7 +185,7 @@ class KeystoneRestTestCase(test.TestCase):
kc.user_get = mock.MagicMock(return_value=user)
response = user.patch(request, 'user123')
self.assertStatusCode(response, 204)
self.assertEqual(response.content, '')
self.assertEqual(response.content, b'')
kc.user_update_password.assert_called_once_with(request,
user,
'sekrit')
@ -199,7 +199,7 @@ class KeystoneRestTestCase(test.TestCase):
kc.user_get = mock.MagicMock(return_value=user)
response = user.patch(request, 'user123')
self.assertStatusCode(response, 204)
self.assertEqual(response.content, '')
self.assertEqual(response.content, b'')
kc.user_get.assert_called_once_with(request, 'user123')
kc.user_update_enabled.assert_called_once_with(request,
user,
@ -214,7 +214,7 @@ class KeystoneRestTestCase(test.TestCase):
kc.user_get = mock.MagicMock(return_value=user)
response = user.patch(request, 'user123')
self.assertStatusCode(response, 204)
self.assertEqual(response.content, '')
self.assertEqual(response.content, b'')
kc.user_update.assert_called_once_with(request,
user,
project='other123')
@ -228,7 +228,7 @@ class KeystoneRestTestCase(test.TestCase):
kc.user_get = mock.MagicMock(return_value=user)
response = user.patch(request, 'user123')
self.assertStatusCode(response, 204)
self.assertEqual(response.content, '')
self.assertEqual(response.content, b'')
kc.user_update.assert_called_once_with(request,
user,
project='other123',
@ -243,7 +243,7 @@ class KeystoneRestTestCase(test.TestCase):
kc.role_get.return_value.to_dict.return_value = {'name': 'Ni!'}
response = keystone.Role().get(request, 'the_id')
self.assertStatusCode(response, 200)
self.assertEqual(response.content, '{"name": "Ni!"}')
self.assertEqual(response.json, {"name": "Ni!"})
kc.role_get.assert_called_once_with(request, 'the_id')
@mock.patch.object(keystone.api, 'keystone')
@ -252,7 +252,7 @@ class KeystoneRestTestCase(test.TestCase):
kc.get_default_role.return_value.to_dict.return_value = {'name': 'Ni!'}
response = keystone.Role().get(request, 'default')
self.assertStatusCode(response, 200)
self.assertEqual(response.content, '{"name": "Ni!"}')
self.assertEqual(response.json, {"name": "Ni!"})
kc.get_default_role.assert_called_once_with(request)
kc.role_get.assert_not_called()
@ -265,8 +265,8 @@ class KeystoneRestTestCase(test.TestCase):
]
response = keystone.Roles().get(request)
self.assertStatusCode(response, 200)
self.assertEqual(response.content,
'{"items": [{"name": "Ni!"}, {"name": "Ptang!"}]}')
self.assertEqual(response.json,
{"items": [{"name": "Ni!"}, {"name": "Ptang!"}]})
kc.role_list.assert_called_once_with(request)
@mock.patch.object(keystone.api, 'keystone')
@ -279,8 +279,8 @@ class KeystoneRestTestCase(test.TestCase):
]
response = keystone.Roles().get(request)
self.assertStatusCode(response, 200)
self.assertEqual(response.content,
'{"items": [{"name": "Ni!"}, {"name": "Ptang!"}]}')
self.assertEqual(response.json,
{"items": [{"name": "Ni!"}, {"name": "Ptang!"}]})
kc.roles_for_user.assert_called_once_with(request, 'user123',
'project123')
@ -298,7 +298,7 @@ class KeystoneRestTestCase(test.TestCase):
self.assertStatusCode(response, 201)
self.assertEqual(response['location'],
'/api/keystone/roles/role123')
self.assertEqual(response.content, '{"id": "role123", "name": "bob"}')
self.assertEqual(response.json, {"id": "role123", "name": "bob"})
kc.role_create.assert_called_once_with(request, 'bob')
@mock.patch.object(keystone.api, 'keystone')
@ -310,7 +310,7 @@ class KeystoneRestTestCase(test.TestCase):
response = keystone.ProjectRole().put(request, "project1", "role2",
"user3")
self.assertStatusCode(response, 204)
self.assertEqual(response.content, '')
self.assertEqual(response.content, b'')
kc.add_tenant_user_role.assert_called_once_with(request, 'project1',
'user3', 'role2')
@ -322,7 +322,7 @@ class KeystoneRestTestCase(test.TestCase):
response = keystone.Roles().delete(request)
self.assertStatusCode(response, 204)
self.assertEqual(response.content, '')
self.assertEqual(response.content, b'')
kc.role_delete.assert_has_calls([
mock.call(request, 'id1'),
mock.call(request, 'id2'),
@ -334,7 +334,7 @@ class KeystoneRestTestCase(test.TestCase):
request = self.mock_rest_request()
response = keystone.Role().delete(request, 'the_id')
self.assertStatusCode(response, 204)
self.assertEqual(response.content, '')
self.assertEqual(response.content, b'')
kc.role_delete.assert_called_once_with(request, 'the_id')
@mock.patch.object(keystone.api, 'keystone')
@ -342,7 +342,7 @@ class KeystoneRestTestCase(test.TestCase):
request = self.mock_rest_request(body='{"name": "spam"}')
response = keystone.Role().patch(request, 'the_id')
self.assertStatusCode(response, 204)
self.assertEqual(response.content, '')
self.assertEqual(response.content, b'')
kc.role_update.assert_called_once_with(request,
'the_id',
'spam')
@ -356,7 +356,7 @@ class KeystoneRestTestCase(test.TestCase):
kc.domain_get.return_value.to_dict.return_value = {'name': 'Ni!'}
response = keystone.Domain().get(request, 'the_id')
self.assertStatusCode(response, 200)
self.assertEqual(response.content, '{"name": "Ni!"}')
self.assertEqual(response.json, {"name": "Ni!"})
kc.domain_get.assert_called_once_with(request, 'the_id')
@mock.patch.object(keystone.api, 'keystone')
@ -367,7 +367,7 @@ class KeystoneRestTestCase(test.TestCase):
}
response = keystone.Domain().get(request, 'default')
self.assertStatusCode(response, 200)
self.assertEqual(response.content, '{"name": "Ni!"}')
self.assertEqual(response.json, {"name": "Ni!"})
kc.get_default_domain.assert_called_once_with(request)
kc.domain_get.assert_not_called()
@ -380,8 +380,8 @@ class KeystoneRestTestCase(test.TestCase):
]
response = keystone.Domains().get(request)
self.assertStatusCode(response, 200)
self.assertEqual(response.content,
'{"items": [{"name": "Ni!"}, {"name": "Ptang!"}]}')
self.assertEqual(response.json,
{"items": [{"name": "Ni!"}, {"name": "Ptang!"}]})
kc.domain_list.assert_called_once_with(request)
def test_domain_create_full(self):
@ -415,8 +415,7 @@ class KeystoneRestTestCase(test.TestCase):
self.assertStatusCode(response, 201)
self.assertEqual(response['location'],
'/api/keystone/domains/domain123')
self.assertEqual(response.content, '{"id": "domain123", '
'"name": "bob"}')
self.assertEqual(response.json, {"id": "domain123", "name": "bob"})
kc.domain_create.assert_called_once_with(request, 'bob',
**expected_call)
@ -428,7 +427,7 @@ class KeystoneRestTestCase(test.TestCase):
response = keystone.Domains().delete(request)
self.assertStatusCode(response, 204)
self.assertEqual(response.content, '')
self.assertEqual(response.content, b'')
kc.domain_delete.assert_has_calls([
mock.call(request, 'id1'),
mock.call(request, 'id2'),
@ -440,7 +439,7 @@ class KeystoneRestTestCase(test.TestCase):
request = self.mock_rest_request()
response = keystone.Domain().delete(request, 'the_id')
self.assertStatusCode(response, 204)
self.assertEqual(response.content, '')
self.assertEqual(response.content, b'')
kc.domain_delete.assert_called_once_with(request, 'the_id')
@mock.patch.object(keystone.api, 'keystone')
@ -448,7 +447,7 @@ class KeystoneRestTestCase(test.TestCase):
request = self.mock_rest_request(body='{"name": "spam"}')
response = keystone.Domain().patch(request, 'the_id')
self.assertStatusCode(response, 204)
self.assertEqual(response.content, '')
self.assertEqual(response.content, b'')
kc.domain_update.assert_called_once_with(request,
'the_id',
name='spam',
@ -464,7 +463,7 @@ class KeystoneRestTestCase(test.TestCase):
kc.tenant_get.return_value.to_dict.return_value = {'name': 'Ni!'}
response = keystone.Project().get(request, 'the_id')
self.assertStatusCode(response, 200)
self.assertEqual(response.content, '{"name": "Ni!"}')
self.assertEqual(response.json, {"name": "Ni!"})
kc.tenant_get.assert_called_once_with(request, 'the_id')
def test_project_get_list(self):
@ -522,8 +521,9 @@ class KeystoneRestTestCase(test.TestCase):
with mock.patch.object(settings, 'DEBUG', True):
response = keystone.Projects().get(request)
self.assertStatusCode(response, 200)
self.assertEqual(response.content, '{"has_more": false, '
'"items": [{"name": "Ni!"}, {"name": "Ptang!"}]}')
self.assertEqual(response.json,
{"has_more": False,
"items": [{"name": "Ni!"}, {"name": "Ptang!"}]})
kc.tenant_list.assert_called_once_with(request, **expected_call)
@mock.patch.object(keystone.api, 'keystone')
@ -537,8 +537,9 @@ class KeystoneRestTestCase(test.TestCase):
with mock.patch.object(settings, 'DEBUG', True):
response = keystone.Projects().get(request)
self.assertStatusCode(response, 200)
self.assertEqual(response.content, '{"has_more": false, '
'"items": [{"name": "Ni!"}, {"name": "Ni!"}]}')
self.assertEqual(response.json,
{"has_more": False,
"items": [{"name": "Ni!"}, {"name": "Ni!"}]})
kc.tenant_list.assert_called_once_with(request, paginate=False,
marker=None, domain=None,
user=None, admin=True,
@ -578,8 +579,8 @@ class KeystoneRestTestCase(test.TestCase):
self.assertStatusCode(response, 201)
self.assertEqual(response['location'],
'/api/keystone/projects/project123')
self.assertEqual(response.content, '{"id": "project123", '
'"name": "bob"}')
self.assertEqual(response.json,
{"id": "project123", "name": "bob"})
kc.tenant_create.assert_called_once_with(request, 'bob',
**expected_call)
@ -591,7 +592,7 @@ class KeystoneRestTestCase(test.TestCase):
response = keystone.Projects().delete(request)
self.assertStatusCode(response, 204)
self.assertEqual(response.content, '')
self.assertEqual(response.content, b'')
kc.tenant_delete.assert_has_calls([
mock.call(request, 'id1'),
mock.call(request, 'id2'),
@ -603,7 +604,7 @@ class KeystoneRestTestCase(test.TestCase):
request = self.mock_rest_request()
response = keystone.Project().delete(request, 'the_id')
self.assertStatusCode(response, 204)
self.assertEqual(response.content, '')
self.assertEqual(response.content, b'')
kc.tenant_delete.assert_called_once_with(request, 'the_id')
@mock.patch.object(keystone.api, 'keystone')
@ -615,7 +616,7 @@ class KeystoneRestTestCase(test.TestCase):
''')
response = keystone.Project().patch(request, 'spam123')
self.assertStatusCode(response, 204)
self.assertEqual(response.content, '')
self.assertEqual(response.content, b'')
kc.tenant_update.assert_called_once_with(request,
'spam123',
name='spam', foo='bar',
@ -633,6 +634,8 @@ class KeystoneRestTestCase(test.TestCase):
self.assertStatusCode(response, 200)
content = jsonutils.dumps(request.user.service_catalog,
sort_keys=settings.DEBUG)
if six.PY3:
content = content.encode('utf-8')
self.assertEqual(content, response.content)
#

View File

@ -28,6 +28,6 @@ class RestNetworkApiSecurityGroupTests(test.TestCase):
response = network.SecurityGroups().get(request)
self.assertStatusCode(response, 200)
self.assertEqual(response.content,
'{"items": [{"name": "default"}]}')
self.assertEqual(response.json,
{"items": [{"name": "default"}]})
client.security_group_list.assert_called_once_with(request)

View File

@ -12,16 +12,14 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import mock
from openstack_dashboard.api.rest import neutron
from openstack_dashboard.test import helpers as test
from openstack_dashboard.test.test_data import neutron_data
from openstack_dashboard.test.test_data.utils import TestData # noqa
from openstack_dashboard.test import helpers as test
TEST = TestData(neutron_data.data)
@ -66,8 +64,7 @@ class NeutronNetworksTestCase(test.TestCase):
self.assertEqual(response['location'],
'/api/neutron/networks/'
+ str(TEST.api_networks.first().get("id")))
self.assertEqual(response.content,
json.dumps(TEST.api_networks.first()))
self.assertEqual(response.json, TEST.api_networks.first())
class NeutronSubnetsTestCase(test.TestCase):
@ -100,8 +97,7 @@ class NeutronSubnetsTestCase(test.TestCase):
self.assertEqual(response['location'],
'/api/neutron/subnets/' +
str(TEST.api_subnets.first().get("id")))
self.assertEqual(response.content,
json.dumps(TEST.api_subnets.first()))
self.assertEqual(response.json, TEST.api_subnets.first())
class NeutronPortsTestCase(test.TestCase):

View File

@ -32,8 +32,8 @@ class NovaRestTestCase(test.TestCase):
]
response = nova.Keypairs().get(request)
self.assertStatusCode(response, 200)
self.assertEqual(response.content,
'{"items": [{"id": "one"}, {"id": "two"}]}')
self.assertEqual(response.json,
{"items": [{"id": "one"}, {"id": "two"}]})
nc.keypair_list.assert_called_once_with(request)
@mock.patch.object(nova.api, 'nova')
@ -45,8 +45,8 @@ class NovaRestTestCase(test.TestCase):
with mock.patch.object(settings, 'DEBUG', True):
response = nova.Keypairs().post(request)
self.assertStatusCode(response, 201)
self.assertEqual(response.content,
'{"name": "Ni!", "public_key": "sekrit"}')
self.assertEqual(response.json,
{"name": "Ni!", "public_key": "sekrit"})
self.assertEqual(response['location'], '/api/nova/keypairs/Ni%21')
nc.keypair_create.assert_called_once_with(request, 'Ni!')
@ -61,8 +61,8 @@ class NovaRestTestCase(test.TestCase):
with mock.patch.object(settings, 'DEBUG', True):
response = nova.Keypairs().post(request)
self.assertStatusCode(response, 201)
self.assertEqual(response.content,
'{"name": "Ni!", "public_key": "hi"}')
self.assertEqual(response.json,
{"name": "Ni!", "public_key": "hi"})
self.assertEqual(response['location'], '/api/nova/keypairs/Ni%21')
nc.keypair_import.assert_called_once_with(request, 'Ni!', 'hi')
@ -87,8 +87,8 @@ class NovaRestTestCase(test.TestCase):
]
response = nova.AvailabilityZones().get(request)
self.assertStatusCode(response, 200)
self.assertEqual(response.content,
'{"items": [{"id": "one"}, {"id": "two"}]}')
self.assertEqual(response.json,
{"items": [{"id": "one"}, {"id": "two"}]})
nc.availability_zone_list.assert_called_once_with(request, detail)
#
@ -110,7 +110,7 @@ class NovaRestTestCase(test.TestCase):
response = nova.Limits().get(request)
self.assertStatusCode(response, 200)
nc.tenant_absolute_limits.assert_called_once_with(request, reserved)
self.assertEqual(response.content, '{"id": "one"}')
self.assertEqual(response.json, {"id": "one"})
#
# Servers
@ -120,8 +120,8 @@ class NovaRestTestCase(test.TestCase):
request = self.mock_rest_request(body='''{"name": "hi"}''')
response = nova.Servers().post(request)
self.assertStatusCode(response, 400)
self.assertEqual(response.content,
'"missing required parameter \'source_id\'"')
self.assertEqual(response.json,
"missing required parameter 'source_id'")
nc.server_create.assert_not_called()
@mock.patch.object(nova.api, 'nova')
@ -136,7 +136,7 @@ class NovaRestTestCase(test.TestCase):
new.id = 'server123'
response = nova.Servers().post(request)
self.assertStatusCode(response, 201)
self.assertEqual(response.content, '{"id": "server123"}')
self.assertEqual(response.json, {"id": "server123"})
self.assertEqual(response['location'], '/api/nova/servers/server123')
nc.server_create.assert_called_once_with(
request, 'Ni!', 'image123', 'flavor123', 'sekrit', 'base64 yes',
@ -167,8 +167,8 @@ class NovaRestTestCase(test.TestCase):
]
response = nova.Extensions().get(request)
self.assertStatusCode(response, 200)
self.assertEqual(response.content,
'{"items": [{"name": "foo"}, {"name": "bar"}]}')
self.assertEqual(response.json,
{"items": [{"name": "foo"}, {"name": "bar"}]})
nc.list_extensions.assert_called_once_with(request)
#
@ -197,9 +197,9 @@ class NovaRestTestCase(test.TestCase):
response = nova.Flavor().get(request, "1")
self.assertStatusCode(response, 200)
if get_extras:
self.assertEqual(response.content, '{"extras": {}, "name": "1"}')
self.assertEqual(response.json, {"extras": {}, "name": "1"})
else:
self.assertEqual(response.content, '{"name": "1"}')
self.assertEqual(response.json, {"name": "1"})
nc.flavor_get.assert_called_once_with(request, "1",
get_extras=get_extras)
@ -217,8 +217,8 @@ class NovaRestTestCase(test.TestCase):
]
response = nova.Flavors().get(request)
self.assertStatusCode(response, 200)
self.assertEqual(response.content,
'{"items": [{"id": "1"}, {"id": "2"}]}')
self.assertEqual(response.json,
{"items": [{"id": "1"}, {"id": "2"}]})
nc.flavor_list.assert_called_once_with(request, is_public=is_public,
get_extras=False)
@ -247,12 +247,12 @@ class NovaRestTestCase(test.TestCase):
response = nova.Flavors().get(request)
self.assertStatusCode(response, 200)
if get_extras:
self.assertEqual(response.content,
'{"items": [{"extras": {}, "id": "1"}, '
'{"extras": {}, "id": "2"}]}')
self.assertEqual(response.json,
{"items": [{"extras": {}, "id": "1"},
{"extras": {}, "id": "2"}]})
else:
self.assertEqual(response.content,
'{"items": [{"id": "1"}, {"id": "2"}]}')
self.assertEqual(response.json,
{"items": [{"id": "1"}, {"id": "2"}]})
nc.flavor_list.assert_called_once_with(request, is_public=None,
get_extras=get_extras)
@ -282,7 +282,7 @@ class NovaRestTestCase(test.TestCase):
response = nova.FlavorExtraSpecs().patch(request, '1')
self.assertStatusCode(response, 204)
self.assertEqual(response.content, '')
self.assertEqual(response.content, b'')
nc.flavor_extra_set.assert_called_once_with(
request, '1', {'a': '1', 'b': '2'}
)
@ -297,7 +297,7 @@ class NovaRestTestCase(test.TestCase):
response = nova.AggregateExtraSpecs().get(request, "1")
self.assertStatusCode(response, 200)
self.assertEqual(response.content, '{"a": "1", "b": "2"}')
self.assertEqual(response.json, {"a": "1", "b": "2"})
nc.aggregate_get.assert_called_once_with(request, "1")
@mock.patch.object(nova.api, 'nova')
@ -308,7 +308,7 @@ class NovaRestTestCase(test.TestCase):
response = nova.AggregateExtraSpecs().patch(request, '1')
self.assertStatusCode(response, 204)
self.assertEqual(response.content, '')
self.assertEqual(response.content, b'')
nc.aggregate_set_metadata.assert_called_once_with(
request, '1', {'a': '1', 'b': '2', 'c': None, 'd': None}
)

View File

@ -23,7 +23,7 @@ class PolicyRestTestCase(test.TestCase):
request = self.mock_rest_request(body=body)
response = policy.Policy().post(request)
self.assertStatusCode(response, 200)
self.assertEqual(response.content, '{"allowed": true}')
self.assertEqual(response.json, {"allowed": True})
@override_settings(POLICY_CHECK_FUNCTION=policy_backend.check)
def test_rule_alone(self):
@ -57,7 +57,7 @@ class PolicyRestTestCase(test.TestCase):
body='''{"rules": [["compute", "compute:unlock_override"]]}''')
response = policy.Policy().post(request)
self.assertStatusCode(response, 200)
self.assertEqual(response.content, '{"allowed": false}')
self.assertEqual(response.json, {"allowed": False})
@override_settings(POLICY_CHECK_FUNCTION=policy_backend.check)
def test_policy_error(self):
@ -75,4 +75,4 @@ class AdminPolicyRestTestCase(test.BaseAdminViewTests):
request = self.mock_rest_request(body=body)
response = policy.Policy().post(request)
self.assertStatusCode(response, 200)
self.assertEqual(response.content, '{"allowed": true}')
self.assertEqual(response.json, {"allowed": True})

View File

@ -25,7 +25,7 @@ class RestUtilsTestCase(test.TestCase):
response = f(None, request)
request.user.is_authenticated.assert_called_once_with()
self.assertStatusCode(response, 200)
self.assertEqual(response.content, '"ok"')
self.assertEqual(response.json, "ok")
def test_api_success_no_auth_ok(self):
@utils.ajax(authenticated=False)
@ -35,7 +35,7 @@ class RestUtilsTestCase(test.TestCase):
response = f(None, request)
request.user.is_authenticated.assert_not_called()
self.assertStatusCode(response, 200)
self.assertEqual(response.content, '"ok"')
self.assertEqual(response.json, "ok")
def test_api_auth_required(self):
@utils.ajax()
@ -47,7 +47,7 @@ class RestUtilsTestCase(test.TestCase):
response = f(None, request)
request.user.is_authenticated.assert_called_once_with()
self.assertStatusCode(response, 401)
self.assertEqual(response.content, '"not logged in"')
self.assertEqual(response.json, "not logged in")
def test_api_success_204(self):
@utils.ajax()
@ -56,7 +56,7 @@ class RestUtilsTestCase(test.TestCase):
request = self.mock_rest_request()
response = f(None, request)
self.assertStatusCode(response, 204)
self.assertEqual(response.content, '')
self.assertEqual(response.content, b'')
def test_api_error(self):
@utils.ajax()
@ -65,7 +65,7 @@ class RestUtilsTestCase(test.TestCase):
request = self.mock_rest_request()
response = f(None, request)
self.assertStatusCode(response, 500)
self.assertEqual(response.content, '"b0rk"')
self.assertEqual(response.json, "b0rk")
def test_api_malformed_json(self):
@utils.ajax()
@ -74,8 +74,7 @@ class RestUtilsTestCase(test.TestCase):
request = self.mock_rest_request(**{'body': 'spam'})
response = f(None, request)
self.assertStatusCode(response, 400)
self.assertEqual(response.content, '"malformed JSON request: No JSON '
'object could be decoded"')
self.assertIn(b'"malformed JSON request: ', response.content)
def test_api_not_found(self):
@utils.ajax()
@ -84,7 +83,7 @@ class RestUtilsTestCase(test.TestCase):
request = self.mock_rest_request()
response = f(None, request)
self.assertStatusCode(response, 404)
self.assertEqual(response.content, '"b0rk"')
self.assertEqual(response.json, "b0rk")
def test_data_required_with_no_data(self):
@utils.ajax(data_required=True)
@ -93,7 +92,7 @@ class RestUtilsTestCase(test.TestCase):
request = self.mock_rest_request()
response = f(None, request)
self.assertStatusCode(response, 400)
self.assertEqual(response.content, '"request requires JSON body"')
self.assertEqual(response.json, "request requires JSON body")
def test_valid_data_required(self):
@utils.ajax(data_required=True)
@ -104,7 +103,7 @@ class RestUtilsTestCase(test.TestCase):
'''})
response = f(None, request)
self.assertStatusCode(response, 200)
self.assertEqual(response.content, '"OK"')
self.assertEqual(response.json, "OK")
def test_api_created_response(self):
@utils.ajax()
@ -115,7 +114,7 @@ class RestUtilsTestCase(test.TestCase):
request.user.is_authenticated.assert_called_once_with()
self.assertStatusCode(response, 201)
self.assertEqual(response['location'], '/api/spam/spam123')
self.assertEqual(response.content, '')
self.assertEqual(response.content, b'')
def test_api_created_response_content(self):
@utils.ajax()
@ -126,7 +125,7 @@ class RestUtilsTestCase(test.TestCase):
request.user.is_authenticated.assert_called_once_with()
self.assertStatusCode(response, 201)
self.assertEqual(response['location'], '/api/spam/spam123')
self.assertEqual(response.content, '"spam!"')
self.assertEqual(response.json, "spam!")
def test_parse_filters_keywords(self):
kwargs = {
@ -189,7 +188,7 @@ class JSONEncoderTestCase(test.TestCase):
request.user.is_authenticated.assert_called_once_with()
self.assertStatusCode(response, 200)
self.assertEqual(response['content-type'], 'application/json')
self.assertEqual(response.content, 'NaN')
self.assertEqual(response.content, b'NaN')
def test_custom_encoder_on_infinity(self):
@utils.ajax(json_encoder=json_encoder.NaNJSONEncoder)
@ -201,7 +200,7 @@ class JSONEncoderTestCase(test.TestCase):
request.user.is_authenticated.assert_called_once_with()
self.assertStatusCode(response, 200)
self.assertEqual(response['content-type'], 'application/json')
self.assertEqual(response.content, '1e+999')
self.assertEqual(response.content, b'1e+999')
def test_custom_encoder_on_negative_infinity(self):
@utils.ajax(json_encoder=json_encoder.NaNJSONEncoder)
@ -213,7 +212,7 @@ class JSONEncoderTestCase(test.TestCase):
request.user.is_authenticated.assert_called_once_with()
self.assertStatusCode(response, 200)
self.assertEqual(response['content-type'], 'application/json')
self.assertEqual(response.content, '-1e+999')
self.assertEqual(response.content, b'-1e+999')
def test_custom_encoder_yields_standard_json_for_conventional_data(self):
@utils.ajax()

View File

@ -19,7 +19,6 @@
import collections
import copy
from functools import wraps # noqa
import json
import os
@ -279,8 +278,7 @@ class TestCase(horizon_helpers.TestCase):
response.content))
def assertItemsCollectionEqual(self, response, items_list):
self.assertEqual(response.content,
'{"items": ' + json.dumps(items_list) + "}")
self.assertEqual(response.json, {"items": items_list})
@staticmethod
def mock_rest_request(**args):

View File

@ -47,15 +47,24 @@ commands =
openstack_dashboard.test.api_tests.base_tests.ApiVersionTests \
openstack_dashboard.test.api_tests.base_tests.QuotaSetTests \
openstack_dashboard.test.api_tests.ceilometer_tests \
openstack_dashboard.test.api_tests.cinder_rest_tests \
openstack_dashboard.test.api_tests.cinder_tests \
openstack_dashboard.test.api_tests.config_rest_tests \
openstack_dashboard.test.api_tests.fwaas_tests \
openstack_dashboard.test.api_tests.glance_rest_tests \
openstack_dashboard.test.api_tests.glance_tests \
openstack_dashboard.test.api_tests.heat_rest_tests \
openstack_dashboard.test.api_tests.heat_tests \
openstack_dashboard.test.api_tests.keystone_rest_tests \
openstack_dashboard.test.api_tests.keystone_tests \
openstack_dashboard.test.api_tests.lbaas_tests \
openstack_dashboard.test.api_tests.network_rest_tests \
openstack_dashboard.test.api_tests.neutron_rest_tests \
openstack_dashboard.test.api_tests.neutron_rest_tests.NeutronPortsTestCase \
openstack_dashboard.test.api_tests.nova_rest_tests \
openstack_dashboard.test.api_tests.nova_tests \
openstack_dashboard.test.api_tests.policy_rest_tests \
openstack_dashboard.test.api_tests.rest_util_tests \
openstack_dashboard.test.test_plugins.panel_group_tests.PanelGroupPluginTests \
openstack_dashboard.test.test_plugins.panel_tests.PanelPluginTests \
openstack_dashboard.test.tests.error_pages \