Merge "Unit test framework: common FakeResponse"
This commit is contained in:
commit
fcfdd34c94
39
nova/tests/unit/fake_requests.py
Normal file
39
nova/tests/unit/fake_requests.py
Normal file
@ -0,0 +1,39 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, 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.
|
||||
"""Fakes relating to the `requests` module."""
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
class FakeResponse(requests.Response):
|
||||
def __init__(self, status_code, content=None, headers=None):
|
||||
"""A requests.Response that can be used as a mock return_value.
|
||||
|
||||
A key feature is that the instance will evaluate to True or False like
|
||||
a real Response, based on the status_code.
|
||||
|
||||
Properties like ok, status_code, text, and content, and methods like
|
||||
json(), work as expected based on the inputs.
|
||||
|
||||
:param status_code: Integer HTTP response code (200, 404, etc.)
|
||||
:param content: String supplying the payload content of the response.
|
||||
Using a json-encoded string will make the json() method
|
||||
behave as expected.
|
||||
:param headers: Dict of HTTP header values to set.
|
||||
"""
|
||||
super(FakeResponse, self).__init__()
|
||||
self.status_code = status_code
|
||||
if content:
|
||||
self._content = content.encode('utf-8')
|
||||
self.encoding = 'utf-8'
|
||||
if headers:
|
||||
self.headers = headers
|
@ -14,7 +14,6 @@ import time
|
||||
|
||||
from keystoneauth1 import exceptions as ks_exc
|
||||
import mock
|
||||
import requests
|
||||
from six.moves.urllib import parse
|
||||
|
||||
import nova.conf
|
||||
@ -25,6 +24,7 @@ from nova import rc_fields as fields
|
||||
from nova.scheduler.client import report
|
||||
from nova.scheduler import utils as scheduler_utils
|
||||
from nova import test
|
||||
from nova.tests.unit import fake_requests
|
||||
from nova.tests import uuidsentinel as uuids
|
||||
|
||||
CONF = nova.conf.CONF
|
||||
@ -1831,12 +1831,9 @@ class TestProviderOperations(SchedulerReportClientTestCase):
|
||||
# record.
|
||||
uuid = uuids.compute_node
|
||||
name = 'computehost'
|
||||
resp_mock = requests.Response()
|
||||
resp_mock.status_code = 409
|
||||
resp_mock.headers = {'x-openstack-request-id': uuids.request_id}
|
||||
resp_mock._content = 'not a name conflict'.encode('utf-8')
|
||||
resp_mock.encoding = 'utf-8'
|
||||
self.ks_adap_mock.post.return_value = resp_mock
|
||||
self.ks_adap_mock.post.return_value = fake_requests.FakeResponse(
|
||||
409, content='not a name conflict',
|
||||
headers={'x-openstack-request-id': uuids.request_id})
|
||||
|
||||
get_rp_mock.return_value = mock.sentinel.get_rp
|
||||
|
||||
@ -1861,13 +1858,9 @@ class TestProviderOperations(SchedulerReportClientTestCase):
|
||||
def test_create_resource_provider_name_conflict(self):
|
||||
# When the API call to create the resource provider fails 409 with a
|
||||
# name conflict, we raise an exception.
|
||||
resp_mock = requests.Response()
|
||||
resp_mock.status_code = 409
|
||||
resp_mock._content = (
|
||||
'<stuff>Conflicting resource provider name: '
|
||||
'foo already exists.</stuff>').encode('utf-8')
|
||||
resp_mock.encoding = 'utf-8'
|
||||
self.ks_adap_mock.post.return_value = resp_mock
|
||||
self.ks_adap_mock.post.return_value = fake_requests.FakeResponse(
|
||||
409, content='<stuff>Conflicting resource provider name: foo '
|
||||
'already exists.</stuff>')
|
||||
|
||||
self.assertRaises(
|
||||
exception.ResourceProviderCreationFailed,
|
||||
@ -1881,11 +1874,8 @@ class TestProviderOperations(SchedulerReportClientTestCase):
|
||||
# deal with
|
||||
uuid = uuids.compute_node
|
||||
name = 'computehost'
|
||||
resp_mock = requests.Response()
|
||||
resp_mock.status_code = 503
|
||||
self.ks_adap_mock.post.return_value = resp_mock
|
||||
self.ks_adap_mock.post.return_value.headers = {
|
||||
'x-openstack-request-id': uuids.request_id}
|
||||
self.ks_adap_mock.post.return_value = fake_requests.FakeResponse(
|
||||
503, headers={'x-openstack-request-id': uuids.request_id})
|
||||
|
||||
self.assertRaises(
|
||||
exception.ResourceProviderCreationFailed,
|
||||
@ -1917,7 +1907,7 @@ class TestProviderOperations(SchedulerReportClientTestCase):
|
||||
url, json=[], raise_exc=False, microversion=None, headers={})
|
||||
|
||||
def test_delete_provider(self):
|
||||
delete_mock = requests.Response()
|
||||
delete_mock = fake_requests.FakeResponse(None)
|
||||
self.ks_adap_mock.delete.return_value = delete_mock
|
||||
|
||||
for status_code in (204, 404):
|
||||
@ -1938,7 +1928,7 @@ class TestProviderOperations(SchedulerReportClientTestCase):
|
||||
self.ks_adap_mock.delete.reset_mock()
|
||||
|
||||
def test_delete_provider_fail(self):
|
||||
delete_mock = requests.Response()
|
||||
delete_mock = fake_requests.FakeResponse(None)
|
||||
self.ks_adap_mock.delete.return_value = delete_mock
|
||||
resp_exc_map = {409: exception.ResourceProviderInUse,
|
||||
503: exception.ResourceProviderDeletionFailed}
|
||||
@ -2138,9 +2128,7 @@ class TestTraits(SchedulerReportClientTestCase):
|
||||
get_mock = mock.Mock(status_code=200)
|
||||
get_mock.json.return_value = {'traits': []}
|
||||
self.ks_adap_mock.get.return_value = get_mock
|
||||
put_mock = requests.Response()
|
||||
put_mock.status_code = 400
|
||||
self.ks_adap_mock.put.return_value = put_mock
|
||||
self.ks_adap_mock.put.return_value = fake_requests.FakeResponse(400)
|
||||
|
||||
self.assertRaises(exception.TraitCreationFailed,
|
||||
self.client._ensure_traits,
|
||||
@ -2831,13 +2819,8 @@ class TestInventory(SchedulerReportClientTestCase):
|
||||
'resource_provider_generation': 42,
|
||||
'inventories': {},
|
||||
}
|
||||
try:
|
||||
mock_put.return_value.__nonzero__.return_value = False
|
||||
except AttributeError:
|
||||
# Thanks py3
|
||||
mock_put.return_value.__bool__.return_value = False
|
||||
mock_put.return_value.headers = {'x-openstack-request-id':
|
||||
uuids.request_id}
|
||||
mock_put.return_value = fake_requests.FakeResponse(
|
||||
400, headers={'x-openstack-request-id': uuids.request_id})
|
||||
|
||||
inv_data = report._compute_node_to_inventory_dict(compute_node)
|
||||
result = self.client._update_inventory_attempt(
|
||||
@ -3240,11 +3223,7 @@ class TestAllocations(SchedulerReportClientTestCase):
|
||||
cn = objects.ComputeNode(uuid=uuids.cn)
|
||||
inst = objects.Instance(uuid=uuids.inst, project_id=uuids.project,
|
||||
user_id=uuids.user)
|
||||
try:
|
||||
mock_put.return_value.__nonzero__.return_value = False
|
||||
except AttributeError:
|
||||
# NOTE(danms): LOL @ py3
|
||||
mock_put.return_value.__bool__.return_value = False
|
||||
mock_put.return_value = fake_requests.FakeResponse(400)
|
||||
self.client.update_instance_allocation(self.context, cn, inst, 1)
|
||||
self.assertTrue(mock_warn.called)
|
||||
|
||||
@ -3265,11 +3244,7 @@ class TestAllocations(SchedulerReportClientTestCase):
|
||||
mock_delete):
|
||||
cn = objects.ComputeNode(uuid=uuids.cn)
|
||||
inst = objects.Instance(uuid=uuids.inst)
|
||||
try:
|
||||
mock_delete.return_value.__nonzero__.return_value = False
|
||||
except AttributeError:
|
||||
# NOTE(danms): LOL @ py3
|
||||
mock_delete.return_value.__bool__.return_value = False
|
||||
mock_delete.return_value = fake_requests.FakeResponse(400)
|
||||
self.client.update_instance_allocation(self.context, cn, inst, -1)
|
||||
self.assertTrue(mock_warn.called)
|
||||
|
||||
@ -3281,13 +3256,7 @@ class TestAllocations(SchedulerReportClientTestCase):
|
||||
"""Tests that we don't log a warning on a 404 response when trying to
|
||||
delete an allocation record.
|
||||
"""
|
||||
mock_response = mock.MagicMock(status_code=404)
|
||||
try:
|
||||
mock_response.__nonzero__.return_value = False
|
||||
except AttributeError:
|
||||
# py3 uses __bool__
|
||||
mock_response.__bool__.return_value = False
|
||||
mock_delete.return_value = mock_response
|
||||
mock_delete.return_value = fake_requests.FakeResponse(404)
|
||||
self.client.delete_allocation_for_instance(self.context, uuids.rp_uuid)
|
||||
# make sure we didn't screw up the logic or the mock
|
||||
mock_log.info.assert_not_called()
|
||||
@ -3349,12 +3318,7 @@ class TestAllocations(SchedulerReportClientTestCase):
|
||||
self.client._provider_tree.new_root(uuids.cn, uuids.cn, 1)
|
||||
cn = objects.ComputeNode(uuid=uuids.cn, host="fake_host",
|
||||
hypervisor_hostname="fake_hostname", )
|
||||
resp_mock = mock.MagicMock(status_code=204)
|
||||
try:
|
||||
resp_mock.__nonzero__.return_value = True
|
||||
except AttributeError:
|
||||
# py3 uses __bool__
|
||||
resp_mock.__bool__.return_value = True
|
||||
resp_mock = fake_requests.FakeResponse(204)
|
||||
mock_delete.return_value = resp_mock
|
||||
self.client.delete_resource_provider(self.context, cn)
|
||||
# With a 204, only the info should be called
|
||||
@ -3364,11 +3328,6 @@ class TestAllocations(SchedulerReportClientTestCase):
|
||||
# Now check a 404 response
|
||||
mock_log.reset_mock()
|
||||
resp_mock.status_code = 404
|
||||
try:
|
||||
resp_mock.__nonzero__.return_value = False
|
||||
except AttributeError:
|
||||
# py3 uses __bool__
|
||||
resp_mock.__bool__.return_value = False
|
||||
self.client.delete_resource_provider(self.context, cn)
|
||||
# With a 404, neither log message should be called
|
||||
self.assertEqual(0, mock_log.info.call_count)
|
||||
@ -3406,9 +3365,7 @@ class TestResourceClass(SchedulerReportClientTestCase):
|
||||
self.mock_put.assert_not_called()
|
||||
|
||||
def test_ensure_resource_classes_put_fail(self):
|
||||
resp = requests.Response()
|
||||
resp.status_code = 503
|
||||
self.mock_put.return_value = resp
|
||||
self.mock_put.return_value = fake_requests.FakeResponse(503)
|
||||
rcs = ['VCPU', 'MEMORY_MB', 'CUSTOM_BAD']
|
||||
self.assertRaises(
|
||||
exception.InvalidResourceClass,
|
||||
|
@ -21,30 +21,7 @@ import webob
|
||||
|
||||
from nova.api.openstack import identity
|
||||
from nova import test
|
||||
|
||||
|
||||
class FakeResponse(object):
|
||||
"""A basic response constainer that simulates requests.Response.
|
||||
|
||||
One of the critical things is that a success error code makes the
|
||||
object return true.
|
||||
|
||||
"""
|
||||
def __init__(self, status_code, content=""):
|
||||
self.status_code = status_code
|
||||
self.content = content
|
||||
|
||||
def __bool__(self):
|
||||
# python 3
|
||||
return self.__nonzero__()
|
||||
|
||||
def __nonzero__(self):
|
||||
# python 2
|
||||
return self.status_code < 400
|
||||
|
||||
@property
|
||||
def text(self):
|
||||
return self.content
|
||||
from nova.tests.unit import fake_requests
|
||||
|
||||
|
||||
class IdentityValidationTest(test.NoDBTestCase):
|
||||
@ -89,7 +66,7 @@ class IdentityValidationTest(test.NoDBTestCase):
|
||||
found the project exists.
|
||||
|
||||
"""
|
||||
self.mock_adap.get.return_value = FakeResponse(200)
|
||||
self.mock_adap.get.return_value = fake_requests.FakeResponse(200)
|
||||
self.assertTrue(identity.verify_project_id(mock.MagicMock(), "foo"))
|
||||
self.validate_common()
|
||||
|
||||
@ -100,7 +77,7 @@ class IdentityValidationTest(test.NoDBTestCase):
|
||||
definitively found the project does not exist.
|
||||
|
||||
"""
|
||||
self.mock_adap.get.return_value = FakeResponse(404)
|
||||
self.mock_adap.get.return_value = fake_requests.FakeResponse(404)
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
identity.verify_project_id,
|
||||
mock.MagicMock(), "foo")
|
||||
@ -113,7 +90,7 @@ class IdentityValidationTest(test.NoDBTestCase):
|
||||
and assume the project exists.
|
||||
|
||||
"""
|
||||
self.mock_adap.get.return_value = FakeResponse(403)
|
||||
self.mock_adap.get.return_value = fake_requests.FakeResponse(403)
|
||||
self.assertTrue(identity.verify_project_id(mock.MagicMock(), "foo"))
|
||||
self.validate_common()
|
||||
|
||||
@ -124,7 +101,8 @@ class IdentityValidationTest(test.NoDBTestCase):
|
||||
side. We don't want to fail on our side.
|
||||
|
||||
"""
|
||||
self.mock_adap.get.return_value = FakeResponse(500, "Oh noes!")
|
||||
self.mock_adap.get.return_value = fake_requests.FakeResponse(
|
||||
500, content="Oh noes!")
|
||||
self.assertTrue(identity.verify_project_id(mock.MagicMock(), "foo"))
|
||||
self.validate_common()
|
||||
|
||||
|
@ -54,7 +54,7 @@ from nova import test
|
||||
from nova.tests.unit.api.openstack import fakes
|
||||
from nova.tests.unit import fake_block_device
|
||||
from nova.tests.unit import fake_network
|
||||
from nova.tests.unit import test_identity
|
||||
from nova.tests.unit import fake_requests
|
||||
from nova.tests import uuidsentinel as uuids
|
||||
from nova import utils
|
||||
from nova.virt import netutils
|
||||
@ -856,9 +856,11 @@ class OpenStackMetadataTestCase(test.TestCase):
|
||||
|
||||
def _test_vendordata2_response_inner(self, request_mock, response_code,
|
||||
include_rest_result=True):
|
||||
fake_response = test_identity.FakeResponse(response_code)
|
||||
content = None
|
||||
if include_rest_result:
|
||||
fake_response.content = '{"color": "blue"}'
|
||||
content = '{"color": "blue"}'
|
||||
fake_response = fake_requests.FakeResponse(response_code,
|
||||
content=content)
|
||||
request_mock.return_value = fake_response
|
||||
|
||||
with utils.tempdir() as tmpdir:
|
||||
|
Loading…
x
Reference in New Issue
Block a user