diff options
| author | Chris Behrens <cbehrens@codestud.com> | 2011-07-07 05:56:15 -0700 |
|---|---|---|
| committer | Chris Behrens <cbehrens@codestud.com> | 2011-07-07 05:56:15 -0700 |
| commit | e817896c7aaf43822cf363a48fac60f013a5ecb0 (patch) | |
| tree | 0035dcc42ce5b2737d0a424975980cad4e8e0b77 /nova/tests | |
| parent | ace9aa5d91d839f66998c39a977857b7a7c466a4 (diff) | |
| parent | 44d4994eadc7413e27ebe60d7880278fc0365b6f (diff) | |
merged trunk
Diffstat (limited to 'nova/tests')
| -rw-r--r-- | nova/tests/api/openstack/test_extensions.py | 23 | ||||
| -rw-r--r-- | nova/tests/api/openstack/test_server_actions.py | 44 | ||||
| -rw-r--r-- | nova/tests/api/openstack/test_server_metadata.py | 62 | ||||
| -rw-r--r-- | nova/tests/api/openstack/test_servers.py | 26 | ||||
| -rw-r--r-- | nova/tests/image/test_glance.py | 36 | ||||
| -rw-r--r-- | nova/tests/test_api.py | 36 | ||||
| -rw-r--r-- | nova/tests/test_block_device.py | 87 | ||||
| -rw-r--r-- | nova/tests/test_cloud.py | 157 | ||||
| -rw-r--r-- | nova/tests/test_compute.py | 40 | ||||
| -rw-r--r-- | nova/tests/test_libvirt.py | 37 | ||||
| -rw-r--r-- | nova/tests/test_metadata.py | 1 | ||||
| -rw-r--r-- | nova/tests/test_virt.py | 83 |
12 files changed, 568 insertions, 64 deletions
diff --git a/nova/tests/api/openstack/test_extensions.py b/nova/tests/api/openstack/test_extensions.py index 409fa0e71..49f0ea8b3 100644 --- a/nova/tests/api/openstack/test_extensions.py +++ b/nova/tests/api/openstack/test_extensions.py @@ -18,7 +18,7 @@ import json import os.path import webob -from xml.etree import ElementTree +from lxml import etree from nova import context from nova import test @@ -26,6 +26,7 @@ from nova.api import openstack from nova.api.openstack import extensions from nova.api.openstack import flavors from nova.api.openstack import wsgi +from nova.api.openstack import xmlutil from nova.tests.api.openstack import fakes NS = "{http://docs.openstack.org/compute/api/v1.1}" @@ -138,7 +139,7 @@ class ExtensionControllerTest(test.TestCase): self.assertEqual(200, response.status_int) print response.body - root = ElementTree.XML(response.body) + root = etree.XML(response.body) self.assertEqual(root.tag.split('extensions')[0], NS) # Make sure we have all the extensions. @@ -154,6 +155,8 @@ class ExtensionControllerTest(test.TestCase): self.assertEqual(fox_ext.findtext('{0}description'.format(NS)), 'The Fox In Socks Extension') + xmlutil.validate_schema(root, 'extensions') + def test_get_extension_xml(self): app = openstack.APIRouterV11() ext_midware = extensions.ExtensionMiddleware(app) @@ -161,9 +164,10 @@ class ExtensionControllerTest(test.TestCase): request.accept = "application/xml" response = request.get_response(ext_midware) self.assertEqual(200, response.status_int) - print response.body + xml = response.body + print xml - root = ElementTree.XML(response.body) + root = etree.XML(xml) self.assertEqual(root.tag.split('extension')[0], NS) self.assertEqual(root.get('alias'), 'FOXNSOX') self.assertEqual(root.get('name'), 'Fox In Socks') @@ -173,6 +177,8 @@ class ExtensionControllerTest(test.TestCase): self.assertEqual(root.findtext('{0}description'.format(NS)), 'The Fox In Socks Extension') + xmlutil.validate_schema(root, 'extension') + class ResourceExtensionTest(test.TestCase): @@ -352,7 +358,8 @@ class ExtensionsXMLSerializerTest(test.TestCase): } xml = serializer.serialize(data, 'show') - root = ElementTree.XML(xml) + print xml + root = etree.XML(xml) ext_dict = data['extension'] self.assertEqual(root.findtext('{0}description'.format(NS)), ext_dict['description']) @@ -366,6 +373,8 @@ class ExtensionsXMLSerializerTest(test.TestCase): for key, value in link.items(): self.assertEqual(link_nodes[i].get(key), value) + xmlutil.validate_schema(root, 'extension') + def test_serialize_extensions(self): serializer = extensions.ExtensionsXMLSerializer() data = { @@ -413,7 +422,7 @@ class ExtensionsXMLSerializerTest(test.TestCase): xml = serializer.serialize(data, 'index') print xml - root = ElementTree.XML(xml) + root = etree.XML(xml) ext_elems = root.findall('{0}extension'.format(NS)) self.assertEqual(len(ext_elems), 2) for i, ext_elem in enumerate(ext_elems): @@ -429,3 +438,5 @@ class ExtensionsXMLSerializerTest(test.TestCase): for i, link in enumerate(ext_dict['links']): for key, value in link.items(): self.assertEqual(link_nodes[i].get(key), value) + + xmlutil.validate_schema(root, 'extensions') diff --git a/nova/tests/api/openstack/test_server_actions.py b/nova/tests/api/openstack/test_server_actions.py index bf18bc1b0..717e11c00 100644 --- a/nova/tests/api/openstack/test_server_actions.py +++ b/nova/tests/api/openstack/test_server_actions.py @@ -9,6 +9,7 @@ import webob from nova import context from nova import db from nova import utils +from nova import flags from nova.api.openstack import create_instance_helper from nova.compute import instance_types from nova.compute import power_state @@ -18,6 +19,9 @@ from nova.tests.api.openstack import common from nova.tests.api.openstack import fakes +FLAGS = flags.FLAGS + + def return_server_by_id(context, id): return _get_instance() @@ -370,6 +374,26 @@ class ServerActionsTest(test.TestCase): self.assertEqual(202, response.status_int) self.assertTrue(response.headers['Location']) + def test_create_backup_with_too_much_metadata(self): + self.flags(allow_admin_api=True) + + body = { + 'createBackup': { + 'name': 'Backup 1', + 'backup_type': 'daily', + 'rotation': 1, + 'metadata': {'123': 'asdf'}, + }, + } + for num in range(FLAGS.quota_metadata_items + 1): + body['createBackup']['metadata']['foo%i' % num] = "bar" + req = webob.Request.blank('/v1.0/servers/1/action') + req.method = 'POST' + req.body = json.dumps(body) + req.headers["content-type"] = "application/json" + response = req.get_response(fakes.wsgi_app()) + self.assertEqual(400, response.status_int) + def test_create_backup_no_name(self): """Name is required for backups""" self.flags(allow_admin_api=True) @@ -809,6 +833,22 @@ class ServerActionsTestV11(test.TestCase): location = response.headers['Location'] self.assertEqual('http://localhost/v1.1/images/123', location) + def test_create_image_with_too_much_metadata(self): + body = { + 'createImage': { + 'name': 'Snapshot 1', + 'metadata': {}, + }, + } + for num in range(FLAGS.quota_metadata_items + 1): + body['createImage']['metadata']['foo%i' % num] = "bar" + req = webob.Request.blank('/v1.1/servers/1/action') + req.method = 'POST' + req.body = json.dumps(body) + req.headers["content-type"] = "application/json" + response = req.get_response(fakes.wsgi_app()) + self.assertEqual(400, response.status_int) + def test_create_image_no_name(self): body = { 'createImage': {}, @@ -943,9 +983,7 @@ class TestServerActionXMLDeserializerV11(test.TestCase): flavorRef="http://localhost/flavors/3"/>""" request = self.deserializer.deserialize(serial_request, 'action') expected = { - "resize": { - "flavorRef": "http://localhost/flavors/3" - }, + "resize": {"flavorRef": "http://localhost/flavors/3"}, } self.assertEquals(request['body'], expected) diff --git a/nova/tests/api/openstack/test_server_metadata.py b/nova/tests/api/openstack/test_server_metadata.py index 08a6a062a..ec446f0f0 100644 --- a/nova/tests/api/openstack/test_server_metadata.py +++ b/nova/tests/api/openstack/test_server_metadata.py @@ -29,11 +29,11 @@ import nova.wsgi FLAGS = flags.FLAGS -def return_create_instance_metadata_max(context, server_id, metadata): +def return_create_instance_metadata_max(context, server_id, metadata, delete): return stub_max_server_metadata() -def return_create_instance_metadata(context, server_id, metadata): +def return_create_instance_metadata(context, server_id, metadata, delete): return stub_server_metadata() @@ -202,21 +202,30 @@ class ServerMetaDataTest(test.TestCase): self.assertEqual(404, res.status_int) def test_create(self): - self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create', + self.stubs.Set(nova.db.api, 'instance_metadata_get', + return_server_metadata) + self.stubs.Set(nova.db.api, 'instance_metadata_update', return_create_instance_metadata) req = webob.Request.blank('/v1.1/servers/1/metadata') req.method = 'POST' req.content_type = "application/json" - expected = {"metadata": {"key1": "value1"}} - req.body = json.dumps(expected) + input = {"metadata": {"key9": "value9"}} + req.body = json.dumps(input) res = req.get_response(fakes.wsgi_app()) self.assertEqual(200, res.status_int) res_dict = json.loads(res.body) - self.assertEqual(expected, res_dict) + input['metadata'].update({ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }) + self.assertEqual(input, res_dict) def test_create_xml(self): - self.stubs.Set(nova.db.api, "instance_metadata_update_or_create", + self.stubs.Set(nova.db.api, 'instance_metadata_get', + return_server_metadata) + self.stubs.Set(nova.db.api, "instance_metadata_update", return_create_instance_metadata) req = webob.Request.blank("/v1.1/servers/1/metadata") req.method = "POST" @@ -225,22 +234,29 @@ class ServerMetaDataTest(test.TestCase): request_metadata = minidom.parseString(""" <metadata xmlns="http://docs.openstack.org/compute/api/v1.1"> - <meta key="key3">value3</meta> - <meta key="key2">value2</meta> - <meta key="key1">value1</meta> + <meta key="key5">value5</meta> </metadata> """.replace(" ", "").replace("\n", "")) req.body = str(request_metadata.toxml()) response = req.get_response(fakes.wsgi_app()) + expected_metadata = minidom.parseString(""" + <metadata xmlns="http://docs.openstack.org/compute/api/v1.1"> + <meta key="key3">value3</meta> + <meta key="key2">value2</meta> + <meta key="key1">value1</meta> + <meta key="key5">value5</meta> + </metadata> + """.replace(" ", "").replace("\n", "")) + self.assertEqual(200, response.status_int) actual_metadata = minidom.parseString(response.body) - self.assertEqual(request_metadata.toxml(), actual_metadata.toxml()) + self.assertEqual(expected_metadata.toxml(), actual_metadata.toxml()) def test_create_empty_body(self): - self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create', + self.stubs.Set(nova.db.api, 'instance_metadata_update', return_create_instance_metadata) req = webob.Request.blank('/v1.1/servers/1/metadata') req.method = 'POST' @@ -258,7 +274,7 @@ class ServerMetaDataTest(test.TestCase): self.assertEqual(404, res.status_int) def test_update_all(self): - self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create', + self.stubs.Set(nova.db.api, 'instance_metadata_update', return_create_instance_metadata) req = webob.Request.blank('/v1.1/servers/1/metadata') req.method = 'PUT' @@ -276,7 +292,7 @@ class ServerMetaDataTest(test.TestCase): self.assertEqual(expected, res_dict) def test_update_all_empty_container(self): - self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create', + self.stubs.Set(nova.db.api, 'instance_metadata_update', return_create_instance_metadata) req = webob.Request.blank('/v1.1/servers/1/metadata') req.method = 'PUT' @@ -289,7 +305,7 @@ class ServerMetaDataTest(test.TestCase): self.assertEqual(expected, res_dict) def test_update_all_malformed_container(self): - self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create', + self.stubs.Set(nova.db.api, 'instance_metadata_update', return_create_instance_metadata) req = webob.Request.blank('/v1.1/servers/1/metadata') req.method = 'PUT' @@ -300,7 +316,7 @@ class ServerMetaDataTest(test.TestCase): self.assertEqual(400, res.status_int) def test_update_all_malformed_data(self): - self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create', + self.stubs.Set(nova.db.api, 'instance_metadata_update', return_create_instance_metadata) req = webob.Request.blank('/v1.1/servers/1/metadata') req.method = 'PUT' @@ -320,7 +336,7 @@ class ServerMetaDataTest(test.TestCase): self.assertEqual(404, res.status_int) def test_update_item(self): - self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create', + self.stubs.Set(nova.db.api, 'instance_metadata_update', return_create_instance_metadata) req = webob.Request.blank('/v1.1/servers/1/metadata/key1') req.method = 'PUT' @@ -334,7 +350,7 @@ class ServerMetaDataTest(test.TestCase): self.assertEqual(expected, res_dict) def test_update_item_xml(self): - self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create', + self.stubs.Set(nova.db.api, 'instance_metadata_update', return_create_instance_metadata) req = webob.Request.blank('/v1.1/servers/1/metadata/key9') req.method = 'PUT' @@ -361,7 +377,7 @@ class ServerMetaDataTest(test.TestCase): self.assertEqual(404, res.status_int) def test_update_item_empty_body(self): - self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create', + self.stubs.Set(nova.db.api, 'instance_metadata_update', return_create_instance_metadata) req = webob.Request.blank('/v1.1/servers/1/metadata/key1') req.method = 'PUT' @@ -370,7 +386,7 @@ class ServerMetaDataTest(test.TestCase): self.assertEqual(400, res.status_int) def test_update_item_too_many_keys(self): - self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create', + self.stubs.Set(nova.db.api, 'instance_metadata_update', return_create_instance_metadata) req = webob.Request.blank('/v1.1/servers/1/metadata/key1') req.method = 'PUT' @@ -380,7 +396,7 @@ class ServerMetaDataTest(test.TestCase): self.assertEqual(400, res.status_int) def test_update_item_body_uri_mismatch(self): - self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create', + self.stubs.Set(nova.db.api, 'instance_metadata_update', return_create_instance_metadata) req = webob.Request.blank('/v1.1/servers/1/metadata/bad') req.method = 'PUT' @@ -390,7 +406,7 @@ class ServerMetaDataTest(test.TestCase): self.assertEqual(400, res.status_int) def test_too_many_metadata_items_on_create(self): - self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create', + self.stubs.Set(nova.db.api, 'instance_metadata_update', return_create_instance_metadata) data = {"metadata": {}} for num in range(FLAGS.quota_metadata_items + 1): @@ -404,7 +420,7 @@ class ServerMetaDataTest(test.TestCase): self.assertEqual(400, res.status_int) def test_to_many_metadata_items_on_update_item(self): - self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create', + self.stubs.Set(nova.db.api, 'instance_metadata_update', return_create_instance_metadata_max) req = webob.Request.blank('/v1.1/servers/1/metadata/key1') req.method = 'PUT' diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index cfb1f9382..b6342ae2f 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -1431,7 +1431,7 @@ class ServersTest(test.TestCase): res = req.get_response(fakes.wsgi_app()) - self.assertEqual(res.status_int, 200) + self.assertEqual(res.status_int, 202) server = json.loads(res.body)['server'] self.assertEqual(16, len(server['adminPass'])) self.assertEqual('server_test', server['name']) @@ -1628,7 +1628,7 @@ class ServersTest(test.TestCase): res = req.get_response(fakes.wsgi_app()) - self.assertEqual(res.status_int, 200) + self.assertEqual(res.status_int, 202) server = json.loads(res.body)['server'] self.assertEqual(16, len(server['adminPass'])) self.assertEqual(1, server['id']) @@ -1723,7 +1723,7 @@ class ServersTest(test.TestCase): res = req.get_response(fakes.wsgi_app()) - self.assertEqual(res.status_int, 200) + self.assertEqual(res.status_int, 202) server = json.loads(res.body)['server'] self.assertEqual(expected_flavor, server['flavor']) self.assertEqual(expected_image, server['image']) @@ -1768,7 +1768,7 @@ class ServersTest(test.TestCase): req.body = json.dumps(body) req.headers['content-type'] = "application/json" res = req.get_response(fakes.wsgi_app()) - self.assertEqual(res.status_int, 200) + self.assertEqual(res.status_int, 202) server = json.loads(res.body)['server'] self.assertEqual(server['adminPass'], body['server']['adminPass']) @@ -2786,13 +2786,13 @@ class TestServerInstanceCreation(test.TestCase): def test_create_instance_with_no_personality(self): request, response, injected_files = \ self._create_instance_with_personality_json(personality=None) - self.assertEquals(response.status_int, 200) + self.assertEquals(response.status_int, 202) self.assertEquals(injected_files, []) def test_create_instance_with_no_personality_xml(self): request, response, injected_files = \ self._create_instance_with_personality_xml(personality=None) - self.assertEquals(response.status_int, 200) + self.assertEquals(response.status_int, 202) self.assertEquals(injected_files, []) def test_create_instance_with_personality(self): @@ -2802,7 +2802,7 @@ class TestServerInstanceCreation(test.TestCase): personality = [(path, b64contents)] request, response, injected_files = \ self._create_instance_with_personality_json(personality) - self.assertEquals(response.status_int, 200) + self.assertEquals(response.status_int, 202) self.assertEquals(injected_files, [(path, contents)]) def test_create_instance_with_personality_xml(self): @@ -2812,7 +2812,7 @@ class TestServerInstanceCreation(test.TestCase): personality = [(path, b64contents)] request, response, injected_files = \ self._create_instance_with_personality_xml(personality) - self.assertEquals(response.status_int, 200) + self.assertEquals(response.status_int, 202) self.assertEquals(injected_files, [(path, contents)]) def test_create_instance_with_personality_no_path(self): @@ -2875,7 +2875,7 @@ class TestServerInstanceCreation(test.TestCase): request = self._get_create_request_json(body_dict) compute_api, response = \ self._run_create_instance_with_mock_compute_api(request) - self.assertEquals(response.status_int, 200) + self.assertEquals(response.status_int, 202) def test_create_instance_with_three_personalities(self): files = [ @@ -2888,7 +2888,7 @@ class TestServerInstanceCreation(test.TestCase): personality.append((path, base64.b64encode(content))) request, response, injected_files = \ self._create_instance_with_personality_json(personality) - self.assertEquals(response.status_int, 200) + self.assertEquals(response.status_int, 202) self.assertEquals(injected_files, files) def test_create_instance_personality_empty_content(self): @@ -2897,13 +2897,13 @@ class TestServerInstanceCreation(test.TestCase): personality = [(path, contents)] request, response, injected_files = \ self._create_instance_with_personality_json(personality) - self.assertEquals(response.status_int, 200) + self.assertEquals(response.status_int, 202) self.assertEquals(injected_files, [(path, contents)]) def test_create_instance_admin_pass_json(self): request, response, dummy = \ self._create_instance_with_personality_json(None) - self.assertEquals(response.status_int, 200) + self.assertEquals(response.status_int, 202) response = json.loads(response.body) self.assertTrue('adminPass' in response['server']) self.assertEqual(16, len(response['server']['adminPass'])) @@ -2911,7 +2911,7 @@ class TestServerInstanceCreation(test.TestCase): def test_create_instance_admin_pass_xml(self): request, response, dummy = \ self._create_instance_with_personality_xml(None) - self.assertEquals(response.status_int, 200) + self.assertEquals(response.status_int, 202) dom = minidom.parseString(response.body) server = dom.childNodes[0] self.assertEquals(server.nodeName, 'server') diff --git a/nova/tests/image/test_glance.py b/nova/tests/image/test_glance.py index 5a40f578f..0ff508ffa 100644 --- a/nova/tests/image/test_glance.py +++ b/nova/tests/image/test_glance.py @@ -235,3 +235,39 @@ class TestMutatorDateTimeTests(BaseGlanceTest): 'updated_at': None, 'deleted_at': None} return fixture + + +class TestGlanceSerializer(unittest.TestCase): + def test_serialize(self): + metadata = {'name': 'image1', + 'is_public': True, + 'foo': 'bar', + 'properties': { + 'prop1': 'propvalue1', + 'mappings': [ + {'virtual': 'aaa', + 'device': 'bbb'}, + {'virtual': 'xxx', + 'device': 'yyy'}], + 'block_device_mapping': [ + {'virtual_device': 'fake', + 'device_name': '/dev/fake'}, + {'virtual_device': 'ephemeral0', + 'device_name': '/dev/fake0'}]}} + + converted_expected = { + 'name': 'image1', + 'is_public': True, + 'foo': 'bar', + 'properties': { + 'prop1': 'propvalue1', + 'mappings': + '[{"device": "bbb", "virtual": "aaa"}, ' + '{"device": "yyy", "virtual": "xxx"}]', + 'block_device_mapping': + '[{"virtual_device": "fake", "device_name": "/dev/fake"}, ' + '{"virtual_device": "ephemeral0", ' + '"device_name": "/dev/fake0"}]'}} + converted = glance._convert_to_string(metadata) + self.assertEqual(converted, converted_expected) + self.assertEqual(glance._convert_from_string(converted), metadata) diff --git a/nova/tests/test_api.py b/nova/tests/test_api.py index d9b1d39c9..2011ae756 100644 --- a/nova/tests/test_api.py +++ b/nova/tests/test_api.py @@ -27,6 +27,7 @@ import random import StringIO import webob +from nova import block_device from nova import context from nova import exception from nova import test @@ -147,10 +148,12 @@ class Ec2utilsTestCase(test.TestCase): properties0 = {'mappings': mappings} properties1 = {'root_device_name': '/dev/sdb', 'mappings': mappings} - root_device_name = ec2utils.properties_root_device_name(properties0) + root_device_name = block_device.properties_root_device_name( + properties0) self.assertEqual(root_device_name, '/dev/sda1') - root_device_name = ec2utils.properties_root_device_name(properties1) + root_device_name = block_device.properties_root_device_name( + properties1) self.assertEqual(root_device_name, '/dev/sdb') def test_mapping_prepend_dev(self): @@ -184,7 +187,7 @@ class Ec2utilsTestCase(test.TestCase): 'device': '/dev/sdc1'}, {'virtual': 'ephemeral1', 'device': '/dev/sdc1'}] - self.assertDictListMatch(ec2utils.mappings_prepend_dev(mappings), + self.assertDictListMatch(block_device.mappings_prepend_dev(mappings), expected_result) @@ -336,6 +339,33 @@ class ApiEc2TestCase(test.TestCase): self.ec2.delete_security_group(security_group_name) + def test_group_name_valid_chars_security_group(self): + """ Test that we sanely handle invalid security group names. + API Spec states we should only accept alphanumeric characters, + spaces, dashes, and underscores. """ + self.expect_http() + self.mox.ReplayAll() + + # Test block group_name of non alphanumeric characters, spaces, + # dashes, and underscores. + security_group_name = "aa #^% -=99" + + self.assertRaises(EC2ResponseError, self.ec2.create_security_group, + security_group_name, 'test group') + + def test_group_name_valid_length_security_group(self): + """Test that we sanely handle invalid security group names. + API Spec states that the length should not exceed 255 chars """ + self.expect_http() + self.mox.ReplayAll() + + # Test block group_name > 255 chars + security_group_name = "".join(random.choice("poiuytrewqasdfghjklmnbvc") + for x in range(random.randint(256, 266))) + + self.assertRaises(EC2ResponseError, self.ec2.create_security_group, + security_group_name, 'test group') + def test_authorize_revoke_security_group_cidr(self): """ Test that we can add and remove CIDR based rules diff --git a/nova/tests/test_block_device.py b/nova/tests/test_block_device.py new file mode 100644 index 000000000..b8e9b35e2 --- /dev/null +++ b/nova/tests/test_block_device.py @@ -0,0 +1,87 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 Isaku Yamahata +# All Rights Reserved. +# +# 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. + +""" +Tests for Block Device utility functions. +""" + +from nova import block_device +from nova import test + + +class BlockDeviceTestCase(test.TestCase): + def test_properties(self): + root_device0 = '/dev/sda' + root_device1 = '/dev/sdb' + mappings = [{'virtual': 'root', + 'device': root_device0}] + + properties0 = {'mappings': mappings} + properties1 = {'mappings': mappings, + 'root_device_name': root_device1} + + self.assertEqual(block_device.properties_root_device_name({}), None) + self.assertEqual( + block_device.properties_root_device_name(properties0), + root_device0) + self.assertEqual( + block_device.properties_root_device_name(properties1), + root_device1) + + def test_ephemeral(self): + self.assertFalse(block_device.is_ephemeral('ephemeral')) + self.assertTrue(block_device.is_ephemeral('ephemeral0')) + self.assertTrue(block_device.is_ephemeral('ephemeral1')) + self.assertTrue(block_device.is_ephemeral('ephemeral11')) + self.assertFalse(block_device.is_ephemeral('root')) + self.assertFalse(block_device.is_ephemeral('swap')) + self.assertFalse(block_device.is_ephemeral('/dev/sda1')) + + self.assertEqual(block_device.ephemeral_num('ephemeral0'), 0) + self.assertEqual(block_device.ephemeral_num('ephemeral1'), 1) + self.assertEqual(block_device.ephemeral_num('ephemeral11'), 11) + + self.assertFalse(block_device.is_swap_or_ephemeral('ephemeral')) + self.assertTrue(block_device.is_swap_or_ephemeral('ephemeral0')) + self.assertTrue(block_device.is_swap_or_ephemeral('ephemeral1')) + self.assertTrue(block_device.is_swap_or_ephemeral('swap')) + self.assertFalse(block_device.is_swap_or_ephemeral('root')) + self.assertFalse(block_device.is_swap_or_ephemeral('/dev/sda1')) + + def test_mappings_prepend_dev(self): + mapping = [ + {'virtual': 'ami', 'device': '/dev/sda'}, + {'virtual': 'root', 'device': 'sda'}, + {'virtual': 'ephemeral0', 'device': 'sdb'}, + {'virtual': 'swap', 'device': 'sdc'}, + {'virtual': 'ephemeral1', 'device': 'sdd'}, + {'virtual': 'ephemeral2', 'device': 'sde'}] + + expected = [ + {'virtual': 'ami', 'device': '/dev/sda'}, + {'virtual': 'root', 'device': 'sda'}, + {'virtual': 'ephemeral0', 'device': '/dev/sdb'}, + {'virtual': 'swap', 'device': '/dev/sdc'}, + {'virtual': 'ephemeral1', 'device': '/dev/sdd'}, + {'virtual': 'ephemeral2', 'device': '/dev/sde'}] + + prepended = block_device.mappings_prepend_dev(mapping) + self.assertEqual(prepended.sort(), expected.sort()) + + def test_strip_dev(self): + self.assertEqual(block_device.strip_dev('/dev/sda'), 'sda') + self.assertEqual(block_device.strip_dev('sda'), 'sda') diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index e891fa197..b2afc53c9 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -17,6 +17,8 @@ # under the License. import mox +import functools + from base64 import b64decode from M2Crypto import BIO from M2Crypto import RSA @@ -892,13 +894,16 @@ class CloudTestCase(test.TestCase): def test_modify_image_attribute(self): modify_image_attribute = self.cloud.modify_image_attribute + fake_metadata = {'id': 1, 'container_format': 'ami', + 'properties': {'kernel_id': 1, 'ramdisk_id': 1, + 'type': 'machine'}, 'is_public': False} + def fake_show(meh, context, id): - return {'id': 1, 'container_format': 'ami', - 'properties': {'kernel_id': 1, 'ramdisk_id': 1, - 'type': 'machine'}, 'is_public': False} + return fake_metadata def fake_update(meh, context, image_id, metadata, data=None): - return metadata + fake_metadata.update(metadata) + return fake_metadata self.stubs.Set(fake._FakeImageService, 'show', fake_show) self.stubs.Set(fake._FakeImageService, 'show_by_name', fake_show) @@ -1464,3 +1469,147 @@ class CloudTestCase(test.TestCase): # TODO(yamahata): clean up snapshot created by CreateImage. self._restart_compute_service() + + @staticmethod + def _fake_bdm_get(ctxt, id): + return [{'volume_id': 87654321, + 'snapshot_id': None, + 'no_device': None, + 'virtual_name': None, + 'delete_on_termination': True, + 'device_name': '/dev/sdh'}, + {'volume_id': None, + 'snapshot_id': 98765432, + 'no_device': None, + 'virtual_name': None, + 'delete_on_termination': True, + 'device_name': '/dev/sdi'}, + {'volume_id': None, + 'snapshot_id': None, + 'no_device': True, + 'virtual_name': None, + 'delete_on_termination': None, + 'device_name': None}, + {'volume_id': None, + 'snapshot_id': None, + 'no_device': None, + 'virtual_name': 'ephemeral0', + 'delete_on_termination': None, + 'device_name': '/dev/sdb'}, + {'volume_id': None, + 'snapshot_id': None, + 'no_device': None, + 'virtual_name': 'swap', + 'delete_on_termination': None, + 'device_name': '/dev/sdc'}, + {'volume_id': None, + 'snapshot_id': None, + 'no_device': None, + 'virtual_name': 'ephemeral1', + 'delete_on_termination': None, + 'device_name': '/dev/sdd'}, + {'volume_id': None, + 'snapshot_id': None, + 'no_device': None, + 'virtual_name': 'ephemeral2', + 'delete_on_termination': None, + 'device_name': '/dev/sd3'}, + ] + + def test_get_instance_mapping(self): + """Make sure that _get_instance_mapping works""" + ctxt = None + instance_ref0 = {'id': 0, + 'root_device_name': None} + instance_ref1 = {'id': 0, + 'root_device_name': '/dev/sda1'} + + self.stubs.Set(db, 'block_device_mapping_get_all_by_instance', + self._fake_bdm_get) + + expected = {'ami': 'sda1', + 'root': '/dev/sda1', + 'ephemeral0': '/dev/sdb', + 'swap': '/dev/sdc', + 'ephemeral1': '/dev/sdd', + 'ephemeral2': '/dev/sd3'} + + self.assertEqual(self.cloud._format_instance_mapping(ctxt, + instance_ref0), + cloud._DEFAULT_MAPPINGS) + self.assertEqual(self.cloud._format_instance_mapping(ctxt, + instance_ref1), + expected) + + def test_describe_instance_attribute(self): + """Make sure that describe_instance_attribute works""" + self.stubs.Set(db, 'block_device_mapping_get_all_by_instance', + self._fake_bdm_get) + + def fake_get(ctxt, instance_id): + return { + 'id': 0, + 'root_device_name': '/dev/sdh', + 'security_groups': [{'name': 'fake0'}, {'name': 'fake1'}], + 'state_description': 'stopping', + 'instance_type': {'name': 'fake_type'}, + 'kernel_id': 1, + 'ramdisk_id': 2, + 'user_data': 'fake-user data', + } + self.stubs.Set(self.cloud.compute_api, 'get', fake_get) + + def fake_volume_get(ctxt, volume_id, session=None): + if volume_id == 87654321: + return {'id': volume_id, + 'attach_time': '13:56:24', + 'status': 'in-use'} + raise exception.VolumeNotFound(volume_id=volume_id) + self.stubs.Set(db.api, 'volume_get', fake_volume_get) + + get_attribute = functools.partial( + self.cloud.describe_instance_attribute, + self.context, 'i-12345678') + + bdm = get_attribute('blockDeviceMapping') + bdm['blockDeviceMapping'].sort() + + expected_bdm = {'instance_id': 'i-12345678', + 'rootDeviceType': 'ebs', + 'blockDeviceMapping': [ + {'deviceName': '/dev/sdh', + 'ebs': {'status': 'in-use', + 'deleteOnTermination': True, + 'volumeId': 87654321, + 'attachTime': '13:56:24'}}]} + expected_bdm['blockDeviceMapping'].sort() + self.assertEqual(bdm, expected_bdm) + # NOTE(yamahata): this isn't supported + # get_attribute('disableApiTermination') + groupSet = get_attribute('groupSet') + groupSet['groupSet'].sort() + expected_groupSet = {'instance_id': 'i-12345678', + 'groupSet': [{'groupId': 'fake0'}, + {'groupId': 'fake1'}]} + expected_groupSet['groupSet'].sort() + self.assertEqual(groupSet, expected_groupSet) + self.assertEqual(get_attribute('instanceInitiatedShutdownBehavior'), + {'instance_id': 'i-12345678', + 'instanceInitiatedShutdownBehavior': 'stop'}) + self.assertEqual(get_attribute('instanceType'), + {'instance_id': 'i-12345678', + 'instanceType': 'fake_type'}) + self.assertEqual(get_attribute('kernel'), + {'instance_id': 'i-12345678', + 'kernel': 'aki-00000001'}) + self.assertEqual(get_attribute('ramdisk'), + {'instance_id': 'i-12345678', + 'ramdisk': 'ari-00000002'}) + self.assertEqual(get_attribute('rootDeviceName'), + {'instance_id': 'i-12345678', + 'rootDeviceName': '/dev/sdh'}) + # NOTE(yamahata): this isn't supported + # get_attribute('sourceDestCheck') + self.assertEqual(get_attribute('userData'), + {'instance_id': 'i-12345678', + 'userData': '}\xa9\x1e\xba\xc7\xabu\xabZ'}) diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py index 18ec08597..80f7ff489 100644 --- a/nova/tests/test_compute.py +++ b/nova/tests/test_compute.py @@ -1333,15 +1333,17 @@ class ComputeTestCase(test.TestCase): return bdm def test_update_block_device_mapping(self): + swap_size = 1 + instance_type = {'swap': swap_size} instance_id = self._create_instance() mappings = [ {'virtual': 'ami', 'device': 'sda1'}, {'virtual': 'root', 'device': '/dev/sda1'}, - {'virtual': 'swap', 'device': 'sdb1'}, - {'virtual': 'swap', 'device': 'sdb2'}, - {'virtual': 'swap', 'device': 'sdb3'}, {'virtual': 'swap', 'device': 'sdb4'}, + {'virtual': 'swap', 'device': 'sdb3'}, + {'virtual': 'swap', 'device': 'sdb2'}, + {'virtual': 'swap', 'device': 'sdb1'}, {'virtual': 'ephemeral0', 'device': 'sdc1'}, {'virtual': 'ephemeral1', 'device': 'sdc2'}, @@ -1383,32 +1385,36 @@ class ComputeTestCase(test.TestCase): 'no_device': True}] self.compute_api._update_image_block_device_mapping( - self.context, instance_id, mappings) + self.context, instance_type, instance_id, mappings) bdms = [self._parse_db_block_device_mapping(bdm_ref) for bdm_ref in db.block_device_mapping_get_all_by_instance( self.context, instance_id)] expected_result = [ - {'virtual_name': 'swap', 'device_name': '/dev/sdb1'}, - {'virtual_name': 'swap', 'device_name': '/dev/sdb2'}, - {'virtual_name': 'swap', 'device_name': '/dev/sdb3'}, - {'virtual_name': 'swap', 'device_name': '/dev/sdb4'}, + {'virtual_name': 'swap', 'device_name': '/dev/sdb1', + 'volume_size': swap_size}, {'virtual_name': 'ephemeral0', 'device_name': '/dev/sdc1'}, - {'virtual_name': 'ephemeral1', 'device_name': '/dev/sdc2'}, - {'virtual_name': 'ephemeral2', 'device_name': '/dev/sdc3'}] + + # NOTE(yamahata): ATM only ephemeral0 is supported. + # they're ignored for now + #{'virtual_name': 'ephemeral1', 'device_name': '/dev/sdc2'}, + #{'virtual_name': 'ephemeral2', 'device_name': '/dev/sdc3'} + ] bdms.sort() expected_result.sort() self.assertDictListMatch(bdms, expected_result) self.compute_api._update_block_device_mapping( - self.context, instance_id, block_device_mapping) + self.context, instance_types.get_default_instance_type(), + instance_id, block_device_mapping) bdms = [self._parse_db_block_device_mapping(bdm_ref) for bdm_ref in db.block_device_mapping_get_all_by_instance( self.context, instance_id)] expected_result = [ {'snapshot_id': 0x12345678, 'device_name': '/dev/sda1'}, - {'virtual_name': 'swap', 'device_name': '/dev/sdb1'}, + {'virtual_name': 'swap', 'device_name': '/dev/sdb1', + 'volume_size': swap_size}, {'snapshot_id': 0x23456789, 'device_name': '/dev/sdb2'}, {'snapshot_id': 0x3456789A, 'device_name': '/dev/sdb3'}, {'no_device': True, 'device_name': '/dev/sdb4'}, @@ -1430,3 +1436,13 @@ class ComputeTestCase(test.TestCase): self.context, instance_id): db.block_device_mapping_destroy(self.context, bdm['id']) self.compute.terminate_instance(self.context, instance_id) + + def test_ephemeral_size(self): + local_size = 2 + inst_type = {'local_gb': local_size} + self.assertEqual(self.compute_api._ephemeral_size(inst_type, + 'ephemeral0'), + local_size) + self.assertEqual(self.compute_api._ephemeral_size(inst_type, + 'ephemeral1'), + 0) diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index f8b866985..c04851d59 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -169,6 +169,7 @@ class LibvirtConnTestCase(test.TestCase): 'project_id': 'fake', 'bridge': 'br101', 'image_ref': '123456', + 'local_gb': 20, 'instance_type_id': '5'} # m1.small def lazy_load_library_exists(self): @@ -744,6 +745,42 @@ class LibvirtConnTestCase(test.TestCase): ip = conn.get_host_ip_addr() self.assertEquals(ip, FLAGS.my_ip) + def test_volume_in_mapping(self): + conn = connection.LibvirtConnection(False) + swap = {'device_name': '/dev/sdb', + 'swap_size': 1} + ephemerals = [{'num': 0, + 'virtual_name': 'ephemeral0', + 'device_name': '/dev/sdc1', + 'size': 1}, + {'num': 2, + 'virtual_name': 'ephemeral2', + 'device_name': '/dev/sdd', + 'size': 1}] + block_device_mapping = [{'mount_device': '/dev/sde', + 'device_path': 'fake_device'}, + {'mount_device': '/dev/sdf', + 'device_path': 'fake_device'}] + block_device_info = { + 'root_device_name': '/dev/sda', + 'swap': swap, + 'ephemerals': ephemerals, + 'block_device_mapping': block_device_mapping} + + def _assert_volume_in_mapping(device_name, true_or_false): + self.assertEquals(conn._volume_in_mapping(device_name, + block_device_info), + true_or_false) + + _assert_volume_in_mapping('sda', False) + _assert_volume_in_mapping('sdb', True) + _assert_volume_in_mapping('sdc1', True) + _assert_volume_in_mapping('sdd', True) + _assert_volume_in_mapping('sde', True) + _assert_volume_in_mapping('sdf', True) + _assert_volume_in_mapping('sdg', False) + _assert_volume_in_mapping('sdh1', False) + class NWFilterFakes: def __init__(self): diff --git a/nova/tests/test_metadata.py b/nova/tests/test_metadata.py index d63394ad6..ad678714e 100644 --- a/nova/tests/test_metadata.py +++ b/nova/tests/test_metadata.py @@ -44,6 +44,7 @@ class MetadataTestCase(test.TestCase): 'user_data': '', 'image_ref': 7, 'fixed_ips': [], + 'root_device_name': '/dev/sda1', 'hostname': 'test'}) def instance_get(*args, **kwargs): diff --git a/nova/tests/test_virt.py b/nova/tests/test_virt.py new file mode 100644 index 000000000..388f075af --- /dev/null +++ b/nova/tests/test_virt.py @@ -0,0 +1,83 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 Isaku Yamahata +# All Rights Reserved. +# +# 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. + +from nova import flags +from nova import test +from nova.virt import driver + +FLAGS = flags.FLAGS + + +class TestVirtDriver(test.TestCase): + def test_block_device(self): + swap = {'device_name': '/dev/sdb', + 'swap_size': 1} + ephemerals = [{'num': 0, + 'virtual_name': 'ephemeral0', + 'device_name': '/dev/sdc1', + 'size': 1}] + block_device_mapping = [{'mount_device': '/dev/sde', + 'device_path': 'fake_device'}] + block_device_info = { + 'root_device_name': '/dev/sda', + 'swap': swap, + 'ephemerals': ephemerals, + 'block_device_mapping': block_device_mapping} + + empty_block_device_info = {} + + self.assertEqual( + driver.block_device_info_get_root(block_device_info), '/dev/sda') + self.assertEqual( + driver.block_device_info_get_root(empty_block_device_info), None) + self.assertEqual( + driver.block_device_info_get_root(None), None) + + self.assertEqual( + driver.block_device_info_get_swap(block_device_info), swap) + self.assertEqual(driver.block_device_info_get_swap( + empty_block_device_info)['device_name'], None) + self.assertEqual(driver.block_device_info_get_swap( + empty_block_device_info)['swap_size'], 0) + self.assertEqual( + driver.block_device_info_get_swap({'swap': None})['device_name'], + None) + self.assertEqual( + driver.block_device_info_get_swap({'swap': None})['swap_size'], + 0) + self.assertEqual( + driver.block_device_info_get_swap(None)['device_name'], None) + self.assertEqual( + driver.block_device_info_get_swap(None)['swap_size'], 0) + + self.assertEqual( + driver.block_device_info_get_ephemerals(block_device_info), + ephemerals) + self.assertEqual( + driver.block_device_info_get_ephemerals(empty_block_device_info), + []) + self.assertEqual( + driver.block_device_info_get_ephemerals(None), + []) + + def test_swap_is_usable(self): + self.assertFalse(driver.swap_is_usable(None)) + self.assertFalse(driver.swap_is_usable({'device_name': None})) + self.assertFalse(driver.swap_is_usable({'device_name': '/dev/sdb', + 'swap_size': 0})) + self.assertTrue(driver.swap_is_usable({'device_name': '/dev/sdb', + 'swap_size': 1})) |
