Start using requests-mock for REST unit tests

Mocking out the whole client is the wrong level. Although we'd still
like to betamax the functional tests - as we put in REST calls, let's
make the mocking of them happen at the requests level so that we test as
much of shade as we can.

Nobody look at the v2 keystone catalog. The existing clouds.yaml entry
was for a v2 cloud and I wanted to keep the patch contained to the task
at hand. We should likely do some crazy testscenarios magic at some
point to make sure _all_ the things work with both v2 and v3.

Change-Id: Ife4d95df5417d329195c737814e89d1370a0597b
This commit is contained in:
Monty Taylor 2016-10-11 21:13:28 -05:00
parent 788932633e
commit 8025c63e11
No known key found for this signature in database
GPG Key ID: 7BAE94BC7141A594
6 changed files with 287 additions and 32 deletions

View File

@ -21,6 +21,7 @@ import fixtures
import mock
import os
import os_client_config as occ
from requests_mock.contrib import fixture as rm_fixture
import tempfile
import shade.openstackcloud
@ -103,3 +104,41 @@ class TestCase(BaseTestCase):
self.session_fixture = self.useFixture(fixtures.MonkeyPatch(
'os_client_config.cloud_config.CloudConfig.get_session',
mock.Mock()))
class RequestsMockTestCase(BaseTestCase):
def setUp(self, cloud_config_fixture='clouds.yaml'):
super(RequestsMockTestCase, self).setUp(
cloud_config_fixture=cloud_config_fixture)
self.adapter = self.useFixture(rm_fixture.Fixture())
self.adapter.register_uri(
'GET', 'http://192.168.0.19:35357/',
text=open(
os.path.join(
self.fixtures_directory,
'discovery.json'),
'r').read())
self.adapter.register_uri(
'POST', 'http://example.com/v2.0/tokens',
text=open(
os.path.join(
self.fixtures_directory,
'catalog.json'),
'r').read())
self.adapter.register_uri(
'GET', 'http://image.example.com/',
text=open(
os.path.join(
self.fixtures_directory,
'image-version.json'),
'r').read())
test_cloud = os.environ.get('SHADE_OS_CLOUD', '_test_cloud_')
self.cloud_config = self.config.get_one_cloud(
cloud=test_cloud, validate=True)
self.cloud = shade.OpenStackCloud(
cloud_config=self.cloud_config,
log_inner_exceptions=True)

View File

@ -0,0 +1,107 @@
{
"access": {
"token": {
"issued_at": "2016-04-14T10:09:58.014014Z",
"expires": "9999-12-31T23:59:59Z",
"id": "7fa3037ae2fe48ada8c626a51dc01ffd",
"tenant": {
"enabled": true,
"description": "Bootstrap project for initializing the cloud.",
"name": "admin",
"id": "1c36b64c840a42cd9e9b931a369337f0"
},
"audit_ids": [
"FgG3Q8T3Sh21r_7HyjHP8A"
]
},
"serviceCatalog": [
{
"endpoints_links": [],
"endpoints": [
{
"adminURL": "http://compute.example.com/v2.1/1c36b64c840a42cd9e9b931a369337f0",
"region": "RegionOne",
"publicURL": "http://compute.example.com/v2.1/1c36b64c840a42cd9e9b931a369337f0",
"internalURL": "http://compute.example.com/v2.1/1c36b64c840a42cd9e9b931a369337f0",
"id": "32466f357f3545248c47471ca51b0d3a"
}
],
"type": "compute",
"name": "nova"
},
{
"endpoints_links": [],
"endpoints": [
{
"adminURL": "http://volume.example.com/v2/1c36b64c840a42cd9e9b931a369337f0",
"region": "RegionOne",
"publicURL": "http://volume.example.com/v2/1c36b64c840a42cd9e9b931a369337f0",
"internalURL": "http://volume.example.com/v2/1c36b64c840a42cd9e9b931a369337f0",
"id": "1e875ca2225b408bbf3520a1b8e1a537"
}
],
"type": "volumev2",
"name": "cinderv2"
},
{
"endpoints_links": [],
"endpoints": [
{
"adminURL": "http://image.example.com",
"region": "RegionOne",
"publicURL": "http://image.example.com",
"internalURL": "http://image.example.com",
"id": "5a64de3c4a614d8d8f8d1ba3dee5f45f"
}
],
"type": "image",
"name": "glance"
},
{
"endpoints_links": [],
"endpoints": [
{
"adminURL": "http://volume.example.com/v1/1c36b64c840a42cd9e9b931a369337f0",
"region": "RegionOne",
"publicURL": "http://volume.example.com/v1/1c36b64c840a42cd9e9b931a369337f0",
"internalURL": "http://volume.example.com/v1/1c36b64c840a42cd9e9b931a369337f0",
"id": "3d15fdfc7d424f3c8923324417e1a3d1"
}
],
"type": "volume",
"name": "cinder"
},
{
"endpoints_links": [],
"endpoints": [
{
"adminURL": "http://identity.example.com/v2.0",
"region": "RegionOne",
"publicURL": "http://identity.example.comv2.0",
"internalURL": "http://identity.example.comv2.0",
"id": "4deb4d0504a044a395d4480741ba628c"
}
],
"type": "identity",
"name": "keystone"
}
],
"user": {
"username": "dummy",
"roles_links": [],
"id": "71675f719c3343e8ac441cc28f396474",
"roles": [
{
"name": "admin"
}
],
"name": "admin"
},
"metadata": {
"is_admin": 0,
"roles": [
"6d813db50b6e4a1ababdbbb5a83c7de5"
]
}
}
}

View File

@ -0,0 +1,45 @@
{
"versions": {
"values": [
{
"status": "stable",
"updated": "2016-04-04T00:00:00Z",
"media-types": [
{
"base": "application/json",
"type": "application/vnd.openstack.identity-v3+json"
}
],
"id": "v3.6",
"links": [
{
"href": "http://example.com/v3/",
"rel": "self"
}
]
},
{
"status": "stable",
"updated": "2014-04-17T00:00:00Z",
"media-types": [
{
"base": "application/json",
"type": "application/vnd.openstack.identity-v2.0+json"
}
],
"id": "v2.0",
"links": [
{
"href": "http://example.com/v2.0/",
"rel": "self"
},
{
"href": "http://docs.openstack.org/",
"type": "text/html",
"rel": "describedby"
}
]
}
]
}
}

View File

@ -0,0 +1,64 @@
{
"versions": [
{
"status": "CURRENT",
"id": "v2.3",
"links": [
{
"href": "https://image.example.com/v2/",
"rel": "self"
}
]
},
{
"status": "SUPPORTED",
"id": "v2.2",
"links": [
{
"href": "https://image.example.com/v2/",
"rel": "self"
}
]
},
{
"status": "SUPPORTED",
"id": "v2.1",
"links": [
{
"href": "https://image.example.com/v2/",
"rel": "self"
}
]
},
{
"status": "SUPPORTED",
"id": "v2.0",
"links": [
{
"href": "https://image.example.com/v2/",
"rel": "self"
}
]
},
{
"status": "SUPPORTED",
"id": "v1.1",
"links": [
{
"href": "https://image.example.com/v1/",
"rel": "self"
}
]
},
{
"status": "SUPPORTED",
"id": "v1.0",
"links": [
{
"href": "https://image.example.com/v1/",
"rel": "self"
}
]
}
]
}

View File

@ -15,20 +15,18 @@
import tempfile
import uuid
import mock
import six
import shade
from shade import exc
from shade.tests.unit import base
class TestImage(base.TestCase):
class TestImage(base.RequestsMockTestCase):
def setUp(self):
super(TestImage, self).setUp()
self.image_id = str(uuid.uuid4())
self.fake_search_return = [{
self.fake_search_return = {'images': [{
u'image_state': u'available',
u'container_format': u'bare',
u'min_ram': 0,
@ -51,10 +49,8 @@ class TestImage(base.TestCase):
u'name': u'fake_image',
u'checksum': u'ee36e35a297980dee1b514de9803ec6d',
u'created_at': u'2016-02-10T05:03:11Z',
u'protected': False}]
self.output = six.BytesIO()
self.output.write(uuid.uuid4().bytes)
self.output.seek(0)
u'protected': False}]}
self.output = uuid.uuid4().bytes
def test_download_image_no_output(self):
self.assertRaises(exc.OpenStackCloudException,
@ -66,33 +62,36 @@ class TestImage(base.TestCase):
self.cloud.download_image, 'fake_image',
output_path='fake_path', output_file=fake_fd)
@mock.patch.object(shade.OpenStackCloud, 'search_images', return_value=[])
def test_download_image_no_images_found(self, mock_search):
def test_download_image_no_images_found(self):
self.adapter.register_uri(
'GET', 'http://image.example.com/v2/images',
json=dict(images=[]))
self.assertRaises(exc.OpenStackCloudResourceNotFound,
self.cloud.download_image, 'fake_image',
output_path='fake_path')
@mock.patch.object(shade.OpenStackCloud, 'glance_client')
@mock.patch.object(shade.OpenStackCloud, 'search_images')
def test_download_image_with_fd(self, mock_search, mock_glance):
output_file = six.BytesIO()
mock_glance.images.data.return_value = self.output
mock_search.return_value = self.fake_search_return
self.cloud.download_image('fake_image', output_file=output_file)
mock_glance.images.data.assert_called_once_with(self.image_id)
output_file.seek(0)
self.output.seek(0)
self.assertEqual(output_file.read(), self.output.read())
def _register_image_mocks(self):
self.adapter.register_uri(
'GET', 'http://image.example.com/v2/images',
json=self.fake_search_return)
self.adapter.register_uri(
'GET', 'http://image.example.com/v2/images/{id}/file'.format(
id=self.image_id),
content=self.output,
headers={
'Content-Type': 'application/octet-stream'
})
@mock.patch.object(shade.OpenStackCloud, 'glance_client')
@mock.patch.object(shade.OpenStackCloud, 'search_images')
def test_download_image_with_path(self, mock_search, mock_glance):
output_file = tempfile.NamedTemporaryFile()
mock_glance.images.data.return_value = self.output
mock_search.return_value = self.fake_search_return
self.cloud.download_image('fake_image',
output_path=output_file.name)
mock_glance.images.data.assert_called_once_with(self.image_id)
def test_download_image_with_fd(self):
self._register_image_mocks()
output_file = six.BytesIO()
self.cloud.download_image('fake_image', output_file=output_file)
output_file.seek(0)
self.output.seek(0)
self.assertEqual(output_file.read(), self.output.read())
self.assertEqual(output_file.read(), self.output)
def test_download_image_with_path(self):
self._register_image_mocks()
output_file = tempfile.NamedTemporaryFile()
self.cloud.download_image('fake_image', output_path=output_file.name)
output_file.seek(0)
self.assertEqual(output_file.read(), self.output)

View File

@ -7,6 +7,7 @@ mock>=1.0
python-openstackclient>=2.1.0
python-subunit
oslosphinx>=2.2.0 # Apache-2.0
requests-mock
sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3
testrepository>=0.0.17
testscenarios>=0.4,<0.5