summaryrefslogtreecommitdiffstats
path: root/nova/tests/api/openstack/compute
diff options
context:
space:
mode:
Diffstat (limited to 'nova/tests/api/openstack/compute')
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_cloudpipe.py11
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_floating_ips.py22
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_volume_types.py38
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_volumes.py70
-rw-r--r--nova/tests/api/openstack/compute/test_limits.py25
-rw-r--r--nova/tests/api/openstack/compute/test_server_actions.py41
-rw-r--r--nova/tests/api/openstack/compute/test_servers.py194
7 files changed, 354 insertions, 47 deletions
diff --git a/nova/tests/api/openstack/compute/contrib/test_cloudpipe.py b/nova/tests/api/openstack/compute/contrib/test_cloudpipe.py
index bb0eafe66..97b78f81e 100644
--- a/nova/tests/api/openstack/compute/contrib/test_cloudpipe.py
+++ b/nova/tests/api/openstack/compute/contrib/test_cloudpipe.py
@@ -152,25 +152,24 @@ class CloudpipesXMLSerializerTest(test.TestCase):
def test_index_serializer(self):
serializer = cloudpipe.CloudpipesTemplate()
exemplar = dict(cloudpipes=[
- dict(cloudpipe=dict(
+ dict(
project_id='1234',
public_ip='1.2.3.4',
public_port='321',
instance_id='1234-1234-1234-1234',
created_at=timeutils.isotime(),
- state='running')),
- dict(cloudpipe=dict(
+ state='running'),
+ dict(
project_id='4321',
public_ip='4.3.2.1',
public_port='123',
- state='pending'))])
+ state='pending')])
text = serializer.serialize(exemplar)
tree = etree.fromstring(text)
self.assertEqual('cloudpipes', tree.tag)
self.assertEqual(len(exemplar['cloudpipes']), len(tree))
for idx, cl_pipe in enumerate(tree):
- self.assertEqual('cloudpipe', cl_pipe.tag)
- kp_data = exemplar['cloudpipes'][idx]['cloudpipe']
+ kp_data = exemplar['cloudpipes'][idx]
for child in cl_pipe:
self.assertTrue(child.tag in kp_data)
self.assertEqual(child.text, kp_data[child.tag])
diff --git a/nova/tests/api/openstack/compute/contrib/test_floating_ips.py b/nova/tests/api/openstack/compute/contrib/test_floating_ips.py
index e9cfc2b9e..a789bbe96 100644
--- a/nova/tests/api/openstack/compute/contrib/test_floating_ips.py
+++ b/nova/tests/api/openstack/compute/contrib/test_floating_ips.py
@@ -197,6 +197,21 @@ class FloatingIpTest(test.TestCase):
'id': 2}]}
self.assertEqual(res_dict, response)
+ def test_floating_ip_release_nonexisting(self):
+ def fake_get_floating_ip(*args, **kwargs):
+ raise exception.FloatingIpNotFound(id=id)
+
+ self.stubs.Set(network.api.API, "get_floating_ip",
+ fake_get_floating_ip)
+
+ req = fakes.HTTPRequest.blank('/v2/fake/os-floating-ips/9876')
+ req.method = 'DELETE'
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 404)
+ expected_msg = ('{"itemNotFound": {"message": "Floating ip not found '
+ 'for id 9876", "code": 404}}')
+ self.assertEqual(res.body, expected_msg)
+
def test_floating_ip_show(self):
req = fakes.HTTPRequest.blank('/v2/fake/os-floating-ips/1')
res_dict = self.controller.show(req, 1)
@@ -214,8 +229,11 @@ class FloatingIpTest(test.TestCase):
req = fakes.HTTPRequest.blank('/v2/fake/os-floating-ips/9876')
- self.assertRaises(webob.exc.HTTPNotFound,
- self.controller.show, req, 9876)
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 404)
+ expected_msg = ('{"itemNotFound": {"message": "Floating ip not found '
+ 'for id 9876", "code": 404}}')
+ self.assertEqual(res.body, expected_msg)
def test_show_associated_floating_ip(self):
def get_floating_ip(self, context, id):
diff --git a/nova/tests/api/openstack/compute/contrib/test_volume_types.py b/nova/tests/api/openstack/compute/contrib/test_volume_types.py
index 4ad6297b8..af88cf601 100644
--- a/nova/tests/api/openstack/compute/contrib/test_volume_types.py
+++ b/nova/tests/api/openstack/compute/contrib/test_volume_types.py
@@ -151,16 +151,6 @@ class VolumeTypesApiTest(test.TestCase):
self.assertEqual(1, len(res_dict))
self.assertEqual('vol_type_1', res_dict['volume_type']['name'])
- def test_create_empty_body(self):
- self.stubs.Set(volume_types, 'create',
- return_volume_types_create)
- self.stubs.Set(volume_types, 'get_volume_type_by_name',
- return_volume_types_get_by_name)
-
- req = fakes.HTTPRequest.blank('/v2/fake/os-volume-types')
- self.assertRaises(webob.exc.HTTPUnprocessableEntity,
- self.controller.create, req, '')
-
class VolumeTypesSerializerTest(test.TestCase):
def _verify_volume_type(self, vtype, tree):
@@ -204,3 +194,31 @@ class VolumeTypesSerializerTest(test.TestCase):
tree = etree.fromstring(text)
self._verify_volume_type(vtype, tree)
+
+
+class VolumeTypesUnprocessableEntityTestCase(test.TestCase):
+ """
+ Tests of places we throw 422 Unprocessable Entity from
+ """
+
+ def setUp(self):
+ super(VolumeTypesUnprocessableEntityTestCase, self).setUp()
+ self.controller = volumetypes.VolumeTypesController()
+
+ def _unprocessable_volume_type_create(self, body):
+ req = fakes.HTTPRequest.blank('/v2/fake/os-volume-types')
+ req.method = 'POST'
+
+ self.assertRaises(webob.exc.HTTPUnprocessableEntity,
+ self.controller.create, req, body)
+
+ def test_create_volume_type_no_body(self):
+ self._unprocessable_volume_type_create(body=None)
+
+ def test_create_volume_type_missing_volume_type(self):
+ body = {'foo': {'a': 'b'}}
+ self._unprocessable_volume_type_create(body=body)
+
+ def test_create_volume_type_malformed_entity(self):
+ body = {'volume_type': 'string'}
+ self._unprocessable_volume_type_create(body=body)
diff --git a/nova/tests/api/openstack/compute/contrib/test_volumes.py b/nova/tests/api/openstack/compute/contrib/test_volumes.py
index 108ec8964..7ed04f1ad 100644
--- a/nova/tests/api/openstack/compute/contrib/test_volumes.py
+++ b/nova/tests/api/openstack/compute/contrib/test_volumes.py
@@ -175,15 +175,6 @@ class VolumeApiTest(test.TestCase):
self.assertEqual(resp_dict['volume']['availabilityZone'],
vol['availability_zone'])
- def test_volume_create_no_body(self):
- req = webob.Request.blank('/v2/fake/os-volumes')
- req.method = 'POST'
- req.body = jsonutils.dumps({})
- req.headers['content-type'] = 'application/json'
-
- resp = req.get_response(fakes.wsgi_app())
- self.assertEqual(resp.status_int, 422)
-
def test_volume_index(self):
req = webob.Request.blank('/v2/fake/os-volumes')
resp = req.get_response(fakes.wsgi_app())
@@ -566,3 +557,64 @@ class TestVolumeCreateRequestXMLDeserializer(test.TestCase):
}
self.maxDiff = None
self.assertEquals(request['body'], expected)
+
+
+class CommonUnprocessableEntityTestCase(object):
+
+ resource = None
+ entity_name = None
+ controller_cls = None
+ kwargs = {}
+
+ """
+ Tests of places we throw 422 Unprocessable Entity from
+ """
+
+ def setUp(self):
+ super(CommonUnprocessableEntityTestCase, self).setUp()
+ self.controller = self.controller_cls()
+
+ def _unprocessable_create(self, body):
+ req = fakes.HTTPRequest.blank('/v2/fake/' + self.resource)
+ req.method = 'POST'
+
+ kwargs = self.kwargs.copy()
+ kwargs['body'] = body
+ self.assertRaises(webob.exc.HTTPUnprocessableEntity,
+ self.controller.create, req, **kwargs)
+
+ def test_create_no_body(self):
+ self._unprocessable_create(body=None)
+
+ def test_create_missing_volume(self):
+ body = {'foo': {'a': 'b'}}
+ self._unprocessable_create(body=body)
+
+ def test_create_malformed_entity(self):
+ body = {self.entity_name: 'string'}
+ self._unprocessable_create(body=body)
+
+
+class UnprocessableVolumeTestCase(CommonUnprocessableEntityTestCase,
+ test.TestCase):
+
+ resource = 'os-volumes'
+ entity_name = 'volume'
+ controller_cls = volumes.VolumeController
+
+
+class UnprocessableAttachmentTestCase(CommonUnprocessableEntityTestCase,
+ test.TestCase):
+
+ resource = 'servers/' + FAKE_UUID + '/os-volume_attachments'
+ entity_name = 'volumeAttachment'
+ controller_cls = volumes.VolumeAttachmentController
+ kwargs = {'server_id': FAKE_UUID}
+
+
+class UnprocessableSnapshotTestCase(CommonUnprocessableEntityTestCase,
+ test.TestCase):
+
+ resource = 'os-snapshots'
+ entity_name = 'snapshot'
+ controller_cls = volumes.SnapshotController
diff --git a/nova/tests/api/openstack/compute/test_limits.py b/nova/tests/api/openstack/compute/test_limits.py
index 2a3038267..84c000035 100644
--- a/nova/tests/api/openstack/compute/test_limits.py
+++ b/nova/tests/api/openstack/compute/test_limits.py
@@ -124,6 +124,8 @@ class LimitsControllerTest(BaseLimitTestSuite):
'volumes': 5,
'key_pairs': 10,
'floating_ips': 10,
+ 'security_groups': 10,
+ 'security_group_rules': 20,
}
response = request.get_response(self.controller)
expected = {
@@ -172,6 +174,8 @@ class LimitsControllerTest(BaseLimitTestSuite):
"maxTotalVolumes": 5,
"maxTotalKeypairs": 10,
"maxTotalFloatingIps": 10,
+ "maxSecurityGroups": 10,
+ "maxSecurityGroupRules": 20,
},
},
}
@@ -272,6 +276,17 @@ class LimitsControllerTest(BaseLimitTestSuite):
}
self._test_index_absolute_limits_json(expected)
+ def test_index_absolute_security_groups(self):
+ self.absolute_limits = {
+ 'security_groups': 8,
+ 'security_group_rules': 16,
+ }
+ expected = {
+ 'maxSecurityGroups': 8,
+ 'maxSecurityGroupRules': 16,
+ }
+ self._test_index_absolute_limits_json(expected)
+
class TestLimiter(limits.Limiter):
pass
@@ -321,9 +336,13 @@ class LimitMiddlewareTest(BaseLimitTestSuite):
body = jsonutils.loads(response.body)
expected = "Only 1 GET request(s) can be made to * every minute."
- value = body["overLimitFault"]["details"].strip()
+ value = body["overLimit"]["details"].strip()
self.assertEqual(value, expected)
+ self.assertTrue("retryAfter" in body["overLimit"])
+ retryAfter = body["overLimit"]["retryAfter"]
+ self.assertEqual(retryAfter, "60")
+
def test_limited_request_xml(self):
"""Test a rate-limited (413) response as XML"""
request = webob.Request.blank("/")
@@ -338,6 +357,10 @@ class LimitMiddlewareTest(BaseLimitTestSuite):
root = minidom.parseString(response.body).childNodes[0]
expected = "Only 1 GET request(s) can be made to * every minute."
+ self.assertNotEqual(root.attributes.getNamedItem("retryAfter"), None)
+ retryAfter = root.attributes.getNamedItem("retryAfter").value
+ self.assertEqual(retryAfter, "60")
+
details = root.getElementsByTagName("details")
self.assertEqual(details.length, 1)
diff --git a/nova/tests/api/openstack/compute/test_server_actions.py b/nova/tests/api/openstack/compute/test_server_actions.py
index 1c7366caa..c765f1dd8 100644
--- a/nova/tests/api/openstack/compute/test_server_actions.py
+++ b/nova/tests/api/openstack/compute/test_server_actions.py
@@ -630,13 +630,13 @@ class ServerActionsControllerTest(test.TestCase):
image_service = nova.image.glance.get_default_image_service()
- bdm = [dict(snapshot_id=_fake_id('a'),
+ bdm = [dict(volume_id=_fake_id('a'),
volume_size=1,
- device_name='sda1',
+ device_name='vda',
delete_on_termination=False)]
props = dict(kernel_id=_fake_id('b'),
ramdisk_id=_fake_id('c'),
- root_device_name='/dev/sda1',
+ root_device_name='/dev/vda',
block_device_mapping=bdm)
original_image = dict(properties=props,
container_format='ami',
@@ -649,11 +649,10 @@ class ServerActionsControllerTest(test.TestCase):
class BDM(object):
def __init__(self):
self.no_device = None
- self.values = dict(snapshot_id=_fake_id('a'),
- volume_id=_fake_id('d'),
+ self.values = dict(volume_id=_fake_id('a'),
virtual_name=None,
volume_size=1,
- device_name='sda1',
+ device_name='vda',
delete_on_termination=False)
def __getattr__(self, name):
@@ -669,32 +668,38 @@ class ServerActionsControllerTest(test.TestCase):
instance = fakes.fake_instance_get(image_ref=original_image['id'],
vm_state=vm_states.ACTIVE,
- root_device_name='/dev/sda1')
+ root_device_name='/dev/vda')
self.stubs.Set(nova.db, 'instance_get_by_uuid', instance)
- def fake_volume_get(context, volume_id):
- return dict(id=volume_id,
- size=1,
- host='fake',
- display_description='fake')
+ volume = dict(id=_fake_id('a'),
+ size=1,
+ host='fake',
+ display_description='fake')
+ snapshot = dict(id=_fake_id('d'))
+ self.mox.StubOutWithMock(self.controller.compute_api, 'volume_api')
+ volume_api = self.controller.compute_api.volume_api
+ volume_api.get(mox.IgnoreArg(), volume['id']).AndReturn(volume)
+ volume_api.create_snapshot_force(mox.IgnoreArg(), volume,
+ mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(snapshot)
- self.stubs.Set(nova.db, 'volume_get', fake_volume_get)
+ self.mox.ReplayAll()
req = fakes.HTTPRequest.blank(self.url)
response = self.controller._action_create_image(req, FAKE_UUID, body)
location = response.headers['Location']
image_id = location.replace('http://localhost/v2/fake/images/', '')
- snapshot = image_service.show(None, image_id)
+ image = image_service.show(None, image_id)
- self.assertEquals(snapshot['name'], 'snapshot_of_volume_backed')
- properties = snapshot['properties']
+ self.assertEquals(image['name'], 'snapshot_of_volume_backed')
+ properties = image['properties']
self.assertEquals(properties['kernel_id'], _fake_id('b'))
self.assertEquals(properties['ramdisk_id'], _fake_id('c'))
- self.assertEquals(properties['root_device_name'], '/dev/sda1')
+ self.assertEquals(properties['root_device_name'], '/dev/vda')
bdms = properties['block_device_mapping']
self.assertEquals(len(bdms), 1)
- self.assertEquals(bdms[0]['device_name'], 'sda1')
+ self.assertEquals(bdms[0]['device_name'], 'vda')
+ self.assertEquals(bdms[0]['snapshot_id'], snapshot['id'])
for k in extra_properties.keys():
self.assertEquals(properties[k], extra_properties[k])
diff --git a/nova/tests/api/openstack/compute/test_servers.py b/nova/tests/api/openstack/compute/test_servers.py
index 1a2026900..b90866813 100644
--- a/nova/tests/api/openstack/compute/test_servers.py
+++ b/nova/tests/api/openstack/compute/test_servers.py
@@ -16,6 +16,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import base64
import datetime
import urlparse
@@ -94,6 +95,43 @@ class MockSetAdminPassword(object):
self.password = password
+class Base64ValidationTest(test.TestCase):
+ def setUp(self):
+ super(Base64ValidationTest, self).setUp()
+ self.ext_mgr = extensions.ExtensionManager()
+ self.ext_mgr.extensions = {}
+ self.controller = servers.Controller(self.ext_mgr)
+
+ def test_decode_base64(self):
+ value = "A random string"
+ result = self.controller._decode_base64(base64.b64encode(value))
+ self.assertEqual(result, value)
+
+ def test_decode_base64_binary(self):
+ value = "\x00\x12\x75\x99"
+ result = self.controller._decode_base64(base64.b64encode(value))
+ self.assertEqual(result, value)
+
+ def test_decode_base64_whitespace(self):
+ value = "A random string"
+ encoded = base64.b64encode(value)
+ white = "\n \n%s\t%s\n" % (encoded[:2], encoded[2:])
+ result = self.controller._decode_base64(white)
+ self.assertEqual(result, value)
+
+ def test_decode_base64_invalid(self):
+ invalid = "A random string"
+ result = self.controller._decode_base64(invalid)
+ self.assertEqual(result, None)
+
+ def test_decode_base64_illegal_bytes(self):
+ value = "A random string"
+ encoded = base64.b64encode(value)
+ white = ">\x01%s*%s()" % (encoded[:2], encoded[2:])
+ result = self.controller._decode_base64(white)
+ self.assertEqual(result, None)
+
+
class ServersControllerTest(test.TestCase):
def setUp(self):
@@ -1934,7 +1972,7 @@ class ServersControllerCreateTest(test.TestCase):
self._test_create_extra(params)
def test_create_instance_with_scheduler_hints_enabled(self):
- self.ext_mgr.extensions = {'os-scheduler-hints': 'fake'}
+ self.ext_mgr.extensions = {'OS-SCH-HNT': 'fake'}
hints = {'a': 'b'}
params = {'scheduler_hints': hints}
old_create = nova.compute.api.API.create
@@ -2765,6 +2803,43 @@ class ServersControllerCreateTest(test.TestCase):
# The fact that the action doesn't raise is enough validation
self.controller.create(req, body)
+ def test_create_instance_invalid_personality(self):
+
+ def fake_create(*args, **kwargs):
+ codec = 'utf8'
+ content = 'b25zLiINCg0KLVJpY2hhcmQgQ$$%QQmFjaA=='
+ start_position = 19
+ end_position = 20
+ msg = 'invalid start byte'
+ raise UnicodeDecodeError(codec, content, start_position,
+ end_position, msg)
+
+ self.stubs.Set(nova.compute.api.API,
+ 'create',
+ fake_create)
+ image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
+ flavor_ref = 'http://localhost/v2/flavors/3'
+ body = {
+ 'server': {
+ 'name': 'server_test',
+ 'imageRef': image_uuid,
+ 'flavorRef': flavor_ref,
+ 'personality': [
+ {
+ "path": "/etc/banner.txt",
+ "contents": "b25zLiINCg0KLVJpY2hhcmQgQ$$%QQmFjaA==",
+ },
+ ],
+ },
+ }
+
+ req = fakes.HTTPRequest.blank('/v2/fake/servers')
+ req.method = 'POST'
+ req.body = jsonutils.dumps(body)
+ req.headers["content-type"] = "application/json"
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.controller.create, req, body)
+
def test_create_location(self):
selfhref = 'http://localhost/v2/fake/servers/%s' % FAKE_UUID
bookhref = 'http://localhost/fake/servers/%s' % FAKE_UUID
@@ -3218,6 +3293,123 @@ class TestServerCreateRequestXMLDeserializer(test.TestCase):
}}
self.assertEquals(request['body'], expected)
+ def test_request_with_availability_zone(self):
+ serial_request = """
+ <server xmlns="http://docs.openstack.org/compute/api/v2"
+ name="new-server-test" imageRef="1" flavorRef="1"
+ availability_zone="some_zone:some_host">
+ </server>"""
+ request = self.deserializer.deserialize(serial_request)
+ expected = {"server": {
+ "name": "new-server-test",
+ "imageRef": "1",
+ "flavorRef": "1",
+ "availability_zone": "some_zone:some_host",
+ }}
+ self.assertEquals(request['body'], expected)
+
+ def test_request_with_multiple_create_args(self):
+ serial_request = """
+ <server xmlns="http://docs.openstack.org/compute/api/v2"
+ name="new-server-test" imageRef="1" flavorRef="1"
+ min_count="1" max_count="3" return_reservation_id="True">
+ </server>"""
+ request = self.deserializer.deserialize(serial_request)
+ expected = {"server": {
+ "name": "new-server-test",
+ "imageRef": "1",
+ "flavorRef": "1",
+ "min_count": "1",
+ "max_count": "3",
+ "return_reservation_id": True,
+ }}
+ self.assertEquals(request['body'], expected)
+
+ def test_request_with_disk_config(self):
+ serial_request = """
+ <server xmlns="http://docs.openstack.org/compute/api/v2"
+ xmlns:OS-DCF="http://docs.openstack.org/compute/ext/disk_config/api/v1.1"
+ name="new-server-test" imageRef="1" flavorRef="1"
+ OS-DCF:diskConfig="True">
+ </server>"""
+ request = self.deserializer.deserialize(serial_request)
+ expected = {"server": {
+ "name": "new-server-test",
+ "imageRef": "1",
+ "flavorRef": "1",
+ "OS-DCF:diskConfig": True,
+ }}
+ self.assertEquals(request['body'], expected)
+
+ def test_request_with_scheduler_hints(self):
+ serial_request = """
+ <server xmlns="http://docs.openstack.org/compute/api/v2"
+ xmlns:OS-SCH-HNT=
+ "http://docs.openstack.org/compute/ext/scheduler-hints/api/v2"
+ name="new-server-test" imageRef="1" flavorRef="1">
+ <OS-SCH-HNT:scheduler_hints>
+ <different_host>
+ 7329b667-50c7-46a6-b913-cb2a09dfeee0
+ </different_host>
+ <different_host>
+ f31efb24-34d2-43e1-8b44-316052956a39
+ </different_host>
+ </OS-SCH-HNT:scheduler_hints>
+ </server>"""
+ request = self.deserializer.deserialize(serial_request)
+ expected = {"server": {
+ "name": "new-server-test",
+ "imageRef": "1",
+ "flavorRef": "1",
+ "OS-SCH-HNT:scheduler_hints": {
+ "different_host": [
+ "7329b667-50c7-46a6-b913-cb2a09dfeee0",
+ "f31efb24-34d2-43e1-8b44-316052956a39",
+ ]
+ }
+ }}
+ self.assertEquals(request['body'], expected)
+
+ def test_request_with_block_device_mapping(self):
+ serial_request = """
+ <server xmlns="http://docs.openstack.org/compute/api/v2"
+ name="new-server-test" imageRef="1" flavorRef="1">
+ <block_device_mapping>
+ <mapping volume_id="7329b667-50c7-46a6-b913-cb2a09dfeee0"
+ device_name="/dev/vda" virtual_name="root"
+ delete_on_termination="False" />
+ <mapping snapshot_id="f31efb24-34d2-43e1-8b44-316052956a39"
+ device_name="/dev/vdb" virtual_name="ephemeral0"
+ delete_on_termination="False" />
+ <mapping device_name="/dev/vdc" no_device="True" />
+ </block_device_mapping>
+ </server>"""
+ request = self.deserializer.deserialize(serial_request)
+ expected = {"server": {
+ "name": "new-server-test",
+ "imageRef": "1",
+ "flavorRef": "1",
+ "block_device_mapping": [
+ {
+ "volume_id": "7329b667-50c7-46a6-b913-cb2a09dfeee0",
+ "device_name": "/dev/vda",
+ "virtual_name": "root",
+ "delete_on_termination": False,
+ },
+ {
+ "snapshot_id": "f31efb24-34d2-43e1-8b44-316052956a39",
+ "device_name": "/dev/vdb",
+ "virtual_name": "ephemeral0",
+ "delete_on_termination": False,
+ },
+ {
+ "device_name": "/dev/vdc",
+ "no_device": True,
+ },
+ ]
+ }}
+ self.assertEquals(request['body'], expected)
+
class TestAddressesXMLSerialization(test.TestCase):