Use wsgi.response for v2.1 API

Now a decorator @wsgi.response() can be used for specifying success
status code. Most v2.1 APIs use the decorator and it makes the code
more readable. This patch replaces webob.Response with the decorator
for the other APIs.
In addition, this patch changes some orders of decorators for showing
success code and expected error codes clearly.

Even if applying this patch, some webob.Response() calls still exist
under the path nova/api/openstack/compute/plugins/v3/ because these
cases need to contain some information in a response header.

Partially implements blueprint v2-on-v3-api

Change-Id: I419819b8e55427979e8d82b972cd237952a5b06b
This commit is contained in:
Ken'ichi Ohmichi 2014-10-21 02:44:13 +00:00
parent 8d8aee74b1
commit e73cb83f9e
24 changed files with 118 additions and 81 deletions

View File

@ -12,7 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import webob
from webob import exc
from nova.api.openstack import common
@ -42,6 +41,7 @@ class AdminActionsController(wsgi.Controller):
super(AdminActionsController, self).__init__(*args, **kwargs)
self.compute_api = compute.API()
@wsgi.response(202)
@extensions.expected_errors((404, 409))
@wsgi.action('resetNetwork')
def _reset_network(self, req, id, body):
@ -54,8 +54,8 @@ class AdminActionsController(wsgi.Controller):
self.compute_api.reset_network(context, instance)
except exception.InstanceIsLocked as e:
raise exc.HTTPConflict(explanation=e.format_message())
return webob.Response(status_int=202)
@wsgi.response(202)
@extensions.expected_errors((404, 409))
@wsgi.action('injectNetworkInfo')
def _inject_network_info(self, req, id, body):
@ -68,8 +68,8 @@ class AdminActionsController(wsgi.Controller):
self.compute_api.inject_network_info(context, instance)
except exception.InstanceIsLocked as e:
raise exc.HTTPConflict(explanation=e.format_message())
return webob.Response(status_int=202)
@wsgi.response(202)
@extensions.expected_errors((400, 404))
@wsgi.action('os-resetState')
@validation.schema(reset_server_state.reset_state)
@ -86,7 +86,6 @@ class AdminActionsController(wsgi.Controller):
instance.vm_state = state
instance.task_state = None
instance.save(admin_state_reset=True)
return webob.Response(status_int=202)
class AdminActions(extensions.V3APIExtensionBase):

View File

@ -21,6 +21,7 @@ from webob import exc
from nova.api.openstack import common
from nova.api.openstack.compute.schemas.v3 import attach_interfaces
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api import validation
from nova import compute
from nova import exception
@ -137,6 +138,7 @@ class InterfaceAttachmentController(object):
return self.show(req, server_id, vif['id'])
@wsgi.response(202)
@extensions.expected_errors((404, 409, 501))
def delete(self, req, server_id, id):
"""Detach an interface from an instance."""
@ -160,8 +162,6 @@ class InterfaceAttachmentController(object):
common.raise_http_conflict_for_instance_invalid_state(state_error,
'detach_interface', server_id)
return webob.Response(status_int=202)
def _items(self, req, server_id, entity_maker):
"""Returns a list of attachments, transformed through entity_maker."""
context = req.environ['nova.context']

View File

@ -13,7 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import webob
from webob import exc
from nova.api.openstack import extensions
@ -81,6 +80,7 @@ class ConsolesController(object):
raise exc.HTTPNotFound(explanation=e.format_message())
return _translate_detail_keys(console)
@wsgi.response(202)
@extensions.expected_errors(404)
def delete(self, req, server_id, id):
"""Deletes a console."""
@ -90,7 +90,6 @@ class ConsolesController(object):
int(id))
except exception.ConsoleNotFound as e:
raise exc.HTTPNotFound(explanation=e.format_message())
return webob.Response(status_int=202)
class Consoles(extensions.V3APIExtensionBase):

View File

@ -33,6 +33,7 @@ class DeferredDeleteController(wsgi.Controller):
super(DeferredDeleteController, self).__init__(*args, **kwargs)
self.compute_api = compute.API()
@wsgi.response(202)
@extensions.expected_errors((404, 409, 403))
@wsgi.action('restore')
def _restore(self, req, id, body):
@ -48,8 +49,8 @@ class DeferredDeleteController(wsgi.Controller):
except exception.InstanceInvalidState as state_error:
common.raise_http_conflict_for_instance_invalid_state(state_error,
'restore', id)
return webob.Response(status_int=202)
@wsgi.response(202)
@extensions.expected_errors((404, 409))
@wsgi.action('forceDelete')
def _force_delete(self, req, id, body):
@ -62,7 +63,6 @@ class DeferredDeleteController(wsgi.Controller):
self.compute_api.force_delete(context, instance)
except exception.InstanceIsLocked as e:
raise webob.exc.HTTPConflict(explanation=e.format_message())
return webob.Response(status_int=202)
class DeferredDelete(extensions.V3APIExtensionBase):

View File

@ -13,7 +13,6 @@
# under the License.
"""The Extended Volumes API extension."""
import webob
from webob import exc
from nova.api.openstack import common
@ -52,6 +51,7 @@ class ExtendedVolumesController(wsgi.Controller):
key = "%s:volumes_attached" % ExtendedVolumes.alias
server[key] = [{'id': volume_id} for volume_id in volume_ids]
@wsgi.response(202)
@extensions.expected_errors((400, 404, 409))
@wsgi.action('swap_volume_attachment')
@validation.schema(extended_volumes.swap_volume_attachment)
@ -99,8 +99,6 @@ class ExtendedVolumesController(wsgi.Controller):
msg = _("The volume was either invalid or not attached to the "
"instance.")
raise exc.HTTPNotFound(explanation=msg)
else:
return webob.Response(status_int=202)
@wsgi.extends
def show(self, req, resp_obj, id):

View File

@ -32,8 +32,12 @@ class FlavorManageController(wsgi.Controller):
def __init__(self):
super(FlavorManageController, self).__init__()
@wsgi.action("delete")
# NOTE(oomichi): Return 202 for backwards compatibility but should be
# 204 as this operation complete the deletion of aggregate resource and
# return no response body.
@wsgi.response(202)
@extensions.expected_errors((404))
@wsgi.action("delete")
def _delete(self, req, id):
context = req.environ['nova.context']
authorize(context)
@ -46,11 +50,6 @@ class FlavorManageController(wsgi.Controller):
flavors.destroy(flavor['name'])
# NOTE(oomichi): Return 202 for backwards compatibility but should be
# 204 as this operation complete the deletion of aggregate resource and
# return no response body.
return webob.Response(status_int=202)
# NOTE(oomichi): Return 200 for backwards compatibility but should be 201
# as this operation complete the creation of flavor resource.
@wsgi.action("create")

View File

@ -13,8 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import webob
from nova.api.openstack import common
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
@ -33,6 +31,7 @@ class LockServerController(wsgi.Controller):
super(LockServerController, self).__init__(*args, **kwargs)
self.compute_api = compute.API()
@wsgi.response(202)
@extensions.expected_errors(404)
@wsgi.action('lock')
def _lock(self, req, id, body):
@ -42,8 +41,8 @@ class LockServerController(wsgi.Controller):
instance = common.get_instance(self.compute_api, context, id,
want_objects=True)
self.compute_api.lock(context, instance)
return webob.Response(status_int=202)
@wsgi.response(202)
@extensions.expected_errors(404)
@wsgi.action('unlock')
def _unlock(self, req, id, body):
@ -53,7 +52,6 @@ class LockServerController(wsgi.Controller):
instance = common.get_instance(self.compute_api, context, id,
want_objects=True)
self.compute_api.unlock(context, instance)
return webob.Response(status_int=202)
class LockServer(extensions.V3APIExtensionBase):

View File

@ -14,7 +14,6 @@
# under the License.
from oslo.utils import strutils
import webob
from webob import exc
from nova.api.openstack import common
@ -38,6 +37,7 @@ class MigrateServerController(wsgi.Controller):
super(MigrateServerController, self).__init__(*args, **kwargs)
self.compute_api = compute.API()
@wsgi.response(202)
@extensions.expected_errors((400, 403, 404, 409))
@wsgi.action('migrate')
def _migrate(self, req, id, body):
@ -61,8 +61,7 @@ class MigrateServerController(wsgi.Controller):
except exception.NoValidHost as e:
raise exc.HTTPBadRequest(explanation=e.format_message())
return webob.Response(status_int=202)
@wsgi.response(202)
@extensions.expected_errors((400, 404, 409))
@wsgi.action('os-migrateLive')
@validation.schema(migrate_server.migrate_live)
@ -102,7 +101,6 @@ class MigrateServerController(wsgi.Controller):
except exception.InstanceInvalidState as state_error:
common.raise_http_conflict_for_instance_invalid_state(state_error,
'os-migrateLive', id)
return webob.Response(status_int=202)
class MigrateServer(extensions.V3APIExtensionBase):

View File

@ -15,7 +15,6 @@
"""The multinic extension."""
import webob
from webob import exc
from nova.api.openstack import common
@ -36,6 +35,7 @@ class MultinicController(wsgi.Controller):
super(MultinicController, self).__init__(*args, **kwargs)
self.compute_api = compute.API()
@wsgi.response(202)
@wsgi.action('addFixedIp')
@extensions.expected_errors((400, 404))
@validation.schema(multinic.add_fixed_ip)
@ -52,8 +52,7 @@ class MultinicController(wsgi.Controller):
except exception.NoMoreFixedIps as e:
raise exc.HTTPBadRequest(explanation=e.format_message())
return webob.Response(status_int=202)
@wsgi.response(202)
@wsgi.action('removeFixedIp')
@extensions.expected_errors((400, 404))
@validation.schema(multinic.remove_fixed_ip)
@ -71,8 +70,6 @@ class MultinicController(wsgi.Controller):
except exception.FixedIpNotFoundForSpecificInstance as e:
raise exc.HTTPBadRequest(explanation=e.format_message())
return webob.Response(status_int=202)
# Note: The class name is as it has to be for this to be loaded as an
# extension--only first character capitalized.

View File

@ -15,7 +15,6 @@
# under the License.
import netaddr
import webob
from webob import exc
from nova.api.openstack import extensions
@ -88,9 +87,9 @@ class NetworkController(wsgi.Controller):
result = [network_dict(context, net_ref) for net_ref in networks]
return {'networks': result}
@wsgi.response(202)
@extensions.expected_errors((404, 501))
@wsgi.action("disassociate")
@wsgi.response(202)
def _disassociate_host_and_project(self, req, id, body):
context = req.environ['nova.context']
authorize(context)
@ -117,6 +116,7 @@ class NetworkController(wsgi.Controller):
raise exc.HTTPNotFound(explanation=msg)
return {'network': network_dict(context, network)}
@wsgi.response(202)
@extensions.expected_errors((404, 409))
def delete(self, req, id):
context = req.environ['nova.context']
@ -129,7 +129,6 @@ class NetworkController(wsgi.Controller):
except exception.NetworkNotFound:
msg = _("Network not found")
raise exc.HTTPNotFound(explanation=msg)
return webob.Response(status_int=202)
@extensions.expected_errors((400, 409, 501))
def create(self, req, body):
@ -171,8 +170,8 @@ class NetworkController(wsgi.Controller):
raise exc.HTTPConflict(explanation=ex.format_message())
return {"network": network_dict(context, network)}
@extensions.expected_errors((400, 409, 501))
@wsgi.response(202)
@extensions.expected_errors((400, 409, 501))
def add(self, req, body):
context = req.environ['nova.context']
authorize(context)

View File

@ -13,7 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import webob
from webob import exc
from nova.api.openstack import common
@ -36,6 +35,7 @@ class PauseServerController(wsgi.Controller):
super(PauseServerController, self).__init__(*args, **kwargs)
self.compute_api = compute.API()
@wsgi.response(202)
@extensions.expected_errors((404, 409, 501))
@wsgi.action('pause')
def _pause(self, req, id, body):
@ -56,8 +56,8 @@ class PauseServerController(wsgi.Controller):
except NotImplementedError:
msg = _("Virt driver does not implement pause function.")
raise exc.HTTPNotImplemented(explanation=msg)
return webob.Response(status_int=202)
@wsgi.response(202)
@extensions.expected_errors((404, 409, 501))
@wsgi.action('unpause')
def _unpause(self, req, id, body):
@ -78,7 +78,6 @@ class PauseServerController(wsgi.Controller):
except NotImplementedError:
msg = _("Virt driver does not implement pause function.")
raise exc.HTTPNotImplemented(explanation=msg)
return webob.Response(status_int=202)
class PauseServer(extensions.V3APIExtensionBase):

View File

@ -136,6 +136,7 @@ class ServerGroupController(wsgi.Controller):
raise webob.exc.HTTPNotFound(explanation=e.format_message())
return {'server_group': self._format_server_group(context, sg)}
@wsgi.response(204)
@extensions.expected_errors(404)
def delete(self, req, id):
"""Delete an server group."""
@ -167,8 +168,6 @@ class ServerGroupController(wsgi.Controller):
if quotas:
quotas.commit()
return webob.Response(status_int=204)
@extensions.expected_errors(())
def index(self, req):
"""Returns a list of server groups."""

View File

@ -453,8 +453,8 @@ class ServersController(wsgi.Controller):
req.cache_db_instance(instance)
return self._view_builder.show(req, instance)
@extensions.expected_errors((400, 403, 409, 413))
@wsgi.response(202)
@extensions.expected_errors((400, 403, 409, 413))
@validation.schema(schema_server_create)
def create(self, req, body):
"""Creates a new server for a given user."""
@ -700,8 +700,8 @@ class ServersController(wsgi.Controller):
# NOTE(gmann): Returns 204 for backwards compatibility but should be 202
# for representing async API as this API just accepts the request and
# request hypervisor driver to complete the same in async mode.
@extensions.expected_errors((400, 404, 409))
@wsgi.response(204)
@extensions.expected_errors((400, 404, 409))
@wsgi.action('confirmResize')
def _action_confirm_resize(self, req, id, body):
context = req.environ['nova.context']
@ -717,8 +717,8 @@ class ServersController(wsgi.Controller):
common.raise_http_conflict_for_instance_invalid_state(state_error,
'confirmResize', id)
@extensions.expected_errors((400, 404, 409))
@wsgi.response(202)
@extensions.expected_errors((400, 404, 409))
@wsgi.action('revertResize')
def _action_revert_resize(self, req, id, body):
context = req.environ['nova.context']
@ -736,10 +736,9 @@ class ServersController(wsgi.Controller):
except exception.InstanceInvalidState as state_error:
common.raise_http_conflict_for_instance_invalid_state(state_error,
'revertResize', id)
return webob.Response(status_int=202)
@extensions.expected_errors((400, 404, 409))
@wsgi.response(202)
@extensions.expected_errors((400, 404, 409))
@wsgi.action('reboot')
def _action_reboot(self, req, id, body):
if 'reboot' in body and 'type' in body['reboot']:
@ -768,7 +767,6 @@ class ServersController(wsgi.Controller):
except exception.InstanceInvalidState as state_error:
common.raise_http_conflict_for_instance_invalid_state(state_error,
'reboot', id)
return webob.Response(status_int=202)
def _resize(self, req, instance_id, flavor_id, **kwargs):
"""Begin the resize process with given instance/flavor."""
@ -810,10 +808,8 @@ class ServersController(wsgi.Controller):
msg = _("Invalid instance image.")
raise exc.HTTPBadRequest(explanation=msg)
return webob.Response(status_int=202)
@extensions.expected_errors((404, 409))
@wsgi.response(204)
@extensions.expected_errors((404, 409))
def delete(self, req, id):
"""Destroys a server."""
try:
@ -859,8 +855,8 @@ class ServersController(wsgi.Controller):
flavor_ref = data['server']['flavorRef']
return common.get_id_from_href(flavor_ref)
@extensions.expected_errors((400, 401, 403, 404, 409))
@wsgi.response(202)
@extensions.expected_errors((400, 401, 403, 404, 409))
@wsgi.action('resize')
def _action_resize(self, req, id, body):
"""Resizes a given instance to the flavor size requested."""
@ -880,10 +876,10 @@ class ServersController(wsgi.Controller):
self.resize_extension_manager.map(self._resize_extension_point,
resize_dict, resize_kwargs)
return self._resize(req, id, flavor_ref, **resize_kwargs)
self._resize(req, id, flavor_ref, **resize_kwargs)
@extensions.expected_errors((400, 403, 404, 409, 413))
@wsgi.response(202)
@extensions.expected_errors((400, 403, 404, 409, 413))
@wsgi.action('rebuild')
@validation.schema(schema_server_rebuild)
def _action_rebuild(self, req, id, body):
@ -958,8 +954,8 @@ class ServersController(wsgi.Controller):
robj = wsgi.ResponseObject(view)
return self._add_location(robj)
@extensions.expected_errors((400, 403, 404, 409))
@wsgi.response(202)
@extensions.expected_errors((400, 403, 404, 409))
@wsgi.action('createImage')
@common.check_snapshots_enabled
def _action_create_image(self, req, id, body):
@ -1045,6 +1041,7 @@ class ServersController(wsgi.Controller):
except exception.InstanceNotFound as e:
raise webob.exc.HTTPNotFound(explanation=e.format_message())
@wsgi.response(202)
@extensions.expected_errors((404, 409))
@wsgi.action('os-start')
def _start_server(self, req, id, body):
@ -1058,8 +1055,8 @@ class ServersController(wsgi.Controller):
except (exception.InstanceNotReady, exception.InstanceIsLocked,
exception.InstanceInvalidState) as e:
raise webob.exc.HTTPConflict(explanation=e.format_message())
return webob.Response(status_int=202)
@wsgi.response(202)
@extensions.expected_errors((404, 409))
@wsgi.action('os-stop')
def _stop_server(self, req, id, body):
@ -1073,7 +1070,6 @@ class ServersController(wsgi.Controller):
except (exception.InstanceNotReady, exception.InstanceIsLocked,
exception.InstanceInvalidState) as e:
raise webob.exc.HTTPConflict(explanation=e.format_message())
return webob.Response(status_int=202)
def remove_invalid_options(context, search_options, allowed_search_options):

View File

@ -14,7 +14,6 @@
"""The shelved mode extension."""
import webob
from webob import exc
from nova.api.openstack import common
@ -36,6 +35,7 @@ class ShelveController(wsgi.Controller):
super(ShelveController, self).__init__(*args, **kwargs)
self.compute_api = compute.API()
@wsgi.response(202)
@exts.expected_errors((404, 409))
@wsgi.action('shelve')
def _shelve(self, req, id, body):
@ -53,8 +53,7 @@ class ShelveController(wsgi.Controller):
common.raise_http_conflict_for_instance_invalid_state(state_error,
'shelve', id)
return webob.Response(status_int=202)
@wsgi.response(202)
@exts.expected_errors((404, 409))
@wsgi.action('shelveOffload')
def _shelve_offload(self, req, id, body):
@ -73,8 +72,7 @@ class ShelveController(wsgi.Controller):
'shelveOffload',
id)
return webob.Response(status_int=202)
@wsgi.response(202)
@exts.expected_errors((404, 409))
@wsgi.action('unshelve')
def _unshelve(self, req, id, body):
@ -91,7 +89,6 @@ class ShelveController(wsgi.Controller):
common.raise_http_conflict_for_instance_invalid_state(state_error,
'unshelve',
id)
return webob.Response(status_int=202)
class Shelve(exts.V3APIExtensionBase):

View File

@ -12,7 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import webob
from webob import exc
from nova.api.openstack import common
@ -36,6 +35,7 @@ class SuspendServerController(wsgi.Controller):
super(SuspendServerController, self).__init__(*args, **kwargs)
self.compute_api = compute.API()
@wsgi.response(202)
@extensions.expected_errors((404, 409))
@wsgi.action('suspend')
def _suspend(self, req, id, body):
@ -51,8 +51,8 @@ class SuspendServerController(wsgi.Controller):
except exception.InstanceInvalidState as state_error:
common.raise_http_conflict_for_instance_invalid_state(state_error,
'suspend', id)
return webob.Response(status_int=202)
@wsgi.response(202)
@extensions.expected_errors((404, 409))
@wsgi.action('resume')
def _resume(self, req, id, body):
@ -68,7 +68,6 @@ class SuspendServerController(wsgi.Controller):
except exception.InstanceInvalidState as state_error:
common.raise_http_conflict_for_instance_invalid_state(state_error,
'resume', id)
return webob.Response(status_int=202)
class SuspendServer(extensions.V3APIExtensionBase):

View File

@ -16,7 +16,6 @@
"""The volumes extension."""
from oslo.utils import strutils
import webob
from webob import exc
from nova.api.openstack import common
@ -98,6 +97,7 @@ class VolumeController(wsgi.Controller):
return {'volume': _translate_volume_detail_view(context, vol)}
@wsgi.response(202)
@extensions.expected_errors(404)
def delete(self, req, id):
"""Delete a volume."""
@ -110,7 +110,6 @@ class VolumeController(wsgi.Controller):
self.volume_api.delete(context, id)
except exception.NotFound as e:
raise exc.HTTPNotFound(explanation=e.format_message())
return webob.Response(status_int=202)
@extensions.expected_errors(())
def index(self, req):
@ -257,6 +256,7 @@ class SnapshotController(wsgi.Controller):
return {'snapshot': _translate_snapshot_detail_view(context, vol)}
@wsgi.response(202)
@extensions.expected_errors(404)
def delete(self, req, id):
"""Delete a snapshot."""
@ -269,7 +269,6 @@ class SnapshotController(wsgi.Controller):
self.volume_api.delete_snapshot(context, id)
except exception.NotFound as e:
raise exc.HTTPNotFound(explanation=e.format_message())
return webob.Response(status_int=202)
@extensions.expected_errors(())
def index(self, req):

View File

@ -702,8 +702,14 @@ class ResetStateTestsV21(test.NoDBTestCase):
body = {"os-resetState": {"state": "active"}}
result = self.admin_api._reset_state(self.request, self.uuid,
body=body)
self.assertEqual(result.status_int, 202)
# NOTE: on v2.1, http status code is set as wsgi_code of API
# method instead of status_int in a response object.
if isinstance(self.admin_api,
admin_actions_v21.AdminActionsController):
status_int = self.admin_api._reset_state.wsgi_code
else:
status_int = result.status_int
self.assertEqual(202, status_int)
def test_reset_error(self):
self._setup_mock(dict(vm_state=vm_states.ERROR,
@ -712,8 +718,14 @@ class ResetStateTestsV21(test.NoDBTestCase):
body = {"os-resetState": {"state": "error"}}
result = self.admin_api._reset_state(self.request, self.uuid,
body=body)
self.assertEqual(result.status_int, 202)
# NOTE: on v2.1, http status code is set as wsgi_code of API
# method instead of status_int in a response object.
if isinstance(self.admin_api,
admin_actions_v21.AdminActionsController):
status_int = self.admin_api._reset_state.wsgi_code
else:
status_int = result.status_int
self.assertEqual(202, status_int)
class ResetStateTestsV2(ResetStateTestsV21):

View File

@ -221,7 +221,14 @@ class InterfaceAttachTestsV21(test.NoDBTestCase):
req.environ['nova.context'] = self.context
result = self.attachments.delete(req, FAKE_UUID1, FAKE_PORT_ID1)
self.assertEqual('202 Accepted', result.status)
# NOTE: on v2.1, http status code is set as wsgi_code of API
# method instead of status_int in a response object.
if isinstance(self.attachments,
attach_interfaces_v3.InterfaceAttachmentController):
status_int = self.attachments.delete.wsgi_code
else:
status_int = result.status_int
self.assertEqual(202, status_int)
def test_detach_interface_instance_locked(self):
def fake_detach_interface_from_locked_server(self, context,

View File

@ -55,7 +55,13 @@ class DeferredDeleteExtensionTestV21(test.NoDBTestCase):
self.mox.ReplayAll()
res = self.extension._force_delete(self.fake_req, self.fake_uuid,
self.fake_input_dict)
self.assertEqual(res.status_int, 202)
# NOTE: on v2.1, http status code is set as wsgi_code of API
# method instead of status_int in a response object.
if isinstance(self.extension, dd_v21.DeferredDeleteController):
status_int = self.extension._force_delete.wsgi_code
else:
status_int = res.status_int
self.assertEqual(202, status_int)
def test_force_delete_instance_not_found(self):
self.mox.StubOutWithMock(compute_api.API, 'get')
@ -97,7 +103,13 @@ class DeferredDeleteExtensionTestV21(test.NoDBTestCase):
self.mox.ReplayAll()
res = self.extension._restore(self.fake_req, self.fake_uuid,
self.fake_input_dict)
self.assertEqual(res.status_int, 202)
# NOTE: on v2.1, http status code is set as wsgi_code of API
# method instead of status_int in a response object.
if isinstance(self.extension, dd_v21.DeferredDeleteController):
status_int = self.extension._restore.wsgi_code
else:
status_int = res.status_int
self.assertEqual(202, status_int)
def test_restore_instance_not_found(self):
self.mox.StubOutWithMock(compute_api.API, 'get')

View File

@ -130,7 +130,15 @@ class FlavorManageTestV21(test.NoDBTestCase):
def test_delete(self):
req = fakes.HTTPRequest.blank(self.base_url + '/1234')
res = self.controller._delete(req, 1234)
self.assertEqual(res.status_int, 202)
# NOTE: on v2.1, http status code is set as wsgi_code of API
# method instead of status_int in a response object.
if isinstance(self.controller,
flavormanage_v21.FlavorManageController):
status_int = self.controller._delete.wsgi_code
else:
status_int = res.status_int
self.assertEqual(202, status_int)
# subsequent delete should fail
self.assertRaises(webob.exc.HTTPNotFound,

View File

@ -163,7 +163,14 @@ class ServerGroupQuotasTestV21(test.TestCase):
req = fakes.HTTPRequest.blank('/v2/fake/os-server-groups/123')
resp = self.controller.delete(req, '123')
self.assertTrue(self.called)
self.assertEqual(resp.status_int, 204)
# NOTE: on v2.1, http status code is set as wsgi_code of API
# method instead of status_int in a response object.
if isinstance(self.controller, sg_v3.ServerGroupController):
status_int = self.controller.delete.wsgi_code
else:
status_int = resp.status_int
self.assertEqual(204, status_int)
class ServerGroupQuotasTestV2(ServerGroupQuotasTestV21):

View File

@ -354,7 +354,14 @@ class ServerGroupTestV21(test.TestCase):
'/os-server-groups/123')
resp = self.controller.delete(req, '123')
self.assertTrue(self.called)
self.assertEqual(resp.status_int, 204)
# NOTE: on v2.1, http status code is set as wsgi_code of API
# method instead of status_int in a response object.
if isinstance(self.controller, sg_v3.ServerGroupController):
status_int = self.controller.delete.wsgi_code
else:
status_int = resp.status_int
self.assertEqual(204, status_int)
def test_delete_non_existing_server_group(self):
req = fakes.HTTPRequest.blank(self._get_url() +

View File

@ -1006,7 +1006,14 @@ class DeleteSnapshotTestCaseV21(test.TestCase):
self.req.method = 'DELETE'
result = self.controller.delete(self.req, result['snapshot']['id'])
self.assertEqual(result.status_int, 202)
# NOTE: on v2.1, http status code is set as wsgi_code of API
# method instead of status_int in a response object.
if isinstance(self.controller, volumes_v3.SnapshotController):
status_int = self.controller.delete.wsgi_code
else:
status_int = result.status_int
self.assertEqual(202, status_int)
def test_delete_snapshot_not_exists(self):
def fake_delete_snapshot_not_exist(self, context, snapshot_id):

View File

@ -327,8 +327,9 @@ class ExtendedVolumesTest(test.TestCase):
def test_swap_volume(self):
self.stubs.Set(compute.api.API, 'swap_volume', fake_swap_volume)
result = self._test_swap()
self.assertEqual('202 Accepted', result.status)
# Check any exceptions don't happen and status code
self._test_swap()
self.assertEqual(202, self.Controller.swap.wsgi_code)
def test_swap_volume_for_locked_server(self):
def fake_swap_volume_for_locked_server(self, context, instance,