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:
parent
788932633e
commit
8025c63e11
@ -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)
|
||||
|
107
shade/tests/unit/fixtures/catalog.json
Normal file
107
shade/tests/unit/fixtures/catalog.json
Normal 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"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
45
shade/tests/unit/fixtures/discovery.json
Normal file
45
shade/tests/unit/fixtures/discovery.json
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
64
shade/tests/unit/fixtures/image-version.json
Normal file
64
shade/tests/unit/fixtures/image-version.json
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user